LMDB开启MDB_NOLOCK后,互斥键并发写的可行性与风险问询
Great question—let’s break down each of your concerns using LMDB’s core design principles, especially when operating with MDB_NOLOCK mode.
1. Can two write transactions modifying non-overlapping key sets run concurrently?
Short answer: Not safely, without additional application-level safeguards. Even if the key sets don’t overlap, LMDB write transactions touch global environment state that isn’t partitioned by key range:
- Every write transaction increments a global transaction ID (txn ID) to track versioning for snapshot isolation.
- For a single database (
Dbi), modifying any key triggers a copy-on-write (COW) update that propagates up to the database’s root page. This root page is a single shared structure for all keys in the database.
Without coordination, concurrent writes will race to update these global structures, leading to lost updates or corrupted metadata.
2. Is the single-writer semantics a waste in this scenario?
From LMDB’s design perspective, no—single-writer semantics are a deliberate tradeoff. LMDB’s COW architecture and global versioning rely on a single authoritative write path to guarantee consistency with minimal overhead. Supporting multi-writer for non-overlapping keys would require:
- Partitioning data into isolated sub-databases or environments (each with their own root pages and txn IDs)
- Building custom application-level locking per partition
While this could unlock some concurrency, it adds significant complexity to your code. For most use cases, LMDB’s single-writer model is efficient enough (writes are fast, and the bottleneck is often disk I/O, not CPU) and avoids the bugs that come with rolling your own concurrency control.
3. What happens if two such write transactions commit concurrently in MDB_NOLOCK mode?
If you force concurrent commits without safeguards, you’ll hit hard consistency issues:
- Lost updates: The second write to commit will overwrite the root page pointer from the first write, discarding all changes from the first transaction entirely.
- Corrupted versioning: Global txn IDs will be incremented out of order or duplicated, breaking LMDB’s snapshot isolation model. Readers may see partial writes, stale data, or even crash when encountering invalid metadata.
- Database corruption: In the worst case, concurrent writes can leave the B-tree structure in an inconsistent state (e.g., orphaned pages, invalid pointers), requiring a database repair or restoration from backup.
4. Can such concurrent writes scale linearly with core count like read-only transactions?
Absolutely not. Read-only transactions in LMDB are completely lock-free and stateless—they just read the current root page snapshot, so they scale perfectly with core count. Write transactions, even for non-overlapping keys, still compete for global resources (txn ID, root page updates). These global bottlenecks mean you won’t get linear scaling; adding more cores won’t increase write throughput beyond a certain point.
If you truly need scalable concurrent writes, you’d have to split your data into separate LMDB environments (each with its own file) for disjoint key sets. But this moves the complexity of data routing to your application and loses the ability to perform cross-partition transactions.
内容的提问来源于stack exchange,提问作者sidnt

