DASFQGORX56YK5E4Y7GGYZSQQQMUXYTZZ4A6IVWSTI3QGRUORLPAC
ACB4A27ZMFLRLDAKFRSGAFJRESN3UCVFADQPYCK7TGAIJMSG3FHQC
QDTOA3CQVM7JBPJ6FXNWSM7ANTALE2CF6PWD3VOASAD6JLCVU7DQC
6BG65Y2PPKIARIAK57ZUQTA6LXW3TUD6I6FTGZH23V4J3EAMHOXQC
PRDUE4YADWSOLJMYTJF4PXOW7MGOVWG7EVYGXZXVYDTFVV6IIHHAC
5LSYTRQ6IOVUW26VJW5SWGFEIB7T2N4PVEB6VMNMR5ZHQ75MFOQAC
DEKK3RUI4GPYQVEYXSFSPNQBK2FP6XJQ5LUITNUSKOZPS4RWBR7AC
PPI5ZTZP2GMKTCFQWF2SXIT6VNOY5U7PJSMX4ZR34DLMYG3GSSFQC
OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC
TSMS6W4DOKQNUQ4PEMTLOIODR33VFPN6MMNS73ZPSU4BOQVRGPNAC
6DMPXOAT5GQ3BQQOMUZN2GMBQPRA4IB7CCPHTQTIFGO3KWWAKF3QC
RV2L6CZWTMUQ2A52YDAFVHDFGURZL3H4SSCDC347UGN23D3J5KZQC
FMN7X4J24EYPOJNBUWM4NKGWSJTRV2DHCIBMPV2AXLZVVAMNOBKQC
ONES3V466GLO5CXKRF5ENK7VFOQPWM3YXLVRGWB56V5SH3W7XNBQC
W26CFMAQOXMUK4ZOJMAN4SMBXMWFQHO7HCTEVW73FQSRMJZFGJIQC
LSQ6V7M66TEGLJ7QBLRVDX4E7UKJTDQTEXZOS3KGPGFKVXNLPKBQC
ESUI5EUZUBDPHNN3APU33IFORYPYR6J3WEMEZG57FKF3EH66ZBHAC
WS4ZQM4RMIHZ6XZKSDQJGHN5SSSWFL4H236USOPUA33S6RC53RFAC
H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC
52X5P7NDBQHIJDIYNY3XUPDHHOO3PDPPNKGO2PGLXKVNM3EVECTQC
OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC
KX3WVNZW5KHVEH6EOQTZ4RBEFFJ3SGF5I467X3JWZ74PURRK4HVAC
L5CVF6UJYR6FRQA2NULFHGQFID7BGM4D622OJ2TVWRU7EAR57DHAC
T73WR2BX2QDQ6APOREBXUKNH52FDLJNBGWPQUYB2TAF2PT7XCL2AC
XEU2QVLCHPYOOD4TQIPEEVYOVSFMKFPLJYWEJYXYJAZ7S54KWDZAC
QEUTVAZ4F4EJXRDMWDMYXF6XEDMX7YPVG4IIXEKPIR3K54E5W5OAC
HN6Z5DU4WYMAIOOSNVHLIIMNF6Q53TNJ7YC27SLKWNXVYCTACQKQC
QYDGYIZRNFRIQD7RUCY5YAN3F2THZA74E5UOHPIFWSULEJFAFVJQC
OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC
X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC
APPY2E7M5NHNC6MFYXSVEKJVAILK7YAZVTVE3W75EK2JNFVS3XBQC
73Z2UB3JGRLFNFORE7D64O4IHIFSZASD4G4FLJ4FJLHANT75MGIAC
CCNPHVQCIGINWTLXCHOASGVWUPBZXFOLM2F7HTKMEA2DMFTOX7TAC
6UVFCERMGSGNRWCVC3GWO5HWV6MSWE433DXBJVC7KRPP6LLJLCSQC
LROAI3NBBSCU4T2YA6EHJYKKKL75AU5A7C7WIRCGIQ56S6HPLRXQC
W2MIZD5BNL7A5HVFWTESF57QU7T6QMEF4RBSLFQXMEEU3XD2NU2QC
UAQX27N4PI4LHEW6LSHJETIE5MV7JTEMPLTJFYUBMYVPC43H7VOAC
FZBLNBGNQPNTLBNPNZ2C6DJ5323MZQ2PH54F6ZEKPFCK7TGJFGWAC
UUUVNC4DWEEL7WV5IRPKPZ6HZMYCPA53XM7LJWICUD4E6GN37IRQC
E4MD6T3LNOYWVFTFFWCUKRNS4M2XVSKRLDWPYHMZHGDNO2T5JREQC
YXKP4AIWDBIWBBUDWF66YIPG5ECMHNKEV3PX6KYXOVXY3EWG3WGQC
T7QB6QEPWBXAU3RL7LE4GRDWWNQ65ZU2YNNTWBYLORJOABAQFEZQC
OHUZ73MKWD7SSB4DKKA532DEQKXQDS6PZ6HJ3EC2DLVJSLQH3NLAC
// Else, the "freed" page is shared with another tree, and
// hence we just need to decrement its RC.
if cursor.len() == cursor.first_rc_len() {
debug_assert_ne!(freed, 0);
free[cursor.len()] = freed;
}
if left != 0 && left != *last_freed {
txn.incr_rc(left)?;
if left != 0 {
if left != (freed & !1) {
txn.incr_rc(left)?;
} else if cursor.len() == cursor.first_rc_len() {
freed = 0
}
// Finally, update the last freed page to be the page we just
// freed (the `&!1` is here because `freed` might have its LSB set
// to indicate that `freed` was allocated by the current
// transaction, but that bit isn't set in references to page
// `freed` on the parent page).
*last_freed = freed & !1;
// This algorithm is probably a bit naive, especially for leaves,
// where if the left page is mutable, we can copy the other page
// onto it.
// Indeed, we first allocate a page, then clone both pages onto
// it, in a different order depending on whether the modified page
// is the left or the right child.
// Here, we first allocate a page, then clone both pages onto it,
// in a different order depending on whether the modified page is
// the left or the right child.
//
// Note that in the case that this merge happens immediately after
// a put that reallocated the two sides of the merge in order to
// split (not all splits do that), we could be slightly more
// efficient, but with considerably more code.
if m.modified.l > 0 {
assert_eq!(m.modified.r, 0);
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur - 1);
*off = (m.modified.l | (u64::from_le(*off) & 0xfff)).to_le();
}
} else if m.modified.r > 0 {
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur);
*off = (m.modified.r | (u64::from_le(*off) & 0xfff)).to_le();
}
}
// First element of the right page.
let rc = P::cursor_first(&m.modified.page);
let rl = P::left_child(m.modified.page.as_page(), &rc);
// mutable, since we just modified it (hence the
// `assert_eq!(freed, 0)`.
// mutable, since we just modified it. Moreover, if it is
// compacted by the `put` below, we know that the `del` didn't
// free anything, hence we can reuse the slot 0..
// First element of the right page (after potential
// modification by `del` above).
let rc = P::cursor_first(&page.0);
let rl = P::left_child(page.0.as_page(), &rc);
// Update the left and right offsets. We know that at
// least one of them is 0, but it can be either one (or
// both), depending on what happened on the page below.
//
// Since we inserted an entry at the beginning of the
// page, we need to add 1 to the index given by
// `m.modified.c1.cur`.
if m.modified.l > 0 {
assert_eq!(m.modified.r, 0);
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur);
*off = (m.modified.l | (u64::from_le(*off) & 0xfff)).to_le();
}
} else if m.modified.r > 0 {
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur + 1);
*off = (m.modified.r | (u64::from_le(*off) & 0xfff)).to_le();
}
}
if m.modified.l > 0 {
assert_eq!(m.modified.r, 0);
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur - 1);
*off = (m.modified.l | (u64::from_le(*off) & 0xfff)).to_le();
}
} else if m.modified.r > 0 {
unsafe {
let off = (page.0.data.add(HDR) as *mut u64).offset(m.modified.c1.cur);
*off = (m.modified.r | (u64::from_le(*off) & 0xfff)).to_le();
}
}
T: AllocPage + LoadPage + core::fmt::Debug,
K: Storable + ?Sized + core::fmt::Debug,
V: Storable + ?Sized + core::fmt::Debug,
P: BTreeMutPage<K, V> + core::fmt::Debug + 'a,
T: AllocPage + LoadPage,
K: Storable + ?Sized,
V: Storable + ?Sized,
P: BTreeMutPage<K, V> + 'a,
// For merges and rebalances, take care of the reference counts of
// pages and key/values.
match merge {
Op::Merged {.. } | Op::Rebalanced { .. } => {
// Increase the RC of the "other page's" descendants. In
// the case of a rebalance, this has the effect of
// increasing the RC of the new middle entry if that entry
// comes from a shared page, which is what we want.
if let Some(other) = incr_other {
let mut curs = P::cursor_first(&other);
let left = P::left_child(other.as_page(), &curs);
txn.incr_rc(left)?;
while let Some((k0, v0, r)) = P::next(txn, other.as_page(), &mut curs) {
for o in k0.page_references().chain(v0.page_references()) {
txn.incr_rc(o)?;
}
if r != 0 {
txn.incr_rc(r)?;
}
}
}
// If the middle element comes from a shared page,
// increment its references.
if let Some((ref k, ref v)) = incr_mid {
for o in k.page_references().chain(v.page_references()) {
txn.incr_rc(o)?;
}
}
}
_ => {}
}
if incr_kv_rc {
// Here, note that the rebalancing element cannot
// possibly be the replacement element, so since it is
// copied, we need to increment its RC (the
// replacement entry has its RC incremented at
// deletion).
for o in k.page_references().chain(v.page_references()) {
txn.incr_rc(o)?;
}
}
if m.r == 0 && r != 0 {
// If `m.skip_first`, we have already skipped the entry above,
// so this `r` has nothing to do with any update.
//
// Else, if we aren't skipping, but also aren't updating the
// right child of the current entry, also increase the RC.
if (m.skip_first || m.r == 0) && r != 0 {
if let Some((k, v, r)) = P::current(txn, current.page.as_page(), &mut current.cursor) {
last_match = Some((k, v));
if r > 0 {
let page = txn.load_page(r)?;
self.push(PageCursor {
cursor: P::cursor_last(&page),
page,
})
} else {
break;
}
Ok(())
}
/// Return the current position of the cursor.
pub fn current<'a, T: LoadPage>(
&mut self,
txn: &'a T,
) -> Result<Option<(&'a K, &'a V)>, T::Error> {
loop {
let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
if P::is_init(¤t.cursor) {
// The cursor hasn't been set.
return Ok(None)
} else if let Some((k, v, _)) = P::current(txn, current.page.as_page(), ¤t.cursor)
{
unsafe {
return Ok(Some((core::mem::transmute(k), core::mem::transmute(v))));
// The page is empty, meaning there's no right or left child.
debug_assert!(P::is_init(¤t.cursor));
// Assert we're looking at the root.
debug_assert_eq!(self.len, 1);
// And the root has no child.
debug_assert_eq!(P::right_child(current.page.as_page(), ¤t.cursor), 0);
// We're past the last element at the root.
}
#[derive(Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy)]
struct U([u64; 3]);
direct_repr!(U);
#[derive(Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy)]
struct V([u64; 5]);
direct_repr!(V);
impl std::fmt::Debug for U {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "U({})", self.0[0])
}
}
impl std::fmt::Debug for V {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "V")
}
}
#[test]
pub fn random_scenario_sized_fork() {
let path = "/home/pe/bla/db";
let l0 = 1 << 20;
std::fs::remove_file(path).unwrap_or(());
let env = Env::new(&path, l0, 1).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db = create_db::<MutTxn<&Env, ()>, U, V>(&mut txn).unwrap();
use rand::{Rng, SeedableRng};
let mut rng = rand::rngs::SmallRng::from_seed(*b"rc',.snjcg'sthomw,.vbw,.p84fcxjw");
let mut ve: Vec<(U, V)> = Vec::with_capacity(100_000);
use std::collections::HashMap;
let mut h: HashMap<U, V> = HashMap::with_capacity(100_000);
let mut refs = BTreeMap::new();
let mut dbs = Vec::new();
for i in 0.. {
let do_debug = i > 5618; // i % 1_000_000 == 0;
if do_debug {
env_logger::try_init().unwrap_or(());
info!("========== i = {:?} {:?}", i, db.db);
}
dbs.push(fork_db(&mut txn, &db).unwrap());
if rng.gen_range(0..4) == 3 {
if let Some((k, v)) = ve.pop() {
if do_debug {
debug!("del {:?} {:?}", k.0[0], v.0[0]);
}
assert!(del(&mut txn, &mut db, &k, Some(&v)).unwrap())
}
} else {
let k = U([rng.gen(), rng.gen(), rng.gen()]);
let v = V([rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()]);
if do_debug {
debug!("put {:?} {:?}", k.0[0], v.0[0]);
}
put(&mut txn, &mut db, &k, &v).unwrap();
ve.push((k, v));
h.insert(k, v);
}
if do_debug {
debug(&txn, &[&db], format!("debug_{}", i), true);
for (i, (k, v)) in ve.iter().enumerate() {
if get(&txn, &db, k, None).unwrap() != Some((k, v)) {
panic!("test {:?} {:?} {:?}", i, k.0[0], v.0[0]);
}
}
for x in iter(&txn, &db, None).unwrap() {
let (k, v) = x.unwrap();
if h.get(k) != Some(v) {
panic!("test {:?}", k);
}
}
refs.clear();
add_refs(&txn, &db, &mut refs).unwrap();
for db in dbs.iter() {
add_refs(&txn, db, &mut refs).unwrap();
}
add_free_refs_mut(&txn, &mut refs).unwrap();
check_free_mut(&mut txn, &refs);
if let Some(ref rc) = txn.rc {
let mut last = 0;
for r in iter(&txn, rc, None).unwrap() {
let (r, _) = r.unwrap();
if last > 0 && last == (r & !0xfff) {
panic!("r = {:?} last = {:?}", r, last);
}
last = r & !0xfff;
}
}
let mut n = Vec::new();
for (p, r) in refs.iter() {
if *r >= 2 {
let rc = txn.rc(*p).unwrap();
if rc != *r as u64 {
n.push((p, *r, rc))
}
} else {
assert_eq!(txn.rc(*p).unwrap(), 0);
}
}
if !n.is_empty() {
panic!("n = {:?} {:?}", n, n.len());
}
}
}
}
#[test]
pub fn random_scenario_sized_test() {
let path = "/home/pe/bla/db";
let l0 = 1 << 20;
std::fs::remove_file(path).unwrap_or(());
let env = Env::new(&path, l0, 1).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db = create_db::<MutTxn<&Env, ()>, U, V>(&mut txn).unwrap();
use rand::{Rng, SeedableRng};
let mut rng = rand::rngs::SmallRng::from_seed(*b"rc',.snjcg'sthomw,.vbw,.p84fcxjw");
let mut ve: Vec<(U, V)> = Vec::with_capacity(100_000);
use std::collections::HashMap;
let mut h: HashMap<U, V> = HashMap::with_capacity(100_000);
let mut refs = BTreeMap::new();
for i in 0.. {
let do_debug = i % 10_000_000 == 0;
if do_debug {
env_logger::try_init().unwrap_or(());
info!("========== i = {:?} {:?}", i, db.db);
}
if rng.gen_range(0..4) == 3 {
if let Some((k, v)) = ve.pop() {
if do_debug {
debug!("del {:?} {:?}", k.0[0], v.0[0]);
}
assert!(del(&mut txn, &mut db, &k, Some(&v)).unwrap())
}
} else {
let k = U([rng.gen(), rng.gen(), rng.gen()]);
let v = V([rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()]);
if do_debug {
debug!("put {:?} {:?}", k.0[0], v.0[0]);
}
put(&mut txn, &mut db, &k, &v).unwrap();
ve.push((k, v));
h.insert(k, v);
}
if do_debug {
for (i, (k, v)) in ve.iter().enumerate() {
if get(&txn, &db, k, None).unwrap() != Some((k, v)) {
panic!("test {:?} {:?} {:?}", i, k.0[0], v.0[0]);
}
}
for x in iter(&txn, &db, None).unwrap() {
let (k, v) = x.unwrap();
if h.get(k) != Some(v) {
panic!("test {:?}", k);
}
}
refs.clear();
add_refs(&txn, &db, &mut refs).unwrap();
check_free_mut(&mut txn, &refs);
for (p, r) in refs.iter() {
if *r >= 2 {
let rc = txn.rc(*p).unwrap();
if rc != *r as u64 {
panic!("p {:?} r {:?} {:?}", p, r, rc);
}
} else {
assert_eq!(txn.rc(*p).unwrap(), 0);
}
}
}
}
}
#[test]
pub fn random_scenario_unsized_test() {
let path = "/home/pe/bla/udb";
let l0 = 1 << 20;
std::fs::remove_file(path).unwrap_or(());
let env = Env::new(&path, l0, 1).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db = create_db_::<MutTxn<&Env, ()>, U, V, btree::page_unsized::Page<U, V>>(&mut txn).unwrap();
use rand::{Rng, SeedableRng};
let mut rng = rand::rngs::SmallRng::from_seed(*b"rc',.snjcg'sthomw,.vbw,.p84fcxjw");
let mut ve: Vec<(U, V)> = Vec::with_capacity(100_000);
use std::collections::HashMap;
let mut h: HashMap<U, V> = HashMap::with_capacity(100_000);
let mut refs = BTreeMap::new();
for i in 0.. {
let do_debug = true; // i % 10_000_000 == 0;
if do_debug {
env_logger::try_init().unwrap_or(());
info!("========== i = {:?} {:?}", i, db.db);
}
if rng.gen_range(0..4) == 3 {
if let Some((k, v)) = ve.pop() {
if do_debug {
debug!("del {:?} {:?}", k.0[0], v.0[0]);
}
assert!(del(&mut txn, &mut db, &k, Some(&v)).unwrap())
}
} else {
let k = U([rng.gen(), rng.gen(), rng.gen()]);
let v = V([rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()]);
if do_debug {
debug!("put {:?} {:?}", k.0[0], v.0[0]);
}
put(&mut txn, &mut db, &k, &v).unwrap();
ve.push((k, v));
h.insert(k, v);
}
if do_debug {
for (i, (k, v)) in ve.iter().enumerate() {
if get(&txn, &db, k, None).unwrap() != Some((k, v)) {
panic!("test {:?} {:?} {:?}", i, k.0[0], v.0[0]);
}
}
for x in iter(&txn, &db, None).unwrap() {
let (k, v) = x.unwrap();
if h.get(k) != Some(v) {
panic!("test {:?}", k);
}
}
refs.clear();
add_refs(&txn, &db, &mut refs).unwrap();
check_free_mut(&mut txn, &refs);
for (p, r) in refs.iter() {
if *r >= 2 {
let rc = txn.rc(*p).unwrap();
if rc != *r as u64 {
panic!("p {:?} r {:?} {:?}", p, r, rc);
}
} else {
assert_eq!(txn.rc(*p).unwrap(), 0);
}
}
}
}
let page_ptr = maps[0].ptr.add(root * PAGE_SIZE);
let crc = (&*(page_ptr as *const GlobalHeader)).crc;
let root_page = std::slice::from_raw_parts(page_ptr.add(8), PAGE_SIZE - 8);
let mut h = HASHER.clone();
h.update(root_page);
if h.finalize() != crc {
return Err(crate::CRCError {});
}
check_crc(maps[0].ptr.add(root * PAGE_SIZE))