I understand your logic about retrying on a SQLITE_BUSY return.  This is a
little difficult because of abstraction layers.  I have a generic sqlite
Exec method that is used for many different statements.  If the database is
busy during a commit, my busy handler will be called.  If the database is
busy during an update, my busy handler will not be called.  If the
sqlite3_exec function returns BUSY, I should retry immediately, but only if
my busy handler wasn't called.  The bookkeeping gets messy. 

I would appreciate being able to control this behavior.  Perhaps a pragma or
database setting?  At the very least, a compile-time switch?  I know this
increase the complexity of testing, but one of the reasons I made the switch
from SQLite 2 to SQLite 3 was to get the increased concurrency, and I really
like being able to control the deadlock behavior. 

--Ned.
-----Original Message-----
From: D. Richard Hipp [mailto:[EMAIL PROTECTED] 
Sent: Monday, August 16, 2004 4:38 PM
To: [EMAIL PROTECTED]
Subject: Re: [sqlite] Concerns about checkin 1879

Ned Batchelder wrote:
> 
> With the change in checkin 1879, it looks like my busy handler doesn't
> get a chance to make a choice any more.  Now thread B immediately gets a
> BUSY error, without invoking the busy handler.
> 
> Wouldn't it be better to invoke the busy handler in all cases?  Have I
> gotten something wrong?
> 

What I found is that most programmers are simply calling
sqlite3_busy_timeout() to set (say) a 10-second timeout on
all locks.  Then they merrily begin issuing SQL statements
in multiple threads.  In that scenario, the old behavior
prior to check-in [1879] was causing deadlocks that resulted
in nasty 10-second timeouts and all kinds of resulting
performance difficulties.  One could, as you observer, handle
the busy callbacks more intelligently and make an informed
choice about which thread to rollback.  But most programmers
would probably prefer to not have to worry with such choices.
The default behavior should be to do the thing that is right
most of the time.  And that is what check-in [1879] does.
Most of the time when you have thread A that is trying to
commit and thread B which is trying to do its very first
update, you'd rather rollback thread B.  Prior to check-in
[1879], the transaction that rolls back was arbitrary and
the rollback only occurred after a long delay.

More sophisticated programs that want more control can still
have it, even with check-in [1879].  If thread A is trying
to COMMIT and thread B is trying to UPDATE, you will get
a busy handler callback from thread A and an SQLITE_BUSY
reply from thread B.  But the SQLITE_BUSY return from thread
B did not clear any locks.  There is nothing that prevents
the program from rolling back thread A then reissuing the
UPDATE statement of thread B.

But even with check-in [1879], I'm finding that a lot of
users are getting all twisted up around locking.  So I'm
thinking of going back to the 2.8 behavior of taking out
an exclusive lock the moment you begin a transaction.  This
reduces the amount of concurrency but it also makes locking
easier to understand for programmers who have more pressing
things to worry with.  A PRAGMA or a new API could be used
to reenable the enhanced-concurrency behavior that was
introduced with version 3.0.  If I make that change, perhaps
I'll start issuing busy callbacks for all lock types again.
We'll see...



-- 
D. Richard Hipp -- [EMAIL PROTECTED] -- 704.948.4565



Reply via email to