sqlite: use immediate transactions to prevent busy errors
commit86129e5d8c816098deca485662a55163afe6a761
authorEric Wong <normalperson@yhbt.net>
Sat, 20 Oct 2012 00:35:54 +0000 (20 00:35 +0000)
committerEric Wong <normalperson@yhbt.net>
Wed, 9 Jan 2013 03:32:00 +0000 (9 03:32 +0000)
treea9eaece0a9743ec1f0e4affe35c5d64d3258b135
parentee5f196ae0b11e893f880cc5df8699290120797f
sqlite: use immediate transactions to prevent busy errors

The default (deferred) transaction mode in SQLite delays
locking, potentially leading to "database is locked" errors on
concurrent access.  Immediate transactions lock the database
immediately, preventing unnecessary errors at the cost of
reduced concurrency.

I've still occasionally encountered a "database is locked"
or two on my SQLite deployment with many workers over the
months.

Tested on MySQL, Postgres, and DBD::SQLite 1.29 and 1.37.
This feature appeared in DBD::SQLite 1.30, but the extra
attribute for DBI->connect is harmless for drivers which
do not support this attribute.

ref: http://search.cpan.org/dist/DBD-SQLite/lib/DBD/SQLite.pm

Using the following instrumentation patch, I have not hit
busy/locked errors while putting my SQLite-based MogileFS
instance through heavy activity (fsck, uploads, deletes):

  --- a/lib/MogileFS/Store/SQLite.pm
  +++ b/lib/MogileFS/Store/SQLite.pm
  @@ -164,7 +164,12 @@ use constant SQLITE_LOCKED => 6; # A table in the database is locked
   sub was_deadlock_error {
       my $err = $_[0]->dbh->err or return 0;

  -    ($err == SQLITE_BUSY || $err == SQLITE_LOCKED);
  +    if ($err == SQLITE_BUSY || $err == SQLITE_LOCKED) {
  +       Mgd::log('info', "DB locked");
  +       1;
  +    } else {
  +       0;
  +    }
   }

   sub was_duplicate_error {
lib/MogileFS/Store.pm