Without wishing to complicate the subject, I have found that retrying a
sqlite3_step() after receiving SQLITE_LOCKED works fine for me without
needing sqlite3_reset(). I do this in a multi-threaded test app (based
on some old SQLite test code) that I have left running with 10 threads
for a long time and did not encounter any errors. I was using
shared-cache.

Are there perhaps some cases where a reset is required on SQLITE_LOCKED,
and other cases where it can be interpreted the same as SQLITE_BUSY?

Cheers,
Dave.


-----Original Message-----
From: Hynes, Tom [mailto:tom.hy...@inin.com] 
Sent: 06 March 2009 05:10
To: General Discussion of SQLite Database
Subject: Re: [sqlite] shared cache and SQLITE_MISUSE on sqlite3_step()

Thanks Dan!

-----Original Message-----
From: sqlite-users-boun...@sqlite.org
[mailto:sqlite-users-boun...@sqlite.org] On Behalf Of Dan
Sent: Thursday, March 05, 2009 10:08 PM
To: General Discussion of SQLite Database
Subject: Re: [sqlite] shared cache and SQLITE_MISUSE on sqlite3_step()


On Mar 6, 2009, at 2:53 AM, Hynes, Tom wrote:

> Dan,
>
> I am a little confused now about how to treat a SQLITE_LOCKED
> error.  Is this to be treated the same as SQLITE_BUSY (i.e. can
> retry, unless an explicit transaction is in effect and the statement
> is not a COMMIT, in which case should roll back), or should it be
> treated differently?  If the latter, should it generally be handled
> like most other db errors (e.g. SQLITE_CONSTRAINT, SQLITE_CANTOPEN,
> etc.), or is there some specific error handling for SQLITE_LOCKED
> that is recommended?

Usually when sqlite3_step() returns something other than SQLITE_ROW, the
statement needs to be reset (sqlite3_reset()) before execution
can be re-attempted. However, SQLITE_BUSY errors are an exception.
After SQLITE_BUSY is returned, you can call sqlite3_step() again
immediately.
This I either didn't know, or forgot.

An SQLITE_LOCKED error means there is something preventing execution
within the same process. For example a lock on a shared-cache table.
For some applications, for example if another thread may release the
lock shortly, it may be appropriate to retry the query. In other apps,
for example single-threaded apps, it may not.

To retry a query that has failed with an SQLITE_LOCKED error, you need
to reset the statement before trying sqlite3_step() again.

Dan.




> Thanks,
>
> Tom
>
> -----Original Message-----
> From: sqlite-users-boun...@sqlite.org
[mailto:sqlite-users-boun...@sqlite.org
> ] On Behalf Of Dan
> Sent: Thursday, March 05, 2009 12:38 PM
> To: General Discussion of SQLite Database
> Subject: Re: [sqlite] shared cache and SQLITE_MISUSE on sqlite3_step()
>
>
> 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
>
>
> _______________________________________________
> 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

Reply via email to