And in addition to Dan's words: if you change "BEGIN" to "BEGIN IMMEDIATE" your code will work as you expect it to.
Pavel On Thu, May 6, 2010 at 12:41 AM, Dan Kennedy <danielk1...@gmail.com> wrote: > > On May 5, 2010, at 8:32 PM, myomancer wrote: > >> Dear Users >> >> I've spent hours reading various web-based documents, examined lots of >> code snippets, written some code of my own, but I still patently do >> not understand SQLite locks. > > 4th paragraph of this page (The presence of a busy...) describes the > condition your program is hitting: > > http://www.sqlite.org/c3ref/busy_handler.html > > > > >> >> My misunderstanding is probably best illustrated with a concrete >> example written in C. >> >> #include <stdio.h> >> #include <stdlib.h> >> #include <sqlite3.h> >> >> int main() >> { >> sqlite3 *db; >> int error; >> sqlite3_stmt *res; >> int count; >> char *sqlite_query; >> >> error = sqlite3_open_v2("simple.db3", &db, SQLITE_OPEN_READWRITE, 0); >> if(error) >> { >> fprintf(stderr, "Can't open database: %s\n", >> sqlite3_errmsg(db)); >> sqlite3_close(db); >> exit(1); >> } >> >> sqlite3_busy_timeout(db, 10000); >> >> sqlite3_exec(db, "BEGIN", NULL, NULL, NULL); >> error = sqlite3_prepare_v2(db, "select count from table1", 100, &res, >> NULL); >> if (error != SQLITE_OK) >> { >> printf("SQLITE_OK is not OK - %d\n", error); >> exit(1); >> } >> >> while (sqlite3_step(res) == SQLITE_ROW) >> { >> count = sqlite3_column_int(res, 0); >> printf("%u", count); >> } >> sqlite3_finalize(res); >> >> count++; >> sqlite_query = sqlite3_mprintf("update table1 set count = %d", >> count); >> error = sqlite3_exec(db, sqlite_query, NULL, NULL, NULL); >> if(error != SQLITE_OK) >> { >> puts(" - error updating count"); >> } >> else >> { >> puts(" - updated OK"); >> } >> >> sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); >> sqlite3_free(sqlite_query); >> sqlite3_close(db); >> >> return 0; >> } >> >> When I run this serially, I get: >> $ ./demo >> 214 - updated OK >> $ ./demo >> 215 - updated OK >> $ ./demo >> 216 - updated OK >> >> When I run it in parallel, using this script: >> >> #!/bin/sh >> >> count=0 >> limit=4 >> while [ ${count} -lt ${limit} ] >> do >> count=`expr $count + 1` >> ./demo 2>&1 & >> done >> >> I get: >> >> $ ./multi.sh >> 219 - updated OK >> 219 - error updating count >> 220 - updated OK >> 220 - error updating count >> >> I thought that this line... >> >> sqlite3_busy_timeout(db, >> 10000); >> >> ...would give me a 10 second window where SQLite would gracefully, >> invisibly take care of locking for me, as per this documentation: >> >> "This routine sets a busy handler that sleeps for a specified amount >> of time when a table is locked. The handler will sleep multiple times >> until at least "ms" milliseconds of sleeping have accumulated. After >> at least "ms" milliseconds of sleeping, the handler returns 0 which >> causes sqlite3_step() to return SQLITE_BUSY or SQLITE_IOERR_BLOCKED." >> >> But things go wrong long before 10 seconds have elapsed, and I get the >> error messages shown. >> >> Now, clearly, SQLite is capable of handling locks, and the fault lies >> with me. Maybe I've simply missed a nuance somewhere, or maybe my >> understanding is fundamentally wrong. I just don't know. I would turn >> cartwheels if somebody could show me what I'm doing wrong in my code, >> and spoon-feed me the canonical way of doing it the right way. I am >> keen to use SQLite, but this locking impass is currently a sticking >> point for me. >> >> Many thanks >> Peter >> _______________________________________________ >> 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 > _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users