Found it!!!

The problem were some SQL statements in Thread1 that called sqlite3_reset() 
before evaluation using sqlite3_step().

It worked alright in the single threaded unit test, but not in the 
multi-threaded application.

It seems that it is very important that every statement evaluation is concluded 
with a sqlite3_reset() (or sqlite3_finalize() if the statement is not going to 
be used anymore). I found an old discussion

http://sqlite.1065341.n5.nabble.com/Sqlite3-reset-needed-td7927.html

were it was stated that

"You should be in the habit of calling sqlite3_reset() on each query as soon as 
that query finishes. Otherwise the query *might* leave a read-lock on the 
database file and thus prevent subsequent write operations for working 
correctly."

I suppose that the "*might* locking part" should be explicitly stated in the 
SQLite API documentation for step/reset.


However, now it works like a charm :)


Pavel, thanks for your input.

Pontus



________________________________
 Från: Pavel Ivanov <paiva...@gmail.com>
Till: Pontus Bergsten <pontus_bergs...@yahoo.se>; General Discussion of SQLite 
Database <sqlite-users@sqlite.org> 
Skickat: onsdag, 20 juni 2012 17:45
Ämne: Re: [sqlite] Problem with concurrent transaction and DETACH DATABASE
 
It looks to me that you have corrupted memory or already closed
database at this point. AFAIK, ROLLBACK cannot return SQLITE_ERROR in
any "normal" situation (I exclude such situations as faulty disk or
some similar I/O error), normally it can return only SQLITE_BUSY.
Check your application in valgrind.

Pavel

