[sqlite] Jan Neerbek is out of the office.

2010-07-10 Thread Jan Neerbek

I will be out of the office starting  09-07-2010 and will not return until
02-08-2010.

I will respond to your message when I return. For urgent matters you may
contact BRE


___
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users


[sqlite] pthreadMutexEnter throws assertion (when it should not)

2009-10-13 Thread Jan Neerbek
Hello,

On several machines running Suse10.2 (gcc 4.1.2) we get the following 
assertion
prog: sqlite3.c:15173: pthreadMutexEnter: Assertion `p->id==1 || 
pthreadMutexNotheld(p)' failed.
Aborted

The problem does not seem to occur on Suse11 (gcc 4.3.2), our Ubuntu, nor 
on our Windows platforms.
We are able to reproduce the problem with both sqlite 3.6.18 and 3.6.3 
(have not tried with other versions)

Using the sqlite-amalgamation-3_6_18.zip package I can reproduce the 
problem with a small example. I have included the example main.c below.
The example is compiled as follows:
gcc -DSQLITE_THREADSAFE=1 -DSQLITE_DEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION -g 
 -pthread  -O2 sqlite3.c main.c -o testprog

The assertion occurs when using -O2, -O3, or -Os, but not when using -O.

My best guess at what is going wrong (disclaimer: I am just guessing here, 
feel free to skip this part) is as follows:
Inside pthreadMutexEnter sqlite do:
  pthread_mutex_lock(&p->mutex);
  p->owner = pthread_self();
  p->nRef++;
I believe the two last statements get swap'ed around by the optimizer, 
such that nRef++ occurs first. This leads to a possible race with the 
assertion in the beginning of the pthreadMutexEnter (another thread 
entering while the first thread is updating nRef and owner). 
The reason I think this is because:
1) gdb is not sure of which line it is at when inspecting the two above 
lines
2) If I insert a printf just before the assertion I can see that nRef is 1 
and owner==self (thus another thread has updated nRef but not yet owner)
Note pthreadMutexEnter gets called like 1 times before it fails for 
the first time.
Since newer compilers seems to be less likely to generate the race, it 
might be a known dangerous/faulty optimization pattern in gcc 4.1.2 that 
is causing the issue (however my friend google could not confirm that).

Regards,
Jan

main.c---
#include 
#include 
#include 
#include 

#include "sqlite3.h"


// Compile: gcc -DSQLITE_THREADSAFE=1 -DSQLITE_DEBUG=1 
-DSQLITE_OMIT_LOAD_EXTENSION -g  -pthread  -O2 sqlite3.c main.c -o 
testprog
// Run: ./testprog;rm test.db;./testprog;rm test.db;./testprog
// the problem usually occurs within 1-3 attemps (but only on Suse10.2)

//#threads= 2*NUMBER_OF_QUERIES
#define NUMBER_OF_QUERIES 1
//size of test db
#define NUMBER_OF_ROWS 1024*1024
#define NUMBER_OF_ROWS_PER_OUTPUT 1024*10


static void *read_db(sqlite3_stmt *statement, int id)
{
int i = 0;

for (;;)
{
int res = sqlite3_step(statement);
switch (res)
{
case SQLITE_DONE:
case SQLITE_BUSY:
//continue
break;
case SQLITE_ROW:
{
const unsigned char *text  = 
sqlite3_column_text(statement, 1);
 
if (i % NUMBER_OF_ROWS_PER_OUTPUT == 0)
{
printf("Thread(%d): \"%s\"\n", id, text);
}
i++;
break;
}
case SQLITE_MISUSE:
case SQLITE_ERROR:
default:
printf("Failed to read statement '%d'\n", statement);
res = SQLITE_DONE;
break;
}
if (res == SQLITE_DONE)
break; //done
}
return NULL;
}

static int populate_db(sqlite3 *db)
{
int res = SQLITE_OK;
const char *insert_item = "INSERT INTO MyTable VALUES(%d,'Test data 
for SQLite:%d')";
int size = strlen(insert_item);
char *buf = (char *) malloc((size + 1 + 20)*sizeof(char));
 
if ((res = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL)) != SQLITE_OK)
printf("Failed to start transaction.\n");

if (res == SQLITE_OK)
{
int i = 0;
int insert_max = NUMBER_OF_ROWS; //lots of data to warmup the 
cache
for (i=0;res==SQLITE_OK && iquery;
const char *filename = data->filename;

int res = sqlite3_open(filename, &db);

if (res == SQLITE_OK)
{
if (res == SQLITE_OK && (res = sqlite3_prepare(db, query, -1, 
&resultSet, NULL)) != SQLITE_OK)
printf("Failed to prepare %s statement.\n", data->debugname);
 
read_db(resultSet, data->id);

if (resultSet != NULL)
sqlite3_finalize(resultSet);
sqlite3_close(db);
}
else
{
printf("db open failed!\n");
}
return NULL;
}

int main(int argc, char **argv)
{
const char *filename = "test.db";
const char *query_asc = "SELECT id,name FROM MyTable ORDER by name 
ASC";
const char *query_desc = "SELECT id,name FROM MyTable ORDER by name 
DESC";
int res = SQLITE_OK;

if (argc > 1)
{
printf("Reusing old db\n");
}
else
{
printf("creating test.db file\n");
sqlite3 *db = NULL;
res = sqlite3_open(filename, &db);
if (res == SQLITE_OK)
{
const char *create_table = "CREATE TABLE MyTable (id INTEGER 
PRIMARY KEY AUTOINCREMENT, name VARCHAR2);";

if (re