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))