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.