You can't simply loop on retrying the last sqlite3_* call.  You need to
rollback one of the transactions and retry the entire transaction.  Your two
threads are deadlocked because (roughly) each has acquired a lock that the
other needs.  One needs to release the locks it holds.  Rolling back is the
way to do that.

--Ned.
http://nedbatchelder.com
 

-----Original Message-----
From: Doug Nebeker [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, 30 November, 2005 11:04 AM
To: sqlite-users@sqlite.org
Subject: [sqlite] Concurrency handling question

I've written a C++ wrapper for SQLite which has been working great.
Lately though I've started getting what might be deadlocks when running
two threads against the same database.  One thread is a reader and the
other is a writer (at the moment, I'm getting 'database locked' errors,
but that's after many hours of failures so not sure where it started).
It's possible to have two or three readers and/or writers, but not more
than that.

Each thread has it's own database handle, however, I keep the database
handle open for many calls (where each 'call' opens a transaction,
executes SQL statements, then closes the transaction).

I've read about concurrency, and it sounds like the best way to work is
just to retry the last call if SQLITE_BUSY is ever returned, but that
doesn't seem to be working for me in this case.  I've stripped my main
processing loop down to make it concise (it is not completely correct
nor will it compile as shown, but it shows the flow).

Can anyone see what I'm doing wrong?  Is the fact that I keep the
database handle open between calls and between retries the problem?  If
the retry loops finally fails, sqlite3_finalize gets called,
sqlite3_close and then sqlite3_open16 to re-initialize the state.

Thanks in advance for any insight.

        do
        {
                long prepareLoopCount = 0;

PrepareLoop:
                if(SQLITE_BUSY == (res = sqlite3_prepare16(m_hDB,
nextStatement, -1, &pStmt, &tail)))
                {
                        if(prepareLoopCount++ < 200)
                        {
                                Sleep(300 ms);
                                goto PrepareLoop;
                        }
                }

                if((SQLITE_OK == res) && (NULL != pStmt)) 
                {
                        long stepLoopCount = 0;
StepLoop:
                        res = sqlite3_step(pStmt);
                        if(SQLITE_BUSY == res)
                        {
                                if(stepLoopCount++ < 200)
                                {
                                        Sleep(300 ms);
                                        goto StepLoop;
                                }
                        }
                        else do other processing like fetching the
rows....

                }

                if(NULL != pStmt)
                {
                        sqlite3_finalize(pStmt);
                        pStmt = NULL;
                }
        }
        while(NULL != nextStatement)


To find out more about Reuters visit www.about.reuters.com

Any views expressed in this message are those of the individual sender,
except where the sender specifically states them to be the views of Reuters
Ltd.


Reply via email to