On Mar 6, 2009, at 12:22 AM, Marcus Grimm wrote: > 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.
Huh. My mistake. > 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 _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users