1#![cfg_attr(test, feature(test))]
5#![deny(missing_docs)]
6#![doc(html_root_url = "https://docs.rs/lmdb-rkv/0.11.0")]
7
8extern crate libc;
9extern crate distill_downstream_lmdb_sys as ffi;
10
11#[cfg(test)] extern crate rand;
12#[cfg(test)] extern crate tempdir;
13#[cfg(test)] extern crate test;
14#[macro_use] extern crate bitflags;
15
16pub use cursor::{
17 Cursor,
18 RoCursor,
19 RwCursor,
20 Iter,
21 IterDup,
22};
23pub use database::Database;
24pub use environment::{Environment, Stat, EnvironmentBuilder};
25pub use error::{Error, Result};
26pub use flags::*;
27pub use transaction::{
28 InactiveTransaction,
29 RoTransaction,
30 RwTransaction,
31 Transaction,
32};
33
34macro_rules! lmdb_try {
35 ($expr:expr) => ({
36 match $expr {
37 ::ffi::MDB_SUCCESS => (),
38 err_code => return Err(::Error::from_err_code(err_code)),
39 }
40 })
41}
42
43macro_rules! lmdb_try_with_cleanup {
44 ($expr:expr, $cleanup:expr) => ({
45 match $expr {
46 ::ffi::MDB_SUCCESS => (),
47 err_code => {
48 let _ = $cleanup;
49 return Err(::Error::from_err_code(err_code))
50 },
51 }
52 })
53}
54
55mod flags;
56mod cursor;
57mod database;
58mod environment;
59mod error;
60mod transaction;
61
62#[cfg(test)]
63mod test_utils {
64
65 extern crate byteorder;
66
67 use self::byteorder::{ByteOrder, LittleEndian};
68 use tempdir::TempDir;
69
70 use super::*;
71
72 pub fn get_key(n: u32) -> String {
73 format!("key{}", n)
74 }
75
76 pub fn get_data(n: u32) -> String {
77 format!("data{}", n)
78 }
79
80 pub fn setup_bench_db<'a>(num_rows: u32) -> (TempDir, Environment) {
81 let dir = TempDir::new("test").unwrap();
82 let env = Environment::new().open(dir.path()).unwrap();
83
84 {
85 let db = env.open_db(None).unwrap();
86 let mut txn = env.begin_rw_txn().unwrap();
87 for i in 0..num_rows {
88 txn.put(db, &get_key(i), &get_data(i), WriteFlags::empty()).unwrap();
89 }
90 txn.commit().unwrap();
91 }
92 (dir, env)
93 }
94
95 #[test]
99 fn issue_21_regression() {
100 const HEIGHT_KEY: [u8; 1] = [0];
101
102 let dir = TempDir::new("test").unwrap();
103
104 let env = {
105 let mut builder = Environment::new();
106 builder.set_max_dbs(2);
107 builder.set_map_size(1_000_000);
108 builder.open(dir.path()).expect("open lmdb env")
109 };
110 let index = env.create_db(None, DatabaseFlags::DUP_SORT).expect("open index db");
111
112 for height in 0..1000 {
113 let mut value = [0u8; 8];
114 LittleEndian::write_u64(&mut value, height);
115 let mut tx = env.begin_rw_txn().expect("begin_rw_txn");
116 tx.put(index,
117 &HEIGHT_KEY,
118 &value,
119 WriteFlags::empty()).expect("tx.put");
120 tx.commit().expect("tx.commit")
121 }
122 }
123
124 #[test]
127 fn verify_sparse() {
128 const HEIGHT_KEY: [u8; 1] = [0];
129
130 let dir = TempDir::new("test").unwrap();
131
132 {
133 let env = {
134 let mut builder = Environment::new();
135 builder.set_map_size(1_000_000_000);
136 builder.open(dir.path()).expect("open lmdb env")
137 };
138 let db = env.open_db(None).unwrap();
139
140 for height in 0..1000 {
141 let mut value = [0u8; 8];
142 LittleEndian::write_u64(&mut value, height);
143 let mut tx = env.begin_rw_txn().expect("begin_rw_txn");
144 tx.put(db, &HEIGHT_KEY, &value, WriteFlags::empty())
145 .expect("tx.put");
146 tx.commit().expect("tx.commit")
147 }
148 }
149
150 let size = std::fs::metadata(dir.path().join("data.mdb"))
151 .expect("get file size")
152 .len();
153 assert!(size < 1_000_000);
154 }
155
156
157 #[test]
159 fn verify_2gb_plus() {
160 let dir = TempDir::new("test").unwrap();
161 let env = Environment::new()
162 .set_map_size(4_000_000_000)
163 .open(dir.path()).expect("open lmdb env");
164 let db = env.open_db(None).unwrap();
165
166 let data: Vec<u8> = (0..1_000_000).into_iter().map(|i| i as u8).collect();
167
168 let mut tx = env.begin_rw_txn().expect("begin_rw_txn");
170 for i in 0..3000 {
171 let key = &data[i..(i+32)];
172 tx.put(db, &key, &data, WriteFlags::empty()).expect("tx.put");
173 }
174 tx.commit().expect("tx.commit")
175 }
176
177}