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 {