Skip to main content

tuwunel_database/map/
open.rs

1use std::sync::Arc;
2
3use rocksdb::ColumnFamily;
4
5use crate::Engine;
6
7pub(super) fn open(engine: &Arc<Engine>, name: &str) -> Arc<ColumnFamily> {
8	let bounded_arc = engine.cf(name);
9	let bounded_ptr = Arc::into_raw(bounded_arc);
10	let cf_ptr = bounded_ptr.cast::<ColumnFamily>();
11
12	// SAFETY: Column family handles out of RocksDB are basic pointers and can
13	// be invalidated: 1. when the database closes. 2. when the column is dropped or
14	// closed. rust_rocksdb wraps this for us by storing handles in their own
15	// `RwLock<BTreeMap>` map and returning an Arc<BoundColumnFamily<'_>>` to
16	// provide expected safety. Similarly in "single-threaded mode" we would
17	// receive `&'_ ColumnFamily`.
18	//
19	// PROBLEM: We need to hold these handles in a field, otherwise we have to take
20	// a lock and get them by name from this map for every query, which is what
21	// conduit was doing, but we're not going to make a query for every query so we
22	// need to be holding it right. The lifetime parameter on these references makes
23	// that complicated. If this can be done without polluting the userspace
24	// with lifetimes on every instance of `Map` then this `unsafe` might not be
25	// necessary.
26	//
27	// SOLUTION: After investigating the underlying types it appears valid to
28	// Arc-swap `BoundColumnFamily<'_>` for `ColumnFamily`. They have the
29	// same inner data, the same Drop behavior, Deref, etc. We're just losing the
30	// lifetime parameter. We should not hold this handle, even in its Arc, after
31	// closing the database (dropping `Engine`). Since `Arc<Engine>` is a sibling
32	// member along with this handle in `Map`, that is prevented.
33	unsafe { Arc::from_raw(cf_ptr) }
34}