On Wed, Jun 20, 2012 at 11:27 AM, Pontus Bergsten
<pontus_bergs...@yahoo.se> wrote:
> Let's see, the code in Thread 2 then look something like this:
>
>
> {
>    ...
>
>    copy data
>
>    request mutex
>
>    sqlite3_get_autocommit         returns 1 ( Autocommit mode enabled )
>
>    exec("ROLLBACK")               returns 1 ( SQLITE_ERROR )
>
>    exec("DETACH DATABASE Dest")   returns 1( SQLITE_ERROR )
>    release mutex
>    ...
>
> }
>
> as before copying data from "main" to "Dest" before entering the synchronized 
> section is successful, but detach fails.
>
>
> Pontus
>
>
>
> ________________________________
>  Från: Pavel Ivanov <paiva...@gmail.com>
> Till: Pontus Bergsten <pontus_bergs...@yahoo.se>; General Discussion of 
> SQLite Database <sqlite-users@sqlite.org>
> Skickat: onsdag, 20 juni 2012 16:24
> Ämne: Re: [sqlite] Problem with concurrent transaction and DETACH DATABASE
>
> Then something else should happen in your application besides the
> given pseudo code. Could you try to check what
> sqlite3_get_autocommit() returns and execute rollback under the mutex
> but before doing detach?
>
> Pavel
>
>
> On Wed, Jun 20, 2012 at 10:11 AM, Pontus Bergsten
> <pontus_bergs...@yahoo.se> wrote:
>>
>>
>>> I guess you meant Thread 1 in the last sentence. And how do you know
>>> that? Do you check the return code?
>>
>> You are absolutely right, I meant Thread 1. We are checking the return value 
>> of the commit statement which indicate success ( 0 ).
>>
>> Pontus
>>
>>
>>>Pavel
>>>
>>>
>>>On Wed, Jun 20, 2012 at 9:27 AM, Pontus Bergsten
>> <pontus_bergs...@yahoo.se> wrote:
>>> Thanks for the response,
>>>
>>>
>>> In fact, Thread 2 uses a series of INSERT INTO...SELECT queries to transfer 
>>> data in chunks in a loop, from "main" to "Dest". The queries are prepared 
>>> once in the beginning of the transfer loop. In each iteration the 
>>> statements are bounded with new time interval parameters and reset, before 
>>> the query is executed.
>>>
>>>
>>> Thread 1 is using transaction statements "BEGIN" and "COMMIT" to start and 
>>> commit transactions. As we know the commit statement in Thread 2 does not 
>>> fail.
>>>
>>> Any ideas?
>>>
>>> Pontus
>>>
>>>
>>>
>>> ________________________________
>>>  Från: Pavel Ivanov <paiva...@gmail.com>
>>> Till: Pontus Bergsten <pontus_bergs...@yahoo.se>; General Discussion of 
>>> SQLite Database <sqlite-users@sqlite.org>
>>> Skickat: onsdag, 20 juni 2012 14:27
>>> Ämne: Re: [sqlite] Problem with concurrent transaction and DETACH DATABASE
>>>
>>> Probably the following scenario is possible in your situation:
>>> - thread 1 locks transaction mutex
>>> - thread 1 inserts buffered data
>>> - thread 2 starts transferring data to Dest database
>>> - thread 1 tries to commit, commit fails (do you check return code
>>> from it?), transaction is left open
>>> - thread 1 unlocks mutex
>>> - thread 2 locks mutex
>>> - thread 2 tries to detach and fails
>>>
>>> So do you check return code from commit? And do you really use only
>>> INSERT INTO ... SELECT in thread 2 and no other SELECT queries?
>>>
>>>
>>> Pavel
>>>
>>>
>>> On Wed, Jun 20, 2012 at 7:42 AM, Pontus Bergsten
>>> <pontus_bergs...@yahoo.se> wrote:
>>>> In our application we have two threads implementing a signal logger 
>>>> functionality, see pseudo code below.
>>>> Thread 1: Reads signal data, and log to a global in-memory SQLite database 
>>>> after a pre-determined number of reads.
>>>>
>>>>  1   while( true )
>>>>  2  {
>>>>  3     // Buffer data, blocks until new data is available
>>>>  4     buffer.append( readData() )
>>>>  5     ++numberOfReads;
>>>>  6
>>>>
>>>>  7     if ( numberOfReads == maxReads )
>>>>  8     {
>>>>  9        globalTransactionMutex.request()
>>>> 10
>>>> 11        begin transaction
>>>> 12        insert bufferered data to "main" in GlobalDbConnection
>>>>
>>>> 13        commit transaction
>>>> 14
>>>>
>>>> 15        globalTransactionMutex.release()
>>>> 16        numberOfReads = 0;
>>>> 17     }
>>>>
>>>> 18   }
>>>>
>>>>
>>>> Thread 2: Upon user action, transfer data within a specified time window 
>>>> from the in-memory database to a database file
>>>>
>>>> 19  while( true )
>>>>
>>>> 20  {
>>>> 21     waitForUserAction()
>>>> 22
>>>>
>>>> 23     DestDbConnection = Create destination database file Dest.db
>>>>
>>>> 24     close DestDbConnection
>>>> 25
>>>>
>>>> 26     attach Dest.db with GlobalDbConnection as "Dest"
>>>>
>>>> 27     transfer log data from "main" to "Dest" in GlobalDbConnection using 
>>>> INSERT INTO Dest SELECT FROM main
>>>>
>>>> 28
>>>>
>>>> 29     globalTransactionMutex.request()
>>>> 30     detach "Dest" from GlobalDbConnection
>>>>
>>>> 31     globalTransactionMutex.release()
>>>> 32  }
>>>>
>>>> Attaching the destination database Dest.db and transferring data (23)-(27) 
>>>> work without any hassle.
>>>>
>>>> The problem we're facing is that the detach statement (30) fails with 
>>>> error message "SQL Logic error or missing database".
>>>>
>>>> The transaction is protected with a mutex, so it should not be possible to 
>>>> execute the detach statement (30) during an ongoing transaction. Moreover, 
>>>> both threads have the same priority, so we don't have any dead-lock issues.
>>>>
>>>> The code in Thread 2 (19) -(32) seems to work fine in a single threaded 
>>>> unit test. We're using SQLite v. 3.6.21 on Windows XP.
>>>>
>>>>
>>>> Does anyone have any idea about the source of this problem? Have we missed 
>>>> something regarding SQLite and multi-threading?
>>>>
>>>>
>>>> Regards,
>>>>
>>>> Pontus Bergsten
>>>> _______________________________________________
>>>> 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