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

Reply via email to