use log::*;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use sanakirja_core::btree;
use sanakirja_core::btree::*;
use sanakirja_core::*;
use crate::environment::*;
use crate::*;
type B<T> = btree::page::Page<u64, A<T>>;
#[derive(Eq, PartialEq, PartialOrd, Ord)]
struct A<T>([u64; 100], std::marker::PhantomData<T>);
impl<T> std::fmt::Debug for A<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "A(…)")?;
Ok(())
}
}
impl<T> Representable<T> for A<T> {
type PageOffsets = core::iter::Empty<u64>;
fn page_offsets(&self) -> Self::PageOffsets {
core::iter::empty()
}
const ALIGN: usize = core::mem::align_of::<Self>();
const SIZE: Option<usize> = Some(core::mem::size_of::<Self>());
type Ord = [u64; 100];
fn ord(&self, _: &T) -> &Self::Ord {
&self.0
}
fn size(&self) -> usize {
core::mem::size_of::<Self>()
}
}
type T<'a> = MutTxn<&'a Env<Exclusive>, ()>;
#[test]
pub fn main() {
env_logger::try_init().unwrap_or(());
let env = Env::new_anon(409600000).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db = create_db::<MutTxn<&Env<Exclusive>, ()>, u64, A<T>, B<T>>(&mut txn).unwrap();
let n = 100_000u64;
let m = 1000;
let now = std::time::SystemTime::now();
let mut values = Vec::with_capacity(n as usize);
let i0 = 500;
for i in 0..n {
// debug!("put {:?} {:?} {:?}", i, (i*i)%m, i*i*i);
if i != i0 && (i * i) % m == (i0 * i0) % m {
continue;
}
let a = A([i * i * i; 100], std::marker::PhantomData);
if put(&mut txn, &mut db, &((i * i) % m), &a).unwrap() {
values.push((i * i) % m);
} else {
// debug!("not inserted");
}
}
debug!("{:?}", now.elapsed());
debug::debug(&txn, &db, "debug_final", true);
values.sort();
let mut curs = btree::cursor::Cursor::new(&db);
let mut nn = 0;
while let Some((k, _v)) = curs.next(&mut txn).unwrap() {
// debug!("{:?} {:?} {:?}", k, values[nn], (v.0)[0]);
assert_eq!(*k, values[nn]);
nn += 1;
}
assert_eq!(nn, values.len());
let db2 = fork_db(&mut txn, &db).unwrap();
let a = A([0; 100], std::marker::PhantomData);
put(&mut txn, &mut db, &(m/2), &a).unwrap();
let mut curs = btree::cursor::Cursor::new(&db);
let (k, v) = curs
.set(&txn, Some((&((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(&db);
let a = A([i0 * i0 * i0; 100], std::marker::PhantomData);
let (k, v) = curs
.set(&txn, Some((&((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(&db);
let (k, _) = curs.set_last(&txn).unwrap().unwrap();
assert_eq!(k, values.last().unwrap());
/*
println!("moi: {:?}", now.elapsed());
let d = 10;
for i in 0..d {
debug!("deleting {:?}", (i*i)%1_000_000);
debug::debug(&txn, &db, &format!("debug{}", i), true);
del(&mut txn, &mut db, &((i * i) % 1_000_000), None).unwrap();
}
debug::debug(&txn, &db, "debug_final", true);
txn.commit().unwrap();
*/
/*
let mut btree = std::collections::BTreeMap::new();
let now = std::time::SystemTime::now();
for i in 0..n {
btree.insert(i * i, i * i * i);
}
println!("std: {:?}", now.elapsed());
*/
/*
std::mem::forget(txn);
{
let env = EnvBuilder::new()
.map_size(1 << 27)
.open("test-lmdb", 0o777)
.unwrap();
let db_handle = env.get_default_db(DbFlags::empty()).unwrap();
let txn = env.new_transaction().unwrap();
{
let db = txn.bind(&db_handle); // get a database bound to this transaction
let now = std::time::SystemTime::now();
for i in 0..n {
db.set(&(i * i), &(i * i * i)).unwrap();
}
println!("lmdb: {:?}", now.elapsed());
}
}
*/
}
#[test]
pub fn u64_unit() {
type B = btree::page::Page<u64, ()>;
env_logger::try_init().unwrap_or(());
let env = Env::new_anon(409600000).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db: Db<_, u64, (), B> = create_db(&mut txn).unwrap();
let n = 100_000 as u64;
let now = std::time::SystemTime::now();
for i in 0..n {
put(&mut txn, &mut db, &((i * i) % 1_000), &()).unwrap();
}
println!("moi: {:?}", now.elapsed());
let d = 10;
for i in 0..d {
// debug!("deleting {:?}", (i*i)%1_000_000);
del(&mut txn, &mut db, &((i * i) % 1_000_000), None).unwrap();
}
txn.commit().unwrap();
}
#[test]
pub fn last_cursor() {
type B = btree::page::Page<u64, ()>;
env_logger::try_init().unwrap_or(());
let env = Env::new_anon(409600000).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db: Db<_, u64, (), B> = create_db(&mut txn).unwrap();
let n = 100_000 as u64;
let m = 10_000;
let now = std::time::SystemTime::now();
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);
debug!("{:?}", now.elapsed());
let mut curs = btree::cursor::Cursor::new(&db);
let (&nn, _) = curs.set_last(&txn).unwrap().unwrap();
assert_eq!(max, nn)
}
#[test]
pub fn fork() {
type B = btree::page::Page<u64, ()>;
env_logger::try_init().unwrap_or(());
let env = Env::new_anon(409600000).unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
let mut db: Db<_, u64, (), B> = create_db(&mut txn).unwrap();
let n = 1000 as u64;
let now = std::time::SystemTime::now();
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);
}
}
debug!("{:?}", now.elapsed());
let db2 = fork_db(&mut txn, &db).unwrap();
debug::debug(&txn, &db2, "debug_just", true);
let mut values2 = values.clone();
values2.sort();
for i in n - 1..n {
if put(&mut txn, &mut db, &i, &()).unwrap() {
values.push(i);
}
}
values.sort();
debug::debug(&txn, &db, "debug", true);
debug::debug(&txn, &db2, "debug_forked", true);
let mut curs = btree::cursor::Cursor::new(&db);
let mut nn = 0;
while let Some((k, _)) = curs.next(&mut txn).unwrap() {
// debug!("{:?}", k);
assert_eq!(*k, values[nn]);
nn += 1;
}
let mut curs = btree::cursor::Cursor::new(&db);
curs.set(&txn, Some((&500, Some(&())))).unwrap();
assert_eq!(nn, values.len());
let mut curs = btree::cursor::Cursor::new(&db2);
let mut nn = 0;
while let Some((k, _)) = curs.next(&mut txn).unwrap() {
assert_eq!(*k, values2[nn]);
nn += 1;
}
assert_eq!(nn, values2.len());
let mut refs = BTreeMap::new();
debug!("{:?} {:?}", db, db2);
add_refs(&txn, &db, &mut refs).unwrap();
add_refs(&txn, &db2, &mut refs).unwrap();
txn.commit().unwrap();
let mut txn = Env::mut_txn_begin(&env).unwrap();
if txn.free.offset > 0 {
let db_free = Db {
db: txn.free,
marker: std::marker::PhantomData,
};
let mut curs: btree::cursor::Cursor<T, _, _, B> = btree::cursor::Cursor::new(&db_free);
debug!("{:?}", db_free);
while let Some((k, _)) = curs.next(&mut txn).unwrap() {
debug!("free: {:?}", k);
}
}
debug!("{:?}", refs);
}
fn add_refs<T: LoadPage, K: Representable<T>, V: Representable<T>, P: BTreePage<T, K, V>>(
txn: &T,
db: &Db<T, K, V, P>,
pages: &mut BTreeMap<u64, usize>,
) -> Result<(), T::Error> {
let mut stack = vec![db.db];
while let Some(p) = stack.pop() {
match pages.entry(p.offset) {
Entry::Vacant(e) => {
e.insert(1);
let mut c = P::first_cursor(p.as_page());
let l = P::left_child(p.as_page(), &c);
if l > 0 {
stack.push(txn.load_page(l)?);
while let Some((_, _, r)) = P::next(p.as_page(), &mut c) {
stack.push(txn.load_page(r)?)
}
}
}
Entry::Occupied(mut e) => {
e.insert(e.get() + 1);
}
}
}
Ok(())
}