[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#7774) LMDB assertion failure during Postfix cache cleanup

Wietse Venema writes:
> (...) what happens when the two above activities happen
> in different processes? That is, process A (opens the database with
> MDB_NOLOCK. opens a cursor, and walks the database without making
> any changes to it), while process B opens the same database with
> MDB_NOLOCK and performs the delete transactions.
> Will the process A cursor read transaction trigger an assertion due
> to the process B delete transactions? If not, why not?

Process A may see garbage data.  This can result in an assert(), a
segfault or other misbehavior.  Just like if you had process A == B.
With MDB_NOLOCK, after a write transaction commits you need to
end existing read-only transactions before starting a new writer.
(Well, it's a bit looser than that, but that's a simple rule.)

Because: A read-only transaction needs a frozen, valid snapshot of the
DB.  Normally it registers itself in the lockfile, so writers know to
not touch the pages that make up that snapshot.  MDB_NOLOCK disables the
lockfile, leaving those pages unprotected from writers.

Maybe MDB_NOLOCK should have kept the lockfile and reader table, and
just omitted the mutexes/semaphores that synchronize transactions.

OTOH mapsize changes in B are not a problem for _existing_ transactions
in A, since it was actually the accompanying map _address_ change which
broke existing transactions.  But if A tries to begin new transactions,
mdb_txn_begin() may soon fail with MDB_MAP_RESIZED until A also resizes.