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.