NXMFNPZ7VWJRLC3M5QJJVTICXCMGE24F3HVIZA7A7RLVMLQMLDVQC
73Z2UB3JGRLFNFORE7D64O4IHIFSZASD4G4FLJ4FJLHANT75MGIAC
OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC
EAAYH6BQWDK52EC5RG3BEZQU3FJPN5RRRN4U5KDKDVPKXBVJMNDAC
WS4ZQM4RMIHZ6XZKSDQJGHN5SSSWFL4H236USOPUA33S6RC53RFAC
T73WR2BX2QDQ6APOREBXUKNH52FDLJNBGWPQUYB2TAF2PT7XCL2AC
X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC
DV4A2LR7Q5LAEGAQHLO34PZCHGJUHPAMRZFGT7GUFNKVQKPJNOYQC
6UVFCERMGSGNRWCVC3GWO5HWV6MSWE433DXBJVC7KRPP6LLJLCSQC
H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC
OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC
XEU2QVLCHPYOOD4TQIPEEVYOVSFMKFPLJYWEJYXYJAZ7S54KWDZAC
OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC
G4JEQLLX6Q7VVFVAEJZAVQXX33MQ36CSCYSMJ5NQM5VZ76DXKU6QC
YWFYZNLZ5JHLIFVBRKZK4TSWVPROUPRG77ZB5M7UHT2OKPL4ZSRQC
ONES3V466GLO5CXKRF5ENK7VFOQPWM3YXLVRGWB56V5SH3W7XNBQC
KMT3MF5NLEQIPZLHCRYDGQ5EA46HJCG3C2ANEPMZGKGHDK77ADPAC
W26CFMAQOXMUK4ZOJMAN4SMBXMWFQHO7HCTEVW73FQSRMJZFGJIQC
QEUTVAZ4F4EJXRDMWDMYXF6XEDMX7YPVG4IIXEKPIR3K54E5W5OAC
Q7DRIBBRE4MNG4NP3PVIXAJF5PQYLFWYIVK2O4VVLEO6XY3BOSFQC
UAQX27N4PI4LHEW6LSHJETIE5MV7JTEMPLTJFYUBMYVPC43H7VOAC
KX3WVNZW5KHVEH6EOQTZ4RBEFFJ3SGF5I467X3JWZ74PURRK4HVAC
impl<'a, K: Representable + ?Sized, V: Representable + ?Sized, P: BTreePage<K, V>>
ModifiedPage<'a, K, V, P>
{
pub fn single_child(&self) -> Option<u64> {
let mut c1 = self.c1.clone();
if self.skip_first {
P::move_next(&mut c1);
}
debug!(
"single_child: {:?} {:?} {:?} {:?}",
self.page, self.c0, c1, self.ins
);
if P::is_empty(self.page.as_page(), &self.c0)
&& self.ins.is_none()
&& P::is_empty(self.page.as_page(), &c1)
{
Some(self.l)
} else {
None
}
}
}
/// Represents the concatenation of a modified page and one of its
/// sibling (left or right).
pub fn fork_db<
T: AllocPage + core::fmt::Debug,
K: Representable + core::fmt::Debug,
V: Representable + core::fmt::Debug,
>(
txn: &mut T,
db: &Db<K, V>,
) -> Result<Db<K, V>, T::Error> {
fork_db_(txn, db)
}
/// Get the first entry of a database greater than or equal to `k` (or
/// to `(k, v)` if `v.is_some()`).
fn drop_<T: AllocPage, K: Representable + ?Sized, V: Representable + ?Sized, P: BTreePage<K, V>>(
txn: &mut T,
p: Page,
) -> Result<(), T::Error> {
let rc = if P::is_dirty(p) {
txn.decr_rc_owned(p.offset)?
} else {
txn.decr_rc(p.offset)?
};
if rc == 0 {
let mut cursor = P::cursor_before(p);
let left_page = P::right_child(p, &cursor);
if left_page == 0 {
return Ok(());
}
drop_::<T, K, V, P>(txn, txn.load_page(left_page)?.as_page())?;
while let Some((k, v, r)) = P::next(txn, p, &mut cursor) {
for o in k.page_offsets().chain(v.page_offsets()) {
txn.decr_rc(o)?;
let mut stack: [MaybeUninit<cursor::PageCursor<K, V, P>>; cursor::N_CURSORS] =
[MaybeUninit::uninit(); cursor::N_CURSORS];
let page = txn.load_page(db.db)?;
stack[0] = MaybeUninit::new(cursor::PageCursor {
page,
cursor: P::cursor_before(page.as_page()),
});
let mut ptr = 0;
loop {
let cur = unsafe { &mut *stack[ptr].as_mut_ptr() };
let rc = txn.rc(cur.page.offset)?;
if rc <= 1 {
if let Some((k, v, _)) = P::current(txn, cur.page.as_page(), &cur.cursor) {
for o in k.page_offsets().chain(v.page_offsets()) {
txn.decr_rc(o)?;
}
drop_::<T, K, V, P>(txn, txn.load_page(r)?.as_page())?;
if P::move_next(&mut cur.cursor) {
let r = P::left_child(cur.page.as_page(), &cur.cursor);
if r > 0 {
ptr += 1;
let page = txn.load_page(r)?;
stack[ptr] = MaybeUninit::new(cursor::PageCursor {
page,
cursor: P::cursor_before(page.as_page()),
})
}
continue
}
fn single_child<K: Representable+?Sized, V: Representable+?Sized, P: BTreeMutPage<K, V>>(m: &ModifiedPage<K, V, P>) -> Option<u64> {
let mut c1 = m.c1.clone();
if m.skip_first {
P::move_next(&mut c1);
}
debug!(
"single_child: {:?} {:?} {:?} {:?}",
m.page,
m.c0, c1, m.ins
);
if P::is_empty(m.page.as_page(), &m.c0)
&& m.ins.is_none()
&& P::is_empty(m.page.as_page(), &c1)
{
Some(m.l)
} else {
None
}
}
#[test]
pub fn fork_drop() {
env_logger::try_init().unwrap_or(());
let env = Env::new_anon(409600000, 1).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db: Db<u64, u64> = create_db(&mut txn).unwrap();
let n = 1000 as u64;
let i0 = 10 as u64;
let mut values = Vec::with_capacity(n as usize);
for i in 0..n {
put(&mut txn, &mut db, &i, &i).unwrap();
if i != i0 {
values.push(i);
}
}
let db2 = fork_db(&mut txn, &db).unwrap();
put(&mut txn, &mut db, &n, &n).unwrap();
crate::debug::debug(&txn, &[&db, &db2], "debug1", true);
drop(&mut txn, db2).unwrap();
crate::debug::debug(&txn, &[&db], "debug2", true);
let mut refs = BTreeMap::new();
add_refs(&txn, &db, &mut refs).unwrap();
let mut err = 0;
for (p, r) in refs.iter() {
println!("{:?} {:?}", p, r);
if *r >= 2 {
error!("{:?} {:?} {:?}", p, txn.rc(*p).unwrap(), *r);
err += 1;
} else {
if txn.rc(*p).unwrap() != 0 {
error!("{:?} {:?} 0", p, txn.rc(*p).unwrap());
err += 1;
}
}
}
assert_eq!(err, 0);
}