FZBLNBGNQPNTLBNPNZ2C6DJ5323MZQ2PH54F6ZEKPFCK7TGJFGWAC 52X5P7NDBQHIJDIYNY3XUPDHHOO3PDPPNKGO2PGLXKVNM3EVECTQC E4MD6T3LNOYWVFTFFWCUKRNS4M2XVSKRLDWPYHMZHGDNO2T5JREQC OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC RV2L6CZWTMUQ2A52YDAFVHDFGURZL3H4SSCDC347UGN23D3J5KZQC H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC DV4A2LR7Q5LAEGAQHLO34PZCHGJUHPAMRZFGT7GUFNKVQKPJNOYQC EHJFNMB2R4MYG6ZSHHEENRFCSPFVWKVHLD5DXAE5HXUGXP5ZVHKQC QEUTVAZ4F4EJXRDMWDMYXF6XEDMX7YPVG4IIXEKPIR3K54E5W5OAC QYDGYIZRNFRIQD7RUCY5YAN3F2THZA74E5UOHPIFWSULEJFAFVJQC OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC 73Z2UB3JGRLFNFORE7D64O4IHIFSZASD4G4FLJ4FJLHANT75MGIAC W2MIZD5BNL7A5HVFWTESF57QU7T6QMEF4RBSLFQXMEEU3XD2NU2QC UAQX27N4PI4LHEW6LSHJETIE5MV7JTEMPLTJFYUBMYVPC43H7VOAC UUUVNC4DWEEL7WV5IRPKPZ6HZMYCPA53XM7LJWICUD4E6GN37IRQC 6DMPXOAT5GQ3BQQOMUZN2GMBQPRA4IB7CCPHTQTIFGO3KWWAKF3QC Q7DRIBBRE4MNG4NP3PVIXAJF5PQYLFWYIVK2O4VVLEO6XY3BOSFQC MSRWB47YP6L5BVTS53QQPBOHY5SXTSTR5KD6IIF35UWCTEUOCQWQC LSQ6V7M66TEGLJ7QBLRVDX4E7UKJTDQTEXZOS3KGPGFKVXNLPKBQC X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC G4JEQLLX6Q7VVFVAEJZAVQXX33MQ36CSCYSMJ5NQM5VZ76DXKU6QC S4V4QZ5CF5LUDYWNR2UMWH6CHJDJ5FPGAZCQYM5GY7FJMJV4NN4QC OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC XEU2QVLCHPYOOD4TQIPEEVYOVSFMKFPLJYWEJYXYJAZ7S54KWDZAC YWFYZNLZ5JHLIFVBRKZK4TSWVPROUPRG77ZB5M7UHT2OKPL4ZSRQC AOX2XQISHGWNNAFBYRN44Q6AWG7H5DPBK5YMFHK42HQNZ2TMHEJQC 6DCQHIFPEH4GZKSRRS32GMKDRPZH4MTCGOUEI7YEUVKWENBF3JWAC KM3JAFGPFV7MP7M2LJIYRVAUTU646B3IRXADTRZKOU2RF7LUB62QC LROAI3NBBSCU4T2YA6EHJYKKKL75AU5A7C7WIRCGIQ56S6HPLRXQC NXMFNPZ7VWJRLC3M5QJJVTICXCMGE24F3HVIZA7A7RLVMLQMLDVQC YXKP4AIWDBIWBBUDWF66YIPG5ECMHNKEV3PX6KYXOVXY3EWG3WGQC T7QB6QEPWBXAU3RL7LE4GRDWWNQ65ZU2YNNTWBYLORJOABAQFEZQC }#[test]pub fn empty_last_cursor() {env_logger::try_init().unwrap_or(());let env = Env::new_anon(409600000, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let db: Db<u64, ()> = create_db(&mut txn).unwrap();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();assert!(curs.set_last(&txn).unwrap().is_none());
}fn check_free(txn: &mut MutTxn<&Env, ()>, refs: &BTreeMap<u64, usize>) {if txn.free > 0 {let db_free = Db {db: txn.free,k: std::marker::PhantomData,v: std::marker::PhantomData,p: std::marker::PhantomData,};let mut curs: Cursor<_, _, B> = btree::cursor::Cursor::new(txn, &db_free).unwrap();debug!("{:?}", db_free);while let Some((k, _)) = curs.next(txn).unwrap() {debug!("free: {:?}", k);assert!(refs.get(k).is_none())}}for (r, _) in refs.iter() {assert!(*r < txn.length)}
fn add_refs<T: LoadPage, K: Storable, V: Storable, P: BTreePage<K, V>>(txn: &T,db: &Db_<K, V, P>,pages: &mut BTreeMap<u64, usize>,) -> Result<(), T::Error> {debug!("------ add_refs {:?}", db.db);let mut stack = vec![db.db];while let Some(p) = stack.pop() {debug!("-- p = {:?}", p);match pages.entry(p) {Entry::Vacant(e) => {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);debug!("l = {:?}", l);if l > 0 {stack.push(l);while let Some((_, _, r)) = P::next(txn, p.as_page(), &mut c) {debug!("r = {:?}", r);stack.push(r);}}}Entry::Occupied(mut e) => {debug!("already there");e.insert(e.get() + 1);}}}Ok(())}
/// std::fs::File size of the database path, if it exists.pub fn file_size<P: AsRef<Path>>(path: P) -> Result<u64, Error> {Ok(std::fs::metadata(&path)?.len())}
/// Initialize an environment. `length` must be a strictly/// positive multiple of 4096.
/// Initialize an environment. If `length` is not a multiple of/// `4096`, it is rounded to the next multiple of the page size/// (4096 bytes).////// The `n_roots` parameter is the maximum number of versions that/// can be alive at the same time, before `mut_txn_begin` must/// wait for old readers to stop.
/// The `n_roots` parameter is the maximum number of mutable/// transactions that can commit during a single immutable/// transaction, and must be at most 255. If it is 1, mutable/// transactions exclude all immutable transactions.
/// If `n_roots` is 1, mutable transactions exclude all readers.
}}type B = btree::page::Page<u64, ()>;pub fn check_free_mut(txn: &crate::MutTxn<&crate::Env, ()>,refs: &std::collections::BTreeMap<u64, usize>,) {let db_free = if txn.free > 0 {let db_free = Db::from_page(txn.free);let mut curs: Cursor<_, _, B> = btree::cursor::Cursor::new(txn, &db_free).unwrap();while let Some((k, _)) = curs.next(txn).unwrap() {assert!(refs.get(k).is_none())}Some(db_free)} else {None};debug!("{:?}", db_free);for (r, _) in refs.iter() {assert!(*r < txn.length)}let env = txn.env;let len = txn.length;for i in env.roots.len() as u64..(len >> 12) {let page = i << 12;if refs.contains_key(&page) {continue;} else if let Some(ref f) = db_free {if let Some((x, _)) = get(txn, f, &page, None).unwrap() {if *x == page {continue;}}}panic!("page not found: 0x{:x} (total length 0x{:x})", page, len);}}pub fn check_free<B: std::borrow::Borrow<crate::Env>>(txn: &crate::Txn<B>,refs: &std::collections::BTreeMap<u64, usize>,) {let env = txn.env.borrow();let (db_free, length): (Option<Db<u64, ()>>, _) = unsafe {let hdr = &*(env.mmaps.lock()[0].ptr.add(txn.root * PAGE_SIZE)as *const crate::environment::GlobalHeader);(if hdr.free_db != 0 {Some(Db::from_page(u64::from_le(hdr.free_db)))} else {None},u64::from_le(hdr.length),)};debug!("db_free: {:?}", db_free);for (r, _) in refs.iter() {debug!("r = 0x{:x}, length = 0x{:x}", r, length);assert!(*r < length)}for i in env.roots.len() as u64..(length >> 12) {let page = i << 12;if refs.contains_key(&page) {continue;} else if let Some(ref f) = db_free {if let Some((x, _)) = get(txn, f, &page, None).unwrap() {if *x == page {continue;}}}panic!("page not found: 0x{:x} (total length 0x{:x})", page, length);}}pub fn add_refs<T: LoadPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>>(txn: &T,db: &Db_<K, V, P>,pages: &mut std::collections::BTreeMap<u64, usize>,) -> Result<(), T::Error> {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);while let Some((_, _, r)) = P::next(txn, p.as_page(), &mut c) {stack.push(r);}}}Entry::Occupied(mut e) => {e.insert(e.get() + 1);}}
pub fn add_free_refs<B: std::borrow::Borrow<crate::Env>>(txn: &crate::Txn<B>,pages: &mut std::collections::BTreeMap<u64, usize>,) -> Result<(), crate::Error> {let env = txn.env.borrow();unsafe {let p = &*(env.mmaps.lock()[0].ptr.add(txn.root * PAGE_SIZE)as *const crate::environment::GlobalHeader);if p.free_db != 0 {debug!("add_free_refs: free = 0x{:x}", p.free_db);let free_db: Db<u64, ()> = btree::Db::from_page(p.free_db);add_refs(txn, &free_db, pages)?;}if p.rc_db != 0 {debug!("add_free_refs: rc = 0x{:x}", p.rc_db);let rc_db: Db<u64, ()> = btree::Db::from_page(p.rc_db);add_refs(txn, &rc_db, pages)?;}};Ok(())}pub fn add_free_refs_mut<B: std::borrow::Borrow<crate::Env>, T>(txn: &crate::MutTxn<B, T>,pages: &mut std::collections::BTreeMap<u64, usize>,) -> Result<(), crate::Error> {let env = txn.env.borrow();unsafe {let p = &*(env.mmaps.lock()[0].ptr.add(txn.root * PAGE_SIZE)as *const crate::environment::GlobalHeader);if p.free_db != 0 {debug!("add_free_refs: free = 0x{:x}", p.free_db);let free_db: Db<u64, ()> = btree::Db::from_page(p.free_db);add_refs(txn, &free_db, pages)?;}if p.rc_db != 0 {debug!("add_free_refs: rc = 0x{:x}", p.rc_db);let rc_db: Db<u64, ()> = btree::Db::from_page(p.rc_db);add_refs(txn, &rc_db, pages)?;}};Ok(())}