YWFYZNLZ5JHLIFVBRKZK4TSWVPROUPRG77ZB5M7UHT2OKPL4ZSRQC
PXF3R6SVXJXN2NMLMWNY5OFV5QYVE2VZTLGIZDZVK5ZVLFTVSSWQC
X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC
YXKP4AIWDBIWBBUDWF66YIPG5ECMHNKEV3PX6KYXOVXY3EWG3WGQC
OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC
WS4ZQM4RMIHZ6XZKSDQJGHN5SSSWFL4H236USOPUA33S6RC53RFAC
EAAYH6BQWDK52EC5RG3BEZQU3FJPN5RRRN4U5KDKDVPKXBVJMNDAC
ONES3V466GLO5CXKRF5ENK7VFOQPWM3YXLVRGWB56V5SH3W7XNBQC
UAQX27N4PI4LHEW6LSHJETIE5MV7JTEMPLTJFYUBMYVPC43H7VOAC
#[cfg(target_family="unix")]
#[test]
fn multi_txn() {
env_logger::try_init().unwrap_or(());
std::fs::remove_dir_all("/tmp/sanakirja0").unwrap_or(());
std::fs::create_dir_all("/tmp/sanakirja0").unwrap();
let env = Env::new("/tmp/sanakirja0", 4096 * 20, 2).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
debug!("txn.root = {:?}", txn.env.root);
let mut db = create_db::<MutTxn<&Env, ()>, u64, ()>(&mut txn).unwrap();
debug!("db = {:?}", db.db.offset);
txn.set_root(0, db.db.offset);
txn.commit().unwrap();
debug!("1. commit done");
let mut txn = Env::mut_txn_begin(&env).unwrap();
debug!("txn.root = {:?}", txn.env.root);
let db: Db<_, u64, ()> = txn.root_db(0).unwrap().unwrap();
debug!("txn.root = {:?}", db);
txn.commit().unwrap();
debug!("2. commit done");
let mut txn = Env::mut_txn_begin(&env).unwrap();
debug!("txn.root = {:?}", txn.env.root);
txn.commit().unwrap();
debug!("commit done");
}
let root_dbs = std::slice::from_raw_parts_mut(
maps[0].ptr.add(*root * PAGE_SIZE + GLOBAL_HEADER_SIZE) as *mut u64,
N_ROOTS,
);
for (&r, rr) in self.roots.iter().zip(root_dbs.iter_mut()) {
debug!("root_db: {:?}", rr as *mut u64);
debug!("committing root: {:?} {:?}", r, rr);
*rr = r
}
let page = MutPage(CowPage {
data,
offset,
});
self.occupied_owned_pages.push(MutPage(CowPage { data, offset }));
let page = MutPage(CowPage { data, offset });
self.occupied_owned_pages
.push(MutPage(CowPage { data, offset }));
}
}
impl<E: Borrow<Env>, T> RootDb for MutTxn<E, T> {
fn root_db<
K: Representable<Self>,
V: Representable<Self>,
>(
&self,
n: usize,
) -> Result<Option<sanakirja_core::btree::Db<Self, K, V>>, Error> {
use sanakirja_core::LoadPage;
if let Some(db) = self.roots.get(n) {
Ok(Some(sanakirja_core::btree::Db {
db: self.load_page(*db)?,
marker: std::marker::PhantomData,
}))
} else {
unsafe {
let env = self.env.borrow();
let db = {
let root = env.root.lock();
let maps = env.mmaps.lock();
*(maps[0].ptr.add(*root * PAGE_SIZE + GLOBAL_HEADER_SIZE + 8 * n) as *mut u64)
};
if db != 0 {
Ok(Some(sanakirja_core::btree::Db {
db: self.load_page(db)?,
marker: std::marker::PhantomData,
}))
} else {
Ok(None)
}
}
}
// Lock order: first take thread locks, then process locks.
// Why are there two synchronization mechanisms?
// Because we would need to upgrade the read lock into a write lock,
// and there is no real way to do this with standard mechanisms.
// So, we take a mutex to make sure no other mutable transaction can start,
// and then at the time of writing, we also take the RwLock.