gpg: When the TOFU DB is in batch mode, periodically drop the locks.

* g10/tofu.c: Include <sched.h>.
(batch_update_started): New variable.
(begin_transaction): If we've been in batch mode for a while, then
commit any extant batch transactions.
(tofu_begin_batch_update): If we are not in batch mode, initialize
batch_update_started.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
This commit is contained in:
Neal H. Walfield 2015-10-26 13:36:12 +01:00
parent 5e7ac031f5
commit 5b0ed7674d
1 changed files with 30 additions and 0 deletions

View File

@ -28,6 +28,7 @@
#include <sys/stat.h>
#include <assert.h>
#include <stdarg.h>
#include <sched.h>
#include <sqlite3.h>
#include "gpg.h"
@ -422,6 +423,9 @@ sqlite3_stepx (sqlite3 *db,
}
static int batch_update;
static time_t batch_update_started;
static gpg_error_t end_transaction (struct db *db, int only_batch);
/* Start a transaction on DB. */
static gpg_error_t
@ -430,6 +434,29 @@ begin_transaction (struct db *db, int only_batch)
int rc;
char *err = NULL;
if (batch_update && batch_update_started != gnupg_get_time ())
/* We've been in batch update mode for a while (on average, more
than 500 ms). To prevent starving other gpg processes, we drop
and retake the batch lock.
Note: if we wanted higher resolution, we could use
npth_clock_gettime. */
{
struct db *t;
for (t = db_cache; t; t = t->next)
if (t->batch_update)
end_transaction (t, 1);
for (t = db; t; t = t->next)
if (t->batch_update)
end_transaction (t, 1);
batch_update_started = gnupg_get_time ();
/* Yield to allow another process a chance to run. */
sched_yield ();
}
/* XXX: In split mode, this can end in deadlock.
Consider: we have two gpg processes running simultaneously and
@ -556,6 +583,9 @@ rollback_transaction (struct db *db)
void
tofu_begin_batch_update (void)
{
if (! batch_update)
batch_update_started = gnupg_get_time ();
batch_update ++;
}