Dan, I'm not sure what you mean by technically the SQLITE_BUSY is also wrong. In the test program I get the SQLITE_BUSY quite often and by retrying the sqlite3_step() it will sooner or later succeed. I guess you mean that there are condition when a BUSY state will NOT allow to retry the sqlite3_step like mentioned in the docs for sqlite3_step: "If the statement is not a COMMIT and occurs within a explicit transaction then you should rollback the transaction before continuing." I have to think about if I have such a condition.
Thanks for confirming that it may happend only for the first call to sqlite3_step(). This is an important point and it makes it in fact easy to workaround. I've changed my test application accordingly and now it can run endless, I even increased now to 10 reader threads and 2 writer threads in parallel without making sqlite particular nervous. Wonderful... :-) Thanks again Marcus Dan wrote: > On Mar 5, 2009, at 11:14 PM, Marcus Grimm wrote: > >> Hi Dan, >> >> thank you! >> >> Yes! I was not aware that it is wrong to redo a step >> when it previously returned the LOCKED state. >> That was the reason for the (correct) MISSUSE return on >> the 2nd attempt. >> >> I think this is the main difference in my case between >> shared cache on/off: Without shared cache I never >> get this lock state and it just does the BUSY handling correctly. > > Technically the SQLITE_BUSY handling is also wrong, for the > same reasons. But it's harder to hit a real SQLITE_BUSY than it > is to hit an SQLITE_LOCKED in shared-cache mode. > >> I'll change my locking handling accordingly, seems to be a problem >> of the very first step after a prepare, so that's should to be easy >> to reset... > > That's correct. An SQLITE_LOCKED or SQLITE_BUSY may only occur > on the first call to sqlite3_step(). > > Dan. > > > >> Thanks again for your feedback >> >> Marcus >> >> Dan wrote: >>> On Mar 5, 2009, at 9:57 PM, Marcus Grimm wrote: >>> >>>> Hi again, >>>> >>>> I did a little test program that simulates the multi threading >>>> issue to understand better why I get a MISSUSE error even >>>> when sqlite_prepare returns no error. >>>> The test program will printout some errors on the console >>>> and exits in that case. If I don't use the shared cache it >>>> runs endless without any problem. >>>> >>>> The code is to long to be placed here, but I would be very happy >>>> if somebody could take a look. I've put it on a web server to >>>> download: >>>> >>>> http://www.exomio.de/sqlitethreadtest.c >>>> >>>> I'm using MS Visual Studio 2008, the program is started within a >>>> dosbox to see the error output. Using it on my dual core PC >>>> it allmost immediately stops with the missuse error, ....but why? >>> do >>> { >>> rc = sqlite3_step(hs); >>> >>> if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) >>> { >>> Sleep(SQLTM_TIME); >>> >>> n++; >>> } >>> }while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == >>> SQLITE_LOCKED))); >>> >>> If sqlite3_step() returns SQLITE_BUSY or SQLITE_LOCKED, you need to >>> reset the statement before trying the sqlite3_step() again. >>> >>> Dan. >>> >>> >>> >>> >>>> Thanks you >>>> >>>> kind regards >>>> >>>> Marcus Grimm >>>> >>>> Marcus Grimm wrote: >>>>> Hi Ken, >>>>> >>>>> yes, I do check the return values also for the >>>>> sqlite3_prepare_v2 call. This is allways >>>>> successful, the first sqlite_step call right after >>>>> this one returns the magic MISSUSE. >>>>> >>>>> Yes, I also tried to call sqlite_reset right >>>>> after this first error and in this case >>>>> sqlite_reset return the LOCK state. I didn't >>>>> yet go on to handle this... >>>>> >>>>> I can't post the code of the original implementation here, >>>>> but also for my debugging and tests I'll produce >>>>> a simplified test application. Just to see if that >>>>> can be used to reproduce the effect. If that one runs >>>>> without any problem, it's my fault, if not: I'll post >>>>> it here for further discussions... ;) >>>>> >>>>> Thanks for your feedback >>>>> >>>>> Marcus >>>>> >>>>> >>>>>> Marcus, >>>>>> >>>>>> I'm not sure if this will help or not... >>>>>> >>>>>> But I noticed your sample code does not test the return value from >>>>>> the >>>>>> sqlite3_prepare_v2 call. Could the code be entering the do loop >>>>>> when an >>>>>> error was returned from prepare? >>>>>> >>>>>> Just an idea. >>>>>> >>>>>> Have you tried the reset call as DRH had suggested? >>>>>> Your prior post indicated you had more code and another loop. Can >>>>>> you post >>>>>> the full code for both loops? >>>>>> >>>>>> HTH >>>>>> >>>>>> >>>>>> >>>>>> --- On Wed, 3/4/09, Marcus Grimm <mgr...@medcom-online.de> wrote: >>>>>> >>>>>>> From: Marcus Grimm <mgr...@medcom-online.de> >>>>>>> Subject: Re: [sqlite] shared cache and SQLITE_MISUSE on >>>>>>> sqlite3_step() >>>>>>> To: kennethinbox-sql...@yahoo.com, "General Discussion of SQLite >>>>>>> Database" <sqlite-users@sqlite.org> >>>>>>> Date: Wednesday, March 4, 2009, 4:31 PM >>>>>>> Ken, >>>>>>> >>>>>>> you are of course right that it needs some checks >>>>>>> for locks and busy states. I left that out to >>>>>>> simplify the code given below. My original code >>>>>>> checks that and it usually works quite well. >>>>>>> that's basically the reason why I was puzzled >>>>>>> by the randomly MISUSE results after I added the shared >>>>>>> cache. >>>>>>> >>>>>>> I'm not yet finished with my debugging since it is a >>>>>>> multithreading/collision issue - ugly to trace. >>>>>>> >>>>>>> My feeling is that it is related to the condition when >>>>>>> one thread is attempting or holding an exclusive lock >>>>>>> while another thread is just doing an sqlite_step (read >>>>>>> only) >>>>>>> on an allready created statement. Both threads use their >>>>>>> own >>>>>>> DB connections. For example: when I do a sqlite_reset >>>>>>> right after sqlite_step returns SQLITE_MISUSE, as Richard >>>>>>> suggest, >>>>>>> I get immediately a SQLITE_LOCK return code from >>>>>>> sqlite_reset in this case. Why I didn't get that before >>>>>>> or >>>>>>> from the sqlite_prepare ? >>>>>>> >>>>>>> Anyway, I'm going on to workaround this.... ALso I >>>>>>> would like >>>>>>> to mention once more that it is only during an artificial >>>>>>> stress >>>>>>> test, mainly to verify my implementation. Under normal >>>>>>> usercondition it is very unlikely to happend and sqlite >>>>>>> works perfect as expected. >>>>>>> >>>>>>> Thanks >>>>>>> >>>>>>> Marcus >>>>>>> >>>>>>>> Marcus, >>>>>>>> >>>>>>>> You might want to also add some checks in for >>>>>>> sqlite_busy as on the result >>>>>>>> of the prepare and the first call to sqlite_step. >>>>>>>> >>>>>>>> >>>>>>>> On the inner loop test for the most common case first >>>>>>> (SQLITE_ROW) then >>>>>>>> test for errors... Slight performance improvement... >>>>>>>> >>>>>>>> >>>>>>>> --- On Wed, 3/4/09, Marcus Grimm >>>>>>> <mgr...@medcom-online.de> wrote: >>>>>>>>> From: Marcus Grimm <mgr...@medcom-online.de> >>>>>>>>> Subject: Re: [sqlite] shared cache and >>>>>>> SQLITE_MISUSE on sqlite3_step() >>>>>>>>> To: "General Discussion of SQLite >>>>>>> Database" <sqlite-users@sqlite.org> >>>>>>>>> Date: Wednesday, March 4, 2009, 10:25 AM >>>>>>>>> Richard, thanks again for the feedback. >>>>>>>>> >>>>>>>>> However, I don't see how it can happend that >>>>>>> the >>>>>>>>> statement >>>>>>>>> is completed internally without returning >>>>>>> SQLITE_DONE. >>>>>>>>> In the particular code of the "reading >>>>>>> thread" I >>>>>>>>> do something like: >>>>>>>>> >>>>>>>>> -- >>>>>>>>> sqlite3_prepare_v2(db, "SELECT * FROM >>>>>>> TableA", >>>>>>>>> -1, &stmt, 0); >>>>>>>>> /** step throu table result **/ >>>>>>>>> do >>>>>>>>> { >>>>>>>>> rc = sqlite3_step(stmt); >>>>>>>>> if( rc == SQLITE_MISUSE ) >>>>>>>>> { fprintf(stderr, "ERROR...\n"); >>>>>>> break; } >>>>>>>>> else >>>>>>>>> if( rc == SQLITE_ROW ) >>>>>>>>> read_data_etc(); >>>>>>>>> else >>>>>>>>> break; >>>>>>>>> }while( rc != SQLITE_DONE ); >>>>>>>>> >>>>>>>>> sqlite3_finalize(stmt); >>>>>>>>> -- >>>>>>>>> >>>>>>>>> The prepare statement pointer is defined locally >>>>>>> and no >>>>>>>>> other >>>>>>>>> thread can access it, except sqlite internal >>>>>>> maybe. >>>>>>>>> To me it looks that in case a parallel thread is >>>>>>> inserting >>>>>>>>> or >>>>>>>>> updating data, the above loop is somehow affected >>>>>>> and >>>>>>>>> returns the >>>>>>>>> MISUSE. >>>>>>>>> >>>>>>>>> Your reply so far indicates either a bug on my >>>>>>> side or a >>>>>>>>> missusage. >>>>>>>>> I'll go on and try to find the reason why the >>>>>>> magic >>>>>>>>> number is resetted >>>>>>>>> without knowing from calling functions. >>>>>>>>> >>>>>>>>> calling sqlite3_reset in these cases is difficult >>>>>>> for me >>>>>>>>> since it might >>>>>>>>> not be the first step and previous data is >>>>>>> allready in use >>>>>>>>> in the upper loop. >>>>>>>>> But maybe an option for the very first step if >>>>>>> that >>>>>>>>> fails... hm... I'll try that. >>>>>>>>> >>>>>>>>> >>>>>>>>> Thanks again >>>>>>>>> >>>>>>>>> kind regards >>>>>>>>> >>>>>>>>> Marcus Grimm >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> D. Richard Hipp wrote: >>>>>>>>>> On Mar 4, 2009, at 9:35 AM, Marcus Grimm >>>>>>> wrote: >>>>>>>>>>> hi, >>>>>>>>>>> >>>>>>>>>>> OK, the value of p->magic is 519C2973 >>>>>>>>> (VDBE_MAGIC_HALT) >>>>>>>>>> That means the prepared statement has run to >>>>>>>>> completion and needs to >>>>>>>>>> be reset using sqlite3_reset() before you >>>>>>> continue. >>>>>>>>>> D. Richard Hipp >>>>>>>>>> d...@hwaci.com >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>> _______________________________________________ >>>>>>>>>> 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 >>>>> _______________________________________________ >>>>> 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 >>> >> -- >> _______________________________________________ >> 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