HMWFIUDS5LITLG5AB2LL6KIHFF6W3Y4LCB4JLZBWIYIIV74PSXQAC LPKM23EUHSWN3BQ3ZGRZTYUNJYJHCXONSJAE6X6LTYTU656TICFAC 26KI6CQSTGLQ4MGPLFQYPLDMH56M6VY6KQB5ONMQXUNV3ZX665TQC 5NBCUZRB6HQHE4CMVI4QJKXNBYON5OGOVGAOJPDV3WGJVVQ55UKAC 76S6EF7U7JCK2IDKWZZLGNCPIFDPW6NRM6UZQFPT6MMWY44L6XEAC C36737FJVMZSBWSQV7ZEYRYUPJVNLK3MGY3EJVAPYHYAM36J7TJQC IXHKA46LGAWUCGMZ6VWHCVEVSDQSFRAGDKBNLCXUBTJBIZR7EPJAC KK3SBH4P3FBZ3ER344TO6WEK7EX5AFB57UX2G5PKANG3NUF5IQLAC CCNPHVQCIGINWTLXCHOASGVWUPBZXFOLM2F7HTKMEA2DMFTOX7TAC QYDGYIZRNFRIQD7RUCY5YAN3F2THZA74E5UOHPIFWSULEJFAFVJQC OP6SVMOD2GTQ7VNJ4E5KYFG4MIYA7HBMXJTADALMZH4PY7OQRMZQC OHG5NX6KVGKNA7S7SU3MTPOZCN4RRZK2SGZWZ5LIRXUMCYIPUHIAC H3FVSQIQGFCFKCPXVOSFHP4OSUOBBURJESCZNGQTNDAAD3WQSBEQC W2MIZD5BNL7A5HVFWTESF57QU7T6QMEF4RBSLFQXMEEU3XD2NU2QC HJ6VZ7HFS2YEQ5LSUJ35TKVS7LHAZ6FJO55ONDTQPUUI5VLRPP6AC G4JEQLLX6Q7VVFVAEJZAVQXX33MQ36CSCYSMJ5NQM5VZ76DXKU6QC WS4ZQM4RMIHZ6XZKSDQJGHN5SSSWFL4H236USOPUA33S6RC53RFAC XEU2QVLCHPYOOD4TQIPEEVYOVSFMKFPLJYWEJYXYJAZ7S54KWDZAC HCDD6FX7YL5MDK757ZE6MYHB2YHCUAO2Y3Y347JBTG4DNCIJJBIQC HN6Z5DU4WYMAIOOSNVHLIIMNF6Q53TNJ7YC27SLKWNXVYCTACQKQC KMT3MF5NLEQIPZLHCRYDGQ5EA46HJCG3C2ANEPMZGKGHDK77ADPAC TSMS6W4DOKQNUQ4PEMTLOIODR33VFPN6MMNS73ZPSU4BOQVRGPNAC 6DMPXOAT5GQ3BQQOMUZN2GMBQPRA4IB7CCPHTQTIFGO3KWWAKF3QC 6UVFCERMGSGNRWCVC3GWO5HWV6MSWE433DXBJVC7KRPP6LLJLCSQC 3CKCVBXTNSYJIQL5P35V5NHM7C7BQZCSGO7OZMGBZRUUVIQHAZAAC LSQ6V7M66TEGLJ7QBLRVDX4E7UKJTDQTEXZOS3KGPGFKVXNLPKBQC 73Z2UB3JGRLFNFORE7D64O4IHIFSZASD4G4FLJ4FJLHANT75MGIAC W26CFMAQOXMUK4ZOJMAN4SMBXMWFQHO7HCTEVW73FQSRMJZFGJIQC OFINGD26ZWCRDVVDI2ZIBLMHXKEMJA6MRNLANJYUHQPIJLPA7J2AC DV4A2LR7Q5LAEGAQHLO34PZCHGJUHPAMRZFGT7GUFNKVQKPJNOYQC RV2L6CZWTMUQ2A52YDAFVHDFGURZL3H4SSCDC347UGN23D3J5KZQC FMN7X4J24EYPOJNBUWM4NKGWSJTRV2DHCIBMPV2AXLZVVAMNOBKQC DASFQGORX56YK5E4Y7GGYZSQQQMUXYTZZ4A6IVWSTI3QGRUORLPAC 52X5P7NDBQHIJDIYNY3XUPDHHOO3PDPPNKGO2PGLXKVNM3EVECTQC SYURNHHL3P22ZAERTML4YW3DYLATHY5ALZH4GL5NF3LENDSKL2NQC L5CVF6UJYR6FRQA2NULFHGQFID7BGM4D622OJ2TVWRU7EAR57DHAC KX3WVNZW5KHVEH6EOQTZ4RBEFFJ3SGF5I467X3JWZ74PURRK4HVAC PPI5ZTZP2GMKTCFQWF2SXIT6VNOY5U7PJSMX4ZR34DLMYG3GSSFQC Q7DRIBBRE4MNG4NP3PVIXAJF5PQYLFWYIVK2O4VVLEO6XY3BOSFQC OTWDDJE7TTE73D6BGF4ZN6BH2NFUFLPME2VJ3CPALH463UGWLEIQC X3QVVQIS7B7L3XYZAWL3OOBUXOJ6RMOKQ45YMLLGAHYPEEKZ45ZAC QEUTVAZ4F4EJXRDMWDMYXF6XEDMX7YPVG4IIXEKPIR3K54E5W5OAC APPY2E7M5NHNC6MFYXSVEKJVAILK7YAZVTVE3W75EK2JNFVS3XBQC NXMFNPZ7VWJRLC3M5QJJVTICXCMGE24F3HVIZA7A7RLVMLQMLDVQC YWFYZNLZ5JHLIFVBRKZK4TSWVPROUPRG77ZB5M7UHT2OKPL4ZSRQC ONES3V466GLO5CXKRF5ENK7VFOQPWM3YXLVRGWB56V5SH3W7XNBQC T73WR2BX2QDQ6APOREBXUKNH52FDLJNBGWPQUYB2TAF2PT7XCL2AC ESUI5EUZUBDPHNN3APU33IFORYPYR6J3WEMEZG57FKF3EH66ZBHAC GGEFV4YYK7E6J3544XSXN5CBASQI3QE6LTFZCJAGOXHEEKD6BRCQC UUUVNC4DWEEL7WV5IRPKPZ6HZMYCPA53XM7LJWICUD4E6GN37IRQC LROAI3NBBSCU4T2YA6EHJYKKKL75AU5A7C7WIRCGIQ56S6HPLRXQC LK2C7EU4SM5HIEBRARQMLRL7IFQYBD3SXWXB2YSZL577NQFTZCIQC UAQX27N4PI4LHEW6LSHJETIE5MV7JTEMPLTJFYUBMYVPC43H7VOAC BYI23QWI44ZINCI32VLVG2JJG3WUZFCYEKNNNLLMXMWQCTKZ6PRAC FZBLNBGNQPNTLBNPNZ2C6DJ5323MZQ2PH54F6ZEKPFCK7TGJFGWAC E4MD6T3LNOYWVFTFFWCUKRNS4M2XVSKRLDWPYHMZHGDNO2T5JREQC 6DCQHIFPEH4GZKSRRS32GMKDRPZH4MTCGOUEI7YEUVKWENBF3JWAC MSRWB47YP6L5BVTS53QQPBOHY5SXTSTR5KD6IIF35UWCTEUOCQWQC S4V4QZ5CF5LUDYWNR2UMWH6CHJDJ5FPGAZCQYM5GY7FJMJV4NN4QC AFKBHYVE25QMIU2WZATEGWG2EXSBQZ44DVDPACKNS3M4QGBF4ONAC 5LSYTRQ6IOVUW26VJW5SWGFEIB7T2N4PVEB6VMNMR5ZHQ75MFOQAC AOX2XQISHGWNNAFBYRN44Q6AWG7H5DPBK5YMFHK42HQNZ2TMHEJQC EYNN7RLSFVBWDLRTLNNFUAF46Q6OX3BR5SUEJIOOHBSNP7FVBXGAC KM3JAFGPFV7MP7M2LJIYRVAUTU646B3IRXADTRZKOU2RF7LUB62QC YDHYZA77LFQ7RSKTVOTOQRL7EUSXMWYOSJAE5YAH6HLHE64B75LQC SO25TWFLSRQIVTJTTSN77LO5FZQVQPIZTSBULH7MWBBDEWSK3OCAC RLVQDUPYOWVNHTVFCHKNIQYNBRLOFY2UGIJPLD6U5S22AMEF5YSAC 3QM7P3RRVYYDEJNFDG3GHZDMSSHPPJC3WQOJGETGREOM4I2A6D5AC YXKP4AIWDBIWBBUDWF66YIPG5ECMHNKEV3PX6KYXOVXY3EWG3WGQC XOXTGNPZRTDWNCZ5BI723A6CZ6LLTP4RXIGVWYYK7NQVRWZEZ77AC TJ2R4HAZ23H3NW7CJSBXLLXUNPLK25XX33CLOL74NWO32JCG4UZQC AI4NKV4J2AXQ4BVFUI7ZWPJO6BCQEBJACZGIXF2EMGFUWEM3X2ZAC WTXLZDYIS2AQZFOO7WCSFGRK235NR2VSOI2LOCORWF5WRS3E76UAC VRAQTH26BACG74FXYGWKXWNWDBKF27Y6DX5KJ7XSLZ3HIUKVLTSQC M6PHQUGLW2UN6LIVF4NCPNBFBMALVCPZFQ2AYZGYHSOKO3RXWG2AC T7QB6QEPWBXAU3RL7LE4GRDWWNQ65ZU2YNNTWBYLORJOABAQFEZQC OHUZ73MKWD7SSB4DKKA532DEQKXQDS6PZ6HJ3EC2DLVJSLQH3NLAC #[derive(Clone, Copy)]pub struct Mut<T>(pub *mut T);unsafe impl<T> Send for Mut<T> {}impl<T> Mut<T> {pub unsafe fn new(p: *mut T) -> Self {Mut(p)}pub fn into_inner(self) -> *mut T {self.0}}#[derive(Clone, Copy)]pub struct Const<T>(pub *const T);unsafe impl<T> Send for Const<T> {}impl<T> Const<T> {pub unsafe fn new(p: *const T) -> Self {Const(p)}pub fn into_inner(self) -> *const T {self.0}}
async fn alloc_page(&mut self) -> Result<MutPage, Self::Error>;
async unsafe fn alloc_page(&mut self) -> Result<MutPage, Self::Error>;/// Allocate a new page, and mark it as not requiring cleaning of the dirty bit.async unsafe fn alloc_page_nodirty(&mut self) -> Result<MutPage, Self::Error> {unimplemented!()}/// Allocate a new block.async unsafe fn alloc_contiguous(&mut self, length: u64) -> Result<MutPage, Self::Error>;
db.db = put_cascade(txn, &mut cursor, put, &mut free).await?.0.offset;for f in &free[..p] {if *f & 1 != 0 {txn.decr_rc_owned((*f) ^ 1).await?;} else if *f > 0 {txn.decr_rc(*f).await?;
db.db = put_cascade(txn, &mut cursor, put, &mut free).await?.0.offset;unsafe {for f in &free[..p] {if *f & 1 != 0 {txn.decr_rc_owned((*f) ^ 1).await?;} else if *f > 0 {txn.decr_rc(*f).await?;}
let (k, v) = read::<K, V>(page.data.as_ptr().add(off as usize));Ok((K::from_raw_ptr(k), V::from_raw_ptr(v), 0))
let (k, v) = {let (k, v) = read::<K, V>(page.data.as_ptr().add(off as usize));let k = Const(k as *const u8);let v = Const(v as *const u8);(k, v)};Ok((K::from_raw_ptr(txn, k).await,V::from_raw_ptr(txn, v).await,0,))
lookup_internal(page, k0, v0, hdr)
lookup_internal(txn, page, k0, v0, hdr).await}}async fn binary_search_by<'a, T, F, O>(s: &'a [T], mut f: F) -> Result<usize, usize>whereF: FnMut(&'a T) -> O,O: core::future::Future<Output = Ordering>,{use Ordering::*;let mut size = s.len();let mut left = 0;let mut right = size;while left < right {let mid = left + size / 2;// SAFETY: the while condition means `size` is strictly positive, so// `size/2 < size`. Thus `left + size/2 < left + size`, which// coupled with the `left + size <= self.len()` invariant means// we have `left + size/2 < self.len()`, and this is in-bounds.let cmp = f(unsafe { s.get_unchecked(mid) }).await;// The reason why we use if/else control flow rather than match// is because match reorders comparison operations, which is perf sensitive.// This is x86 asm for u8: https://rust.godbolt.org/z/8Y8Pra.if cmp == Less {left = mid + 1;} else if cmp == Greater {right = mid;} else {return Ok(mid);}size = right - left;
let (k, v) = read::<K, V>(page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(k);match k.compare(k0) {
let (k, v) = {let (k, v) = read::<K, V>(page.data.as_ptr().offset(off as isize & 0xfff));(Const(k), Const(v))};let k = K::from_raw_ptr(txn, k).await;match k.compare(txn, k0).await {
let (k, _) = read::<K, V>(page.data.as_ptr().offset(off as isize & 0xfff));let k = K::from_raw_ptr(k);k.compare(k0)}) {
let k = Const(read::<K, V>(page.data.as_ptr().offset(off as isize & 0xfff)).0);let k = K::from_raw_ptr(txn, k).await;k.compare(txn, k0).await}).await{
let off = u64::from_le(s[i-1]) & 0xfff;let (k, _) = read::<K, V>(page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(k);if let Ordering::Equal = k.compare(k0) {
let off = u64::from_le(s[i - 1]) & 0xfff;let k = Const(read::<K, V>(page.data.as_ptr().offset(off as isize)).0);let k = K::from_raw_ptr(txn, k).await;if let Ordering::Equal = k.compare(txn, k0).await {
let (k, v) = read::<K, V>(page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(k as *const u8);match k.compare(k0) {
let (k, v) = {let (k, v) = read::<K, V>(page.data.as_ptr().offset(off as isize));(Const(k as *const u8), Const(v as *const u8))};let k = K::from_raw_ptr(txn, k).await;match k.compare(txn, k0).await {
let (k, _) = read::<K, V>(page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(k);k.compare(k0)}) {
let k = Const(read::<K, V>(page.data.as_ptr().offset(off as isize)).0);let k = K::from_raw_ptr(txn, k).await;k.compare(txn, k0).await}).await{
let off = u16::from_le(s[i-1]);let (k, _) = read::<K, V>(page.data.as_ptr().offset(off as isize));let k = K::from_raw_ptr(k);if let Ordering::Equal = k.compare(k0){
let off = u16::from_le(s[i - 1]);let k = Const(read::<K, V>(page.data.as_ptr().offset(off as isize)).0);let k = K::from_raw_ptr(txn, k).await;if let Ordering::Equal = k.compare(txn, k0).await {
return Ok(Op::Put(Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,).await?));
return Ok(Op::Put(Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,).await?,));
fn modify<K: core::fmt::Debug + ?Sized, V: core::fmt::Debug + ?Sized, P: BTreeMutPage<K, V>, L: AllocWrite<K, V>>(
async fn modify<'a,K: core::fmt::Debug + ?Sized,V: core::fmt::Debug + ?Sized,P: BTreeMutPage<K, V>,L: AllocWrite<K, V>,T: AllocPage,>(txn: &mut T,
L::alloc_write(&mut new, m.mid.0, m.mid.1, 0, l, &mut n);while let Some((k, v, r)) = P::next(m.other.as_page(), &mut rc) {L::alloc_write(&mut new, k, v, 0, r, &mut n);
L::alloc_write(txn, &mut new, m.mid.0, m.mid.1, 0, l, &mut n).await;while let Some((k, v, r)) = P::next(txn, m.other.as_page(), &mut rc).await {L::alloc_write(txn, &mut new, k, v, 0, r, &mut n).await;
L::alloc_write(&mut new, m.mid.0, m.mid.1, 0, 0, &mut n);modify::<_, _, _, L>(&mut new, &mut m.modified, &mut n);
L::alloc_write(txn, &mut new, m.mid.0, m.mid.1, 0, 0, &mut n).await;modify::<_, _, _, L, _>(txn, &mut new, &mut m.modified, &mut n).await;
fn alloc_write(new: &mut MutPage, k0: &K, v0: &V, l: u64, r: u64, n: &mut isize) {alloc_write::<K, V, Self>(new, k0, v0, l, r, n)
async fn alloc_write<T: AllocPage>(txn: &mut T,new: &mut MutPage,k0: &K,v0: &V,l: u64,r: u64,n: &mut isize,) {alloc_write::<K, V, Self, T>(txn, new, k0, v0, l, r, n).await
fn alloc_write(new: &mut MutPage, k0: &K, v0: &V, l: u64, r: u64, n: &mut isize) {alloc_write::<K, V, Self>(new, k0, v0, l, r, n)
async fn alloc_write<T: AllocPage>(txn: &mut T,new: &mut MutPage,k0: &K,v0: &V,l: u64,r: u64,n: &mut isize,) {alloc_write::<K, V, Self, T>(txn, new, k0, v0, l, r, n).await
return Ok(Op::Put(Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,).await?));
return Ok(Op::Put(Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,).await?,));
let tup = unsafe { &*(p.as_ptr().offset(off as isize & 0xfff) as *const Tuple<K, V>) };match tup.k.compare(k0) {
let (k, v) = unsafe {let ptr = &*(p.as_ptr().offset(off as isize & 0xfff) as *const Tuple<K, V>);(&ptr.k, &ptr.v)};match k.compare(txn, k0).await {
if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,).await? {
if let Put::Ok(Ok { page, freed }) =<Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl).await?{
if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,).await? {
if let Put::Ok(Ok { page, freed }) =<Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl).await?{
#[async_trait(?Send)]impl<K:Storable, V:Storable, P: BTreePage<K, V> + Send + core::fmt::Debug> Storable for Db_<K, V, P> {
#[async_trait]impl<K: Storable, V: Storable, P: BTreePage<K, V> + core::fmt::Debug> Storable for Db_<K, V, P> {
let cur = unsafe { &mut *stack[ptr].0.as_mut_ptr() };if P::move_next(&mut cur.cursor) {Some(P::left_child(cur.page.as_page(), &cur.cursor))
let (page, cursor) = unsafe {let cur = &mut *stack[ptr].0.as_mut_ptr();(cur.page.as_page(), &mut cur.cursor)};if P::move_next(cursor) {Some(P::left_child(page, cursor))
(Some((k, v)), Some(value)) if k == key && v == value => {}(Some((k, _)), None) if k == key => {}
(Some((k, v)), Some(value))if k.compare(txn, key).await == Ordering::Equal&& v.compare(txn, value).await == Ordering::Equal => {}(Some((k, _)), None) if k.compare(txn, key).await == Ordering::Equal => {}
(Some((k, v)), Some(value)) if k == key && v == value => {}(Some((k, _)), None) if k == key => {}
(Some((k, v)), Some(value))if k.compare(txn, key).await == Ordering::Equal&& v.compare(txn, value).await == Ordering::Equal => {}(Some((k, _)), None) if k.compare(txn, key).await == Ordering::Equal => {}
for p in free.iter() {if p[0] & 1 == 1 {txn.decr_rc_owned(p[0] ^ 1).await?;} else if p[0] > 0 {txn.decr_rc(p[0]).await?;}if p[1] & 1 == 1 {txn.decr_rc_owned(p[1] ^ 1).await?;} else if p[1] > 0 {txn.decr_rc(p[1]).await?;
unsafe {for p in free.iter() {if p[0] & 1 == 1 {txn.decr_rc_owned(p[0] ^ 1).await?;} else if p[0] > 0 {txn.decr_rc(p[0]).await?;}if p[1] & 1 == 1 {txn.decr_rc_owned(p[1] ^ 1).await?;} else if p[1] > 0 {txn.decr_rc(p[1]).await?;}
if d > 0 {if last_op.page.is_dirty() {txn.decr_rc_owned(last_op.page.offset).await?;
unsafe {if d > 0 {if last_op.page.is_dirty() {txn.decr_rc_owned(last_op.page.offset).await?;} else {txn.decr_rc(last_op.page.offset).await?;}db.db = d;
let page = if let Put::Ok(p) = P::put(txn, page.0, true, false, &c, k, v, None, l, r).await? {p.page} else {unreachable!()};
let page =if let Put::Ok(p) = P::put(txn, page.0, true, false, &c, k, v, None, l, r).await? {p.page} else {unreachable!()};
unsafe impl<K, V, P: BTreePage<K, V>> Send for PageCursor<K, V, P>{}unsafe impl<K, V, P: BTreePage<K, V>> Sync for PageCursor<K, V, P>{}
unsafe impl<K, V, P: BTreePage<K, V>> Send for PageCursor<K, V, P> {}unsafe impl<K, V, P: BTreePage<K, V>> Sync for PageCursor<K, V, P> {}
unsafe impl<K, V, P: BTreePage<K, V>> Send for Cursor<K, V, P>{}unsafe impl<K, V, P: BTreePage<K, V>> Sync for Cursor<K, V, P>{}
struct StackElt<K: ?Sized, V: ?Sized, P: BTreePage<K, V>>(*mut PageCursor<K, V, P>);unsafe impl<K, V, P: BTreePage<K, V>> Send for StackElt<K, V, P> {}unsafe impl<K, V, P: BTreePage<K, V>> Sync for StackElt<K, V, P> {}unsafe impl<K, V, P: BTreePage<K, V>> Send for Cursor<K, V, P> {}unsafe impl<K, V, P: BTreePage<K, V>> Sync for Cursor<K, V, P> {}impl<K: ?Sized, V: ?Sized, P: BTreePage<K, V>> StackElt<K, V, P> {unsafe fn page<'a>(&self) -> Page<'a> {(&*self.0).page.as_page()}unsafe fn cursor<'a>(&self) -> &'a P::Cursor {&(&*self.0).cursor}}
let (cur_entry, r) = if let Some((k, v, r)) = P::current(current.page.as_page(), ¤t.cursor) {(Some((k, v)), r)} else {(None, P::right_child(current.page.as_page(), ¤t.cursor))
let (cur_entry, r) = {let cur_page = unsafe { current.page() };let cur_cursor = unsafe { current.cursor() };if let Some((k, v, r)) = P::current(txn, cur_page, cur_cursor).await {(Some((k, v)), r)} else {(None, P::right_child(cur_page, cur_cursor))}
let cur_entry = P::current(current.page.as_page(), ¤t.cursor);let left = P::left_child(current.page.as_page(), ¤t.cursor);
let cur_entry = unsafe { P::current(txn, current.page(), current.cursor()).await };let left = unsafe { P::left_child(current.page(), current.cursor()) };
////// The size limit for an entry depends on the datastructure. For B/// trees, nodes are guaranteed to be at least half-full (i.e. at/// least 2kiB), and we need at least two entries in each page in/// order to be able to rebalance in a deletion. A sufficient/// condition for this is that the size of any entry is less than/// 1/4th of the blocks. Now, internal nodes need 16 bytes of block/// header, and then 8 extra bytes for each entry. Entries must/// therefore not exceed 4080/4 - 8 = 1012 bytes.
unsafe fn write_to_page<T: AllocPage>(&self, t: &mut T, p: *mut u8);
unsafe fn write_to_page(&self, _: *mut u8) {unimplemented!()}/// Write to a page. Must not overwrite the allocated size, but/// this isn't checked (which is why it's unsafe).////// This is similar to `write_to_page`, but allows the user to/// allocate a value as needed when inserting the value into the/// base; do not implement both methods, since only/// `write_to_page_alloc` gets called by the library.////// The default implementation just calls `write_to_page`.unsafe fn write_to_page_alloc<T: AllocPage>(&self, _: &mut T, p: *mut u8) {self.write_to_page(p)}
let page = if len > 4096 {t.alloc_contiguous((((len + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE)as u64).unwrap()} else {t.alloc_page().unwrap()};
let page = t.alloc_contiguous((((len + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE) as u64).unwrap();assert!(page.0.offset > 0);
pub fn crc(&self, hasher: &crc32fast::Hasher) -> u32 {let mut hasher = hasher.clone();hasher.reset();// Hash the beginning and the end of the page (i.e. remove// the CRC).unsafe {// Remove the dirty bit.let x = [(*self.data) & 0xfe];hasher.update(&x[..]);hasher.update(core::slice::from_raw_parts(self.data.add(1), 3));hasher.update(core::slice::from_raw_parts(self.data.add(8), PAGE_SIZE - 8));}hasher.finalize()
pub unsafe fn crc(&self, hasher: &crc32fast::Hasher) -> u32 {crc(self.data, hasher)
pub fn crc_check(&self, hasher: &crc32fast::Hasher) -> bool {let crc = unsafe { u32::from_le(*(self.data as *const u32).add(1)) };self.crc(hasher) == crc
pub unsafe fn crc_check(&self, hasher: &crc32fast::Hasher) -> bool {crc_check(self.data, hasher)
pub fn clear_dirty(&mut self, hasher: &crc32fast::Hasher) {unsafe {*self.0.data &= 0xfe;let crc = (self.0.data as *mut u32).add(1);*crc = self.0.crc(hasher)}
pub unsafe fn clear_dirty(&mut self, hasher: &crc32fast::Hasher) {*self.0.data &= 0xfe;let crc_ = (self.0.data as *mut u32).add(1);*crc_ = crc(self.0.data, hasher)}}#[cfg(feature = "crc32")]pub unsafe fn crc(data: *mut u8, hasher: &crc32fast::Hasher) -> u32 {let mut hasher = hasher.clone();hasher.reset();// Hash the beginning and the end of the page (i.e. remove// the CRC).unsafe {// Remove the dirty bit.let x = [(*data) & 0xfe];hasher.update(&x[..]);hasher.update(core::slice::from_raw_parts(data.add(1), 3));hasher.update(core::slice::from_raw_parts(data.add(8), PAGE_SIZE - 8));}hasher.finalize()}#[cfg(feature = "crc32")]pub unsafe fn crc_check(data: *mut u8, hasher: &crc32fast::Hasher) -> bool {let crc_ = unsafe { u32::from_le(*(data as *const u32).add(1)) };crc(data, hasher) == crc_}#[cfg(not(feature = "crc32"))]pub fn clear_dirty(p: *mut u8) {unsafe { *p &= 0xfe }}#[cfg(feature = "crc32")]pub fn clear_dirty(p: *mut u8, hasher: &crc32fast::Hasher) {unsafe {*p &= 0xfe;let crc_ = (p as *mut u32).add(1);*crc_ = crc(p, hasher)
fn load_page(&self, off: u64) -> Result<CowPage, Self::Error>;
unsafe fn load_page(&self, off: u64) -> Result<CowPage, Self::Error>;/// Loading multiple pages written contiguously in the underlying/// storage media.////// If the type also implements `AllocPage`, attention must be/// paid to the compatibility with `alloc_contiguous`.unsafe fn load_page_contiguous(&self, _off: u64, _len: u64) -> Result<CowPage, Self::Error> {unimplemented!()}
fn alloc_page(&mut self) -> Result<MutPage, Self::Error>;/// Allocate many contiguous pages, return the first onefn alloc_contiguous(&mut self, length: u64) -> Result<MutPage, Self::Error>;
unsafe fn alloc_page(&mut self) -> Result<MutPage, Self::Error>;/// Allocate a new page, in a context where we cannot use the/// "dirty bit" trick directly on the page.unsafe fn alloc_page_no_dirty(&mut self) -> Result<MutPage, Self::Error> {unimplemented!()}/// Allocate many contiguous pages, return the first one. The/// dirty bit is not needed.unsafe fn alloc_contiguous(&mut self, length: u64) -> Result<MutPage, Self::Error>;
pub fn put<T: AllocPage,K: Storable + ?Sized,V: Storable + ?Sized,P: BTreeMutPage<K, V>,>(
pub fn put<T: AllocPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreeMutPage<K, V>>(
let put = P::put(txn,cur.page,is_owned,false,&cur.cursor,key,value,None,0,0,)?;
let put = unsafe {P::put(txn,cur.page,is_owned,false,&cur.cursor,key,value,None,0,0,)?};
db.db = put_cascade(txn, &mut cursor, put, &mut free)?.0.offset;for f in &free[..p] {if *f & 1 != 0 {txn.decr_rc_owned((*f) ^ 1)?;} else if *f > 0 {txn.decr_rc(*f)?;
unsafe {db.db = core::num::NonZeroU64::new_unchecked(put_cascade(txn, &mut cursor, put, &mut free)?.0.offset,);for f in &free[..p] {if *f & 1 != 0 {txn.decr_rc_owned((*f) ^ 1)?;} else if *f > 0 {txn.decr_rc(*f)?;}
fn put_cascade<T: AllocPage,K: Storable + ?Sized,V: Storable + ?Sized,P: BTreeMutPage<K, V>,>(
fn put_cascade<T: AllocPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreeMutPage<K, V>>(
put = P::put(txn,cur.page,is_owned,false,&cur.cursor,split_key,split_value,None,left.0.offset,right.0.offset,)?;
put = unsafe {P::put(txn,cur.page,is_owned,false,&cur.cursor,split_key,split_value,None,left.0.offset,right.0.offset,)?};
if let Put::Ok(p) = P::put(txn,p.0,true,false,&cursor,split_key,split_value,None,left.0.offset,right.0.offset,)? {
if let Put::Ok(p) = unsafe {P::put(txn,p.0,true,false,&cursor,split_key,split_value,None,left.0.offset,right.0.offset,)?} {
put = Put::Ok(P::update_left_child(txn,curs.page,is_owned,&curs.cursor,page.0.offset,)?)
// Same as above: increment the relevant reference// counters.incr_descendants::<T, K, V, P>(txn, cursor, free, freed)?;// And update the left child of the current cursor,// since the main invariant of cursors is that we're// always visiting the left child (if we're visiting// the last child of a page, the cursor is set to the// position strictly after the entries).let is_owned = cursor.len() < cursor.first_rc_len();if let Some(curs) = cursor.pop() {// If we aren't at the root, just update the child.put = Put::Ok(unsafe {P::update_left_child(txn, curs.page, is_owned, &curs.cursor, page.0.offset)?})
// Same as above: increment the relevant reference// counters.incr_descendants::<T, K, V, P>(txn, cursor, free, freed)?;// And update the left child of the current cursor,// since the main invariant of cursors is that we're// always visiting the left child (if we're visiting// the last child of a page, the cursor is set to the// position strictly after the entries).let is_owned = cursor.len() < cursor.first_rc_len();if let Some(curs) = cursor.pop() {// If we aren't at the root, just update the child.
fn modify<T: LoadPage + AllocPage, K: core::fmt::Debug + ?Sized, V: core::fmt::Debug + ?Sized, P: BTreeMutPage<K, V>, L: AllocWrite<K, V>>(
fn modify<T: LoadPage + AllocPage,K: core::fmt::Debug + ?Sized,V: core::fmt::Debug + ?Sized,P: BTreeMutPage<K, V>,L: AllocWrite<K, V>,>(
let new_left = if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)? {
let new_left = if let Put::Ok(Ok { page, freed }) = unsafe {<Page<K, V>>::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)?} {
if let Put::Ok(Ok { freed, page }) = <Page<K, V>>::put(txn, new_left.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,)? {
if let Put::Ok(Ok { freed, page }) = unsafe {<Page<K, V>>::put(txn, new_left.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,)?} {
let off =unsafe { *(page.data.as_ptr().offset((HDR as isize + c.cur * 8) - 8) as *const u64) };
let off = unsafe {*(page.data.as_ptr().offset((HDR as isize + c.cur * 8) - 8) as *const u64)};
return Ok(Op::Put(Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)?));
return Ok(Op::Put(unsafe {Self::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)?}));
let page = if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)? {
let page = if let Put::Ok(Ok { page, freed }) = unsafe {<Page<K, V>>::put(txn,m.modified.page,m.modified.mutable,m.modified.skip_first,&m.modified.c1,k,v,m.modified.ins2,m.modified.l,m.modified.r,)?} {
if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,)? {
if let Put::Ok(Ok { page, freed }) = unsafe {<Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl)?} {
let (page, freed) = <Page<K, V>>::del(txn,m.modified.page,m.modified.mutable,&m.modified.c1,m.modified.l,)?;
let (page, freed) = unsafe {<Page<K, V>>::del(txn,m.modified.page,m.modified.mutable,&m.modified.c1,m.modified.l,)?};
if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl,)? {
if let Put::Ok(Ok { page, freed }) = unsafe {<Page<K, V>>::put(txn, page.0, true, false, &lc, m.mid.0, m.mid.1, None, 0, rl)?} {
if let Put::Ok(Ok { page, freed }) = <Page<K, V>>::put(txn, m.modified.page, m.modified.mutable, false, &lc, m.mid.0, m.mid.1, None, 0, rl,)? {
if let Put::Ok(Ok { page, freed }) = unsafe {<Page<K, V>>::put(txn,m.modified.page,m.modified.mutable,false,&lc,m.mid.0,m.mid.1,None,0,rl,)?} {
fn alloc_write<T: AllocPage>(t: &mut T, new: &mut MutPage, k0: &K, v0: &V, l: u64, r: u64, n: &mut isize) {alloc_write::<T, K, V, Self>(t, new, k0, v0, l, r, n)
fn alloc_write<T: AllocPage>(_txn: &mut T,new: &mut MutPage,k0: &K,v0: &V,l: u64,r: u64,n: &mut isize,) {alloc_write::<K, V, Self>(new, k0, v0, l, r, n)
fn alloc_write<T: AllocPage>(t: &mut T, new: &mut MutPage, k0: &K, v0: &V, l: u64, r: u64, n: &mut isize) {alloc_write::<T, K, V, Self>(t, new, k0, v0, l, r, n)
fn alloc_write<T: AllocPage>(_txn: &mut T,new: &mut MutPage,k0: &K,v0: &V,l: u64,r: u64,n: &mut isize,) {alloc_write::<K, V, Self>(new, k0, v0, l, r, n)
impl<K:Storable, V:Storable, P: BTreePage<K, V> + core::fmt::Debug> Storable for Db_<K, V, P> {
#[cfg(feature = "typeids")]impl<K: Storable + TypeId, V: Storable + TypeId, P: BTreePage<K, V> + core::fmt::Debug> TypeIdfor Db_<K, V, P>{fn type_id() -> [u8; 32] {let mut h = sha2::Sha256::new();h.update("sanakirja-core::Db".as_bytes());h.update(&K::type_id());h.update(&V::type_id());h.finalize().into()}}impl<K: Storable, V: Storable, P: BTreePage<K, V> + core::fmt::Debug> Storable for Db_<K, V, P> {
}}impl<K: Storable, V: Storable, P: BTreePage<K, V> + core::fmt::Debug> Storablefor Option<Db_<K, V, P>>{type PageReferences = core::iter::Once<u64>;fn page_references(&self) -> Self::PageReferences {if let Some(ref db) = self {core::iter::once(db.db.into())} else {let mut it = core::iter::once(0);it.next();it}}unsafe fn drop<T: AllocPage>(&self, t: &mut T) -> Result<(), T::Error> {if let Some(ref db) = self {drop_(t, db)} else {Ok(())}
// Then, climb up the stack, performing the operations lazily. At// each step, we are one level above the page that we plan to// modify, since `last_op` is the result of popping the// stack.//// We iterate up to the root. The last iteration builds a modified// page for the root, but doesn't actually execute it.while cursor.len() > 0 {// Prepare a plan for merging the current modified page (which// is stored in `last_op`) with one of its neighbours.let concat = concat(txn, cursor, p0, &k0v0, last_op)?;let mil = concat.mod_is_left;let incr_page = if !concat.other_is_mutable {Some(CowPage {offset: concat.other.offset,data: concat.other.data,})} else {None};let incr_mid = if cursor.len() >= cursor.first_rc_len() {Some(concat.mid)} else {None};// Execute the modification plan, resulting in one of four// different outcomes (described in the big match in// `handle_merge`). This mutates or clones the current// modified page, returning an `Op` describing what happened// (between update, merge, rebalance and split).let merge = unsafe { P::merge_or_rebalance(txn, concat)? };
for p in free.iter() {if p[0] & 1 == 1 {txn.decr_rc_owned(p[0] ^ 1)?;} else if p[0] > 0 {txn.decr_rc(p[0])?;}if p[1] & 1 == 1 {txn.decr_rc_owned(p[1] ^ 1)?;} else if p[1] > 0 {txn.decr_rc(p[1])?;
unsafe {for p in free.iter() {if p[0] & 1 == 1 {txn.decr_rc_owned(p[0] ^ 1)?;} else if p[0] > 0 {txn.decr_rc(p[0])?;}if p[1] & 1 == 1 {txn.decr_rc_owned(p[1] ^ 1)?;} else if p[1] > 0 {txn.decr_rc(p[1])?;}
P::put(txn,m.page,m.mutable,m.skip_first,&c1,k,v,m.ins2,m.l,m.r,)
unsafe {P::put(txn,m.page,m.mutable,m.skip_first,&c1,k,v,m.ins2,m.l,m.r,)}
Ok(Put::Ok(P::update_left_child(txn, m.page, m.mutable, &m.c1, m.l,)?))
Ok(Put::Ok(unsafe {P::update_left_child(txn, m.page, m.mutable, &m.c1, m.l)?}))
// Then, climb up the stack, performing the operations lazily. At// each step, we are one level above the page that we plan to// modify, since `last_op` is the result of popping the// stack.//// We iterate up to the root. The last iteration builds a modified// page for the root, but doesn't actually execute it.while cursor.len() > 0 {// Prepare a plan for merging the current modified page (which// is stored in `last_op`) with one of its neighbours.let concat = concat(txn, cursor, p0, &k0v0, last_op)?;let mil = concat.mod_is_left;let incr_page = if !concat.other_is_mutable {Some(CowPage {offset: concat.other.offset,data: concat.other.data,})} else {None};let incr_mid = if cursor.len() >= cursor.first_rc_len() {Some(concat.mid)} else {None};// Execute the modification plan, resulting in one of four// different outcomes (described in the big match in// `handle_merge`). This mutates or clones the current// modified page, returning an `Op` describing what happened// (between update, merge, rebalance and split).let merge = P::merge_or_rebalance(txn, concat)?;
sha2 = { version = "0.10", optional = true }
env_logger::try_init().unwrap_or(());let path = tempfile::tempdir().unwrap();let path = path.path().join("db");let l0 = 1 << 13; // 2 pageslet env = Env::new(&path, l0, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db::<MutTxn<&Env, ()>, u64, u64>(&mut txn).unwrap();let n = 100_000u64;for i in 0..n {put(&mut txn, &mut db, &i, &i).unwrap();
unsafe {env_logger::try_init().unwrap_or(());let path = tempfile::tempdir().unwrap();let path = path.path().join("db");let l0 = 1 << 13; // 2 pageslet env = Env::new(&path, l0, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db::<MutTxn<&Env, ()>, u64, u64>(&mut txn).unwrap();let n = 100_000u64;for i in 0..n {put(&mut txn, &mut db, &i, &i).unwrap();}println!("{:?}", env.mmaps);let len = std::fs::metadata(&path).unwrap().len();assert_eq!(len, (l0 << 9) - l0);let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, u64> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
println!("{:?}", env.mmaps);let len = std::fs::metadata(&path).unwrap().len();assert_eq!(len, (l0 << 9) - l0);let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, u64> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
let path = "/tmp/sanakirja1";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
unsafe {let path = "/tmp/sanakirja1";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
env_logger::try_init().unwrap_or(());for i in 0..1_000_000 {let do_debug = false;if i % 100_000 == 0 {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() {
env_logger::try_init().unwrap_or(());for i in 0..200_000 {let do_debug = false;if i % 100_000 == 0 {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()]);
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]);
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]);}
}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);
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();let r = r.as_u64();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))
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);
let path = "/tmp/sanakirja2";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
unsafe {let path = "/tmp/sanakirja2";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
for i in 0..1_000_000 {let do_debug = false; // 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() {
for i in 0..1_000_000 {let do_debug = false; // 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()]);
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 (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]);}
}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);
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 path = "/tmp/sanakirja3";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
unsafe {let path = "/tmp/sanakirja3";std::fs::remove_dir_all(path).unwrap_or(());std::fs::create_dir_all(path).unwrap();let path = Path::new(path).join("db");let l0 = 1 << 20;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);
for i in 0..448696 {let do_debug = i >= 448_693;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]);debug(&txn, &[&db], "debug0", true);}if !del(&mut txn, &mut db, &k, Some(&v)).unwrap() {panic!("del {}", i);
for i in 0..448696 {let do_debug = i >= 448_693;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]);debug(&txn, &[&db], "debug0", true);}if !del(&mut txn, &mut db, &k, Some(&v)).unwrap() {panic!("del {}", i);}if do_debug {debug(&txn, &[&db], "debug1", true);}
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)) {debug(&txn, &[&db], "debug1", true);panic!("test {:?} {:?} {:?} {:?}", i, i_, k.0[0], v.0[0]);
for (i_, (k, v)) in ve.iter().enumerate() {if get(&txn, &db, k, None).unwrap() != Some((k, v)) {debug(&txn, &[&db], "debug1", true);panic!("test {:?} {:?} {:?} {:?}", i, i_, k.0[0], v.0[0]);}
}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);
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);
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 = create_db::<MutTxn<&Env, ()>, u64, A>(&mut txn).unwrap();let n = 1_000u64;let m = 1000;let mut values = Vec::with_capacity(n as usize);let i0 = 500;for i in 0..n {if i != i0 && (i * i) % m == (i0 * i0) % m {continue;
unsafe {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 = create_db::<MutTxn<&Env, ()>, u64, A>(&mut txn).unwrap();let n = 1_000u64;let m = 1000;let mut values = Vec::with_capacity(n as usize);let i0 = 500;for i in 0..n {if i != i0 && (i * i) % m == (i0 * i0) % m {continue;}let a = A([i * i * i; 100]);if put(&mut txn, &mut db, &((i * i) % m), &a).unwrap() {values.push((i * i) % m);}
let a = A([i * i * i; 100]);if put(&mut txn, &mut db, &((i * i) % m), &a).unwrap() {values.push((i * i) % m);
values.sort();debug(&txn, &[&db], "debug0", true);let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let mut nn = 0;while let Some((k, v)) = curs.next(&mut txn).unwrap() {debug!("{:?} {:?}", k, v.0[0]);assert_eq!(*k, values[nn]);nn += 1;
}values.sort();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let mut nn = 0;while let Some((k, v)) = curs.next(&mut txn).unwrap() {debug!("{:?} {:?}", k, v.0[0]);assert_eq!(*k, values[nn]);nn += 1;}assert_eq!(nn, values.len());
assert_eq!(nn, values.len());
let db2 = fork_db(&mut txn, &db).unwrap();let a = A([0; 100]);put(&mut txn, &mut db, &(m / 2), &a).unwrap();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let (k, v) = curs.set(&txn, &((i0 * i0) % m), None).unwrap().unwrap();assert_eq!((i0 * i0) % m, *k);assert_eq!(i0 * i0 * i0, (v.0)[0]);
let db2 = fork_db(&mut txn, &db).unwrap();let a = A([0; 100]);put(&mut txn, &mut db, &(m / 2), &a).unwrap();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let (k, v) = curs.set(&txn, &((i0 * i0) % m), None).unwrap().unwrap();assert_eq!((i0 * i0) % m, *k);assert_eq!(i0 * i0 * i0, (v.0)[0]);
let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let a = A([i0 * i0 * i0; 100]);let (k, v) = curs.set(&txn, &((i0 * i0) % m), Some(&a)).unwrap().unwrap();assert_eq!((i0 * i0) % m, *k);assert_eq!(i0 * i0 * i0, (v.0)[0]);
let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let a = A([i0 * i0 * i0; 100]);let (k, v) = curs.set(&txn, &((i0 * i0) % m), Some(&a)).unwrap().unwrap();assert_eq!((i0 * i0) % m, *k);assert_eq!(i0 * i0 * i0, (v.0)[0]);
debug(&txn, &[&db], "debug0", true);let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();curs.set_last(&txn).unwrap();let (k, _) = curs.prev(&txn).unwrap().unwrap();assert_eq!(k, values.last().unwrap());txn.commit().unwrap();
debug(&txn, &[&db], "debug0", true);let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();curs.set_last(&txn).unwrap();let (k, _) = curs.prev(&txn).unwrap().unwrap();assert_eq!(k, values.last().unwrap());txn.commit().unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);}
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, ()> = create_db(&mut txn).unwrap();let n = 10_000_000u64;for i in 0..n {put(&mut txn, &mut db, &((i * i) % 1_000), &()).unwrap();}let d = 10;for i in 0..d {del(&mut txn, &mut db, &((i * i) % 1_000), None).unwrap();
unsafe {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, ()> = create_db(&mut txn).unwrap();let n = 10_000_000u64;for i in 0..n {put(&mut txn, &mut db, &((i * i) % 1_000), &()).unwrap();}let d = 10;for i in 0..d {del(&mut txn, &mut db, &((i * i) % 1_000), None).unwrap();}txn.set_root(0, db.db.into());txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn,&txn.root_db::<u64, (), btree::page::Page<u64, ()>>(0).unwrap(),&mut refs,).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
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, A> = create_db(&mut txn).unwrap();let n = 40u64;let a = A([0; 100]);for i in 0..n {put(&mut txn, &mut db, &i, &a).unwrap();}debug(&txn, &[&db], "debug0", true);for i in (0..n).rev() {del(&mut txn, &mut db, &((i * i) % 1_000), None).unwrap();}txn.commit().unwrap();
unsafe {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, A> = create_db(&mut txn).unwrap();let n = 40u64;let a = A([0; 100]);for i in 0..n {put(&mut txn, &mut db, &i, &a).unwrap();}debug(&txn, &[&db], "debug0", true);for i in (0..n).rev() {del(&mut txn, &mut db, &((i * i) % 1_000), None).unwrap();}txn.commit().unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);}
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 = 1_000_000u64;for i in 0..n {put(&mut txn, &mut db, &((i * i) % 1_000), &i).unwrap();
unsafe {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 = 1_000_000u64;for i in 0..n {put(&mut txn, &mut db, &((i * i) % 1_000), &i).unwrap();}txn.set_root(0, db.db.into());txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_free_mut(&mut txn, &refs);check_refs(&txn, &refs);
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, ()> = create_db(&mut txn).unwrap();let n = 100_000u64;let m = 10_000;let mut max = 0;for i in 0..n {put(&mut txn, &mut db, &((i * i) % m), &()).unwrap();max = max.max((i * i) % m);}let db2 = fork_db(&mut txn, &db).unwrap();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();curs.set_last(&txn).unwrap();let (&nn, _) = curs.prev(&txn).unwrap().unwrap();assert_eq!(max, nn);let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();for (p, r) in refs.iter() {if *r >= 2 {assert_eq!(txn.rc(*p).unwrap(), *r as u64);} else {assert_eq!(txn.rc(*p).unwrap(), 0);
unsafe {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, ()> = create_db(&mut txn).unwrap();let n = 100_000u64;let m = 10_000;let mut max = 0;for i in 0..n {put(&mut txn, &mut db, &((i * i) % m), &()).unwrap();max = max.max((i * i) % m);}let db2 = fork_db(&mut txn, &db).unwrap();let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();curs.set_last(&txn).unwrap();let (&nn, _) = curs.prev(&txn).unwrap().unwrap();assert_eq!(max, nn);let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();for (p, r) in refs.iter() {if *r >= 2 {assert_eq!(txn.rc(*p).unwrap(), *r as u64);} else {assert_eq!(txn.rc(*p).unwrap(), 0);}
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();curs.set_last(&txn).unwrap();assert!(curs.next(&txn).unwrap().is_none());txn.set_root(0, db.db);txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, u64> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
unsafe {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();curs.set_last(&txn).unwrap();assert!(curs.next(&txn).unwrap().is_none());txn.set_root(0, db.db.into());txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, u64> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);}
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, ()> = create_db(&mut txn).unwrap();let n = 2_000u64;let mut values = Vec::with_capacity(n as usize);for i in 0..n - 1 {if put(&mut txn, &mut db, &i, &()).unwrap() {values.push(i);
unsafe {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, ()> = create_db(&mut txn).unwrap();let n = 2_000u64;let mut values = Vec::with_capacity(n as usize);for i in 0..n - 1 {if put(&mut txn, &mut db, &i, &()).unwrap() {values.push(i);}
del(&mut txn, &mut db, &1274, None).unwrap();del(&mut txn, &mut db, &1529, None).unwrap();assert!(!del(&mut txn, &mut db, &(n + 1), None).unwrap());txn.set_root(0, db.db.into());txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, ()> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
del(&mut txn, &mut db, &1274, None).unwrap();del(&mut txn, &mut db, &1529, None).unwrap();assert!(!del(&mut txn, &mut db, &(n + 1), None).unwrap());txn.set_root(0, db.db);txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, ()> = txn.root_db(0).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
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, A> = create_db(&mut txn).unwrap();let n = 200u64;let i0 = 10u64;let mut values = Vec::with_capacity(n as usize);for i in 0..n {let a = A([i; 100]);put(&mut txn, &mut db, &i, &a).unwrap();if i != i0 {values.push(i);
unsafe {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, A> = create_db(&mut txn).unwrap();let n = 200u64;let i0 = 10u64;let mut values = Vec::with_capacity(n as usize);for i in 0..n {let a = A([i; 100]);put(&mut txn, &mut db, &i, &a).unwrap();if i != i0 {values.push(i);}
}let db2 = fork_db(&mut txn, &db).unwrap();del(&mut txn, &mut db, &i0, None).unwrap();debug(&txn, &[&db, &db2], "debug0", true);assert_eq!(iter(&txn, &db, None).unwrap().map(|kv| *kv.unwrap().0).collect::<Vec<_>>(),values);txn.set_root(0, db.db);txn.set_root(1, db2.db);
let db2 = fork_db(&mut txn, &db).unwrap();del(&mut txn, &mut db, &i0, None).unwrap();debug(&txn, &[&db, &db2], "debug0", true);assert_eq!(iter(&txn, &db, None).unwrap().map(|kv| *kv.unwrap().0).collect::<Vec<_>>(),values);txn.set_root(0, db.db.into());txn.set_root(1, db2.db.into());
txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, A> = txn.root_db(0).unwrap();let db2: Db<u64, A> = txn.root_db(1).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();let db: Db<u64, A> = txn.root_db(0).unwrap();let db2: Db<u64, A> = txn.root_db(1).unwrap();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);}
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 = 256u64;let i0 = 127u64;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);
unsafe {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 = 256u64;let i0 = 127u64;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);}
}debug!("===============");debug(&txn, &[&db], "debug", true);let db2 = fork_db(&mut txn, &db).unwrap();del(&mut txn, &mut db, &i0, None).unwrap();debug(&txn, &[&db, &db2], "debug1", true);let db3: Db<u64, u64> = Db {db: 20480,k: std::marker::PhantomData,v: std::marker::PhantomData,p: std::marker::PhantomData,};debug(&txn, &[&db, &db2, &db3], "debug2", true);assert_eq!(iter(&txn, &db, None).unwrap().map(|kv| *kv.unwrap().0).collect::<Vec<_>>(),values);txn.set_root(0, db.db);txn.set_root(1, db2.db);
debug!("===============");debug(&txn, &[&db], "debug", true);let db2 = fork_db(&mut txn, &db).unwrap();del(&mut txn, &mut db, &i0, None).unwrap();debug(&txn, &[&db, &db2], "debug1", true);let db3: Db<u64, u64> = Db {db: core::num::NonZeroU64::new_unchecked(20480),k: std::marker::PhantomData,v: std::marker::PhantomData,p: std::marker::PhantomData,};debug(&txn, &[&db, &db2, &db3], "debug2", true);assert_eq!(iter(&txn, &db, None).unwrap().map(|kv| *kv.unwrap().0).collect::<Vec<_>>(),values);txn.set_root(0, db.db.into());txn.set_root(1, db2.db.into());
txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);}
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, A> = create_db(&mut txn).unwrap();let n = 19u64;let mut values = Vec::with_capacity(n as usize);let a = A([0; 100]);for i in 0..n - 1 {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);
unsafe {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, A> = create_db(&mut txn).unwrap();let n = 19u64;let mut values = Vec::with_capacity(n as usize);let a = A([0; 100]);for i in 0..n - 1 {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);}
let db2 = fork_db(&mut txn, &db).unwrap();let mut values2 = values.clone();values2.sort();debug(&txn, &[&db, &db2], "debug0", true);debug!(">>>>>>");for i in n - 1..n {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);
let db2 = fork_db(&mut txn, &db).unwrap();let mut values2 = values.clone();values2.sort();debug(&txn, &[&db, &db2], "debug0", true);debug!(">>>>>>");for i in n - 1..n {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);}
}debug!("<<<<<<<<<");values.sort();debug(&txn, &[&db, &db2], "debug1", true);
debug!("<<<<<<<<<");values.sort();debug(&txn, &[&db, &db2], "debug1", true);
let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let mut nn = 0;while let Some((k, _)) = curs.next(&mut txn).unwrap() {assert_eq!(*k, values[nn]);nn += 1;}
let mut curs = btree::cursor::Cursor::new(&txn, &db).unwrap();let mut nn = 0;while let Some((k, _)) = curs.next(&mut txn).unwrap() {assert_eq!(*k, values[nn]);nn += 1;}
assert_eq!(nn, values.len());let mut curs = btree::cursor::Cursor::new(&txn, &db2).unwrap();let mut nn = 0;while let Some((k, _)) = curs.next(&mut txn).unwrap() {debug!("{:?}", *k);assert_eq!(*k, values2[nn]);nn += 1;}assert_eq!(nn, values2.len());
assert_eq!(nn, values.len());let mut curs = btree::cursor::Cursor::new(&txn, &db2).unwrap();let mut nn = 0;while let Some((k, _)) = curs.next(&mut txn).unwrap() {debug!("{:?}", *k);assert_eq!(*k, values2[nn]);nn += 1;}assert_eq!(nn, values2.len());
debug!("==============");del(&mut txn, &mut db, &11, None).unwrap();debug!("free_owned_pages = {:?}", txn.free_owned_pages);debug(&txn, &[&db, &db2], "debug1", true);debug!("=============");for i in 0..15 {debug(&txn, &[&db, &db2], &format!("debug-{}", i), true);debug!("deleting {:?}", i);del(&mut txn, &mut db, &i, None).unwrap();}for i in n / 2..n {del(&mut txn, &mut db, &i, None).unwrap();}debug!("{:?} {:?}", db, db2);debug(&txn, &[&db, &db2], "debug3", true);
debug!("==============");del(&mut txn, &mut db, &11, None).unwrap();debug!("free_owned_pages = {:?}", txn.free_owned_pages);debug(&txn, &[&db, &db2], "debug1", true);debug!("=============");for i in 0..15 {debug(&txn, &[&db, &db2], &format!("debug-{}", i), true);debug!("deleting {:?}", i);del(&mut txn, &mut db, &i, None).unwrap();}for i in n / 2..n {del(&mut txn, &mut db, &i, None).unwrap();}debug!("{:?} {:?}", db, db2);debug(&txn, &[&db, &db2], "debug3", true);
let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();// add_refs(&txn, &db3, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {println!("{:?} {:?}", p, r);if *r >= 2 {if txn.rc(*p).unwrap() != *r as u64 {error!("{:?} {:?} {:?}", p, txn.rc(*p).unwrap(), *r);err += 1;
let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();// add_refs(&txn, &db3, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {println!("{:?} {:?}", p, r);if *r >= 2 {if txn.rc(*p).unwrap() != *r as u64 {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;}
env_logger::try_init().unwrap_or(());let child = unsafe { libc::fork() };if child == 0 {// child
env_logger::try_init().unwrap_or(());let child = libc::fork();if child == 0 {// child
// Mutable txnlet mut txn = Env::mut_txn_begin(&env).unwrap();info!("started child mutable txn {:?}", txn.root);
// Mutable txnlet mut txn = Env::mut_txn_begin(&env).unwrap();info!("started child mutable txn {:?}", txn.root);
let db = create_db::<MutTxn<&Env, ()>, u64, ()>(&mut txn).unwrap();debug!("db = {:?}", db.db);txn.set_root(0, db.db);std::thread::sleep(std::time::Duration::from_millis(200));txn.commit().unwrap();info!("committed");let t = std::time::SystemTime::now();let mut txn = Env::mut_txn_begin(&env).unwrap();
let db = create_db::<MutTxn<&Env, ()>, u64, ()>(&mut txn).unwrap();debug!("db = {:?}", db.db);txn.set_root(0, db.db.into());std::thread::sleep(std::time::Duration::from_millis(200));txn.commit().unwrap();info!("committed");let t = std::time::SystemTime::now();let mut txn = Env::mut_txn_begin(&env).unwrap();
// Since the parent has an immutable transaction started, we// need to wait for at least some time (1s - 100ms of// synchronisation margin).assert!(t.elapsed().unwrap() >= std::time::Duration::from_millis(90));info!("started child mutable txn {:?}", txn.root);let db = create_db::<MutTxn<&Env, ()>, u64, ()>(&mut txn).unwrap();debug!("db = {:?}", db.db);txn.set_root(1, db.db);std::thread::sleep(std::time::Duration::from_millis(100));txn.commit().unwrap();
// Since the parent has an immutable transaction started, we// need to wait for at least some time (1s - 100ms of// synchronisation margin).assert!(t.elapsed().unwrap() >= std::time::Duration::from_millis(90));info!("started child mutable txn {:?}", txn.root);let db = create_db::<MutTxn<&Env, ()>, u64, ()>(&mut txn).unwrap();debug!("db = {:?}", db.db);txn.set_root(1, db.db.into());std::thread::sleep(std::time::Duration::from_millis(100));txn.commit().unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);unsafe { libc::exit(0) }} else {// parentstd::thread::sleep(std::time::Duration::from_millis(100));
/*let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);*/debug!("child exit");libc::exit(0)} else {// parentstd::thread::sleep(std::time::Duration::from_millis(100));
// Immutablelet txn = Env::txn_begin(&env).unwrap();info!("started parent txn {:?}", txn.root);
// Immutablelet txn = Env::txn_begin(&env).unwrap();info!("started parent txn {:?}", txn.root);
std::thread::sleep(std::time::Duration::from_millis(100));let txn = Env::txn_begin(&env).unwrap();info!("started parent txn {:?}", txn.root);
std::thread::sleep(std::time::Duration::from_millis(100));let txn = Env::txn_begin(&env).unwrap();info!("started parent txn {:?}", txn.root);
let mut status = 1;unsafe { libc::wait(&mut status) };assert_eq!(status, 0);std::mem::drop(txn);let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
let mut status = 1;libc::wait(&mut status);assert_eq!(status, 0);std::mem::drop(txn);let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn,&txn.root_db::<u64, (), btree::page::Page<u64, ()>>(0).unwrap(),&mut refs,).unwrap();add_refs(&txn,&txn.root_db::<u64, (), btree::page::Page<u64, ()>>(1).unwrap(),&mut refs,).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);}
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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();let n = 10_000u64;let m = 1000;let mut values = Vec::with_capacity(n as usize);for i in 0..n {debug!("=============== putting {:?}", i);let alpha = b"abcdefgihjklmnopqrstuvwxyz";let a = &alpha[..((i as usize * 7) % 25) + 1];if put(&mut txn, &mut db, &i, &a[..]).unwrap() {values.push((i * i) % m);
unsafe {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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();let n = 10_000u64;let m = 1000;let mut values = Vec::with_capacity(n as usize);for i in 0..n {debug!("=============== putting {:?}", i);let alpha = b"abcdefgihjklmnopqrstuvwxyz";let a = &alpha[..((i as usize * 7) % 25) + 1];if put(&mut txn, &mut db, &i, &a[..]).unwrap() {values.push((i * i) % m);}
let mut txn = Env::mut_txn_begin(&env).unwrap();unsafe {let p = &*(env.mmaps.lock()[0].ptr.add(txn.root * PAGE_SIZE) as *const GlobalHeader);debug!("free page: 0x{:x}", u64::from_le(p.free_db));let db: Db<u64, ()> = Db {db: u64::from_le(p.free_db),k: std::marker::PhantomData,v: std::marker::PhantomData,p: std::marker::PhantomData,};for x in iter(&txn, &db, None).unwrap() {debug!("0x{:x}", x.unwrap().0);
// Allocate two pages.for i in 0..n {let page = txn.alloc_page().unwrap();debug!("page = {:?}", page);txn.set_root(i, page.0.offset);
}let page = txn.alloc_page().unwrap();debug!("page = {:?}", page);}#[test]fn sized_vs_unsized() {env_logger::try_init().unwrap_or(());let env = Env::new_anon(409_600_000, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();
txn.commit().unwrap();
let mut db = create_db_::<MutTxn<&Env, ()>, u64, u64, P<u64, u64>>(&mut txn).unwrap();let now = std::time::SystemTime::now();let n = 1_000u64;for i in 0..n {debug!("=================== {:?}", i);assert!(put(&mut txn, &mut db, &i, &i).unwrap());}println!("sized put: {:?}", now.elapsed());let now = std::time::SystemTime::now();for i in 0..n {debug!("=================== {:?}", i);get(&txn, &db, &i, None).unwrap();}println!("sized lookup: {:?}", now.elapsed());
for i in 0..n {let mut txn = Env::mut_txn_begin(&env).unwrap();// Free one of the pages.debug!("root(0) = {:?}", txn.root(i));txn.decr_rc(txn.root(i).unwrap()).unwrap();txn.remove_root(i);txn.commit().unwrap();}
let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {if *r >= 2 {error!("{:?} referenced twice", p);err += 1
let mut txn = Env::mut_txn_begin(&env).unwrap();{let p = &*(env.mmaps.lock()[0].ptr.add(txn.root * PAGE_SIZE) as *const GlobalHeader);debug!("free page: 0x{:x}", u64::from_le(p.free_db));let db: Db<u64, ()> = Db {db: core::num::NonZeroU64::new_unchecked(u64::from_le(p.free_db)),k: std::marker::PhantomData,v: std::marker::PhantomData,p: std::marker::PhantomData,};for x in iter(&txn, &db, None).unwrap() {debug!("0x{:x}", x.unwrap().0);}
}debug!("{:?}", txn.free);add_free_refs_mut(&mut txn, &mut refs).unwrap();check_free_mut(&mut txn, &refs);assert_eq!(err, 0);let len = txn.length >> 12;println!("sized length = {:?}", len);
let env = Env::new_anon(409_600_000, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db2 = create_db_::<MutTxn<&Env, ()>, u64, u64, UP<u64, u64>>(&mut txn).unwrap();let now = std::time::SystemTime::now();let n = 1_000u64;for i in 0..n {assert!(put(&mut txn, &mut db2, &i, &i).unwrap());}println!("unsized put: {:?}", now.elapsed());let now = std::time::SystemTime::now();for i in 0..n {get(&txn, &db2, &i, None).unwrap();
let page = txn.alloc_page().unwrap();debug!("page = {:?}", page);
println!("unsized lookup: {:?}", now.elapsed());refs.clear();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&mut txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
fn lmdb() {use lmdb_rs::*;env_logger::try_init().unwrap_or(());for i in 1..2 {let n = i * 5000;let mut times = [0f64; 12];let mut test = Vec::with_capacity(n);let mut rng = rand::thread_rng();for _ in 0..n {use rand::Rng;test.push((rng.gen(), rng.gen()))}std::fs::remove_dir_all("/tmp/sanakirja0").unwrap_or(());std::fs::create_dir_all("/tmp/sanakirja0").unwrap();std::fs::remove_file("/tmp/sanakirja0/db").unwrap_or(());let env = Env::new("/tmp/sanakirja0/db", 409_600_000, 2).unwrap();
fn sized_vs_unsized() {unsafe {env_logger::try_init().unwrap_or(());let env = Env::new_anon(409_600_000, 1).unwrap();
debug(&txn, &[&db], "debug", true);for (k, v) in test.iter() {assert_eq!(get(&txn, &db, &k, None).unwrap(), Some((k, v)))
for i in 0..n {debug!("=================== {:?}", i);get(&txn, &db, &i, None).unwrap();
let env = Env::new_anon(409_600_000, 2).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db_::<MutTxn<&Env, ()>, u64, u64, P<u64, u64>>(&mut txn).unwrap();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert!(put(&mut txn, &mut db, k, v).unwrap());}debug(&txn, &[&db], "debug", true);times[2] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert_eq!(get(&txn, &db, &k, None).unwrap(), Some((k, v)))
let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {if *r >= 2 {error!("{:?} referenced twice", p);err += 1}
let mut b = std::collections::BTreeMap::new();
let env = Env::new_anon(409_600_000, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db2 = create_db_::<MutTxn<&Env, ()>, u64, u64, UP<u64, u64>>(&mut txn).unwrap();
times[5] = now.elapsed().unwrap().as_secs_f64();
println!("unsized lookup: {:?}", now.elapsed());refs.clear();add_refs(&txn, &db2, &mut refs).unwrap();add_free_refs_mut(&mut txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);}}#[test]fn lmdb() {unsafe {use lmdb_rs::*;env_logger::try_init().unwrap_or(());for i in 1..2 {let n = i * 5000;let mut times = [0f64; 12];let mut test = Vec::with_capacity(n);let mut rng = rand::thread_rng();for _ in 0..n {use rand::Rng;test.push((rng.gen(), rng.gen()))}std::fs::remove_dir_all("/tmp/sanakirja0").unwrap_or(());std::fs::create_dir_all("/tmp/sanakirja0").unwrap();std::fs::remove_file("/tmp/sanakirja0/db").unwrap_or(());let env = Env::new("/tmp/sanakirja0/db", 409_600_000, 2).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();
std::fs::remove_dir_all("/tmp/test-lmdb").unwrap_or(());std::fs::create_dir_all("/tmp/test-lmdb").unwrap_or(());let env = EnvBuilder::new().map_size(1 << 30).open("/tmp/test-lmdb", 0o777).unwrap();
let mut db = create_db_::<MutTxn<&Env, ()>, u64, u64, P<u64, u64>>(&mut txn).unwrap();
times[6] = now.elapsed().unwrap().as_secs_f64();}
times[0] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();debug(&txn, &[&db], "debug", true);for (k, v) in test.iter() {assert_eq!(get(&txn, &db, &k, None).unwrap(), Some((k, v)))}times[1] = now.elapsed().unwrap().as_secs_f64();
// Note: `commit` is choosen to be explicit as// in case of failure it is responsibility of// the client to handle the errormatch txn.commit() {Err(_) => panic!("failed to commit!"),Ok(_) => (),}
let env = Env::new_anon(409_600_000, 2).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db_::<MutTxn<&Env, ()>, u64, u64, P<u64, u64>>(&mut txn).unwrap();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert!(put(&mut txn, &mut db, k, v).unwrap());}debug(&txn, &[&db], "debug", true);times[2] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert_eq!(get(&txn, &db, &k, None).unwrap(), Some((k, v)))}times[3] = now.elapsed().unwrap().as_secs_f64();let mut b = std::collections::BTreeMap::new();let now = std::time::SystemTime::now();for (k, v) in test.iter() {b.insert(*k, *v);}times[4] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert_eq!(b.get(k), Some(v));}times[5] = now.elapsed().unwrap().as_secs_f64();
let reader = env.get_reader().unwrap();let db = reader.bind(&db_handle);let now = std::time::SystemTime::now();for (k, v) in test.iter() {let name = db.get::<u64>(k).ok();assert_eq!(name, Some(*v))}times[7] = now.elapsed().unwrap().as_secs_f64();/*std::fs::remove_dir_all("/tmp/test-sled").unwrap_or(());std::fs::create_dir_all("/tmp/test-sled").unwrap_or(());let db: sled::Db = sled::open("/tmp/test-sled").unwrap();let now = std::time::SystemTime::now();for (k, v) in test.iter() {unsafe {db.insert(std::slice::from_raw_parts(k as *const u64 as *const u8, 8),std::slice::from_raw_parts(v as *const u64 as *const u8, 8),)
std::fs::remove_dir_all("/tmp/test-lmdb").unwrap_or(());std::fs::create_dir_all("/tmp/test-lmdb").unwrap_or(());let env = EnvBuilder::new().map_size(1 << 30).open("/tmp/test-lmdb", 0o777)
let db_handle = env.get_default_db(lmdb_rs::core::DbIntKey).unwrap();let txn = env.new_transaction().unwrap();{let db = txn.bind(&db_handle);let now = std::time::SystemTime::now();for (k, v) in test.iter() {db.set(k, v).unwrap();}times[6] = now.elapsed().unwrap().as_secs_f64();
}times[8] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, _v) in test.iter() {unsafe {db.get(std::slice::from_raw_parts(k as *const u64 as *const u8, 8)).unwrap();
// Note: `commit` is choosen to be explicit as// in case of failure it is responsibility of// the client to handle the errormatch txn.commit() {Err(_) => panic!("failed to commit!"),Ok(_) => (),
}times[9] = now.elapsed().unwrap().as_secs_f64();*//*{use old_sanakirja::*;std::fs::remove_dir_all("/tmp/sanakirja1").unwrap_or(());std::fs::create_dir_all("/tmp/sanakirja1").unwrap();let env = Env::new("/tmp/sanakirja1", 409_600_000).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = txn.create_db::<u64, u64>().unwrap();
let reader = env.get_reader().unwrap();let db = reader.bind(&db_handle);
times[10] = now.elapsed().unwrap().as_secs_f64();
times[7] = now.elapsed().unwrap().as_secs_f64();/*std::fs::remove_dir_all("/tmp/test-sled").unwrap_or(());std::fs::create_dir_all("/tmp/test-sled").unwrap_or(());let db: sled::Db = sled::open("/tmp/test-sled").unwrap();
assert_eq!(txn.get(&db, *k, None).unwrap(), Some(*v))
unsafe {db.insert(std::slice::from_raw_parts(k as *const u64 as *const u8, 8),std::slice::from_raw_parts(v as *const u64 as *const u8, 8),).unwrap();}}times[8] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, _v) in test.iter() {unsafe {db.get(std::slice::from_raw_parts(k as *const u64 as *const u8, 8)).unwrap();}
times[11] = now.elapsed().unwrap().as_secs_f64();}*/print!("{}", n);for t in times.iter() {print!(", {}", t)
times[9] = now.elapsed().unwrap().as_secs_f64();*//*{use old_sanakirja::*;std::fs::remove_dir_all("/tmp/sanakirja1").unwrap_or(());std::fs::create_dir_all("/tmp/sanakirja1").unwrap();let env = Env::new("/tmp/sanakirja1", 409_600_000).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = txn.create_db::<u64, u64>().unwrap();let now = std::time::SystemTime::now();let mut rng = rand::thread_rng();for (k, v) in test.iter() {assert!(txn.put(&mut rng, &mut db, *k, *v).unwrap());}times[10] = now.elapsed().unwrap().as_secs_f64();let now = std::time::SystemTime::now();for (k, v) in test.iter() {assert_eq!(txn.get(&db, *k, None).unwrap(), Some(*v))}times[11] = now.elapsed().unwrap().as_secs_f64();}*/print!("{}", n);for t in times.iter() {print!(", {}", t)}println!();
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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();for i in (0..157).step_by(10) {for i in i..i + 4 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();
unsafe {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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();for i in (0..157).step_by(10) {for i in i..i + 4 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();}put(&mut txn, &mut db, &(i + 9), &[b'b'; 250]).unwrap();}for i in (0..157).step_by(10) {for i in i + 4..i + 7 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();}
put(&mut txn, &mut db, &(i + 9), &[b'b'; 250]).unwrap();}for i in (0..157).step_by(10) {for i in i + 4..i + 7 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();
for i in 0..3 {debug!("====== del {:?}", i);del(&mut txn, &mut db, &i, None).unwrap();
}for i in 0..3 {debug!("====== del {:?}", i);del(&mut txn, &mut db, &i, None).unwrap();
assert_eq!(depth::<_, u64, [u8], UP<u64, [u8]>>(&txn, db.db.into()).unwrap(),2);del(&mut txn, &mut db, &3, None).unwrap();assert_eq!(depth::<_, u64, [u8], UP<u64, [u8]>>(&txn, db.db.into()).unwrap(),3);txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
assert_eq!(depth::<_, u64, [u8], UP<u64, [u8]>>(&txn, db.db).unwrap(),2);del(&mut txn, &mut db, &3, None).unwrap();assert_eq!(depth::<_, u64, [u8], UP<u64, [u8]>>(&txn, db.db).unwrap(),3);txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
let mut n = 1;loop {let pp = txn.load_page(p)?;let cursor = P::cursor_first(&pp);let l = P::left_child(pp.as_page(), &cursor);if l == 0 {return Ok(n);
unsafe {let mut n = 1;loop {let pp = txn.load_page(p)?;let cursor = P::cursor_first(&pp);let l = P::left_child(pp.as_page(), &cursor);if l == 0 {return Ok(n);}p = l;n += 1;
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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();for i in (0..157).step_by(10) {for i in i..i + 4 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();
unsafe {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 = create_db_::<MutTxn<&Env, ()>, u64, [u8], UP<u64, [u8]>>(&mut txn).unwrap();for i in (0..157).step_by(10) {for i in i..i + 4 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();}put(&mut txn, &mut db, &(i + 9), &[b'b'; 255]).unwrap();
put(&mut txn, &mut db, &(i + 9), &[b'b'; 255]).unwrap();}for i in (0..157).step_by(10) {for i in i + 4..i + 7 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();
for i in (0..157).step_by(10) {for i in i + 4..i + 7 {let a = [b'a'; 500];put(&mut txn, &mut db, &i, &a[..]).unwrap();}
del(&mut txn, &mut db, &0, None).unwrap();txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
del(&mut txn, &mut db, &0, None).unwrap();txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut refs = BTreeMap::new();add_free_refs_mut(&txn, &mut refs).unwrap();add_refs(&txn, &db, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);
for i in (25..50).rev() {let (k, v) = cursor.prev(&txn).unwrap().unwrap();debug!("b {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}for i in 24..75 {let (k, v) = cursor.next(&txn).unwrap().unwrap();debug!("c {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}for i in (0..75).rev() {let (k, v) = cursor.prev(&txn).unwrap().unwrap();debug!("d {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}debug(&txn, &[&db], "debug", true);let i0 = 30;for (kv, n) in rev_iter(&txn, &db, Some((&i0, None))).unwrap().zip((0..=i0).rev()){let (k, _v) = kv.unwrap();assert_eq!(*k, n);debug!("k = {:?}", k);}let i0 = 40;for (kv, n) in iter(&txn, &db, Some((&i0, None))).unwrap().zip(i0..) {let (k, _v) = kv.unwrap();assert_eq!(*k, n);debug!("k = {:?}", k);}
}#[test]fn iterators() {unsafe {env_logger::try_init().unwrap_or(());let env = Env::new_anon(40960, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db_::<MutTxn<&Env, ()>, u64, A, P<u64, A>>(&mut txn).unwrap();for i in 0..100 {let a = A([i; 100]);put(&mut txn, &mut db, &i, &a).unwrap();}let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();debug(&txn, &[&db], "debug", true);for i in 0..50 {let (k, v) = cursor.next(&txn).unwrap().unwrap();debug!("a {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}for i in (25..50).rev() {let (k, v) = cursor.prev(&txn).unwrap().unwrap();debug!("b {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}for i in 24..75 {let (k, v) = cursor.next(&txn).unwrap().unwrap();debug!("c {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}for i in (0..75).rev() {let (k, v) = cursor.prev(&txn).unwrap().unwrap();debug!("d {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);}debug(&txn, &[&db], "debug", true);let i0 = 30;for (kv, n) in rev_iter(&txn, &db, Some((&i0, None))).unwrap().zip((0..=i0).rev()){let (k, _v) = kv.unwrap();assert_eq!(*k, n);debug!("k = {:?}", k);}let i0 = 40;for (kv, n) in iter(&txn, &db, Some((&i0, None))).unwrap().zip(i0..) {let (k, _v) = kv.unwrap();assert_eq!(*k, n);debug!("k = {:?}", k);}
let mut it = rev_iter(&txn, &db, Some((&100, None))).unwrap();let (k, _v) = it.next().unwrap().unwrap();assert_eq!(*k, 99);
let mut it = rev_iter(&txn, &db, Some((&100, None))).unwrap();let (k, _v) = it.next().unwrap().unwrap();assert_eq!(*k, 99);
let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();for i in 0..100 {debug!("i = {:?}", i);let (&k, v) = cursor.set(&txn, &i, None).unwrap().unwrap();debug!("kv = {:?} {:?}", k, v);assert_eq!(i, k);let (&k1, v1) = cursor.next(&txn).unwrap().unwrap();debug!("next = {:?} {:?}", k1, v1);assert_eq!(i, k1);}
let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();for i in 0..100 {debug!("i = {:?}", i);let (&k, v) = cursor.set(&txn, &i, None).unwrap().unwrap();debug!("kv = {:?} {:?}", k, v);assert_eq!(i, k);let (&k1, v1) = cursor.next(&txn).unwrap().unwrap();debug!("next = {:?} {:?}", k1, v1);assert_eq!(i, k1);}
let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();for i in 0..100 {debug!("i = {:?}", i);let (&k, v) = cursor.set(&txn, &i, None).unwrap().unwrap();debug!("kv = {:?} {:?}", k, v);assert_eq!(i, k);let (&k1, v1) = cursor.prev(&txn).unwrap().unwrap();debug!("prev = {:?} {:?}", k1, v1);assert_eq!(i, k1);
let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();for i in 0..100 {debug!("i = {:?}", i);let (&k, v) = cursor.set(&txn, &i, None).unwrap().unwrap();debug!("kv = {:?} {:?}", k, v);assert_eq!(i, k);let (&k1, v1) = cursor.prev(&txn).unwrap().unwrap();debug!("prev = {:?} {:?}", k1, v1);assert_eq!(i, k1);}
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, A> = create_db(&mut txn).unwrap();
unsafe {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, A> = create_db(&mut txn).unwrap();
let n = 6u64;let mut values = Vec::with_capacity(n as usize);let a = A([0; 100]);for i in 0..n {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);
let n = 6u64;let mut values = Vec::with_capacity(n as usize);let a = A([0; 100]);for i in 0..n {if put(&mut txn, &mut db, &i, &a).unwrap() {values.push(i);}
debug(&txn, &[&db, &db2], "debug1", true);let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {println!("{:?} {:?}", p, r);if *r >= 2 {if txn.rc(*p).unwrap() != *r as u64 {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;
debug(&txn, &[&db, &db2], "debug1", true);let mut refs = BTreeMap::new();add_refs(&txn, &db, &mut refs).unwrap();add_refs(&txn, &db2, &mut refs).unwrap();let mut err = 0;for (p, r) in refs.iter() {println!("{:?} {:?}", p, r);if *r >= 2 {if txn.rc(*p).unwrap() != *r as u64 {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;}
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 = 1000u64;let i0 = 10u64;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);
unsafe {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 = 1000u64;let i0 = 10u64;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();debug(&txn, &[&db, &db2], "debug1", true);drop(&mut txn, db2).unwrap();debug(&txn, &[&db], "debug2", true);
let db2 = fork_db(&mut txn, &db).unwrap();put(&mut txn, &mut db, &n, &n).unwrap();debug(&txn, &[&db, &db2], "debug1", true);drop(&mut txn, db2).unwrap();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());
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);
}assert_eq!(err, 0);}assert_eq!(err, 0);txn.commit().unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);debug!("{:?}", refs);
assert_eq!(err, 0);
#[test]fn iterators() {env_logger::try_init().unwrap_or(());let env = Env::new_anon(40960, 1).unwrap();let mut txn = Env::mut_txn_begin(&env).unwrap();let mut db = create_db_::<MutTxn<&Env, ()>, u64, A, P<u64, A>>(&mut txn).unwrap();for i in 0..100 {let a = A([i; 100]);put(&mut txn, &mut db, &i, &a).unwrap();}let mut cursor = btree::cursor::Cursor::new(&txn, &db).unwrap();debug(&txn, &[&db], "debug", true);for i in 0..50 {let (k, v) = cursor.next(&txn).unwrap().unwrap();debug!("a {:?} {:?}", i, k);assert_eq!(*k, i);assert_eq!(v.0[0], i);add_free_refs_mut(&txn, &mut refs).unwrap();check_refs(&txn, &refs);check_free_mut(&mut txn, &refs);debug!("{:?}", refs);debug(&txn, &[&db], "debug0", true);
pub use environment::{Commit, Env, MutTxn, RootDb, Txn, RootPage};pub use sanakirja_core::{btree, direct_repr, LoadPage, AllocPage, Storable, UnsizedStorable, MutPage, CowPage, Page, Slice};
pub use environment::{Commit, Env, MutTxn, RootDb, RootPage, Txn};pub use sanakirja_core::{btree, direct_repr, AllocPage, CowPage, LoadPage, MutPage, Page, Slice, Storable,UnsizedStorable,};
/// A 64-bit unsigned integer in little-endian ordering.#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]pub struct L64(pub u64);impl serde::Serialize for L64 {#[inline]fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>whereS: serde::Serializer,{serializer.serialize_u64(u64::from_le(self.0))}}use serde::de::{self, Visitor};struct L64Visitor;impl<'de> Visitor<'de> for L64Visitor {type Value = L64;fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {formatter.write_str("an unsigned, little-endian integer")}fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>whereE: de::Error,{log::debug!("visit u64 {:?}", value);Ok(L64(value.to_le()))}}impl<'de> serde::Deserialize<'de> for L64 {fn deserialize<D>(deserializer: D) -> Result<L64, D::Error>whereD: serde::Deserializer<'de>,{deserializer.deserialize_u64(L64Visitor)}}impl From<u64> for L64 {fn from(u: u64) -> Self {L64(u.to_le())}}impl From<L64> for u64 {fn from(u: L64) -> Self {u64::from_le(u.0)}}impl Ord for L64 {fn cmp(&self, x: &Self) -> std::cmp::Ordering {u64::from_le(self.0).cmp(&u64::from_le(x.0))}}impl PartialOrd for L64 {fn partial_cmp(&self, x: &Self) -> Option<std::cmp::Ordering> {u64::from_le(self.0).partial_cmp(&u64::from_le(x.0))}}impl From<usize> for L64 {fn from(u: usize) -> Self {L64((u as u64).to_le())}}impl From<L64> for usize {fn from(u: L64) -> Self {u64::from_le(u.0) as usize}}impl L64 {/// Convert to machine 64-bit integerspub fn as_u64(&self) -> u64 {u64::from_le(self.0)}/// Convert to usizepub fn as_usize(&self) -> usize {u64::from_le(self.0) as usize}}impl std::fmt::Display for L64 {fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {self.0.fmt(fmt)}}impl std::ops::Add<L64> for L64 {type Output = Self;fn add(self, x: L64) -> L64 {L64((u64::from_le(self.0) + u64::from_le(x.0)).to_le())}}impl std::ops::Add<usize> for L64 {type Output = Self;fn add(self, x: usize) -> L64 {L64((u64::from_le(self.0) + x as u64).to_le())}}impl std::ops::SubAssign<usize> for L64 {fn sub_assign(&mut self, x: usize) {self.0 = ((u64::from_le(self.0)) - x as u64).to_le()}}#[allow(trivial_casts)]impl L64 {/// Read an L64 from its binary representation.pub fn from_slice_le(s: &[u8]) -> Self {let mut u = 0u64;assert!(s.len() >= 8);unsafe { std::ptr::copy_nonoverlapping(s.as_ptr(), &mut u as *mut u64 as *mut u8, 8) }L64(u)}/// Write an L64 as its binary representation.pub fn to_slice_le(&self, s: &mut [u8]) {assert!(s.len() >= 8);unsafe {std::ptr::copy_nonoverlapping(&self.0 as *const u64 as *const u8, s.as_mut_ptr(), 8)}}}direct_repr!(L64);impl debug::Check for L64 {}
/// have not been freed since.pub(crate) occupied_owned_pages: Vec<MutPage>,
/// have not been freed since. The boolean indicates whether this/// was allocated with a dirty bit or not.pub(crate) occupied_owned_pages: Vec<(MutPage, bool)>,
for p in occ.iter_mut() {if let Some(ref free_db) = free_db {if let Some((pp, ())) = btree::get(&self, free_db, &p.0.offset, None)? {if *pp == p.0.offset {continue;
for (p, uses_dirty) in occ.iter_mut() {if *uses_dirty {if let Some(ref free_db) = free_db {if let Some((pp, ())) =btree::get(&self, free_db, &L64(p.0.offset.to_le()), None)?{if u64::from_le(pp.0) == p.0.offset {continue;}
unsafe {trace!("commit page {:x}: {:?}",p.0.offset,std::slice::from_raw_parts(p.0.data, 32));}clear_dirty(p);
impl<E: Borrow<Env>, T> sanakirja_core::AllocPage for MutTxn<E, T> {/// Allocate a single page.fn alloc_page(&mut self) -> Result<MutPage, Error> {
impl<E: Borrow<Env>, T> MutTxn<E, T> {unsafe fn alloc_page_(&mut self, dirty: bool) -> Result<MutPage, Error> {
impl<E: Borrow<Env>, T> sanakirja_core::AllocPage for MutTxn<E, T> {/// Allocate a single page.unsafe fn alloc_page(&mut self) -> Result<MutPage, Error> {self.alloc_page_(true)}/// Allocate a single page.unsafe fn alloc_page_no_dirty(&mut self) -> Result<MutPage, Error> {self.alloc_page_(false)}
fn load_page(&self, off: u64) -> Result<CowPage, Self::Error> {if off > self.length {return Err(Error::Corrupt(off));}unsafe {let data = self.env.borrow().find_offset(off)?;Ok(CowPage { data, offset: off })}
unsafe fn load_page(&self, off: u64) -> Result<CowPage, Self::Error> {let data = self.env.borrow().find_offset(off)?;Ok(CowPage { data, offset: off })
if let Some((rc, _)) = btree::get(self, rc, &page, None)? {if *rc & !0xfff == page {let r = *rc & 0xfff;
if let Some((rc, _)) = btree::get(self, rc, &L64(page.to_le()), None)? {let rc = rc.as_u64();if rc & !0xfff == page {let r = rc & 0xfff;
*(maps[0].ptr.add(self.root * PAGE_SIZE + GLOBAL_HEADER_SIZE + 8 * n)as *mut u64)
u64::from_le(*(maps[0].ptr.add(self.root * PAGE_SIZE + GLOBAL_HEADER_SIZE + 8 * n)as *mut u64),)
impl<K: Check + Ord + UnsizedStorable + ?Sized, V: Check + Ord + UnsizedStorable + ?Sized, P: BTreePage<K, V> + std::fmt::Debug> Checkfor Db_<K, V, P>
impl<K: Check + Ord + UnsizedStorable + ?Sized,V: Check + Ord + UnsizedStorable + ?Sized,P: BTreePage<K, V> + std::fmt::Debug,> Check for Db_<K, V, P>