>There are two possibilities:

>1. Transactions do work, but I'm misusing them and must learn how to
>be more careful.  In this case, I will update documentation to
>properly explain their use to others.

>2. Transactions don't work, at least not for my task.  In this case,
>I will do my best to investigate the problem and suggest a
>correction.

>Either way, the right thing for me to do is continue digging in.

>Going from BEGIN to BEGIN IMMEDIATE indeed fixed the test program I
>wrote, but my application is still broken, and I don't know what's
>different about it.  I'm working on instrumenting the fcntl() calls
>to log the sequence of operations.

Transactions do work provided you use them properly.  The rules you need to 
obey are:

Make sure you are doing nothing foolish like using "shared cache".  Doing so 
changes how things work considerably and open a completely different kettle of 
fish.

Make sure that you are using the default SERIALIZED or FULLMUTEX thread 
management on all connections whether you think you know better or do not need 
it or whatever.  A few microseconds of CPU might save you many MONTHS of trying 
to locate a defect in your code.

If you think that you need to use either "shared cache" or some threading mode 
other than the default serialized, then do that ONLY AFTER your application is 
working using the defaults.  Do not fall into the premature optimization trap.

Place all read and write statements which require a consistent database context 
in the same transaction.  Context may change BETWEEN transactions but will not 
change WITHIN a transaction.  That is, if you are executing multiple SELECT 
statements which require a consistent view of the database then they should all 
be located in the same read transaction.  If you are selecting data and then 
performing updates based on the retrieved data, those operations need to occur 
within the same write transaction.  SQLite3 does not have cursors and does not 
do UPDATE ... WHERE CURRENT OF CURSOR nor does it do SELECT ... FOR UPDATE OF 
... which means that processing an update may mutate what you are reading and 
therefore you should complete your read before performing the update.

IF THE TRANSACTION WILL OR MAY WRITE TO THE DATABASE AT SOME POINT BEFORE 
COMMIT/ROLLBACK then start the transaction with BEGIN IMMEDIATE.

IF THE TRANSACTION WILL ONLY READ AND CANNOT EVER WRITE TO THE DATABASE BEFORE 
COMMIT/ROLLBACK then start the transaction with BEGIN DEFERRED (this is the 
default for a naked BEGIN).

Transactions are an attribute of the DATABASE CONNECTION and not of a STATEMENT 
(a STATEMENT is an attribute of a CONNECTION).  Multiple STATEMENTs may execute 
concurrently sharing a single CONNECTION (and hence transaction) context.

In DELETE or TRUNCATE (that is, all modes except WAL) a READ transaction in 
progress blocks a WRITE transaction and a WRITE transaction in progress blocks 
all other attempts to commence a transaction of any type on any other 
connection.  WAL mode permits READ and WRITE to proceed independantly provided 
that the WRITE transaction must only be performed against the "current" (head) 
database context and will fail if the context is not the head context at the 
time the attempt is made to obtain the WRITE lock (and since there is only one 
"current" head, there can only be one WRITE in progress at a time).

An attempt to UPGRADE a READ transaction to a WRITE transaction will DEADLOCK 
(and immediately return an error) if another WRITE TRANSACTION is pending.  
(Hence always signal your intent when commencing a transaction by using the 
appropriate BEGIN syntax in order to avoid this state of affairs).

WAL journalling only works where all database user processes are local to each 
other (ie, between connections all originating from the same computer -- where 
"same computer" means all processes have access to the same shared memory, so 
that you may determine whether a SYSPLEX or NUMA architecture constitutes "same 
computer" or not, by whether or not they can all access the same "shared 
memory" region).

File locking only works reliably on local filesystems.  It is unreliable for 
*ALL* remote filesystems, even if the target "remote" filesystem is local.

A local filesystem is defined as one wherein the filesystem code resides and is 
executed "on the same computer" as the application.  See the requirement 2 
above to determine the meaning of "same computer".  The cable between the 
"computer running the filesystem code" and the "block storage device" may have 
a length varying from inches to many thousands of miles.  The command language 
the "filesystem" uses to access the underlying block storage is irrelevant (it 
may be ATA, SATA, SCSI, SAS, iSCSI, SAC (SCSI over Avian Carriers) or what ever 
your heart may desire).

---
The fact that there's a Highway to Hell but only a Stairway to Heaven says a 
lot about anticipated traffic volume.




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

Reply via email to