* Fix concurrency issues in download-using-manifests' handling of the

SQLite manifest cache.  The DBI AutoCommit feature caused every
  process to have an active transaction at all times, which could
  indefinitely block processes wanting to update the manifest cache.

* Disable fsync() in the manifest cache because we don't need
  integrity (the cache can always be recreated if it gets corrupted).
This commit is contained in:
Eelco Dolstra 2011-07-13 14:05:54 +00:00
parent 0a623a10c7
commit e649f3168b
2 changed files with 12 additions and 1 deletions

View file

@ -219,11 +219,12 @@ sub updateManifestDB {
# Open/create the database. # Open/create the database.
our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "") our $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
or die "cannot open database `$dbPath'"; or die "cannot open database `$dbPath'";
$dbh->{AutoCommit} = 0;
$dbh->{RaiseError} = 1; $dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0; $dbh->{PrintError} = 0;
$dbh->do("pragma foreign_keys = on"); $dbh->do("pragma foreign_keys = on");
$dbh->do("pragma synchronous = off"); # we can always reproduce the cache
$dbh->do("pragma journal_mode = truncate");
# Initialise the database schema, if necessary. # Initialise the database schema, if necessary.
$dbh->do(<<EOF); $dbh->do(<<EOF);
@ -278,6 +279,8 @@ EOF
open MAINLOCK, ">>$manifestDir/cache.lock" or die; open MAINLOCK, ">>$manifestDir/cache.lock" or die;
flock(MAINLOCK, LOCK_EX) or die; flock(MAINLOCK, LOCK_EX) or die;
$dbh->begin_work;
# Read each manifest in $manifestDir and add it to the database, # Read each manifest in $manifestDir and add it to the database,
# unless we've already done so on a previous run. # unless we've already done so on a previous run.
my %seen; my %seen;
@ -291,6 +294,8 @@ EOF
"select 1 from Manifests where path = ? and timestamp = ?", "select 1 from Manifests where path = ? and timestamp = ?",
{}, $manifest, $timestamp)} == 1; {}, $manifest, $timestamp)} == 1;
print STDERR "caching $manifest...\n";
$dbh->do("delete from Manifests where path = ?", {}, $manifest); $dbh->do("delete from Manifests where path = ?", {}, $manifest);
$dbh->do("insert into Manifests(path, timestamp) values (?, ?)", $dbh->do("insert into Manifests(path, timestamp) values (?, ?)",

View file

@ -267,6 +267,12 @@ my @path = computeSmallestDownload $targetPath;
die "don't know how to produce $targetPath\n" if scalar @path == 0; die "don't know how to produce $targetPath\n" if scalar @path == 0;
# We don't need the manifest anymore, so close it as an optimisation:
# if we still have SQLite locks blocking other processes (we
# shouldn't), this gets rid of them.
$dbh->disconnect;
# Traverse the shortest path, perform the actions described by the # Traverse the shortest path, perform the actions described by the
# edges. # edges.
my $curStep = 1; my $curStep = 1;