You weren't handling your forks correctly.... This works and ends up with 200 rows...take out the srandom() line and you'll get 100 due to random() repeating itself across processes which I hope is what you intended.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sqlite3.h> #define DBNAME "sessiontest.sqlite3" void execute_sql(sqlite3 *db, const char *sql, const char *param) { sqlite3_stmt *stmt; int rc; if(SQLITE_OK != (rc = sqlite3_prepare(db, sql, -1, &stmt, NULL))) { printf("sqlite3_prepare: %s\n", sqlite3_errmsg(db)); abort(); } if(param != NULL) if(SQLITE_OK != sqlite3_bind_text(stmt, 1, param, strlen(param), free)) abort(); while(SQLITE_ROW == (rc = sqlite3_step(stmt))) ; if(SQLITE_DONE != rc) { printf("sqlite3_step: %s\n", sqlite3_errmsg(db)); abort(); } if(SQLITE_OK != sqlite3_finalize(stmt)) { printf("sqlite3_finalize: %s\n", sqlite3_errmsg(db)); abort(); } } int main(void) { sqlite3 *db; int i, j, status; char *p; if(0 != unlink(DBNAME)) if(errno != ENOENT) abort(); if(0 != sqlite3_open(DBNAME, &db)) abort(); if(SQLITE_OK != sqlite3_exec(db, "BEGIN", NULL, NULL, NULL)) abort(); execute_sql(db, "CREATE TABLE sessions (sid TEXT, UNIQUE(sid));", NULL); if(SQLITE_OK != sqlite3_exec(db, "COMMIT", NULL, NULL, NULL)) abort(); if(0 != sqlite3_close(db); abort(); for(i = 0; i < 2; ++i) { /* TWO processes */ int childpid = fork(); if (childpid < 0) { perror("fork"); abort(); } if (childpid==0) { int mypid = getpid(); srandom(mypid); if(0 != sqlite3_open(DBNAME, &db)) abort(); for(i = 0; i < 100; ++i) { p = malloc(16); if(p == NULL) abort(); for(j = 0; j < 15; ++j) p[j] = 'a' + (random() % 26); p[j] = '\0'; if(SQLITE_OK != sqlite3_exec(db, "BEGIN", NULL, NULL, NULL)) { perror(sqlite3_errmsg(db)); abort(); } execute_sql(db, "INSERT OR REPLACE INTO sessions VALUES (?);", p); if(SQLITE_OK != sqlite3_exec(db, "COMMIT", NULL, NULL, NULL)) { printf("sqlite3_exec(COMMIT): %s\n", sqlite3_errmsg(db)); abort(); } } sqlite3_close(db); return; } else { // parent just waits for children to finish wait(&status); } } return 0; } Michael D. Black Senior Scientist Advanced Analytics Directorate Advanced GEOINT Solutions Operating Unit Northrop Grumman Information Systems ________________________________________ From: sqlite-users-boun...@sqlite.org [sqlite-users-boun...@sqlite.org] on behalf of Helmut Grohne [hel...@subdivi.de] Sent: Thursday, September 20, 2012 5:45 AM To: sqlite-users@sqlite.org Subject: EXT :Re: [sqlite] Potential SQLITE_LOCKED bug? Richard Hipp pointed out that the list strips attachments. For completeness I am copying the complete mail here. Please CC me in reply as I am not subscribed. Original message follows: I am occasionally receiving SQLITE_LOCKED in a forking Python application. Now according to the documentation http://www.sqlite.org/cvstrac/wiki/wiki?p=DatabaseIsLocked and http://www.sqlite.org/c_interface.html I should only get this error if two actions happen on the same connection in parallel (either via threads or via recursive calls). Since I have no clue why this happens I reproduced the problem in a small example C program. Find sessiontest.c attached. So compile sessiontest.c and link it against sqlite on a unixoid platform. Ensure that the filename "sessiontest.sqlite3" is absent and writeable in the working directory. Run the executable. Observed behaviour: sqlite3_exec(COMMIT): database is locked sqlite3_prepare: database is locked Expected behaviour: SQLITE_BUSY or no error, but certainly not SQLITE_LOCKED. Rationale: My example program first forks and then opens individual connections. So sharing via file descriptors or threads is not possible. Also my program does not pass handlers (besides free) to sqlite, so it cannot cause recursive calls. Therefore SQLITE_LOCKED should never happen. System used: Debian squeeze amd64 libsqlite3-0 3.7.3-1 Debian sid amd64 libsqlite3-0 3.7.13-1 Is this behaviour correct? If yes, why? Any proposed workarounds? Thanks in advance Helmut #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sqlite3.h> #define DBNAME "sessiontest.sqlite3" void execute_sql(sqlite3 *db, const char *sql, const char *param) { sqlite3_stmt *stmt; int rc; if(SQLITE_OK != (rc = sqlite3_prepare(db, sql, -1, &stmt, NULL))) { printf("sqlite3_prepare: %s\n", sqlite3_errmsg(db)); abort(); } if(param != NULL) if(SQLITE_OK != sqlite3_bind_text(stmt, 1, param, strlen(param), free)) abort(); while(SQLITE_ROW == (rc = sqlite3_step(stmt))) ; if(SQLITE_DONE != rc) abort(); if(SQLITE_OK != sqlite3_finalize(stmt)) abort(); } int main(void) { sqlite3 *db; int i, j; char *p; if(0 != unlink(DBNAME)) if(errno != ENOENT) abort(); if(0 != sqlite3_open(DBNAME, &db)) abort(); if(SQLITE_OK != sqlite3_exec(db, "BEGIN", NULL, NULL, NULL)) abort(); execute_sql(db, "CREATE TABLE sessions (sid TEXT, UNIQUE(sid));", NULL); if(SQLITE_OK != sqlite3_exec(db, "COMMIT", NULL, NULL, NULL)) abort(); if(0 != sqlite3_close(db)) abort(); for(i = 0; i < 2; ++i) /* FOUR processes */ if(fork() < 0) abort(); if(0 != sqlite3_open(DBNAME, &db)) abort(); for(i = 0; i < 100; ++i) { p = malloc(16); if(p == NULL) abort(); for(j = 0; j < 15; ++j) p[j] = 'a' + (random() % 26); p[j] = '\0'; if(SQLITE_OK != sqlite3_exec(db, "BEGIN", NULL, NULL, NULL)) abort(); execute_sql(db, "INSERT OR REPLACE INTO sessions VALUES (?);", p); if(SQLITE_OK != sqlite3_exec(db, "COMMIT", NULL, NULL, NULL)) { printf("sqlite3_exec(COMMIT): %s\n", sqlite3_errmsg(db)); abort(); } } sqlite3_close(db); return 0; } _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users