Is it okay to use Mutex<bool>?

Looking at it, the check for closed in CursorBackend::assert_txn_backend() appears entirely redundant. To call assert_txn_backend(), you must have a valid &CursorBackend and a valid &TxnBackend. The only operations which close a cursor are <CursorBackend as Drop>::drop() and TxnBackend::close_cursors(), which respectively require a &mut CursorBackend or &mut TxnBackend. Since both of those are part of a destructor, and neither calls assert_txn_backend(), all possible callers of assert_txn_backend() must ensure that the end of each &Backend's lifetime happens-before the destruction of each Backend. (At least, Miri enforces that references' liveness durations must follow the happens-before relationship, even though I can't find it explicitly documented anywhere.) Therefore, the cursor can never be closed when assert_txn_backend() is called.

All that's left is to ensure that CursorBackend::drop() and TxnBackend::close_cursors() don't both call lmdb::mdb_cursor_close(). Dropping the upgraded Arc<CursorBackend> within close_cursors() synchronizes-with dropping the Arc<CursorBackend> in a Cursor<K, V, C>, since Arc uses an release–acquire pair on its reference count before calling the inner value's destructor. (If it didn't, it would be unsound, as before.) Therefore, the mdb_cursor_close() in TxnBackend::close_cursors() on one thread must always happen-before CursorBackend::drop() is called on another thread. Consequently, no additional synchronization is needed on closed: it could use Relaxed operations, or even an UnsafeCell, since Arc handles the necessary synchronization for us. (In either case, CursorBackend::drop() can just safely use get_mut().)

1 Like