Woody Wu wrote:
> Hi, Simon
> 
> On 7 January 2014 19:32, Simon Slavin <slav...@bigfraud.org> wrote:
> 
>> On 7 Jan 2014, at 10:13am, Woody Wu <narkewo...@gmail.com> wrote:
>>
>>> Thanks for the clear guide.  _busy_timeout is easier to use.  By the
>>> way, i want confirm that if i am not in an explicit transaction, i can 
>>> simply
>>> redo the _step() invoking, right?
>> However, if you are using _timeout() properly, you should never need to

(That's incorrect. _busy_timeout() can simplify program logic, but *it is not
sufficient* by itself. See below.)

> What means "using _timeout()" properly?  The manual says, _timeout() can
> still make _step() returns SQLITE_BUSY or SQLITE_IOERR_BLOCKED if the user
> provided timeout value eventually accumulated.   For example, if I set
> _timeout() to 3000ms, but after that time, the table I was trying to update
> still locked by another process.  This is normal, right?

sqlite can return BUSY immediately if it detects dead-lock condition (e.g. two
connections issues BEGIN; SELECT ...; UPDATE ...; in parallel).

thread A                        thread B
BEGIN;                          BEGIN;
SELECT; /* acquires SHARED lock*/
                                SELECT; /* also acquires SHARED lock */
             /* (two SHARED locks can coexist!) */
UPDATE; /* upgrades SHARED lock to RESERVED lock */
             /* (one RESERVED lock can coexist with SHARED lock) */
                                UPDATE; /* tries to upgrade to RESERVED lock and
                                           *fails*;
                                           returns SQLITE_BUSY [*immediately*]*/
             /* (only one connection can own RESERVED lock!) */

Note that there are no sense to wait and retry in thread B here, it won't fix
deadlock!
Moreover, if you keep transaction in thread B and thread A will issue COMMIT, it
will fail *too* (after waiting for _busy_timeout), as COMMIT requires EXCLUSIVE
lock, and it cannot be acquired before thread B will release its SHARED lock:

=== If you keep transaction in thread B: ===
thread A:                       thread B:
                                /* still have SHARED lock */
COMMIT; /* tries to upgrade lock to EXCLUSIVE and *fails* [after waiting for
busy_timeout] with SQLITE_BUSY too! (EXCLUSIVE lock cannot coexist with any
other lock) */
===

So, you should either properly handle that (ROLLBACK and retry transaction from
beginning in thread B), or use BEGIN IMMEDIATE with all transaction that *may*
modify database (at some point) [then BEGIN IMMEDIATE acquires RESERVED lock,
and so thread B will wait for _busy_timeout [or return SQLITE_BUSY] before
transaction start).

Note: above scenario apply to ROLLBACK-type journal, WAL is somewhat different
(but, IIRC, above scenario still *can* happen, with slight alterations).

>> recover to an understood situation after a SQLITE_BUSY, since a _BUSY
>> result will always indicate an unrecoverable error.  Therefore you will
>> never need to figure out whether you should be doing a ROLLBACK.  Just
>> _finalize() the operation (then probably _close() and quit the program) and

IMO, _finalize is somewhat overkill (unless you are planning to return error to
user terminate program right after that).
You only need to _reset() all affected (incomplete) statements.

>> it either worked or it didn't.

P.S.
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to