OHG5NX6KVGKNA7S7SU3MTPOZCN4RRZK2SGZWZ5LIRXUMCYIPUHIAC 3QM7P3RRVYYDEJNFDG3GHZDMSSHPPJC3WQOJGETGREOM4I2A6D5AC ECPAFJSBBQ6KMGESKYDMSGPSO32TKLWOUQ4ABALKP6U2IEABWN6AC BYI23QWI44ZINCI32VLVG2JJG3WUZFCYEKNNNLLMXMWQCTKZ6PRAC 4Z4GEJTFQFYDOJK3D72LKOFSC5Q42SNL3N6UOYCYW5FXCA67G66AC OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC QYDGYIZRNFRIQD7RUCY5YAN3F2THZA74E5UOHPIFWSULEJFAFVJQC LSQ6V7M66TEGLJ7QBLRVDX4E7UKJTDQTEXZOS3KGPGFKVXNLPKBQC 52X5P7NDBQHIJDIYNY3XUPDHHOO3PDPPNKGO2PGLXKVNM3EVECTQC H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC G7K2WSVY2FT4BZ4OKVODP3TJL6ISOTMLO6NHDYLAYYPOS3ZNEI6QC TSMS6W4DOKQNUQ4PEMTLOIODR33VFPN6MMNS73ZPSU4BOQVRGPNAC OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC NXMFNPZ7VWJRLC3M5QJJVTICXCMGE24F3HVIZA7A7RLVMLQMLDVQC ONES3V466GLO5CXKRF5ENK7VFOQPWM3YXLVRGWB56V5SH3W7XNBQC W26CFMAQOXMUK4ZOJMAN4SMBXMWFQHO7HCTEVW73FQSRMJZFGJIQC CCNPHVQCIGINWTLXCHOASGVWUPBZXFOLM2F7HTKMEA2DMFTOX7TAC KMT3MF5NLEQIPZLHCRYDGQ5EA46HJCG3C2ANEPMZGKGHDK77ADPAC HN6Z5DU4WYMAIOOSNVHLIIMNF6Q53TNJ7YC27SLKWNXVYCTACQKQC OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC T73WR2BX2QDQ6APOREBXUKNH52FDLJNBGWPQUYB2TAF2PT7XCL2AC S4V4QZ5CF5LUDYWNR2UMWH6CHJDJ5FPGAZCQYM5GY7FJMJV4NN4QC YWFYZNLZ5JHLIFVBRKZK4TSWVPROUPRG77ZB5M7UHT2OKPL4ZSRQC E4MD6T3LNOYWVFTFFWCUKRNS4M2XVSKRLDWPYHMZHGDNO2T5JREQC DASFQGORX56YK5E4Y7GGYZSQQQMUXYTZZ4A6IVWSTI3QGRUORLPAC SYURNHHL3P22ZAERTML4YW3DYLATHY5ALZH4GL5NF3LENDSKL2NQC T7QB6QEPWBXAU3RL7LE4GRDWWNQ65ZU2YNNTWBYLORJOABAQFEZQC FZBLNBGNQPNTLBNPNZ2C6DJ5323MZQ2PH54F6ZEKPFCK7TGJFGWAC PUOGOIJ3SCPHJADRYHIQJXIUQMJFKGFMHY4HWEQI6VQNNDSHVXJAC 5LSYTRQ6IOVUW26VJW5SWGFEIB7T2N4PVEB6VMNMR5ZHQ75MFOQAC ACB4A27ZMFLRLDAKFRSGAFJRESN3UCVFADQPYCK7TGAIJMSG3FHQC let s = core::slice::from_raw_parts(page.data.as_ptr().add(HDR) as *const u16,hdr.n() as usize,);if let Some(v0) = v0 {s.binary_search_by(|&off| {let off = u16::from_le(off);let (k, v) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k as *const u8);match k.compare(txn, k0) {Ordering::Equal => {let v = V::from_raw_ptr(txn, v as *const u8);v.compare(txn, v0)}cmp => cmp,
lookup_leaf(txn, page, k0, v0, hdr)} else {lookup_internal(txn, page, k0, v0, hdr)}}unsafe fn lookup_internal<T: LoadPage, K: UnsizedStorable + ?Sized, V: UnsizedStorable + ?Sized>(txn: &T,page: crate::Page,k0: &K,v0: Option<&V>,hdr: &header::Header,) -> Result<usize, usize> {let s = core::slice::from_raw_parts(page.data.as_ptr().add(HDR) as *const u64,hdr.n() as usize,);if let Some(v0) = v0 {s.binary_search_by(|&off| {let off = u64::from_le(off) & 0xfff;let (k, v) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(txn, k);match k.compare(txn, k0) {Ordering::Equal => {let v = V::from_raw_ptr(txn, v);v.compare(txn, v0)
})} else {s.binary_search_by(|&off| {let off = u16::from_le(off);let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k);match k.compare(txn, k0) {Ordering::Equal => Ordering::Greater,cmp => cmp
cmp => cmp,}})} else {match s.binary_search_by(|&off| {let off = u64::from_le(off) & 0xfff;let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(txn, k);k.compare(txn, k0)}) {Err(i) => Err(i),Ok(mut i) => {// Rewind if there are multiple matching keys.while i > 0 {let off = u64::from_le(s[i-1]) & 0xfff;let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k);if let Ordering::Equal = k.compare(txn, k0) {i -= 1} else {break}
}}unsafe fn lookup_leaf<T: LoadPage, K: UnsizedStorable + ?Sized, V: UnsizedStorable + ?Sized>(txn: &T,page: crate::Page,k0: &K,v0: Option<&V>,hdr: &header::Header,) -> Result<usize, usize> {let s = core::slice::from_raw_parts(page.data.as_ptr().add(HDR) as *const u16,hdr.n() as usize,);if let Some(v0) = v0 {s.binary_search_by(|&off| {let off = u16::from_le(off);let (k, v) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k as *const u8);match k.compare(txn, k0) {Ordering::Equal => {let v = V::from_raw_ptr(txn, v as *const u8);v.compare(txn, v0)}cmp => cmp,}})
let s = core::slice::from_raw_parts(page.data.as_ptr().add(HDR) as *const u64,hdr.n() as usize,);if let Some(v0) = v0 {s.binary_search_by(|&off| {let off = u64::from_le(off) & 0xfff;let (k, v) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(txn, k);match k.compare(txn, k0) {Ordering::Equal => {let v = V::from_raw_ptr(txn, v);v.compare(txn, v0)
match s.binary_search_by(|&off| {let off = u16::from_le(off);let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k);k.compare(txn, k0)}) {Err(e) => Err(e),Ok(mut i) => {// Rewind if there are multiple matching keys.while i > 0 {let off = u16::from_le(s[i-1]);let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(txn, k);if let Ordering::Equal = k.compare(txn, k0) {i -= 1} else {break
cmp => cmp,}})} else {s.binary_search_by(|&off| {let off = u64::from_le(off) & 0xfff;let (k, _) = read::<T, K, V>(txn, page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(txn, k);match k.compare(txn, k0) {Ordering::Equal => Ordering::Greater,cmp => cmp
impl<K:Storable, V:Storable, P: BTreePage<K, V> + core::fmt::Debug> Storable for Db_<K, V, P> {type PageReferences = core::iter::Once<u64>;fn page_references(&self) -> Self::PageReferences {core::iter::once(self.db)}fn drop<T: AllocPage>(&self, t: &mut T) -> Result<(), T::Error> {drop_(t, self)}}
/// to `(k, v)` if `v.is_some()`).
/// to `(k, v)` if `v.is_some()`), and return `true` if this entry is/// shared with another structure (i.e. the RC of at least one page/// along a path to the entry is at least 2).pub fn get_shared<'a, T: LoadPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>>(txn: &'a T,db: &Db_<K, V, P>,k: &K,v: Option<&V>,) -> Result<Option<(&'a K, &'a V, bool)>, T::Error> {// Set the "cursor stack" by setting a skip list cursor in// each page from the root to the appropriate leaf.let mut last_match = None;let mut page = txn.load_page(db.db)?;let mut is_shared = txn.rc(db.db)? >= 2;// This is a for loop, to allow the compiler to unroll (maybe).for _ in 0..cursor::N_CURSORS {let mut cursor = P::cursor_before(&page);if let Ok((kk, vv, _)) = P::set_cursor(txn, page.as_page(), &mut cursor, k, v) {if v.is_some() {return Ok(Some((kk, vv, is_shared)));}last_match = Some((kk, vv, is_shared));} else if let Some((k, v, _)) = P::current(txn, page.as_page(), &cursor) {// Here, Rust says that `k` and `v` have the same lifetime// as `page`, but we actually know that they're alive for// as long as `txn` doesn't change, so we can safely// extend their lifetimes:unsafe { last_match = Some((core::mem::transmute(k), core::mem::transmute(v), is_shared)) }}// The cursor is set to the first element greater than or// equal to the (k, v) we're looking for, so we need to// explore the left subtree.let next_page = P::left_child(page.as_page(), &cursor);if next_page > 0 {page = txn.load_page(next_page)?;is_shared |= txn.rc(db.db)? >= 2;} else {break;}}Ok(last_match)}/// Get the first entry of a database greater than or equal to `k` (or/// to `(k, v)` if `v.is_some()`), and return `true` if this entry is/// shared with another structure (i.e. the RC of at least one page/// along a path to the entry is at least 2).
del_at_cursor(txn, db, &mut cursor)
del_at_cursor(txn, db, &mut cursor, true)}/// If `value` is `None`, delete the first entry for `key` from the/// database, if present. Else, delete the entry for `(key, value)`,/// if present.pub fn del_no_decr<T: AllocPage + LoadPage,K: Storable + ?Sized + PartialEq,V: Storable + ?Sized + PartialEq,P: BTreeMutPage<K, V>,>(txn: &mut T,db: &mut Db_<K, V, P>,key: &K,value: Option<&V>,) -> Result<bool, T::Error> {let mut cursor = Cursor::new(txn, db)?;// If the key and value weren't found, return.match (cursor.set(txn, key, value)?, value) {(Some((k, v)), Some(value)) if k == key && v == value => {}(Some((k, _)), None) if k == key => {}_ => return Ok(false),}// Else, the cursor is set on `(key, value)` if `value.is_some()`// or on the first entry with key `key` else.//// We delete that position, which might be in a leaf or in an// internal node.del_at_cursor(txn, db, &mut cursor, false)
if p0 < cursor.first_rc_len() {
//// Note in particular that if p0 == cursor.first_rc_len(), then we// don't need to touch the RC, since we're cloning this page, but// without including a reference to the deleted entry.if decr_del_rc && p0 < cursor.first_rc_len() {
for o in delk.page_references().chain(delv.page_references()) {txn.decr_rc(o)?;}
delk.drop(txn)?;delv.drop(txn)?;
})
};if txn.free > 0 {let free_db: btree::Db<u64, ()> = btree::Db::from_page(txn.free);let mut init = Vec::new();for p in btree::rev_iter(&txn, &free_db, None)? {let (p, _) = p?;init.push(*p)}txn.initial_free = (init.len(), init)}Ok(txn)
debug!("free_db = {:?}", free_db);
debug!("free_db = {:x}", free_db.db);{for p in btree::iter(&self, &free_db, None).unwrap() {debug!("was free: p = {:x}", p.unwrap().0);}for p in self.free_pages.iter().chain(self.free_owned_pages.iter()) {debug!("free_pages {:x}", p);}}// Deleting the pages allocated during this transaction.let mut f = self.initial_free.1.len();while f > self.initial_free.0 {f -= 1;let p = self.initial_free.1[f];btree::del(&mut self, &mut free_db, &p.to_le(), None)?;}
// First, set the free table to 0 in this transaction, to// avoid recursing in the calls to `put` below (indeed,// the table of free pages is used when allocating new// pages, which may happen in a call to `put`).self.free = 0;// Then, while there are pages to free, free them. Since// the calls to `put` below might free pages (and add// pages to these two vectors), the (outer) loop might run// for more than one iteration.
if self.free == 0 {debug!("self.free = 0");return Ok(None);}let mut db: btree::Db<u64, ()> = btree::Db::from_page(self.free);let mut curs = btree::cursor::Cursor::new(self, &db)?;curs.set_last(self)?;let mut f = if let Some((f, ())) = curs.prev(self)? {*f} else {return Ok(None);};// Get the last page that is also free in all other versions.loop {debug!("trying 0x{:x}", f);
while self.initial_free.0 > 0 {self.initial_free.0 -= 1;let f = self.initial_free.1[self.initial_free.0];
impl<K: Check + Ord + UnsizedStorable + ?Sized, V: Check + Ord + UnsizedStorable + ?Sized, P: BTreePage<K, V> + std::fmt::Debug> Checkfor Db_<K, V, P>{fn add_refs<T: LoadPage>(&self,txn: &T,pages: &mut std::collections::BTreeMap<u64, usize>,) -> Result<(), T::Error>whereT::Error: std::fmt::Debug,{use std::collections::btree_map::Entry;let mut stack = vec![self.db];while let Some(p) = stack.pop() {match pages.entry(p) {Entry::Vacant(e) => {debug!("add_refs: 0x{:x}", p);e.insert(1);let p = txn.load_page(p)?;let mut c = P::cursor_first(&p);let l = P::left_child(p.as_page(), &c);if l > 0 {stack.push(l);}let mut kv = None;while let Some((k, v, r)) = P::next(txn, p.as_page(), &mut c) {debug!("{:?} {:?} {:?}", k, v, kv);if let Some((k_, v_)) = kv {debug!("{:?} {:?} {:?}", k_ > k, k_ == k, v_ > v);if k_ > k || (k_ == k && v_ > v) {debug(txn, &[self], "debug_ord", true);panic!("{:?} {:?} {:?} {:?} {:?}", kv, k_, v_, k_ > k, v_ > v);}}k.add_refs(txn, pages)?;v.add_refs(txn, pages)?;kv = Some((k, v));if r > 0 {stack.push(r);}}}Entry::Occupied(mut e) => {e.insert(e.get() + 1);}}}Ok(())}}
}}pub fn add_refs<T: LoadPage, K: Storable + Ord + ?Sized + std::fmt::Debug, V: Storable + Ord + ?Sized + std::fmt::Debug, P: BTreePage<K, V>>(txn: &T,db: &Db_<K, V, P>,pages: &mut std::collections::BTreeMap<u64, usize>,) -> Result<(), T::Error>whereT::Error: std::fmt::Debug{use std::collections::btree_map::Entry;let mut stack = vec![db.db];while let Some(p) = stack.pop() {match pages.entry(p) {Entry::Vacant(e) => {debug!("add_refs: 0x{:x}", p);e.insert(1);let p = txn.load_page(p)?;let mut c = P::cursor_first(&p);let l = P::left_child(p.as_page(), &c);if l > 0 {stack.push(l);}let mut kv = None;while let Some((k, v, r)) = P::next(txn, p.as_page(), &mut c) {debug!("{:?} {:?} {:?}", k, v, kv);if let Some((k_, v_)) = kv {debug!("{:?} {:?} {:?}", k_ > k, k_ == k, v_ > v);if k_ > k || (k_ == k && v_ > v) {debug(txn, &[db], "debug_ord", true);panic!("{:?} {:?} {:?} {:?} {:?}", kv, k_, v_, k_>k, v_>v);}}kv = Some((k, v));if r > 0 {stack.push(r);}}}Entry::Occupied(mut e) => {e.insert(e.get() + 1);}}
pub fn check_refs<B: std::borrow::Borrow<crate::Env>, T>(txn: &crate::MutTxn<B, T>, refs: &std::collections::BTreeMap<u64, usize>) {
pub fn check_refs<B: std::borrow::Borrow<crate::Env>, T>(txn: &crate::MutTxn<B, T>,refs: &std::collections::BTreeMap<u64, usize>,) {