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>
where
F: 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 one
fn 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> TypeId
for 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> Storable
for 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 pages
let 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 pages
let 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 txn
let mut txn = Env::mut_txn_begin(&env).unwrap();
info!("started child mutable txn {:?}", txn.root);
// Mutable txn
let 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 {
// parent
std::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 {
// parent
std::thread::sleep(std::time::Duration::from_millis(100));
// Immutable
let txn = Env::txn_begin(&env).unwrap();
info!("started parent txn {:?}", txn.root);
// Immutable
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);
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 error
match 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 error
match 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>
where
S: 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>
where
E: 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>
where
D: 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 integers
pub fn as_u64(&self) -> u64 {
u64::from_le(self.0)
}
/// Convert to usize
pub 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> Check
for 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>