g10: Avoid gratuitious SQLite aborts and starving writers.
authorNeal H. Walfield <neal@g10code.com>
Mon, 31 Oct 2016 02:02:36 +0000 (19:02 -0700)
committerNeal H. Walfield <neal@g10code.com>
Mon, 31 Oct 2016 02:10:42 +0000 (19:10 -0700)
commit7a634e48b13c5d5d295b8fed9b429e1b2109a333
tree5ce95d0c0d923f1d79aad2752eedcf5ae40931f3
parenteec365a02bd35d2d5c9e4d2c8d18bcd9180cf859
g10: Avoid gratuitious SQLite aborts and starving writers.

* g10/tofu.c: Include <time.h>, <utime.h>, <fcntl.h> and <unistd.h>.
(tofu_dbs_s): Add fields want_lock_file and want_lock_file_ctime.
(begin_transaction): Only yield if DBS->WANT_LOCK_FILE_CTIME has
changed since we took the lock.  Don't use gpgrt_yield to yield, but
sleep for 100ms.  After taking the batch lock, update
DBS->WANT_LOCK_FILE_CTIME.  Also take the batch lock the first time we
take the real lock.  When taking the real lock, use immediate not
deferred mode to avoid gratuitious aborts.
(end_transaction): When dropping the outermost real lock, drop the
batch lock.
(busy_handler): New function.
(opendbs): Set the busy handler to it when opening the DB.  Initialize
CTRL->TOFU.DBS->WANT_LOCK_FILE.
(tofu_closedbs): Free DBS->WANT_LOCK_FILE.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
By default, SQLite defers transactions until they are actually needed.
A consequence of this is that if we have two readers and both decide
to do a write, then one has to abort.  To avoid this problem, we can
make the outermost transaction an immediate transaction.  This has the
disadvantage that we only allow a single reader at a time, but at
least we don't have gratuitous aborts anymore.

A second problem is that SQLite apparently doesn't actually create a
queue of waiters.  The result is that doing a sched_yield between
dropping and retaking the batch transaction is not enough to allow the
other process to make progress.  Instead, we need to wait a
while (emperically: 100ms seems reasonable).  To avoid waiting when
there is no contention, we use a new file's timestamp to signal that
there is a waiter.
g10/tofu.c