Follow the default behavior of rustfmt (#224)

without.crypto
Kagami Sascha Rosylight 2 years ago committed by GitHub
parent c30523065a
commit 0f3e934f77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      .github/workflows/ci.yml
  2. 18
      .rustfmt.toml
  3. 23
      examples/iterator.rs
  4. 137
      examples/simple-store.rs
  5. 42
      src/backend.rs
  6. 25
      src/backend/impl_lmdb.rs
  7. 189
      src/backend/impl_lmdb/arch_migrator.rs
  8. 6
      src/backend/impl_lmdb/arch_migrator_error.rs
  9. 92
      src/backend/impl_lmdb/environment.rs
  10. 15
      src/backend/impl_lmdb/error.rs
  11. 13
      src/backend/impl_lmdb/flags.rs
  12. 10
      src/backend/impl_lmdb/iter.rs
  13. 40
      src/backend/impl_lmdb/transaction.rs
  14. 21
      src/backend/impl_safe.rs
  15. 18
      src/backend/impl_safe/cursor.rs
  16. 12
      src/backend/impl_safe/database.rs
  17. 67
      src/backend/impl_safe/environment.rs
  18. 19
      src/backend/impl_safe/error.rs
  19. 18
      src/backend/impl_safe/flags.rs
  20. 35
      src/backend/impl_safe/snapshot.rs
  21. 92
      src/backend/impl_safe/transaction.rs
  22. 37
      src/backend/traits.rs
  23. 13
      src/bin/dump.rs
  24. 29
      src/bin/rand.rs
  25. 63
      src/env.rs
  26. 13
      src/error.rs
  27. 14
      src/helpers.rs
  28. 30
      src/lib.rs
  29. 76
      src/manager.rs
  30. 30
      src/migrator.rs
  31. 27
      src/readwrite.rs
  32. 4
      src/store.rs
  33. 189
      src/store/integer.rs
  34. 356
      src/store/integermulti.rs
  35. 33
      src/store/multi.rs
  36. 25
      src/store/single.rs
  37. 39
      src/value.rs
  38. 275
      tests/env-all.rs
  39. 696
      tests/env-lmdb.rs
  40. 280
      tests/env-migration.rs
  41. 592
      tests/env-safe.rs
  42. 27
      tests/integer-store.rs
  43. 250
      tests/manager.rs
  44. 59
      tests/multi-integer-store.rs
  45. 37
      tests/test_txn.rs

@ -4,12 +4,6 @@ on: [push, pull_request]
env:
RUST_BACKTRACE: 1
# We install a known-to-have-rustfmt version of the nightly toolchain
# in order to run the nightly version of rustfmt, which supports rules
# that we depend upon. When updating, pick a suitable nightly version
# from https://rust-lang.github.io/rustup-components-history/
# See .rustfmt.toml for the list of unstable features.
KNOWN_TO_HAVE_RUSTFMT: nightly-2022-08-12
defaults:
run:
@ -37,11 +31,7 @@ jobs:
rustup default ${{ matrix.toolchain }}${{ matrix.target.host }}
- if: ${{ matrix.toolchain == 'nightly' }}
run: |
rustup toolchain install $KNOWN_TO_HAVE_RUSTFMT --profile minimal --component rustfmt clippy
cargo +$KNOWN_TO_HAVE_RUSTFMT fmt --all -- --check
- if: ${{ matrix.toolchain == 'nightly' }}
run: cargo +$KNOWN_TO_HAVE_RUSTFMT clippy --all-features -- -D warnings
run: cargo clippy --all-features -- -D warnings
env:
CC: clang

@ -1,18 +0,0 @@
match_block_trailing_comma = true
max_width = 120
use_small_heuristics = "Off"
### unstable, nightly-only
# https://github.com/rust-lang/rustfmt/issues/3349
comment_width = 90
# https://github.com/rust-lang/rustfmt/issues/3374
force_multiline_blocks = true
# https://github.com/rust-lang/rustfmt/issues/4991
imports_granularity="Crate"
# https://github.com/rust-lang/rustfmt/issues/3361
imports_layout = "Vertical"
# https://github.com/rust-lang/rustfmt/issues/3363
reorder_impl_items = true
# https://github.com/rust-lang/rustfmt/issues/3347
wrap_comments = true

@ -7,25 +7,13 @@
//!
//! cargo run --example iterator
use std::{
fs,
str,
};
use std::{fs, str};
use tempfile::Builder;
use rkv::{
backend::{
SafeMode,
SafeModeDatabase,
SafeModeEnvironment,
},
Manager,
Rkv,
SingleStore,
StoreError,
StoreOptions,
Value,
backend::{SafeMode, SafeModeDatabase, SafeModeEnvironment},
Manager, Rkv, SingleStore, StoreError, StoreOptions, Value,
};
fn main() {
@ -67,7 +55,10 @@ fn main() {
}
}
fn populate_store(k: &Rkv<SafeModeEnvironment>, store: SingleStore<SafeModeDatabase>) -> Result<(), StoreError> {
fn populate_store(
k: &Rkv<SafeModeEnvironment>,
store: SingleStore<SafeModeDatabase>,
) -> Result<(), StoreError> {
let mut writer = k.write()?;
for (country, city) in vec![
("Canada", Value::Str("Ottawa")),

@ -12,16 +12,8 @@ use std::fs;
use tempfile::Builder;
use rkv::{
backend::{
SafeMode,
SafeModeDatabase,
SafeModeEnvironment,
SafeModeRwTransaction,
},
Manager,
Rkv,
StoreOptions,
Value,
backend::{SafeMode, SafeModeDatabase, SafeModeEnvironment, SafeModeRwTransaction},
Manager, Rkv, StoreOptions, Value,
};
type MultiStore = rkv::MultiStore<SafeModeDatabase>;
@ -51,7 +43,9 @@ fn delete(store: MultiStore, writer: &mut Writer) {
let vals = vec!["string uno", "string quatro", "string siete"];
// we convert the writer into a cursor so that we can safely read
for i in 0..keys.len() {
store.delete(writer, &keys[i], &Value::Str(vals[i])).unwrap();
store
.delete(writer, &keys[i], &Value::Str(vals[i]))
.unwrap();
}
}
@ -74,13 +68,31 @@ fn main() {
// Use a writer to mutate the store
let mut writer = k.write().unwrap();
store.put(&mut writer, "int", &Value::I64(1234)).unwrap();
store.put(&mut writer, "uint", &Value::U64(1234_u64)).unwrap();
store.put(&mut writer, "float", &Value::F64(1234.0.into())).unwrap();
store.put(&mut writer, "instant", &Value::Instant(1_528_318_073_700)).unwrap();
store.put(&mut writer, "boolean", &Value::Bool(true)).unwrap();
store.put(&mut writer, "string", &Value::Str("héllo, yöu")).unwrap();
store.put(&mut writer, "json", &Value::Json(r#"{"foo":"bar", "number": 1}"#)).unwrap();
store.put(&mut writer, "blob", &Value::Blob(b"blob")).unwrap();
store
.put(&mut writer, "uint", &Value::U64(1234_u64))
.unwrap();
store
.put(&mut writer, "float", &Value::F64(1234.0.into()))
.unwrap();
store
.put(&mut writer, "instant", &Value::Instant(1_528_318_073_700))
.unwrap();
store
.put(&mut writer, "boolean", &Value::Bool(true))
.unwrap();
store
.put(&mut writer, "string", &Value::Str("héllo, yöu"))
.unwrap();
store
.put(
&mut writer,
"json",
&Value::Json(r#"{"foo":"bar", "number": 1}"#),
)
.unwrap();
store
.put(&mut writer, "blob", &Value::Blob(b"blob"))
.unwrap();
writer.commit().unwrap();
}
@ -88,15 +100,33 @@ fn main() {
{
let mut ids = Vec::new();
let mut writer = k.write().unwrap();
multistore.put(&mut writer, "str1", &Value::Str("string uno")).unwrap();
multistore.put(&mut writer, "str1", &Value::Str("string dos")).unwrap();
multistore.put(&mut writer, "str1", &Value::Str("string tres")).unwrap();
multistore.put(&mut writer, "str2", &Value::Str("string quatro")).unwrap();
multistore.put(&mut writer, "str2", &Value::Str("string cinco")).unwrap();
multistore.put(&mut writer, "str2", &Value::Str("string seis")).unwrap();
multistore.put(&mut writer, "str3", &Value::Str("string siete")).unwrap();
multistore.put(&mut writer, "str3", &Value::Str("string ocho")).unwrap();
multistore.put(&mut writer, "str3", &Value::Str("string nueve")).unwrap();
multistore
.put(&mut writer, "str1", &Value::Str("string uno"))
.unwrap();
multistore
.put(&mut writer, "str1", &Value::Str("string dos"))
.unwrap();
multistore
.put(&mut writer, "str1", &Value::Str("string tres"))
.unwrap();
multistore
.put(&mut writer, "str2", &Value::Str("string quatro"))
.unwrap();
multistore
.put(&mut writer, "str2", &Value::Str("string cinco"))
.unwrap();
multistore
.put(&mut writer, "str2", &Value::Str("string seis"))
.unwrap();
multistore
.put(&mut writer, "str3", &Value::Str("string siete"))
.unwrap();
multistore
.put(&mut writer, "str3", &Value::Str("string ocho"))
.unwrap();
multistore
.put(&mut writer, "str3", &Value::Str("string nueve"))
.unwrap();
getput(multistore, &mut writer, &mut ids);
writer.commit().unwrap();
let mut writer = k.write().unwrap();
@ -116,7 +146,10 @@ fn main() {
println!("Get string {:?}", store.get(&reader, "string").unwrap());
println!("Get json {:?}", store.get(&reader, "json").unwrap());
println!("Get blob {:?}", store.get(&reader, "blob").unwrap());
println!("Get non-existent {:?}", store.get(&reader, "non-existent").unwrap());
println!(
"Get non-existent {:?}",
store.get(&reader, "non-existent").unwrap()
);
}
println!("Looking up keys via Writer.get()...");
@ -125,11 +158,17 @@ fn main() {
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
store.put(&mut writer, "bar", &Value::Str("baz")).unwrap();
store.delete(&mut writer, "foo").unwrap();
println!("It should be None! ({:?})", store.get(&writer, "foo").unwrap());
println!(
"It should be None! ({:?})",
store.get(&writer, "foo").unwrap()
);
println!("Get bar ({:?})", store.get(&writer, "bar").unwrap());
writer.commit().unwrap();
let reader = k.read().expect("reader");
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
println!(
"It should be None! ({:?})",
store.get(&reader, "foo").unwrap()
);
println!("Get bar {:?}", store.get(&reader, "bar").unwrap());
}
@ -141,7 +180,10 @@ fn main() {
writer.abort();
let reader = k.read().expect("reader");
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
println!(
"It should be None! ({:?})",
store.get(&reader, "foo").unwrap()
);
// Explicitly aborting a transaction is not required unless an early
// abort is desired, since both read and write transactions will
// implicitly be aborted once they go out of scope.
@ -153,7 +195,10 @@ fn main() {
let mut writer = k.write().unwrap();
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
store.delete(&mut writer, "foo").unwrap();
println!("It should be None! ({:?})", store.get(&writer, "foo").unwrap());
println!(
"It should be None! ({:?})",
store.get(&writer, "foo").unwrap()
);
writer.commit().unwrap();
// Committing a transaction consumes the writer, preventing you
@ -172,20 +217,36 @@ fn main() {
writer.commit().unwrap();
let reader = k.read().expect("reader");
println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap());
println!("It should be None! ({:?})", store.get(&reader, "bar").unwrap());
println!(
"It should be None! ({:?})",
store.get(&reader, "foo").unwrap()
);
println!(
"It should be None! ({:?})",
store.get(&reader, "bar").unwrap()
);
}
println!("Write and read on multiple stores...");
{
let another_store = k.open_single("another_store", StoreOptions::create()).unwrap();
let another_store = k
.open_single("another_store", StoreOptions::create())
.unwrap();
let mut writer = k.write().unwrap();
store.put(&mut writer, "foo", &Value::Str("bar")).unwrap();
another_store.put(&mut writer, "foo", &Value::Str("baz")).unwrap();
another_store
.put(&mut writer, "foo", &Value::Str("baz"))
.unwrap();
writer.commit().unwrap();
let reader = k.read().unwrap();
println!("Get from store value: {:?}", store.get(&reader, "foo").unwrap());
println!("Get from another store value: {:?}", another_store.get(&reader, "foo").unwrap());
println!(
"Get from store value: {:?}",
store.get(&reader, "foo").unwrap()
);
println!(
"Get from another store value: {:?}",
another_store.get(&reader, "foo").unwrap()
);
}
}

@ -19,38 +19,22 @@ pub use traits::*;
#[cfg(feature = "lmdb")]
pub use impl_lmdb::{
ArchMigrateError as LmdbArchMigrateError,
ArchMigrateResult as LmdbArchMigrateResult,
ArchMigrator as LmdbArchMigrator,
DatabaseFlagsImpl as LmdbDatabaseFlags,
DatabaseImpl as LmdbDatabase,
EnvironmentBuilderImpl as Lmdb,
EnvironmentFlagsImpl as LmdbEnvironmentFlags,
EnvironmentImpl as LmdbEnvironment,
ErrorImpl as LmdbError,
InfoImpl as LmdbInfo,
IterImpl as LmdbIter,
RoCursorImpl as LmdbRoCursor,
RoTransactionImpl as LmdbRoTransaction,
RwCursorImpl as LmdbRwCursor,
RwTransactionImpl as LmdbRwTransaction,
StatImpl as LmdbStat,
ArchMigrateError as LmdbArchMigrateError, ArchMigrateResult as LmdbArchMigrateResult,
ArchMigrator as LmdbArchMigrator, DatabaseFlagsImpl as LmdbDatabaseFlags,
DatabaseImpl as LmdbDatabase, EnvironmentBuilderImpl as Lmdb,
EnvironmentFlagsImpl as LmdbEnvironmentFlags, EnvironmentImpl as LmdbEnvironment,
ErrorImpl as LmdbError, InfoImpl as LmdbInfo, IterImpl as LmdbIter,
RoCursorImpl as LmdbRoCursor, RoTransactionImpl as LmdbRoTransaction,
RwCursorImpl as LmdbRwCursor, RwTransactionImpl as LmdbRwTransaction, StatImpl as LmdbStat,
WriteFlagsImpl as LmdbWriteFlags,
};
pub use impl_safe::{
DatabaseFlagsImpl as SafeModeDatabaseFlags,
DatabaseImpl as SafeModeDatabase,
EnvironmentBuilderImpl as SafeMode,
EnvironmentFlagsImpl as SafeModeEnvironmentFlags,
EnvironmentImpl as SafeModeEnvironment,
ErrorImpl as SafeModeError,
InfoImpl as SafeModeInfo,
IterImpl as SafeModeIter,
RoCursorImpl as SafeModeRoCursor,
RoTransactionImpl as SafeModeRoTransaction,
RwCursorImpl as SafeModeRwCursor,
RwTransactionImpl as SafeModeRwTransaction,
StatImpl as SafeModeStat,
DatabaseFlagsImpl as SafeModeDatabaseFlags, DatabaseImpl as SafeModeDatabase,
EnvironmentBuilderImpl as SafeMode, EnvironmentFlagsImpl as SafeModeEnvironmentFlags,
EnvironmentImpl as SafeModeEnvironment, ErrorImpl as SafeModeError, InfoImpl as SafeModeInfo,
IterImpl as SafeModeIter, RoCursorImpl as SafeModeRoCursor,
RoTransactionImpl as SafeModeRoTransaction, RwCursorImpl as SafeModeRwCursor,
RwTransactionImpl as SafeModeRwTransaction, StatImpl as SafeModeStat,
WriteFlagsImpl as SafeModeWriteFlags,
};

@ -21,29 +21,14 @@ mod stat;
mod transaction;
pub use arch_migrator::{
MigrateError as ArchMigrateError,
MigrateResult as ArchMigrateResult,
Migrator as ArchMigrator,
};
pub use cursor::{
RoCursorImpl,
RwCursorImpl,
MigrateError as ArchMigrateError, MigrateResult as ArchMigrateResult, Migrator as ArchMigrator,
};
pub use cursor::{RoCursorImpl, RwCursorImpl};
pub use database::DatabaseImpl;
pub use environment::{
EnvironmentBuilderImpl,
EnvironmentImpl,
};
pub use environment::{EnvironmentBuilderImpl, EnvironmentImpl};
pub use error::ErrorImpl;
pub use flags::{
DatabaseFlagsImpl,
EnvironmentFlagsImpl,
WriteFlagsImpl,
};
pub use flags::{DatabaseFlagsImpl, EnvironmentFlagsImpl, WriteFlagsImpl};
pub use info::InfoImpl;
pub use iter::IterImpl;
pub use stat::StatImpl;
pub use transaction::{
RoTransactionImpl,
RwTransactionImpl,
};
pub use transaction::{RoTransactionImpl, RwTransactionImpl};

@ -58,38 +58,18 @@
//! variants identify specific kinds of migration failures.
use std::{
collections::{
BTreeMap,
HashMap,
},
collections::{BTreeMap, HashMap},
convert::TryFrom,
fs::File,
io::{
Cursor,
Read,
Seek,
SeekFrom,
Write,
},
path::{
Path,
PathBuf,
},
io::{Cursor, Read, Seek, SeekFrom, Write},
path::{Path, PathBuf},
rc::Rc,
str,
};
use bitflags::bitflags;
use byteorder::{
LittleEndian,
ReadBytesExt,
};
use lmdb::{
DatabaseFlags,
Environment,
Transaction,
WriteFlags,
};
use byteorder::{LittleEndian, ReadBytesExt};
use lmdb::{DatabaseFlags, Environment, Transaction, WriteFlags};
pub use super::arch_migrator_error::MigrateError;
@ -278,9 +258,7 @@ impl Page {
match Self::parse_page_header(&mut cursor, bits)? {
PageHeader::Regular {
mp_flags,
pb_lower,
..
mp_flags, pb_lower, ..
} => {
if mp_flags.contains(PageFlags::LEAF2) || mp_flags.contains(PageFlags::SUBP) {
// We don't yet support DUPFIXED and DUPSORT databases.
@ -299,22 +277,21 @@ impl Page {
} else {
Err(MigrateError::UnexpectedPageHeaderVariant)
}
},
PageHeader::Overflow {
..
} => {
}
PageHeader::Overflow { .. } => {
// There isn't anything to do, nor should we try to instantiate
// a page of this type, as we only access them when reading
// a value that is too large to fit into a leaf node.
Err(MigrateError::UnexpectedPageHeaderVariant)
},
}
}
}
fn parse_page_header(cursor: &mut Cursor<&[u8]>, bits: Bits) -> MigrateResult<PageHeader> {
let mp_pgno = cursor.read_uint::<LittleEndian>(bits.size())?;
let _mp_pad = cursor.read_u16::<LittleEndian>()?;
let mp_flags = PageFlags::from_bits(cursor.read_u16::<LittleEndian>()?).ok_or(MigrateError::InvalidPageBits)?;
let mp_flags = PageFlags::from_bits(cursor.read_u16::<LittleEndian>()?)
.ok_or(MigrateError::InvalidPageBits)?;
if mp_flags.contains(PageFlags::OVERFLOW) {
let pb_pages = cursor.read_u32::<LittleEndian>()?;
@ -352,7 +329,11 @@ impl Page {
})
}
fn parse_leaf_nodes(cursor: &mut Cursor<&[u8]>, pb_lower: u16, bits: Bits) -> MigrateResult<Vec<LeafNode>> {
fn parse_leaf_nodes(
cursor: &mut Cursor<&[u8]>,
pb_lower: u16,
bits: Bits,
) -> MigrateResult<Vec<LeafNode>> {
cursor.set_position(page_header_size(bits));
let num_keys = Self::num_keys(pb_lower, bits);
let mp_ptrs = Self::parse_mp_ptrs(cursor, num_keys)?;
@ -373,7 +354,8 @@ impl Page {
let mn_lo = cursor.read_u16::<LittleEndian>()?;
let mn_hi = cursor.read_u16::<LittleEndian>()?;
let mn_flags = NodeFlags::from_bits(cursor.read_u16::<LittleEndian>()?).ok_or(MigrateError::InvalidNodeBits)?;
let mn_flags = NodeFlags::from_bits(cursor.read_u16::<LittleEndian>()?)
.ok_or(MigrateError::InvalidNodeBits)?;
let mn_ksize = cursor.read_u16::<LittleEndian>()?;
let start = usize::try_from(cursor.position())?;
@ -430,7 +412,11 @@ impl Page {
u32::from(mn_lo) + ((u32::from(mn_hi)) << 16)
}
fn parse_branch_nodes(cursor: &mut Cursor<&[u8]>, pb_lower: u16, bits: Bits) -> MigrateResult<Vec<BranchNode>> {
fn parse_branch_nodes(
cursor: &mut Cursor<&[u8]>,
pb_lower: u16,
bits: Bits,
) -> MigrateResult<Vec<BranchNode>> {
let num_keys = Self::num_keys(pb_lower, bits);
let mp_ptrs = Self::parse_mp_ptrs(cursor, num_keys)?;
@ -523,10 +509,7 @@ impl Migrator {
}
};
Ok(Migrator {
file,
bits,
})
Ok(Migrator { file, bits })
}
/// Dump the data in one of the databases in the LMDB environment. If the `database`
@ -549,8 +532,9 @@ impl Migrator {
let pairs;
if let Some(database) = database {
let subdbs = self.get_subdbs(root_page)?;
let database =
subdbs.get(database.as_bytes()).ok_or_else(|| MigrateError::DatabaseNotFound(database.to_string()))?;
let database = subdbs
.get(database.as_bytes())
.ok_or_else(|| MigrateError::DatabaseNotFound(database.to_string()))?;
let root_page_num = database.md_root;
let root_page = Rc::new(self.get_page(root_page_num)?);
pairs = self.get_pairs(root_page)?;
@ -658,22 +642,17 @@ impl Migrator {
for branch in nodes {
pages.push(Rc::new(self.get_page(branch.mp_pgno)?));
}
},
}
Page::LEAF(nodes) => {
for leaf in nodes {
if let LeafNode::SubData {
key,
db,
..
} = leaf
{
if let LeafNode::SubData { key, db, .. } = leaf {
subdbs.insert(key.to_vec(), db.clone());
};
}
},
}
_ => {
return Err(MigrateError::UnexpectedPageVariant);
},
}
}
}
@ -690,17 +669,13 @@ impl Migrator {
for branch in nodes {
pages.push(Rc::new(self.get_page(branch.mp_pgno)?));
}
},
}
Page::LEAF(nodes) => {
for leaf in nodes {
match leaf {
LeafNode::Regular {
key,
value,
..
} => {
LeafNode::Regular { key, value, .. } => {
pairs.insert(key.to_vec(), value.to_vec());
},
}
LeafNode::BigData {
mv_size,
key,
@ -711,14 +686,13 @@ impl Migrator {
// migration by waiting to read big data until it's time
// to write it to the new database.
let value = self.read_data(
*overflow_pgno * u64::from(PAGESIZE) + page_header_size(self.bits),
*overflow_pgno * u64::from(PAGESIZE)
+ page_header_size(self.bits),
*mv_size as usize,
)?;
pairs.insert(key.to_vec(), value);
},
LeafNode::SubData {
..
} => {
}
LeafNode::SubData { .. } => {
// We don't include subdatabase leaves in pairs, since
// there's no architecture-neutral representation of them,
// and in any case they're meta-data that should get
@ -728,13 +702,13 @@ impl Migrator {
// produced by `mdb_dump`, however, we could allow
// consumers to specify that they'd like to include these
// records.
},
}
};
}
},
}
_ => {
return Err(MigrateError::UnexpectedPageVariant);
},
}
}
}
@ -749,7 +723,10 @@ impl Migrator {
}
fn get_page(&mut self, page_no: u64) -> MigrateResult<Page> {
Page::new(self.read_data(page_no * u64::from(PAGESIZE), usize::from(PAGESIZE))?, self.bits)
Page::new(
self.read_data(page_no * u64::from(PAGESIZE), usize::from(PAGESIZE))?,
self.bits,
)
}
fn get_meta_data(&mut self) -> MigrateResult<MetaData> {
@ -769,7 +746,7 @@ impl Migrator {
return Err(MigrateError::InvalidDataVersion);
}
Ok(meta)
},
}
_ => Err(MigrateError::UnexpectedPageVariant),
}
}
@ -779,20 +756,10 @@ impl Migrator {
mod tests {
use super::*;
use std::{
env,
fs,
mem::size_of,
};
use std::{env, fs, mem::size_of};
use lmdb::{
Environment,
Error as LmdbError,
};
use tempfile::{
tempdir,
tempfile,
};
use lmdb::{Environment, Error as LmdbError};
use tempfile::{tempdir, tempfile};
fn compare_files(ref_file: &mut File, new_file: &mut File) -> MigrateResult<()> {
ref_file.seek(SeekFrom::Start(0))?;
@ -804,16 +771,14 @@ mod tests {
loop {
match ref_file.read(ref_buf) {
Err(err) => panic!("{}", err),
Ok(ref_len) => {
match new_file.read(new_buf) {
Err(err) => panic!("{}", err),
Ok(new_len) => {
assert_eq!(ref_len, new_len);
if ref_len == 0 {
break;
};
assert_eq!(ref_buf[0..ref_len], new_buf[0..new_len]);
},
Ok(ref_len) => match new_file.read(new_buf) {
Err(err) => panic!("{}", err),
Ok(new_len) => {
assert_eq!(ref_len, new_len);
if ref_len == 0 {
break;
};
assert_eq!(ref_buf[0..ref_len], new_buf[0..new_len]);
}
},
}
@ -855,7 +820,9 @@ mod tests {
migrator.dump(Some("subdb"), &new_dump_file)?;
// Open the reference dump file.
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
.iter()
.collect();
let mut ref_dump_file = File::open(ref_dump_file_path)?;
// Compare the new dump file to the reference dump file.
@ -897,7 +864,9 @@ mod tests {
migrator.dump(Some("subdb"), &new_dump_file)?;
// Open the reference dump file.
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
.iter()
.collect();
let mut ref_dump_file = File::open(ref_dump_file_path)?;
// Compare the new dump file to the reference dump file.
@ -923,7 +892,9 @@ mod tests {
migrator.dump(Some("subdb"), &new_dump_file)?;
// Open the reference dump file.
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
.iter()
.collect();
let mut ref_dump_file = File::open(ref_dump_file_path)?;
// Compare the new dump file to the reference dump file.
@ -949,7 +920,9 @@ mod tests {
migrator.dump(Some("subdb"), &new_dump_file)?;
// Open the reference dump file.
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
.iter()
.collect();
let mut ref_dump_file = File::open(ref_dump_file_path)?;
// Compare the new dump file to the reference dump file.
@ -971,8 +944,14 @@ mod tests {
let test_env_path: PathBuf = [cwd, "tests", "envs", test_env_name].iter().collect();
let old_env = tempdir()?;
fs::copy(test_env_path.join("data.mdb"), old_env.path().join("data.mdb"))?;
fs::copy(test_env_path.join("lock.mdb"), old_env.path().join("lock.mdb"))?;
fs::copy(
test_env_path.join("data.mdb"),
old_env.path().join("data.mdb"),
)?;
fs::copy(
test_env_path.join("lock.mdb"),
old_env.path().join("lock.mdb"),
)?;
// Confirm that it isn't possible to open the old environment with LMDB.
assert_eq!(
@ -994,7 +973,9 @@ mod tests {
migrator.dump(Some("subdb"), &new_dump_file)?;
// Open the reference dump file.
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"].iter().collect();
let ref_dump_file_path: PathBuf = [cwd, "tests", "envs", "ref_dump_subdb.txt"]
.iter()
.collect();
let mut ref_dump_file = File::open(ref_dump_file_path)?;
// Compare the new dump file to the reference dump file.
@ -1002,8 +983,14 @@ mod tests {
// Overwrite the old env's files with the new env's files and confirm that it's now
// possible to open the old env with LMDB.
fs::copy(new_env.path().join("data.mdb"), old_env.path().join("data.mdb"))?;
fs::copy(new_env.path().join("lock.mdb"), old_env.path().join("lock.mdb"))?;
fs::copy(
new_env.path().join("data.mdb"),
old_env.path().join("data.mdb"),
)?;
fs::copy(
new_env.path().join("lock.mdb"),
old_env.path().join("lock.mdb"),
)?;
assert!(Environment::new().open(old_env.path()).is_ok());
Ok(())

@ -8,11 +8,7 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
io,
num,
str,
};
use std::{io, num, str};
use thiserror::Error;

@ -10,32 +10,18 @@
use std::{
fs,
path::{
Path,
PathBuf,
},
path::{Path, PathBuf},
};
use lmdb::Error as LmdbError;
use super::{
DatabaseFlagsImpl,
DatabaseImpl,
EnvironmentFlagsImpl,
ErrorImpl,
InfoImpl,
RoTransactionImpl,
RwTransactionImpl,
StatImpl,
DatabaseFlagsImpl, DatabaseImpl, EnvironmentFlagsImpl, ErrorImpl, InfoImpl, RoTransactionImpl,
RwTransactionImpl, StatImpl,
};
use crate::backend::traits::{
BackendEnvironment,
BackendEnvironmentBuilder,
BackendInfo,
BackendIter,
BackendRoCursor,
BackendRoCursorTransaction,
BackendStat,
BackendEnvironment, BackendEnvironmentBuilder, BackendInfo, BackendIter, BackendRoCursor,
BackendRoCursorTransaction, BackendStat,
};
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -112,7 +98,7 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
if !path.is_file() {
return Err(ErrorImpl::UnsuitableEnvironmentPath(path.into()));
}
},
}
EnvironmentPathType::SubDir => {
if !path.is_dir() {
if !self.make_dir_if_needed {
@ -120,12 +106,21 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
}
fs::create_dir_all(path)?;
}
},
}
}
self.builder.open(path).map_err(ErrorImpl::LmdbError).and_then(|lmdbenv| {
EnvironmentImpl::new(path, self.env_path_type, self.env_lock_type, self.env_db_type, lmdbenv)
})
self.builder
.open(path)
.map_err(ErrorImpl::LmdbError)
.and_then(|lmdbenv| {
EnvironmentImpl::new(
path,
self.env_path_type,
self.env_lock_type,
self.env_db_type,
lmdbenv,
)
})
}
}
@ -187,33 +182,54 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
if self.env_db_type == EnvironmentDefaultDbType::SingleDatabase {
return Ok(vec![None]);
}
let db = self.lmdbenv.open_db(None).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)?;
let db = self
.lmdbenv
.open_db(None)
.map(DatabaseImpl)
.map_err(ErrorImpl::LmdbError)?;
let reader = self.begin_ro_txn()?;
let cursor = reader.open_ro_cursor(&db)?;
let mut iter = cursor.into_iter();
let mut store = vec![];
while let Some(result) = iter.next() {
let (key, _) = result?;
let name = String::from_utf8(key.to_owned()).map_err(|_| ErrorImpl::LmdbError(lmdb::Error::Corrupted))?;
let name = String::from_utf8(key.to_owned())
.map_err(|_| ErrorImpl::LmdbError(lmdb::Error::Corrupted))?;
store.push(Some(name));
}
Ok(store)
}
fn open_db(&self, name: Option<&str>) -> Result<Self::Database, Self::Error> {
self.lmdbenv.open_db(name).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.open_db(name)
.map(DatabaseImpl)
.map_err(ErrorImpl::LmdbError)
}
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error> {
self.lmdbenv.create_db(name, flags.0).map(DatabaseImpl).map_err(ErrorImpl::LmdbError)
fn create_db(
&self,
name: Option<&str>,
flags: Self::Flags,
) -> Result<Self::Database, Self::Error> {
self.lmdbenv
.create_db(name, flags.0)
.map(DatabaseImpl)
.map_err(ErrorImpl::LmdbError)
}
fn begin_ro_txn(&'e self) -> Result<Self::RoTransaction, Self::Error> {
self.lmdbenv.begin_ro_txn().map(RoTransactionImpl).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.begin_ro_txn()
.map(RoTransactionImpl)
.map_err(ErrorImpl::LmdbError)
}
fn begin_rw_txn(&'e self) -> Result<Self::RwTransaction, Self::Error> {
self.lmdbenv.begin_rw_txn().map(RwTransactionImpl).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.begin_rw_txn()
.map(RwTransactionImpl)
.map_err(ErrorImpl::LmdbError)
}
fn sync(&self, force: bool) -> Result<(), Self::Error> {
@ -221,11 +237,17 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
}
fn stat(&self) -> Result<Self::Stat, Self::Error> {
self.lmdbenv.stat().map(StatImpl).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.stat()
.map(StatImpl)
.map_err(ErrorImpl::LmdbError)
}
fn info(&self) -> Result<Self::Info, Self::Error> {
self.lmdbenv.info().map(InfoImpl).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.info()
.map(InfoImpl)
.map_err(ErrorImpl::LmdbError)
}
fn freelist(&self) -> Result<usize, Self::Error> {
@ -247,7 +269,9 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
}
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
self.lmdbenv.set_map_size(size).map_err(ErrorImpl::LmdbError)
self.lmdbenv
.set_map_size(size)
.map_err(ErrorImpl::LmdbError)
}
fn get_files_on_disk(&self) -> Vec<PathBuf> {

@ -8,16 +8,9 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
fmt,
io,
path::PathBuf,
};
use std::{fmt, io, path::PathBuf};
use crate::{
backend::traits::BackendError,
error::StoreError,
};
use crate::{backend::traits::BackendError, error::StoreError};
#[derive(Debug)]
pub enum ErrorImpl {
@ -49,7 +42,9 @@ impl Into<StoreError> for ErrorImpl {
ErrorImpl::LmdbError(lmdb::Error::DbsFull) => StoreError::DbsFull,
ErrorImpl::LmdbError(lmdb::Error::ReadersFull) => StoreError::ReadersFull,
ErrorImpl::LmdbError(error) => StoreError::LmdbError(error),
ErrorImpl::UnsuitableEnvironmentPath(path) => StoreError::UnsuitableEnvironmentPath(path),
ErrorImpl::UnsuitableEnvironmentPath(path) => {
StoreError::UnsuitableEnvironmentPath(path)
}
ErrorImpl::IoError(error) => StoreError::IoError(error),
}
}

@ -9,17 +9,8 @@
// specific language governing permissions and limitations under the License.
use crate::backend::{
common::{
DatabaseFlags,
EnvironmentFlags,
WriteFlags,
},
traits::{
BackendDatabaseFlags,
BackendEnvironmentFlags,
BackendFlags,
BackendWriteFlags,
},
common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
traits::{BackendDatabaseFlags, BackendEnvironmentFlags, BackendFlags, BackendWriteFlags},
};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]

@ -22,12 +22,12 @@ pub struct IterImpl<'i, C> {
}
impl<'i, C> IterImpl<'i, C> {
pub(crate) fn new(mut cursor: C, to_iter: impl FnOnce(&mut C) -> lmdb::Iter<'i>) -> IterImpl<'i, C> {
pub(crate) fn new(
mut cursor: C,
to_iter: impl FnOnce(&mut C) -> lmdb::Iter<'i>,
) -> IterImpl<'i, C> {
let iter = to_iter(&mut cursor);
IterImpl {
cursor,
iter,
}
IterImpl { cursor, iter }
}
}

@ -10,16 +10,9 @@
use lmdb::Transaction;
use super::{
DatabaseImpl,
ErrorImpl,
RoCursorImpl,
WriteFlagsImpl,
};
use super::{DatabaseImpl, ErrorImpl, RoCursorImpl, WriteFlagsImpl};
use crate::backend::traits::{
BackendRoCursorTransaction,
BackendRoTransaction,
BackendRwCursorTransaction,
BackendRoCursorTransaction, BackendRoTransaction, BackendRwCursorTransaction,
BackendRwTransaction,
};
@ -43,7 +36,10 @@ impl<'t> BackendRoCursorTransaction<'t> for RoTransactionImpl<'t> {
type RoCursor = RoCursorImpl<'t>;
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl::LmdbError)
self.0
.open_ro_cursor(db.0)
.map(RoCursorImpl)
.map_err(ErrorImpl::LmdbError)
}
}
@ -59,8 +55,16 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
self.0.get(db.0, &key).map_err(ErrorImpl::LmdbError)
}
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error> {
self.0.put(db.0, &key, &value, flags.0).map_err(ErrorImpl::LmdbError)
fn put(
&mut self,
db: &Self::Database,
key: &[u8],
value: &[u8],
flags: Self::Flags,
) -> Result<(), Self::Error> {
self.0
.put(db.0, &key, &value, flags.0)
.map_err(ErrorImpl::LmdbError)
}
#[cfg(not(feature = "db-dup-sort"))]
@ -69,7 +73,12 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
}
#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
fn del(
&mut self,
db: &Self::Database,
key: &[u8],
value: Option<&[u8]>,
) -> Result<(), Self::Error> {
self.0.del(db.0, &key, value).map_err(ErrorImpl::LmdbError)
}
@ -90,6 +99,9 @@ impl<'t> BackendRwCursorTransaction<'t> for RwTransactionImpl<'t> {
type RoCursor = RoCursorImpl<'t>;
fn open_ro_cursor(&'t self, db: &Self::Database) -> Result<Self::RoCursor, Self::Error> {
self.0.open_ro_cursor(db.0).map(RoCursorImpl).map_err(ErrorImpl::LmdbError)
self.0
.open_ro_cursor(db.0)
.map(RoCursorImpl)
.map_err(ErrorImpl::LmdbError)
}
}

@ -19,25 +19,12 @@ mod snapshot;
mod stat;
mod transaction;
pub use cursor::{
RoCursorImpl,
RwCursorImpl,
};
pub use cursor::{RoCursorImpl, RwCursorImpl};
pub use database::DatabaseImpl;
pub use environment::{
EnvironmentBuilderImpl,
EnvironmentImpl,
};
pub use environment::{EnvironmentBuilderImpl, EnvironmentImpl};
pub use error::ErrorImpl;
pub use flags::{
DatabaseFlagsImpl,
EnvironmentFlagsImpl,
WriteFlagsImpl,
};
pub use flags::{DatabaseFlagsImpl, EnvironmentFlagsImpl, WriteFlagsImpl};
pub use info::InfoImpl;
pub use iter::IterImpl;
pub use stat::StatImpl;
pub use transaction::{
RoTransactionImpl,
RwTransactionImpl,
};
pub use transaction::{RoTransactionImpl, RwTransactionImpl};

@ -8,10 +8,7 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use super::{
snapshot::Snapshot,
IterImpl,
};
use super::{snapshot::Snapshot, IterImpl};
use crate::backend::traits::BackendRoCursor;
#[derive(Debug)]
@ -29,14 +26,18 @@ impl<'c> BackendRoCursor<'c> for RoCursorImpl<'c> {
where
K: AsRef<[u8]> + 'c,
{
IterImpl(Box::new(self.0.iter().skip_while(move |&(k, _)| k < key.as_ref())))
IterImpl(Box::new(
self.0.iter().skip_while(move |&(k, _)| k < key.as_ref()),
))
}
fn into_iter_dup_of<K>(self, key: K) -> Self::Iter
where
K: AsRef<[u8]> + 'c,
{
IterImpl(Box::new(self.0.iter().filter(move |&(k, _)| k == key.as_ref())))
IterImpl(Box::new(
self.0.iter().filter(move |&(k, _)| k == key.as_ref()),
))
}
}
@ -45,7 +46,10 @@ impl<'c> BackendRoCursor<'c> for RoCursorImpl<'c> {
type Iter = IterImpl<'c>;
fn into_iter(self) -> Self::Iter {
let flattened = self.0.iter().flat_map(|(key, values)| values.map(move |value| (key, value)));
let flattened = self
.0
.iter()
.flat_map(|(key, values)| values.map(move |value| (key, value)));
IterImpl(Box::new(flattened))
}

@ -9,15 +9,9 @@
// specific language governing permissions and limitations under the License.
use id_arena::Id;
use serde_derive::{
Deserialize,
Serialize,
};
use super::{
snapshot::Snapshot,
DatabaseFlagsImpl,
};
use serde_derive::{Deserialize, Serialize};
use super::{snapshot::Snapshot, DatabaseFlagsImpl};
use crate::backend::traits::BackendDatabase;
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]

@ -13,36 +13,18 @@ use std::{
collections::HashMap,
fs,
ops::DerefMut,
path::{
Path,
PathBuf,
},
sync::{
Arc,
RwLock,
RwLockReadGuard,
RwLockWriteGuard,
},
path::{Path, PathBuf},
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use id_arena::Arena;
use log::warn;
use super::{
database::Database,
DatabaseFlagsImpl,
DatabaseImpl,
EnvironmentFlagsImpl,
ErrorImpl,
InfoImpl,
RoTransactionImpl,
RwTransactionImpl,
StatImpl,
};
use crate::backend::traits::{
BackendEnvironment,
BackendEnvironmentBuilder,
database::Database, DatabaseFlagsImpl, DatabaseImpl, EnvironmentFlagsImpl, ErrorImpl, InfoImpl,
RoTransactionImpl, RwTransactionImpl, StatImpl,
};
use crate::backend::traits::{BackendEnvironment, BackendEnvironmentBuilder};
const DEFAULT_DB_FILENAME: &str = "data.safe.bin";
@ -117,7 +99,13 @@ impl<'b> BackendEnvironmentBuilder<'b> for EnvironmentBuilderImpl {
}
fs::create_dir_all(path)?;
}
let mut env = EnvironmentImpl::new(path, self.flags, self.max_readers, self.max_dbs, self.map_size)?;
let mut env = EnvironmentImpl::new(
path,
self.flags,
self.max_readers,
self.max_dbs,
self.map_size,
)?;
env.read_from_disk(self.discard_if_corrupted)?;
Ok(env)
}
@ -156,11 +144,18 @@ pub struct EnvironmentImpl {
impl EnvironmentImpl {
fn serialize(&self) -> Result<Vec<u8>, ErrorImpl> {
let dbs = self.dbs.read().map_err(|_| ErrorImpl::EnvPoisonError)?;
let data: HashMap<_, _> = dbs.name_map.iter().map(|(name, id)| (name, &dbs.arena[id.0])).collect();
let data: HashMap<_, _> = dbs
.name_map
.iter()
.map(|(name, id)| (name, &dbs.arena[id.0]))
.collect();
Ok(bincode::serialize(&data)?)
}
fn deserialize(bytes: &[u8], discard_if_corrupted: bool) -> Result<(DatabaseArena, DatabaseNameMap), ErrorImpl> {
fn deserialize(
bytes: &[u8],
discard_if_corrupted: bool,
) -> Result<(DatabaseArena, DatabaseNameMap), ErrorImpl> {
let mut arena = DatabaseArena::new();
let mut name_map = HashMap::new();
let data: HashMap<_, _> = match bincode::deserialize(bytes) {
@ -213,10 +208,7 @@ impl EnvironmentImpl {
return Ok(());
};
let (arena, name_map) = Self::deserialize(&fs::read(&path)?, discard_if_corrupted)?;
self.dbs = RwLock::new(EnvironmentDbs {
arena,
name_map,
});
self.dbs = RwLock::new(EnvironmentDbs { arena, name_map });
Ok(())
}
@ -263,7 +255,11 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
Ok(*db)
}
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error> {
fn create_db(
&self,
name: Option<&str>,
flags: Self::Flags,
) -> Result<Self::Database, Self::Error> {
if Arc::strong_count(&self.ro_txns) > 1 {
return Err(ErrorImpl::DbsIllegalOpen);
}
@ -276,7 +272,9 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
let parts = EnvironmentDbsRefMut::from(dbs.deref_mut());
let arena = parts.arena;
let name_map = parts.name_map;
let id = name_map.entry(key).or_insert_with(|| DatabaseImpl(arena.alloc(Database::new(Some(flags), None))));
let id = name_map
.entry(key)
.or_insert_with(|| DatabaseImpl(arena.alloc(Database::new(Some(flags), None))));
Ok(*id)
}
@ -311,7 +309,10 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
}
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
warn!("`set_map_size({})` is ignored by this storage backend.", size);
warn!(
"`set_map_size({})` is ignored by this storage backend.",
size
);
Ok(())
}

@ -8,18 +8,11 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
fmt,
io,
path::PathBuf,
};
use std::{fmt, io, path::PathBuf};
use bincode::Error as BincodeError;
use crate::{
backend::traits::BackendError,
error::StoreError,
};
use crate::{backend::traits::BackendError, error::StoreError};
#[derive(Debug)]
pub enum ErrorImpl {
@ -45,7 +38,9 @@ impl fmt::Display for ErrorImpl {
ErrorImpl::DbsIllegalOpen => write!(fmt, "DbIllegalOpen (safe mode)"),
ErrorImpl::DbNotFoundError => write!(fmt, "DbNotFoundError (safe mode)"),
ErrorImpl::DbIsForeignError => write!(fmt, "DbIsForeignError (safe mode)"),
ErrorImpl::UnsuitableEnvironmentPath(_) => write!(fmt, "UnsuitableEnvironmentPath (safe mode)"),
ErrorImpl::UnsuitableEnvironmentPath(_) => {
write!(fmt, "UnsuitableEnvironmentPath (safe mode)")
}
ErrorImpl::IoError(e) => e.fmt(fmt),
ErrorImpl::BincodeError(e) => e.fmt(fmt),
}
@ -62,7 +57,9 @@ impl Into<StoreError> for ErrorImpl {
ErrorImpl::KeyValuePairNotFound => StoreError::KeyValuePairNotFound,
ErrorImpl::BincodeError(_) => StoreError::FileInvalid,
ErrorImpl::DbsFull => StoreError::DbsFull,
ErrorImpl::UnsuitableEnvironmentPath(path) => StoreError::UnsuitableEnvironmentPath(path),
ErrorImpl::UnsuitableEnvironmentPath(path) => {
StoreError::UnsuitableEnvironmentPath(path)
}
ErrorImpl::IoError(error) => StoreError::IoError(error),
_ => StoreError::SafeModeError(self),
}

@ -9,23 +9,11 @@
// specific language governing permissions and limitations under the License.
use bitflags::bitflags;
use serde_derive::{
Deserialize,
Serialize,
};
use serde_derive::{Deserialize, Serialize};
use crate::backend::{
common::{
DatabaseFlags,
EnvironmentFlags,
WriteFlags,
},
traits::{
BackendDatabaseFlags,
BackendEnvironmentFlags,
BackendFlags,
BackendWriteFlags,
},
common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
traits::{BackendDatabaseFlags, BackendEnvironmentFlags, BackendFlags, BackendWriteFlags},
};
bitflags! {

@ -9,17 +9,11 @@
// specific language governing permissions and limitations under the License.
use std::{
collections::{
BTreeMap,
BTreeSet,
},
collections::{BTreeMap, BTreeSet},
sync::Arc,
};
use serde_derive::{
Deserialize,
Serialize,
};
use serde_derive::{Deserialize, Serialize};
use super::DatabaseFlagsImpl;
@ -69,14 +63,19 @@ impl Snapshot {
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
self.map.iter().map(|(key, value)| (key.as_ref(), value.as_ref()))
self.map
.iter()
.map(|(key, value)| (key.as_ref(), value.as_ref()))
}
}
#[cfg(feature = "db-dup-sort")]
impl Snapshot {
pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> {
self.map.get(key).and_then(|v| v.iter().next()).map(|v| v.as_ref())
self.map
.get(key)
.and_then(|v| v.iter().next())
.map(|v| v.as_ref())
}
pub(crate) fn put(&mut self, key: &[u8], value: &[u8]) {
@ -86,11 +85,11 @@ impl Snapshot {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
}
Some(values) => {
values.clear();
values.insert(Box::from(value));
},
}
}
}
@ -102,12 +101,14 @@ impl Snapshot {
let was_empty = values.is_empty();
values.clear();
Some(()).filter(|_| !was_empty)
},
}
}
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], impl Iterator<Item = &[u8]>)> {
self.map.iter().map(|(key, values)| (key.as_ref(), values.iter().map(|value| value.as_ref())))
self.map
.iter()
.map(|(key, values)| (key.as_ref(), values.iter().map(|value| value.as_ref())))
}
}
@ -120,10 +121,10 @@ impl Snapshot {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
}
Some(values) => {
values.insert(Box::from(value));
},
}
}
}
@ -134,7 +135,7 @@ impl Snapshot {
Some(values) => {
let was_removed = values.remove(value);
Some(()).filter(|_| was_removed)
},
}
}
}
}

@ -9,23 +9,13 @@
// specific language governing permissions and limitations under the License.
#![allow(dead_code)] // TODO: Get rid of unused struct members
use std::{
collections::HashMap,
sync::Arc,
};
use std::{collections::HashMap, sync::Arc};
use super::{
snapshot::Snapshot,
DatabaseImpl,
EnvironmentImpl,
ErrorImpl,
RoCursorImpl,
WriteFlagsImpl,
snapshot::Snapshot, DatabaseImpl, EnvironmentImpl, ErrorImpl, RoCursorImpl, WriteFlagsImpl,
};
use crate::backend::traits::{
BackendRoCursorTransaction,
BackendRoTransaction,
BackendRwCursorTransaction,
BackendRoCursorTransaction, BackendRoTransaction, BackendRwCursorTransaction,
BackendRwTransaction,
};
@ -37,8 +27,16 @@ pub struct RoTransactionImpl<'t> {
}
impl<'t> RoTransactionImpl<'t> {
pub(crate) fn new(env: &'t EnvironmentImpl, idx: Arc<()>) -> Result<RoTransactionImpl<'t>, ErrorImpl> {
let snapshots = env.dbs()?.arena.iter().map(|(id, db)| (DatabaseImpl(id), db.snapshot())).collect();
pub(crate) fn new(
env: &'t EnvironmentImpl,
idx: Arc<()>,
) -> Result<RoTransactionImpl<'t>, ErrorImpl> {
let snapshots = env
.dbs()?
.arena
.iter()
.map(|(id, db)| (DatabaseImpl(id), db.snapshot()))
.collect();
Ok(RoTransactionImpl {
env,
snapshots,
@ -78,8 +76,16 @@ pub struct RwTransactionImpl<'t> {
}
impl<'t> RwTransactionImpl<'t> {
pub(crate) fn new(env: &'t EnvironmentImpl, idx: Arc<()>) -> Result<RwTransactionImpl<'t>, ErrorImpl> {
let snapshots = env.dbs()?.arena.iter().map(|(id, db)| (DatabaseImpl(id), db.snapshot())).collect();
pub(crate) fn new(
env: &'t EnvironmentImpl,
idx: Arc<()>,
) -> Result<RwTransactionImpl<'t>, ErrorImpl> {
let snapshots = env
.dbs()?
.arena
.iter()
.map(|(id, db)| (DatabaseImpl(id), db.snapshot()))
.collect();
Ok(RwTransactionImpl {
env,
snapshots,
@ -99,16 +105,34 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
}
#[cfg(not(feature = "db-dup-sort"))]
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
fn put(
&mut self,
db: &Self::Database,
key: &[u8],
value: &[u8],
_flags: Self::Flags,
) -> Result<(), Self::Error> {
let snapshot = self
.snapshots
.get_mut(db)
.ok_or_else(|| ErrorImpl::DbIsForeignError)?;
snapshot.put(key, value);
Ok(())
}
#[cfg(feature = "db-dup-sort")]
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
fn put(
&mut self,
db: &Self::Database,
key: &[u8],
value: &[u8],
_flags: Self::Flags,
) -> Result<(), Self::Error> {
use super::DatabaseFlagsImpl;
let snapshot = self.snapshots.get_mut(db).ok_or(ErrorImpl::DbIsForeignError)?;
let snapshot = self
.snapshots
.get_mut(db)
.ok_or(ErrorImpl::DbIsForeignError)?;
if snapshot.flags().contains(DatabaseFlagsImpl::DUP_SORT) {
snapshot.put_dup(key, value);
} else {
@ -119,24 +143,40 @@ impl<'t> BackendRwTransaction for RwTransactionImpl<'t> {
#[cfg(not(feature = "db-dup-sort"))]
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error> {
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
let snapshot = self
.snapshots
.get_mut(db)
.ok_or_else(|| ErrorImpl::DbIsForeignError)?;
let deleted = snapshot.del(key);
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?)
}
#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
fn del(
&mut self,
db: &Self::Database,
key: &[u8],
value: Option<&[u8]>,
) -> Result<(), Self::Error> {
use super::DatabaseFlagsImpl;
let snapshot = self.snapshots.get_mut(db).ok_or(ErrorImpl::DbIsForeignError)?;
let snapshot = self
.snapshots
.get_mut(db)
.ok_or(ErrorImpl::DbIsForeignError)?;
let deleted = match (value, snapshot.flags()) {
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => snapshot.del_exact(key, value),
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => {
snapshot.del_exact(key, value)
}
_ => snapshot.del(key),
};
deleted.ok_or(ErrorImpl::KeyValuePairNotFound)
}
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error> {
let snapshot = self.snapshots.get_mut(db).ok_or(ErrorImpl::DbIsForeignError)?;
let snapshot = self
.snapshots
.get_mut(db)
.ok_or(ErrorImpl::DbIsForeignError)?;
snapshot.clear();
Ok(())
}

@ -9,22 +9,12 @@
// specific language governing permissions and limitations under the License.
use std::{
fmt::{
Debug,
Display,
},
path::{
Path,
PathBuf,
},
fmt::{Debug, Display},
path::{Path, PathBuf},
};
use crate::{
backend::common::{
DatabaseFlags,
EnvironmentFlags,
WriteFlags,
},
backend::common::{DatabaseFlags, EnvironmentFlags, WriteFlags},
error::StoreError,
};
@ -111,7 +101,11 @@ pub trait BackendEnvironment<'e>: Debug {
fn open_db(&self, name: Option<&str>) -> Result<Self::Database, Self::Error>;
fn create_db(&self, name: Option<&str>, flags: Self::Flags) -> Result<Self::Database, Self::Error>;
fn create_db(
&self,
name: Option<&str>,
flags: Self::Flags,
) -> Result<Self::Database, Self::Error>;
fn begin_ro_txn(&'e self) -> Result<Self::RoTransaction, Self::Error>;
@ -148,13 +142,24 @@ pub trait BackendRwTransaction: Debug {
fn get(&self, db: &Self::Database, key: &[u8]) -> Result<&[u8], Self::Error>;
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error>;
fn put(
&mut self,
db: &Self::Database,
key: &[u8],
value: &[u8],
flags: Self::Flags,
) -> Result<(), Self::Error>;
#[cfg(not(feature = "db-dup-sort"))]
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error>;
#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error>;
fn del(
&mut self,
db: &Self::Database,
key: &[u8],
value: Option<&[u8]>,
) -> Result<(), Self::Error>;
fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error>;

@ -8,16 +8,9 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
env::args,
io,
path::Path,
};
use std::{env::args, io, path::Path};
use rkv::migrator::{
LmdbArchMigrateError,
LmdbArchMigrator,
};
use rkv::migrator::{LmdbArchMigrateError, LmdbArchMigrator};
fn main() -> Result<(), LmdbArchMigrateError> {
let mut cli_args = args();
@ -35,7 +28,7 @@ fn main() -> Result<(), LmdbArchMigrateError> {
None => return Err("-s must be followed by database name".into()),
Some(str) => Some(str),
};
},
}
str => return Err(format!("arg -{} not recognized", str).into()),
}
} else {

@ -14,22 +14,11 @@
//! the number of key/value pairs to create via the `-n <number>` flag
//! (for which the default value is 50).
use std::{
env::args,
fs,
fs::File,
io::Read,
path::Path,
};
use std::{env::args, fs, fs::File, io::Read, path::Path};
use rkv::{
backend::{
BackendEnvironmentBuilder,
Lmdb,
},
Rkv,
StoreOptions,
Value,
backend::{BackendEnvironmentBuilder, Lmdb},
Rkv, StoreOptions, Value,
};
fn main() {
@ -49,13 +38,13 @@ fn main() {
None => panic!("-s must be followed by database arg"),
Some(str) => Some(str),
};
},
}
"n" => {
num_pairs = match args.next() {
None => panic!("-s must be followed by number of pairs"),
Some(str) => str.parse().expect("number"),
};
},
}
str => panic!("arg -{} not recognized", str),
}
} else {
@ -80,7 +69,9 @@ fn main() {
// of the pairs (assuming maximum key and value sizes).
builder.set_map_size((511 + 65535) * num_pairs * 2);
let rkv = Rkv::from_builder(Path::new(&path), builder).expect("Rkv");
let store = rkv.open_single(database.as_deref(), StoreOptions::create()).expect("opened");
let store = rkv
.open_single(database.as_deref(), StoreOptions::create())
.expect("opened");
let mut writer = rkv.write().expect("writer");
// Generate random values for the number of keys and key/value lengths.
@ -106,7 +97,9 @@ fn main() {
let mut value: Vec<u8> = vec![0; value_len];
random.read_exact(&mut value[0..value_len]).unwrap();
store.put(&mut writer, key, &Value::Blob(&value)).expect("wrote");
store
.put(&mut writer, key, &Value::Blob(&value))
.expect("wrote");
}
writer.commit().expect("committed");

@ -11,38 +11,19 @@
use std::{
fs,
os::raw::c_uint,
path::{
Path,
PathBuf,
},
path::{Path, PathBuf},
};
#[cfg(any(feature = "db-dup-sort", feature = "db-int-key"))]
use crate::backend::{
BackendDatabaseFlags,
DatabaseFlags,
};
use crate::backend::{BackendDatabaseFlags, DatabaseFlags};
use crate::{
backend::{
BackendEnvironment,
BackendEnvironmentBuilder,
BackendRoCursorTransaction,
BackendRwCursorTransaction,
SafeModeError,
},
error::{
CloseError,
StoreError,
},
readwrite::{
Reader,
Writer,
},
store::{
single::SingleStore,
CloseOptions,
Options as StoreOptions,
BackendEnvironment, BackendEnvironmentBuilder, BackendRoCursorTransaction,
BackendRwCursorTransaction, SafeModeError,
},
error::{CloseError, StoreError},
readwrite::{Reader, Writer},
store::{single::SingleStore, CloseOptions, Options as StoreOptions},
};
#[cfg(feature = "db-dup-sort")]
@ -190,22 +171,28 @@ where
T: Into<Option<&'s str>>,
{
if opts.create {
self.env.create_db(name.into(), opts.flags).map_err(|e| {
match e.into() {
self.env
.create_db(name.into(), opts.flags)
.map_err(|e| match e.into() {
#[cfg(feature = "lmdb")]
StoreError::LmdbError(lmdb::Error::BadRslot) => StoreError::open_during_transaction(),
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => StoreError::open_during_transaction(),
StoreError::LmdbError(lmdb::Error::BadRslot) => {
StoreError::open_during_transaction()
}
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => {
StoreError::open_during_transaction()
}
e => e,
}
})
})
} else {
self.env.open_db(name.into()).map_err(|e| {
match e.into() {
#[cfg(feature = "lmdb")]
StoreError::LmdbError(lmdb::Error::BadRslot) => StoreError::open_during_transaction(),
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => StoreError::open_during_transaction(),
e => e,
self.env.open_db(name.into()).map_err(|e| match e.into() {
#[cfg(feature = "lmdb")]
StoreError::LmdbError(lmdb::Error::BadRslot) => {
StoreError::open_during_transaction()
}
StoreError::SafeModeError(SafeModeError::DbsIllegalOpen) => {
StoreError::open_during_transaction()
}
e => e,
})
}
}

@ -8,13 +8,7 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
io,
path::PathBuf,
sync,
thread,
thread::ThreadId,
};
use std::{io, path::PathBuf, sync, thread, thread::ThreadId};
use thiserror::Error;
@ -27,10 +21,7 @@ pub enum DataError {
UnknownType(u8),
#[error("unexpected type tag: expected {expected}, got {actual}")]
UnexpectedType {
expected: Type,
actual: Type,
},
UnexpectedType { expected: Type, actual: Type },
#[error("empty data; expected tag")]
Empty,

@ -10,18 +10,12 @@
use std::{
io,
path::{
Path,
PathBuf,
},
path::{Path, PathBuf},
};
use url::Url;
use crate::{
error::StoreError,
value::Value,
};
use crate::{error::StoreError, value::Value};
pub(crate) fn read_transform(value: Result<&[u8], StoreError>) -> Result<Value, StoreError> {
match value {
@ -40,7 +34,9 @@ where
Ok(if cfg!(target_os = "windows") {
let map_err = |_| io::Error::new(io::ErrorKind::Other, "path canonicalization error");
Url::from_file_path(&canonical).and_then(|url| url.to_file_path()).map_err(map_err)?
Url::from_file_path(&canonical)
.and_then(|url| url.to_file_path())
.map_err(map_err)?
} else {
canonical
})

@ -214,35 +214,15 @@ pub mod migrator;
pub mod store;
pub mod value;
pub use backend::{
DatabaseFlags,
EnvironmentFlags,
WriteFlags,
};
pub use backend::{DatabaseFlags, EnvironmentFlags, WriteFlags};
pub use env::Rkv;
pub use error::{
DataError,
MigrateError,
StoreError,
};
pub use error::{DataError, MigrateError, StoreError};
pub use manager::Manager;
#[cfg(feature = "lmdb")]
pub use migrator::Migrator;
pub use readwrite::{
Readable,
Reader,
Writer,
};
pub use store::{
keys::EncodableKey,
single::SingleStore,
CloseOptions,
Options as StoreOptions,
};
pub use value::{
OwnedValue,
Value,
};
pub use readwrite::{Readable, Reader, Writer};
pub use store::{keys::EncodableKey, single::SingleStore, CloseOptions, Options as StoreOptions};
pub use value::{OwnedValue, Value};
#[cfg(feature = "db-dup-sort")]
pub use store::multi::MultiStore;

@ -9,20 +9,11 @@
// specific language governing permissions and limitations under the License.
use std::{
collections::{
btree_map::Entry,
BTreeMap,
},
collections::{btree_map::Entry, BTreeMap},
os::raw::c_uint,
path::{
Path,
PathBuf,
},
path::{Path, PathBuf},
result,
sync::{
Arc,
RwLock,
},
sync::{Arc, RwLock},
};
use lazy_static::lazy_static;
@ -30,15 +21,8 @@ use lazy_static::lazy_static;
#[cfg(feature = "lmdb")]
use crate::backend::LmdbEnvironment;
use crate::{
backend::{
BackendEnvironment,
BackendEnvironmentBuilder,
SafeModeEnvironment,
},
error::{
CloseError,
StoreError,
},
backend::{BackendEnvironment, BackendEnvironmentBuilder, SafeModeEnvironment},
error::{CloseError, StoreError},
helpers::canonicalize_path,
store::CloseOptions,
Rkv,
@ -54,7 +38,8 @@ lazy_static! {
}
lazy_static! {
static ref MANAGER_SAFE_MODE: RwLock<Manager<SafeModeEnvironment>> = RwLock::new(Manager::new());
static ref MANAGER_SAFE_MODE: RwLock<Manager<SafeModeEnvironment>> =
RwLock::new(Manager::new());
}
/// A process is only permitted to have one open handle to each Rkv environment. This
@ -111,12 +96,17 @@ where
Entry::Vacant(e) => {
let k = Arc::new(RwLock::new(f(e.key().as_path())?));
e.insert(k).clone()
},
}
})
}
/// Return the open env at `path` with `capacity`, or create it by calling `f`.
pub fn get_or_create_with_capacity<'p, F, P>(&mut self, path: P, capacity: c_uint, f: F) -> Result<SharedRkv<E>>
pub fn get_or_create_with_capacity<'p, F, P>(
&mut self,
path: P,
capacity: c_uint,
f: F,
) -> Result<SharedRkv<E>>
where
F: FnOnce(&Path, c_uint) -> Result<Rkv<E>>,
P: Into<&'p Path>,
@ -131,12 +121,17 @@ where
Entry::Vacant(e) => {
let k = Arc::new(RwLock::new(f(e.key().as_path(), capacity)?));
e.insert(k).clone()
},
}
})
}
/// Return a new Rkv environment from the builder, or create it by calling `f`.
pub fn get_or_create_from_builder<'p, F, P, B>(&mut self, path: P, builder: B, f: F) -> Result<SharedRkv<E>>
pub fn get_or_create_from_builder<'p, F, P, B>(
&mut self,
path: P,
builder: B,
f: F,
) -> Result<SharedRkv<E>>
where
F: FnOnce(&Path, B) -> Result<Rkv<E>>,
P: Into<&'p Path>,
@ -152,7 +147,7 @@ where
Entry::Vacant(e) => {
let k = Arc::new(RwLock::new(f(e.key().as_path(), builder)?));
e.insert(k).clone()
},
}
})
}
@ -169,12 +164,15 @@ where
};
match self.environments.entry(canonical) {
Entry::Vacant(_) => Ok(()),
Entry::Occupied(e) if Arc::strong_count(e.get()) > 1 => Err(CloseError::EnvironmentStillOpen),
Entry::Occupied(e) if Arc::strong_count(e.get()) > 1 => {
Err(CloseError::EnvironmentStillOpen)
}
Entry::Occupied(e) => {
let env = Arc::try_unwrap(e.remove()).map_err(|_| CloseError::UnknownEnvironmentStillOpen)?;
let env = Arc::try_unwrap(e.remove())
.map_err(|_| CloseError::UnknownEnvironmentStillOpen)?;
env.into_inner()?.close(options)?;
Ok(())
},
}
}
}
}
@ -210,14 +208,22 @@ mod tests {
fn test_mutate_managed_rkv() {
let mut manager = Manager::<LmdbEnvironment>::new();
let root1 = Builder::new().prefix("test_mutate_managed_rkv_1").tempdir().expect("tempdir");
let root1 = Builder::new()
.prefix("test_mutate_managed_rkv_1")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root1.path()).expect("dir created");
let path1 = root1.path();
let arc = manager.get_or_create(path1, Rkv::new::<Lmdb>).expect("created");
let arc = manager
.get_or_create(path1, Rkv::new::<Lmdb>)
.expect("created");
// Arc<RwLock<>> has interior mutability, so we can replace arc's Rkv instance with a new
// instance that has a different path.
let root2 = Builder::new().prefix("test_mutate_managed_rkv_2").tempdir().expect("tempdir");
let root2 = Builder::new()
.prefix("test_mutate_managed_rkv_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root2.path()).expect("dir created");
let path2 = root2.path();
{
@ -233,7 +239,9 @@ mod tests {
// Meanwhile, a new Arc for path2 has a different pointer, even though its Rkv's path is
// the same as arc's current path.
let path2_arc = manager.get_or_create(path2, Rkv::new::<Lmdb>).expect("success");
let path2_arc = manager
.get_or_create(path2, Rkv::new::<Lmdb>)
.expect("success");
assert!(!Arc::ptr_eq(&path2_arc, &arc));
}
}

@ -44,20 +44,12 @@
//! it cannot overwrite nor append data.
use crate::{
backend::{
LmdbEnvironment,
SafeModeEnvironment,
},
backend::{LmdbEnvironment, SafeModeEnvironment},
error::MigrateError,
Rkv,
StoreOptions,
Rkv, StoreOptions,
};
pub use crate::backend::{
LmdbArchMigrateError,
LmdbArchMigrateResult,
LmdbArchMigrator,
};
pub use crate::backend::{LmdbArchMigrateError, LmdbArchMigrateResult, LmdbArchMigrator};
// FIXME: should parametrize this instead.
@ -108,17 +100,15 @@ macro_rules! fn_migrator {
F: FnOnce(crate::backend::$builder) -> crate::backend::$builder,
D: std::ops::Deref<Target = Rkv<$dst_env>>,
{
use crate::{
backend::*,
CloseOptions,
};
use crate::{backend::*, CloseOptions};
let mut manager = crate::Manager::<$src_env>::singleton().write()?;
let mut builder = Rkv::<$src_env>::environment_builder::<$builder>();
builder.set_max_dbs(crate::env::DEFAULT_MAX_DBS);
builder = build(builder);
let src_env = manager.get_or_create_from_builder(path, builder, Rkv::from_builder::<$builder>)?;
let src_env =
manager.get_or_create_from_builder(path, builder, Rkv::from_builder::<$builder>)?;
Migrator::$migrate(src_env.read()?, dst_env)?;
drop(src_env);
@ -143,11 +133,15 @@ macro_rules! fn_migrator {
match Migrator::$migrate(path, |builder| builder, dst_env) {
// Source environment is an invalid file or corrupted database.
Err(crate::MigrateError::StoreError(crate::StoreError::FileInvalid)) => Ok(()),
Err(crate::MigrateError::StoreError(crate::StoreError::DatabaseCorrupted)) => Ok(()),
Err(crate::MigrateError::StoreError(crate::StoreError::DatabaseCorrupted)) => {
Ok(())
}
// Path not accessible.
Err(crate::MigrateError::StoreError(crate::StoreError::IoError(_))) => Ok(()),
// Path accessible but incompatible for configuration.
Err(crate::MigrateError::StoreError(crate::StoreError::UnsuitableEnvironmentPath(_))) => Ok(()),
Err(crate::MigrateError::StoreError(
crate::StoreError::UnsuitableEnvironmentPath(_),
)) => Ok(()),
// Couldn't close source environment and delete files on disk (e.g. other stores still open).
Err(crate::MigrateError::CloseError(_)) => Ok(()),
// Nothing to migrate.

@ -10,12 +10,8 @@
use crate::{
backend::{
BackendDatabase,
BackendRoCursor,
BackendRoCursorTransaction,
BackendRoTransaction,
BackendRwCursorTransaction,
BackendRwTransaction,
BackendDatabase, BackendRoCursor, BackendRoCursorTransaction, BackendRoTransaction,
BackendRwCursorTransaction, BackendRwTransaction,
},
error::StoreError,
helpers::read_transform,
@ -115,12 +111,20 @@ where
self.0.abort();
}
pub(crate) fn put<K>(&mut self, db: &T::Database, k: &K, v: &Value, flags: T::Flags) -> Result<(), StoreError>
pub(crate) fn put<K>(
&mut self,
db: &T::Database,
k: &K,
v: &Value,
flags: T::Flags,
) -> Result<(), StoreError>
where
K: AsRef<[u8]>,
{
// TODO: don't allocate twice.
self.0.put(db, k.as_ref(), &v.to_bytes()?, flags).map_err(|e| e.into())
self.0
.put(db, k.as_ref(), &v.to_bytes()?, flags)
.map_err(|e| e.into())
}
#[cfg(not(feature = "db-dup-sort"))]
@ -132,7 +136,12 @@ where
}
#[cfg(feature = "db-dup-sort")]
pub(crate) fn delete<K>(&mut self, db: &T::Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError>
pub(crate) fn delete<K>(
&mut self,
db: &T::Database,
k: &K,
v: Option<&[u8]>,
) -> Result<(), StoreError>
where
K: AsRef<[u8]>,
{

@ -47,8 +47,6 @@ pub struct CloseOptions {
impl CloseOptions {
pub fn delete_files_on_disk() -> CloseOptions {
CloseOptions {
delete: true,
}
CloseOptions { delete: true }
}
}

@ -11,20 +11,11 @@
use std::marker::PhantomData;
use crate::{
backend::{
BackendDatabase,
BackendRwTransaction,
},
backend::{BackendDatabase, BackendRwTransaction},
error::StoreError,
readwrite::{
Readable,
Writer,
},
readwrite::{Readable, Writer},
store::{
keys::{
Key,
PrimitiveInt,
},
keys::{Key, PrimitiveInt},
single::SingleStore,
},
value::Value,
@ -90,7 +81,10 @@ mod tests {
#[test]
fn test_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -100,12 +94,19 @@ mod tests {
($type:ty, $key:expr) => {{
let mut writer = k.write().expect("writer");
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
assert_eq!(s.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, $key, &Value::Str("hello!"))
.expect("write");
assert_eq!(
s.get(&writer, $key).expect("read"),
Some(Value::Str("hello!"))
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get(&reader, $key).expect("read"),
Some(Value::Str("hello!"))
);
}};
}
@ -115,7 +116,10 @@ mod tests {
#[test]
fn test_clear() {
let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_clear")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -146,7 +150,10 @@ mod tests {
#[test]
fn test_dup() {
let root = Builder::new().prefix("test_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -177,7 +184,10 @@ mod tests {
#[test]
fn test_del() {
let root = Builder::new().prefix("test_integer_del").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_del")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -224,7 +234,10 @@ mod tests {
#[test]
fn test_persist() {
let root = Builder::new().prefix("test_integer_persist").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_persist")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
@ -254,7 +267,10 @@ mod tests {
#[test]
fn test_intertwine_read_write() {
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_intertwine_read_write")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -279,12 +295,24 @@ mod tests {
}
{
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
s.put(&mut writer, 1, &Value::Str("goodbye!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("goodbye!"))
.expect("write");
s.put(&mut writer, 3, &Value::Str("goodbye!"))
.expect("write");
assert_eq!(
s.get(&writer, 1).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
writer.commit().expect("committed");
}
@ -298,16 +326,28 @@ mod tests {
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(
s.get(&writer, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
writer.commit().expect("committed");
}
{
let reader = k.write().expect("reader");
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(
s.get(&reader, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&reader, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
reader.commit().expect("committed");
}
}
@ -324,7 +364,10 @@ mod tests_safe {
#[test]
fn test_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -334,12 +377,19 @@ mod tests_safe {
($type:ty, $key:expr) => {{
let mut writer = k.write().expect("writer");
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
assert_eq!(s.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, $key, &Value::Str("hello!"))
.expect("write");
assert_eq!(
s.get(&writer, $key).expect("read"),
Some(Value::Str("hello!"))
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
assert_eq!(s.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get(&reader, $key).expect("read"),
Some(Value::Str("hello!"))
);
}};
}
@ -349,7 +399,10 @@ mod tests_safe {
#[test]
fn test_clear() {
let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_clear")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -380,7 +433,10 @@ mod tests_safe {
#[test]
fn test_dup() {
let root = Builder::new().prefix("test_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -411,7 +467,10 @@ mod tests_safe {
#[test]
fn test_del() {
let root = Builder::new().prefix("test_integer_del").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_del")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -458,7 +517,10 @@ mod tests_safe {
#[test]
fn test_persist() {
let root = Builder::new().prefix("test_integer_persist").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_persist")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
@ -488,7 +550,10 @@ mod tests_safe {
#[test]
fn test_intertwine_read_write() {
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_intertwine_read_write")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
@ -513,12 +578,24 @@ mod tests_safe {
}
{
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
s.put(&mut writer, 1, &Value::Str("goodbye!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("goodbye!"))
.expect("write");
s.put(&mut writer, 3, &Value::Str("goodbye!"))
.expect("write");
assert_eq!(
s.get(&writer, 1).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
writer.commit().expect("committed");
}
@ -532,16 +609,28 @@ mod tests_safe {
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(
s.get(&writer, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&writer, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
writer.commit().expect("committed");
}
{
let reader = k.write().expect("reader");
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
assert_eq!(
s.get(&reader, 2).expect("read"),
Some(Value::Str("goodbye!"))
);
assert_eq!(
s.get(&reader, 3).expect("read"),
Some(Value::Str("goodbye!"))
);
reader.commit().expect("committed");
}
}

@ -11,26 +11,12 @@
use std::marker::PhantomData;
use crate::{
backend::{
BackendDatabase,
BackendIter,
BackendRoCursor,
BackendRwTransaction,
},
backend::{BackendDatabase, BackendIter, BackendRoCursor, BackendRwTransaction},
error::StoreError,
readwrite::{
Readable,
Writer,
},
readwrite::{Readable, Writer},
store::{
keys::{
Key,
PrimitiveInt,
},
multi::{
Iter,
MultiStore,
},
keys::{Key, PrimitiveInt},
multi::{Iter, MultiStore},
},
value::Value,
};
@ -79,7 +65,13 @@ where
self.inner.put(writer, Key::new(&k)?, v)
}
pub fn put_with_flags<T>(&self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
pub fn put_with_flags<T>(
&self,
writer: &mut Writer<T>,
k: K,
v: &Value,
flags: T::Flags,
) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
{
@ -119,22 +111,34 @@ mod tests {
#[test]
fn test_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
macro_rules! test_integer_keys {
($type:ty, $key:expr) => {{
let mut writer = k.write().expect("writer");
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
assert_eq!(s.get_first(&writer, $key).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, $key, &Value::Str("hello!"))
.expect("write");
assert_eq!(
s.get_first(&writer, $key).expect("read"),
Some(Value::Str("hello!"))
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
assert_eq!(s.get_first(&reader, $key).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get_first(&reader, $key).expect("read"),
Some(Value::Str("hello!"))
);
}};
}
@ -144,19 +148,31 @@ mod tests {
#[test]
fn test_clear() {
let root = Builder::new().prefix("test_multi_integer_clear").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_clear")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get_first(&writer, 2).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get_first(&writer, 1).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(
s.get_first(&writer, 2).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
writer.commit().expect("committed");
}
@ -175,18 +191,27 @@ mod tests {
#[test]
fn test_dup() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
assert_eq!(
s.get_first(&writer, 1).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(s.get_first(&writer, 2).expect("read"), None);
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
writer.commit().expect("committed");
@ -206,42 +231,66 @@ mod tests {
#[test]
fn test_dup_2() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
}
#[test]
fn test_del() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
{
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
writer.commit().expect("committed");
@ -249,29 +298,38 @@ mod tests {
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello!")).expect("deleted");
s.delete(&mut writer, 1, &Value::Str("hello!"))
.expect("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello!")).expect_err("deleted");
s.delete(&mut writer, 1, &Value::Str("hello!"))
.expect_err("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect("deleted");
s.delete(&mut writer, 1, &Value::Str("hello1!"))
.expect("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
@ -281,7 +339,8 @@ mod tests {
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect_err("deleted");
s.delete(&mut writer, 1, &Value::Str("hello1!"))
.expect_err("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
@ -292,21 +351,33 @@ mod tests {
#[test]
fn test_persist() {
let root = Builder::new().prefix("test_multi_integer_persist").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_persist")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
{
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
writer.commit().expect("committed");
@ -314,12 +385,20 @@ mod tests {
{
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
}
@ -336,22 +415,34 @@ mod tests_safe {
#[test]
fn test_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
macro_rules! test_integer_keys {
($type:ty, $key:expr) => {{
let mut writer = k.write().expect("writer");
s.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
assert_eq!(s.get_first(&writer, $key).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, $key, &Value::Str("hello!"))
.expect("write");
assert_eq!(
s.get_first(&writer, $key).expect("read"),
Some(Value::Str("hello!"))
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
assert_eq!(s.get_first(&reader, $key).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get_first(&reader, $key).expect("read"),
Some(Value::Str("hello!"))
);
}};
}
@ -361,19 +452,31 @@ mod tests_safe {
#[test]
fn test_clear() {
let root = Builder::new().prefix("test_multi_integer_clear").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_clear")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
assert_eq!(s.get_first(&writer, 2).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
s.get_first(&writer, 1).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(
s.get_first(&writer, 2).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
writer.commit().expect("committed");
}
@ -392,18 +495,27 @@ mod tests_safe {
#[test]
fn test_dup() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
assert_eq!(s.get_first(&writer, 1).expect("read"), Some(Value::Str("hello!")));
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
assert_eq!(
s.get_first(&writer, 1).expect("read"),
Some(Value::Str("hello!"))
);
assert_eq!(s.get_first(&writer, 2).expect("read"), None);
assert_eq!(s.get_first(&writer, 3).expect("read"), None);
writer.commit().expect("committed");
@ -423,42 +535,66 @@ mod tests_safe {
#[test]
fn test_dup_2() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
}
#[test]
fn test_del() {
let root = Builder::new().prefix("test_multi_integer_dup").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_dup")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
{
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
{
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
writer.commit().expect("committed");
@ -466,29 +602,38 @@ mod tests_safe {
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello!")).expect("deleted");
s.delete(&mut writer, 1, &Value::Str("hello!"))
.expect("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello!")).expect_err("deleted");
s.delete(&mut writer, 1, &Value::Str("hello!"))
.expect_err("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect("deleted");
s.delete(&mut writer, 1, &Value::Str("hello1!"))
.expect("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
@ -498,7 +643,8 @@ mod tests_safe {
{
let mut writer = k.write().expect("writer");
s.delete(&mut writer, 1, &Value::Str("hello1!")).expect_err("deleted");
s.delete(&mut writer, 1, &Value::Str("hello1!"))
.expect_err("deleted");
writer.commit().expect("committed");
let reader = k.read().expect("reader");
@ -509,21 +655,33 @@ mod tests_safe {
#[test]
fn test_persist() {
let root = Builder::new().prefix("test_multi_integer_persist").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_multi_integer_persist")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
let mut writer = k.write().expect("writer");
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write");
s.put(&mut writer, 1, &Value::Str("hello1!"))
.expect("write");
s.put(&mut writer, 2, &Value::Str("hello!")).expect("write");
{
let mut iter = s.get(&writer, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
writer.commit().expect("committed");
@ -531,12 +689,20 @@ mod tests_safe {
{
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
let reader = k.read().expect("reader");
let mut iter = s.get(&reader, 1).expect("read");
assert_eq!(iter.next().expect("first").expect("ok").1, Value::Str("hello!"));
assert_eq!(iter.next().expect("second").expect("ok").1, Value::Str("hello1!"));
assert_eq!(
iter.next().expect("first").expect("ok").1,
Value::Str("hello!")
);
assert_eq!(
iter.next().expect("second").expect("ok").1,
Value::Str("hello1!")
);
assert!(iter.next().is_none());
}
}

@ -11,19 +11,10 @@
use std::marker::PhantomData;
use crate::{
backend::{
BackendDatabase,
BackendFlags,
BackendIter,
BackendRoCursor,
BackendRwTransaction,
},
backend::{BackendDatabase, BackendFlags, BackendIter, BackendRoCursor, BackendRwTransaction},
error::StoreError,
helpers::read_transform,
readwrite::{
Readable,
Writer,
},
readwrite::{Readable, Writer},
value::Value,
};
@ -44,9 +35,7 @@ where
D: BackendDatabase,
{
pub(crate) fn new(db: D) -> MultiStore<D> {
MultiStore {
db,
}
MultiStore { db }
}
/// Provides a cursor to all of the values for the duplicate entries that match this
@ -87,7 +76,13 @@ where
writer.put(&self.db, &k, v, T::Flags::empty())
}
pub fn put_with_flags<T, K>(&self, writer: &mut Writer<T>, k: K, v: &Value, flags: T::Flags) -> EmptyResult
pub fn put_with_flags<T, K>(
&self,
writer: &mut Writer<T>,
k: K,
v: &Value,
flags: T::Flags,
) -> EmptyResult
where
T: BackendRwTransaction<Database = D>,
K: AsRef<[u8]>,
@ -128,11 +123,9 @@ where
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(Ok((key, bytes))) => {
match read_transform(Ok(bytes)) {
Ok(val) => Some(Ok((key, val))),
Err(err) => Some(Err(err)),
}
Some(Ok((key, bytes))) => match read_transform(Ok(bytes)) {
Ok(val) => Some(Ok((key, val))),
Err(err) => Some(Err(err)),
},
Some(Err(err)) => Some(Err(err.into())),
}

@ -11,19 +11,10 @@
use std::marker::PhantomData;
use crate::{
backend::{
BackendDatabase,
BackendFlags,
BackendIter,
BackendRoCursor,
BackendRwTransaction,
},
backend::{BackendDatabase, BackendFlags, BackendIter, BackendRoCursor, BackendRwTransaction},
error::StoreError,
helpers::read_transform,
readwrite::{
Readable,
Writer,
},
readwrite::{Readable, Writer},
value::Value,
};
@ -44,9 +35,7 @@ where
D: BackendDatabase,
{
pub(crate) fn new(db: D) -> SingleStore<D> {
SingleStore {
db,
}
SingleStore { db }
}
pub fn get<'r, R, K>(&self, reader: &'r R, k: K) -> Result<Option<Value<'r>>, StoreError>
@ -133,11 +122,9 @@ where
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(Ok((key, bytes))) => {
match read_transform(Ok(bytes)) {
Ok(val) => Some(Ok((key, val))),
Err(err) => Some(Err(err)),
}
Some(Ok((key, bytes))) => match read_transform(Ok(bytes)) {
Ok(val) => Some(Ok((key, val))),
Err(err) => Some(Err(err)),
},
Some(Err(err)) => Some(Err(err.into())),
}

@ -11,16 +11,9 @@
use std::fmt;
use arrayref::array_ref;
use bincode::{
deserialize,
serialize,
serialized_size,
};
use bincode::{deserialize, serialize, serialized_size};
use ordered_float::OrderedFloat;
use uuid::{
Bytes,
Uuid,
};
use uuid::{Bytes, Uuid};
use crate::error::DataError;
@ -128,11 +121,9 @@ impl<'v> Value<'v> {
fn from_type_and_data(t: Type, data: &'v [u8]) -> Result<Value<'v>, DataError> {
if t == Type::Uuid {
return deserialize(data)
.map_err(|e| {
DataError::DecodingError {
value_type: t,
err: e,
}
.map_err(|e| DataError::DecodingError {
value_type: t,
err: e,
})
.map(uuid)?;
}
@ -149,13 +140,11 @@ impl<'v> Value<'v> {
Type::Uuid => {
// Processed above to avoid verbose duplication of error transforms.
unreachable!()
},
}
.map_err(|e| {
DataError::DecodingError {
value_type: t,
err: e,
}
}
.map_err(|e| DataError::DecodingError {
value_type: t,
err: e,
})
}
@ -240,8 +229,14 @@ mod tests {
assert_eq!(Value::I64(-1000).serialized_size().unwrap(), 9);
assert_eq!(Value::U64(1000u64).serialized_size().unwrap(), 9);
assert_eq!(Value::Bool(true).serialized_size().unwrap(), 2);
assert_eq!(Value::Instant(1_558_020_865_224).serialized_size().unwrap(), 9);
assert_eq!(Value::F64(OrderedFloat(10000.1)).serialized_size().unwrap(), 9);
assert_eq!(
Value::Instant(1_558_020_865_224).serialized_size().unwrap(),
9
);
assert_eq!(
Value::F64(OrderedFloat(10000.1)).serialized_size().unwrap(),
9
);
assert_eq!(Value::Str("hello!").serialized_size().unwrap(), 15);
assert_eq!(Value::Str("¡Hola").serialized_size().unwrap(), 15);
assert_eq!(Value::Blob(b"hello!").serialized_size().unwrap(), 15);

@ -13,18 +13,16 @@ use std::fs;
use tempfile::Builder;
use rkv::{
backend::{
Lmdb,
SafeMode,
},
Rkv,
StoreOptions,
Value,
backend::{Lmdb, SafeMode},
Rkv, StoreOptions, Value,
};
#[test]
fn test_open_safe_same_dir_as_lmdb() {
let root = Builder::new().prefix("test_open_safe_same_dir_as_lmdb").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_open_safe_same_dir_as_lmdb")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Create database of type A and save to disk.
@ -33,39 +31,75 @@ fn test_open_safe_same_dir_as_lmdb() {
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
sk.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
assert_eq!(sk.get(&writer, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&writer, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&writer, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
sk.put(&mut writer, "foo", &Value::I64(1234))
.expect("wrote");
sk.put(&mut writer, "bar", &Value::Bool(true))
.expect("wrote");
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
.expect("wrote");
assert_eq!(
sk.get(&writer, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&writer, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&writer, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
writer.commit().expect("committed");
k.sync(true).expect("synced");
}
// Verify that database of type A was written to disk.
{
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Create database of type B and verify that it is empty.
{
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let _ = k.open_single("sk", StoreOptions::default()).expect_err("not opened");
let _ = k
.open_single("sk", StoreOptions::default())
.expect_err("not opened");
}
// Verify that database of type A wasn't changed.
{
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Create database of type B and save to disk (type A exists at the same path).
{
@ -73,40 +107,77 @@ fn test_open_safe_same_dir_as_lmdb() {
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "foo1", &Value::I64(5678)).expect("wrote");
sk.put(&mut writer, "bar1", &Value::Bool(false)).expect("wrote");
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu")).expect("wrote");
assert_eq!(sk.get(&writer, "foo1").expect("read"), Some(Value::I64(5678)));
assert_eq!(sk.get(&writer, "bar1").expect("read"), Some(Value::Bool(false)));
assert_eq!(sk.get(&writer, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
sk.put(&mut writer, "foo1", &Value::I64(5678))
.expect("wrote");
sk.put(&mut writer, "bar1", &Value::Bool(false))
.expect("wrote");
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu"))
.expect("wrote");
assert_eq!(
sk.get(&writer, "foo1").expect("read"),
Some(Value::I64(5678))
);
assert_eq!(
sk.get(&writer, "bar1").expect("read"),
Some(Value::Bool(false))
);
assert_eq!(
sk.get(&writer, "baz1").expect("read"),
Some(Value::Str("héllo~ yöu"))
);
writer.commit().expect("committed");
k.sync(true).expect("synced");
}
// Verify that database of type B was written to disk.
{
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo1").expect("read"), Some(Value::I64(5678)));
assert_eq!(sk.get(&reader, "bar1").expect("read"), Some(Value::Bool(false)));
assert_eq!(sk.get(&reader, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
assert_eq!(
sk.get(&reader, "foo1").expect("read"),
Some(Value::I64(5678))
);
assert_eq!(
sk.get(&reader, "bar1").expect("read"),
Some(Value::Bool(false))
);
assert_eq!(
sk.get(&reader, "baz1").expect("read"),
Some(Value::Str("héllo~ yöu"))
);
}
// Verify that database of type A still wasn't changed.
{
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
}
#[test]
fn test_open_lmdb_same_dir_as_safe() {
let root = Builder::new().prefix("test_open_lmdb_same_dir_as_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_open_lmdb_same_dir_as_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Create database of type A and save to disk.
@ -115,39 +186,75 @@ fn test_open_lmdb_same_dir_as_safe() {
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
sk.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
assert_eq!(sk.get(&writer, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&writer, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&writer, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
sk.put(&mut writer, "foo", &Value::I64(1234))
.expect("wrote");
sk.put(&mut writer, "bar", &Value::Bool(true))
.expect("wrote");
sk.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
.expect("wrote");
assert_eq!(
sk.get(&writer, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&writer, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&writer, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
writer.commit().expect("committed");
k.sync(true).expect("synced");
}
// Verify that database of type A was written to disk.
{
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Create database of type B and verify that it is empty.
{
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let _ = k.open_single("sk", StoreOptions::default()).expect_err("not opened");
let _ = k
.open_single("sk", StoreOptions::default())
.expect_err("not opened");
}
// Verify that database of type A wasn't changed.
{
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Create database of type B and save to disk (type A exists at the same path).
{
@ -155,33 +262,67 @@ fn test_open_lmdb_same_dir_as_safe() {
let sk = k.open_single("sk", StoreOptions::create()).expect("opened");
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "foo1", &Value::I64(5678)).expect("wrote");
sk.put(&mut writer, "bar1", &Value::Bool(false)).expect("wrote");
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu")).expect("wrote");
assert_eq!(sk.get(&writer, "foo1").expect("read"), Some(Value::I64(5678)));
assert_eq!(sk.get(&writer, "bar1").expect("read"), Some(Value::Bool(false)));
assert_eq!(sk.get(&writer, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
sk.put(&mut writer, "foo1", &Value::I64(5678))
.expect("wrote");
sk.put(&mut writer, "bar1", &Value::Bool(false))
.expect("wrote");
sk.put(&mut writer, "baz1", &Value::Str("héllo~ yöu"))
.expect("wrote");
assert_eq!(
sk.get(&writer, "foo1").expect("read"),
Some(Value::I64(5678))
);
assert_eq!(
sk.get(&writer, "bar1").expect("read"),
Some(Value::Bool(false))
);
assert_eq!(
sk.get(&writer, "baz1").expect("read"),
Some(Value::Str("héllo~ yöu"))
);
writer.commit().expect("committed");
k.sync(true).expect("synced");
}
// Verify that database of type B was written to disk.
{
let k = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo1").expect("read"), Some(Value::I64(5678)));
assert_eq!(sk.get(&reader, "bar1").expect("read"), Some(Value::Bool(false)));
assert_eq!(sk.get(&reader, "baz1").expect("read"), Some(Value::Str("héllo~ yöu")));
assert_eq!(
sk.get(&reader, "foo1").expect("read"),
Some(Value::I64(5678))
);
assert_eq!(
sk.get(&reader, "bar1").expect("read"),
Some(Value::Bool(false))
);
assert_eq!(
sk.get(&reader, "baz1").expect("read"),
Some(Value::Str("héllo~ yöu"))
);
}
// Verify that database of type A still wasn't changed.
{
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let sk = k.open_single("sk", StoreOptions::default()).expect("opened");
let sk = k
.open_single("sk", StoreOptions::default())
.expect("opened");
let reader = k.read().expect("reader");
assert_eq!(sk.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(sk.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(sk.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
sk.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
sk.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
sk.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
}

File diff suppressed because it is too large Load Diff

@ -8,41 +8,40 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
fs,
path::Path,
};
use std::{fs, path::Path};
use tempfile::Builder;
use rkv::{
backend::{
Lmdb,
LmdbEnvironment,
SafeMode,
SafeModeEnvironment,
},
Manager,
Migrator,
Rkv,
StoreOptions,
Value,
backend::{Lmdb, LmdbEnvironment, SafeMode, SafeModeEnvironment},
Manager, Migrator, Rkv, StoreOptions, Value,
};
macro_rules! populate_store {
($env:expr) => {
let store = $env.open_single("store", StoreOptions::create()).expect("opened");
let store = $env
.open_single("store", StoreOptions::create())
.expect("opened");
let mut writer = $env.write().expect("writer");
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
store
.put(&mut writer, "foo", &Value::I64(1234))
.expect("wrote");
store
.put(&mut writer, "bar", &Value::Bool(true))
.expect("wrote");
store
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
.expect("wrote");
writer.commit().expect("committed");
};
}
#[test]
fn test_open_migrator_lmdb_to_safe() {
let root = Builder::new().prefix("test_open_migrator_lmdb_to_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_open_migrator_lmdb_to_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Populate source environment and persist to disk.
@ -63,25 +62,48 @@ fn test_open_migrator_lmdb_to_safe() {
// Verify that database was written to disk.
{
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let store = src_env.open_single("store", StoreOptions::default()).expect("opened");
let store = src_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = src_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Open and migrate.
{
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env).expect("migrated");
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
.expect("migrated");
}
// Verify that the database was indeed migrated.
{
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
let store = dst_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = dst_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Check if the old files were deleted from disk.
{
@ -96,7 +118,10 @@ fn test_open_migrator_lmdb_to_safe() {
#[test]
fn test_open_migrator_safe_to_lmdb() {
let root = Builder::new().prefix("test_open_migrator_safe_to_lmdb").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_open_migrator_safe_to_lmdb")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Populate source environment and persist to disk.
@ -114,25 +139,48 @@ fn test_open_migrator_safe_to_lmdb() {
// Verify that database was written to disk.
{
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let store = src_env.open_single("store", StoreOptions::default()).expect("opened");
let store = src_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = src_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Open and migrate.
{
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env).expect("migrated");
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
.expect("migrated");
}
// Verify that the database was indeed migrated.
{
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
let store = dst_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = dst_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Check if the old files were deleted from disk.
{
@ -144,7 +192,10 @@ fn test_open_migrator_safe_to_lmdb() {
#[test]
fn test_open_migrator_round_trip() {
let root = Builder::new().prefix("test_open_migrator_lmdb_to_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_open_migrator_lmdb_to_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Populate source environment and persist to disk.
@ -156,21 +207,34 @@ fn test_open_migrator_round_trip() {
// Open and migrate.
{
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env).expect("migrated");
Migrator::open_and_migrate_lmdb_to_safe_mode(root.path(), |builder| builder, &dst_env)
.expect("migrated");
}
// Open and migrate back.
{
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env).expect("migrated");
Migrator::open_and_migrate_safe_mode_to_lmdb(root.path(), |builder| builder, &dst_env)
.expect("migrated");
}
// Verify that the database was indeed migrated twice.
{
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
let store = dst_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = dst_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
// Check if the right files are finally present on disk.
{
@ -188,7 +252,10 @@ fn test_open_migrator_round_trip() {
#[test]
fn test_easy_migrator_no_dir_1() {
let root = Builder::new().prefix("test_easy_migrator_no_dir").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_no_dir")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// This won't fail with IoError even though the path is a bogus path, because this
@ -209,7 +276,10 @@ fn test_easy_migrator_no_dir_1() {
#[test]
fn test_easy_migrator_no_dir_2() {
let root = Builder::new().prefix("test_easy_migrator_no_dir").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_no_dir")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// This won't fail with IoError even though the path is a bogus path, because this
@ -230,7 +300,10 @@ fn test_easy_migrator_no_dir_2() {
#[test]
fn test_easy_migrator_invalid_1() {
let root = Builder::new().prefix("test_easy_migrator_invalid").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_invalid")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let dbfile = root.path().join("data.mdb");
@ -254,7 +327,10 @@ fn test_easy_migrator_invalid_1() {
#[test]
fn test_easy_migrator_invalid_2() {
let root = Builder::new().prefix("test_easy_migrator_invalid").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_invalid")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let dbfile = root.path().join("data.safe.bin");
@ -279,7 +355,10 @@ fn test_easy_migrator_invalid_2() {
#[test]
#[should_panic(expected = "migrated: SourceEmpty")]
fn test_migrator_lmdb_to_safe_1() {
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_lmdb_to_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
@ -290,7 +369,10 @@ fn test_migrator_lmdb_to_safe_1() {
#[test]
#[should_panic(expected = "migrated: DestinationNotEmpty")]
fn test_migrator_lmdb_to_safe_2() {
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_lmdb_to_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
@ -302,7 +384,10 @@ fn test_migrator_lmdb_to_safe_2() {
#[test]
fn test_migrator_lmdb_to_safe_3() {
let root = Builder::new().prefix("test_migrate_lmdb_to_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_lmdb_to_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
@ -310,17 +395,31 @@ fn test_migrator_lmdb_to_safe_3() {
let dst_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
Migrator::migrate_lmdb_to_safe_mode(&src_env, &dst_env).expect("migrated");
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
let store = dst_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = dst_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
#[test]
#[should_panic(expected = "migrated: SourceEmpty")]
fn test_migrator_safe_to_lmdb_1() {
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_safe_to_lmdb")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
@ -331,7 +430,10 @@ fn test_migrator_safe_to_lmdb_1() {
#[test]
#[should_panic(expected = "migrated: DestinationNotEmpty")]
fn test_migrator_safe_to_lmdb_2() {
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_safe_to_lmdb")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
@ -343,7 +445,10 @@ fn test_migrator_safe_to_lmdb_2() {
#[test]
fn test_migrator_safe_to_lmdb_3() {
let root = Builder::new().prefix("test_migrate_safe_to_lmdb").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_migrate_safe_to_lmdb")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let src_env = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
@ -351,16 +456,30 @@ fn test_migrator_safe_to_lmdb_3() {
let dst_env = Rkv::new::<Lmdb>(root.path()).expect("new succeeded");
Migrator::migrate_safe_mode_to_lmdb(&src_env, &dst_env).expect("migrated");
let store = dst_env.open_single("store", StoreOptions::default()).expect("opened");
let store = dst_env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = dst_env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
}
#[test]
fn test_easy_migrator_failed_migration_1() {
let root = Builder::new().prefix("test_easy_migrator_failed_migration_1").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_failed_migration_1")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let dbfile = root.path().join("data.mdb");
@ -387,7 +506,10 @@ fn test_easy_migrator_failed_migration_1() {
#[test]
fn test_easy_migrator_failed_migration_2() {
let root = Builder::new().prefix("test_easy_migrator_failed_migration_2").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_failed_migration_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let dbfile = root.path().join("data.safe.bin");
@ -413,19 +535,26 @@ fn test_easy_migrator_failed_migration_2() {
}
fn test_easy_migrator_from_manager_failed_migration_1() {
let root = Builder::new().prefix("test_easy_migrator_from_manager_failed_migration_1").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_from_manager_failed_migration_1")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
let mut src_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
let created_src_arc = src_manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
let created_src_arc = src_manager
.get_or_create(root.path(), Rkv::new::<Lmdb>)
.unwrap();
let src_env = created_src_arc.read().unwrap();
populate_store!(&src_env);
src_env.sync(true).expect("synced");
}
{
let mut dst_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
let created_dst_arc_1 = dst_manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
let created_dst_arc_1 = dst_manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.unwrap();
let dst_env_1 = created_dst_arc_1.read().unwrap();
populate_store!(&dst_env_1);
dst_env_1.sync(true).expect("synced");
@ -439,19 +568,26 @@ fn test_easy_migrator_from_manager_failed_migration_1() {
}
fn test_easy_migrator_from_manager_failed_migration_2() {
let root = Builder::new().prefix("test_easy_migrator_from_manager_failed_migration_2").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_easy_migrator_from_manager_failed_migration_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
{
let mut src_manager = Manager::<SafeModeEnvironment>::singleton().write().unwrap();
let created_src_arc = src_manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
let created_src_arc = src_manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.unwrap();
let src_env = created_src_arc.read().unwrap();
populate_store!(&src_env);
src_env.sync(true).expect("synced");
}
{
let mut dst_manager = Manager::<LmdbEnvironment>::singleton().write().unwrap();
let created_dst_arc_1 = dst_manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
let created_dst_arc_1 = dst_manager
.get_or_create(root.path(), Rkv::new::<Lmdb>)
.unwrap();
let dst_env_1 = created_dst_arc_1.read().unwrap();
populate_store!(&dst_env_1);
dst_env_1.sync(true).expect("synced");

File diff suppressed because it is too large Load Diff

@ -15,17 +15,14 @@ use std::fs;
use serde_derive::Serialize;
use tempfile::Builder;
use rkv::{
backend::SafeMode,
PrimitiveInt,
Rkv,
StoreOptions,
Value,
};
use rkv::{backend::SafeMode, PrimitiveInt, Rkv, StoreOptions, Value};
#[test]
fn test_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
@ -35,12 +32,20 @@ fn test_integer_keys() {
($store:expr, $key:expr) => {{
let mut writer = k.write().expect("writer");
$store.put(&mut writer, $key, &Value::Str("hello!")).expect("write");
assert_eq!($store.get(&writer, $key).expect("read"), Some(Value::Str("hello!")));
$store
.put(&mut writer, $key, &Value::Str("hello!"))
.expect("write");
assert_eq!(
$store.get(&writer, $key).expect("read"),
Some(Value::Str("hello!"))
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
assert_eq!($store.get(&reader, $key).expect("read"), Some(Value::Str("hello!")));
assert_eq!(
$store.get(&reader, $key).expect("read"),
Some(Value::Str("hello!"))
);
}};
}

@ -8,28 +8,15 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
use std::{
fs,
sync::Arc,
};
use std::{fs, sync::Arc};
use tempfile::Builder;
#[cfg(feature = "lmdb")]
use rkv::backend::{
Lmdb,
LmdbEnvironment,
};
use rkv::backend::{Lmdb, LmdbEnvironment};
use rkv::{
backend::{
BackendEnvironmentBuilder,
SafeMode,
SafeModeEnvironment,
},
CloseOptions,
Rkv,
StoreOptions,
Value,
backend::{BackendEnvironmentBuilder, SafeMode, SafeModeEnvironment},
CloseOptions, Rkv, StoreOptions, Value,
};
/// Test that a manager can be created with simple type inference.
@ -57,11 +44,16 @@ fn test_simple_safe() {
fn test_simple_2() {
type Manager = rkv::Manager<LmdbEnvironment>;
let root = Builder::new().prefix("test_simple_2").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_simple_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let mut manager = Manager::singleton().write().unwrap();
let _ = manager.get_or_create(root.path(), Rkv::new::<Lmdb>).unwrap();
let _ = manager
.get_or_create(root.path(), Rkv::new::<Lmdb>)
.unwrap();
}
/// Test that a shared Rkv instance can be created with simple type inference.
@ -69,11 +61,16 @@ fn test_simple_2() {
fn test_simple_safe_2() {
type Manager = rkv::Manager<SafeModeEnvironment>;
let root = Builder::new().prefix("test_simple_safe_2").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_simple_safe_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let mut manager = Manager::singleton().write().unwrap();
let _ = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).unwrap();
let _ = manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.unwrap();
}
/// Test that the manager will return the same Rkv instance each time for each path.
@ -82,14 +79,31 @@ fn test_simple_safe_2() {
fn test_same() {
type Manager = rkv::Manager<LmdbEnvironment>;
let root = Builder::new().prefix("test_same").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_same")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let p = root.path();
assert!(Manager::singleton().read().unwrap().get(p).expect("success").is_none());
let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new::<Lmdb>).expect("created");
let fetched_arc = Manager::singleton().read().unwrap().get(p).expect("success").expect("existed");
assert!(Manager::singleton()
.read()
.unwrap()
.get(p)
.expect("success")
.is_none());
let created_arc = Manager::singleton()
.write()
.unwrap()
.get_or_create(p, Rkv::new::<Lmdb>)
.expect("created");
let fetched_arc = Manager::singleton()
.read()
.unwrap()
.get(p)
.expect("success")
.expect("existed");
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
}
@ -98,14 +112,31 @@ fn test_same() {
fn test_same_safe() {
type Manager = rkv::Manager<SafeModeEnvironment>;
let root = Builder::new().prefix("test_same_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_same_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let p = root.path();
assert!(Manager::singleton().read().unwrap().get(p).expect("success").is_none());
let created_arc = Manager::singleton().write().unwrap().get_or_create(p, Rkv::new::<SafeMode>).expect("created");
let fetched_arc = Manager::singleton().read().unwrap().get(p).expect("success").expect("existed");
assert!(Manager::singleton()
.read()
.unwrap()
.get(p)
.expect("success")
.is_none());
let created_arc = Manager::singleton()
.write()
.unwrap()
.get_or_create(p, Rkv::new::<SafeMode>)
.expect("created");
let fetched_arc = Manager::singleton()
.read()
.unwrap()
.get(p)
.expect("success")
.expect("existed");
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
}
@ -115,7 +146,10 @@ fn test_same_safe() {
fn test_same_with_capacity() {
type Manager = rkv::Manager<LmdbEnvironment>;
let root = Builder::new().prefix("test_same_with_capacity").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_same_with_capacity")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let mut manager = Manager::singleton().write().unwrap();
@ -123,7 +157,9 @@ fn test_same_with_capacity() {
let p = root.path();
assert!(manager.get(p).expect("success").is_none());
let created_arc = manager.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<Lmdb>).expect("created");
let created_arc = manager
.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<Lmdb>)
.expect("created");
let fetched_arc = manager.get(p).expect("success").expect("existed");
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
}
@ -133,7 +169,10 @@ fn test_same_with_capacity() {
fn test_same_with_capacity_safe() {
type Manager = rkv::Manager<SafeModeEnvironment>;
let root = Builder::new().prefix("test_same_with_capacity_safe").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_same_with_capacity_safe")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let mut manager = Manager::singleton().write().unwrap();
@ -141,7 +180,9 @@ fn test_same_with_capacity_safe() {
let p = root.path();
assert!(manager.get(p).expect("success").is_none());
let created_arc = manager.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<SafeMode>).expect("created");
let created_arc = manager
.get_or_create_with_capacity(p, 10, Rkv::with_capacity::<SafeMode>)
.expect("created");
let fetched_arc = manager.get(p).expect("success").expect("existed");
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
}
@ -152,20 +193,33 @@ fn test_same_with_capacity_safe() {
fn test_safe_mode_corrupt_while_open_1() {
type Manager = rkv::Manager<SafeModeEnvironment>;
let root = Builder::new().prefix("test_safe_mode_corrupt_while_open_1").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_safe_mode_corrupt_while_open_1")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Create environment.
let mut manager = Manager::singleton().write().unwrap();
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
let shared_env = manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.expect("created");
let env = shared_env.read().unwrap();
// Write some data.
let store = env.open_single("store", StoreOptions::create()).expect("opened");
let store = env
.open_single("store", StoreOptions::create())
.expect("opened");
let mut writer = env.write().expect("writer");
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
store
.put(&mut writer, "foo", &Value::I64(1234))
.expect("wrote");
store
.put(&mut writer, "bar", &Value::Bool(true))
.expect("wrote");
store
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
.expect("wrote");
writer.commit().expect("committed");
env.sync(true).expect("synced");
@ -180,17 +234,23 @@ fn test_safe_mode_corrupt_while_open_1() {
// Close everything.
drop(env);
drop(shared_env);
manager.try_close(root.path(), CloseOptions::default()).expect("closed without deleting");
manager
.try_close(root.path(), CloseOptions::default())
.expect("closed without deleting");
assert!(manager.get(root.path()).expect("success").is_none());
// Recreating environment fails.
manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect_err("not created");
manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.expect_err("not created");
assert!(manager.get(root.path()).expect("success").is_none());
// But we can use a builder and pass `discard_if_corrupted` to deal with it.
let mut builder = Rkv::environment_builder::<SafeMode>();
builder.set_discard_if_corrupted(true);
manager.get_or_create_from_builder(root.path(), builder, Rkv::from_builder::<SafeMode>).expect("created");
manager
.get_or_create_from_builder(root.path(), builder, Rkv::from_builder::<SafeMode>)
.expect("created");
assert!(manager.get(root.path()).expect("success").is_some());
}
@ -200,20 +260,33 @@ fn test_safe_mode_corrupt_while_open_1() {
fn test_safe_mode_corrupt_while_open_2() {
type Manager = rkv::Manager<SafeModeEnvironment>;
let root = Builder::new().prefix("test_safe_mode_corrupt_while_open_2").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_safe_mode_corrupt_while_open_2")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
// Create environment.
let mut manager = Manager::singleton().write().unwrap();
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
let shared_env = manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.expect("created");
let env = shared_env.read().unwrap();
// Write some data.
let store = env.open_single("store", StoreOptions::create()).expect("opened");
let store = env
.open_single("store", StoreOptions::create())
.expect("opened");
let mut writer = env.write().expect("writer");
store.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote");
store.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote");
store.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote");
store
.put(&mut writer, "foo", &Value::I64(1234))
.expect("wrote");
store
.put(&mut writer, "bar", &Value::Bool(true))
.expect("wrote");
store
.put(&mut writer, "baz", &Value::Str("héllo, yöu"))
.expect("wrote");
writer.commit().expect("committed");
env.sync(true).expect("synced");
@ -226,39 +299,82 @@ fn test_safe_mode_corrupt_while_open_2() {
fs::write(&safebin, "bogus").expect("dbfile corrupted");
// Reading still works. Magic.
let store = env.open_single("store", StoreOptions::default()).expect("opened");
let store = env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
reader.abort();
// Writing still works, dbfile will be un-corrupted.
let store = env.open_single("store", StoreOptions::default()).expect("opened");
let store = env
.open_single("store", StoreOptions::default())
.expect("opened");
let mut writer = env.write().expect("writer");
store.put(&mut writer, "foo2", &Value::I64(5678)).expect("wrote");
store.put(&mut writer, "bar2", &Value::Bool(false)).expect("wrote");
store.put(&mut writer, "baz2", &Value::Str("byé, yöu")).expect("wrote");
store
.put(&mut writer, "foo2", &Value::I64(5678))
.expect("wrote");
store
.put(&mut writer, "bar2", &Value::Bool(false))
.expect("wrote");
store
.put(&mut writer, "baz2", &Value::Str("byé, yöu"))
.expect("wrote");
writer.commit().expect("committed");
env.sync(true).expect("synced");
// Close everything.
drop(env);
drop(shared_env);
manager.try_close(root.path(), CloseOptions::default()).expect("closed without deleting");
manager
.try_close(root.path(), CloseOptions::default())
.expect("closed without deleting");
assert!(manager.get(root.path()).expect("success").is_none());
// Recreate environment.
let shared_env = manager.get_or_create(root.path(), Rkv::new::<SafeMode>).expect("created");
let shared_env = manager
.get_or_create(root.path(), Rkv::new::<SafeMode>)
.expect("created");
let env = shared_env.read().unwrap();
// Verify that the dbfile is not corrupted.
let store = env.open_single("store", StoreOptions::default()).expect("opened");
let store = env
.open_single("store", StoreOptions::default())
.expect("opened");
let reader = env.read().expect("reader");
assert_eq!(store.get(&reader, "foo").expect("read"), Some(Value::I64(1234)));
assert_eq!(store.get(&reader, "bar").expect("read"), Some(Value::Bool(true)));
assert_eq!(store.get(&reader, "baz").expect("read"), Some(Value::Str("héllo, yöu")));
assert_eq!(store.get(&reader, "foo2").expect("read"), Some(Value::I64(5678)));
assert_eq!(store.get(&reader, "bar2").expect("read"), Some(Value::Bool(false)));
assert_eq!(store.get(&reader, "baz2").expect("read"), Some(Value::Str("byé, yöu")));
assert_eq!(
store.get(&reader, "foo").expect("read"),
Some(Value::I64(1234))
);
assert_eq!(
store.get(&reader, "bar").expect("read"),
Some(Value::Bool(true))
);
assert_eq!(
store.get(&reader, "baz").expect("read"),
Some(Value::Str("héllo, yöu"))
);
assert_eq!(
store.get(&reader, "foo2").expect("read"),
Some(Value::I64(5678))
);
assert_eq!(
store.get(&reader, "bar2").expect("read"),
Some(Value::Bool(false))
);
assert_eq!(
store.get(&reader, "baz2").expect("read"),
Some(Value::Str("byé, yöu"))
);
}

@ -15,36 +15,48 @@ use std::fs;
use serde_derive::Serialize;
use tempfile::Builder;
use rkv::{
backend::SafeMode,
PrimitiveInt,
Rkv,
StoreOptions,
Value,
};
use rkv::{backend::SafeMode, PrimitiveInt, Rkv, StoreOptions, Value};
#[test]
fn test_multi_integer_keys() {
let root = Builder::new().prefix("test_integer_keys").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_integer_keys")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let s = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let s = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
macro_rules! test_integer_keys {
($store:expr, $key:expr) => {{
let mut writer = k.write().expect("writer");
$store.put(&mut writer, $key, &Value::Str("hello1")).expect("write");
$store.put(&mut writer, $key, &Value::Str("hello2")).expect("write");
$store.put(&mut writer, $key, &Value::Str("hello3")).expect("write");
$store
.put(&mut writer, $key, &Value::Str("hello1"))
.expect("write");
$store
.put(&mut writer, $key, &Value::Str("hello2"))
.expect("write");
$store
.put(&mut writer, $key, &Value::Str("hello3"))
.expect("write");
let vals = $store
.get(&writer, $key)
.expect("read")
.map(|result| result.expect("ok"))
.map(|(_, v)| v)
.collect::<Vec<Value>>();
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
assert_eq!(
vals,
vec![
Value::Str("hello1"),
Value::Str("hello2"),
Value::Str("hello3")
]
);
writer.commit().expect("committed");
let reader = k.read().expect("reader");
@ -54,7 +66,14 @@ fn test_multi_integer_keys() {
.map(|result| result.expect("ok"))
.map(|(_, v)| v)
.collect::<Vec<Value>>();
assert_eq!(vals, vec![Value::Str("hello1"), Value::Str("hello2"), Value::Str("hello3")]);
assert_eq!(
vals,
vec![
Value::Str("hello1"),
Value::Str("hello2"),
Value::Str("hello3")
]
);
}};
}
@ -71,7 +90,9 @@ fn test_multi_integer_keys() {
// different integer key types, which may result in unexpected behavior.
// Make sure you know what you're doing!
let t = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let t = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
#[derive(Serialize)]
struct I32(i32);
@ -79,7 +100,9 @@ fn test_multi_integer_keys() {
test_integer_keys!(t, I32(std::i32::MIN));
test_integer_keys!(t, I32(std::i32::MAX));
let u = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let u = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
#[derive(Serialize)]
struct U16(u16);
@ -87,7 +110,9 @@ fn test_multi_integer_keys() {
test_integer_keys!(u, U16(std::u16::MIN));
test_integer_keys!(u, U16(std::u16::MAX));
let v = k.open_multi_integer("s", StoreOptions::create()).expect("open");
let v = k
.open_multi_integer("s", StoreOptions::create())
.expect("open");
#[derive(Serialize)]
struct U64(u64);

@ -14,17 +14,8 @@ use std::fs;
use tempfile::Builder;
use rkv::{
backend::{
SafeMode,
SafeModeDatabase,
SafeModeRoCursor,
SafeModeRwTransaction,
},
Readable,
Rkv,
StoreOptions,
Value,
Writer,
backend::{SafeMode, SafeModeDatabase, SafeModeRoCursor, SafeModeRwTransaction},
Readable, Rkv, StoreOptions, Value, Writer,
};
/// Consider a struct like this:
@ -46,7 +37,10 @@ type MultiStore = rkv::MultiStore<SafeModeDatabase>;
#[test]
fn read_many() {
let root = Builder::new().prefix("test_txns").tempdir().expect("tempdir");
let root = Builder::new()
.prefix("test_txns")
.tempdir()
.expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");
let k = Rkv::new::<SafeMode>(root.path()).expect("new succeeded");
let samplestore = k.open_single("s", StoreOptions::create()).expect("open");
@ -97,11 +91,9 @@ where
store
.get(txn, field)
.expect("get iterator")
.map(|id| {
match id.expect("field") {
(_, Value::U64(id)) => id,
_ => panic!("getting value in iter"),
}
.map(|id| match id.expect("field") {
(_, Value::U64(id)) => id,
_ => panic!("getting value in iter"),
})
.collect::<Vec<u64>>()
}
@ -122,9 +114,16 @@ where
.collect::<Vec<String>>()
}
fn put_sample(txn: &mut Writer<SafeModeRwTransaction>, samplestore: SingleStore, id: u64, value: &str) {
fn put_sample(
txn: &mut Writer<SafeModeRwTransaction>,
samplestore: SingleStore,
id: u64,
value: &str,
) {
let idbytes = id.to_be_bytes();
samplestore.put(txn, &idbytes, &Value::Str(value)).expect("put id");
samplestore
.put(txn, &idbytes, &Value::Str(value))
.expect("put id");
}
fn put_id_field(txn: &mut Writer<SafeModeRwTransaction>, store: MultiStore, field: &str, id: u64) {

Loading…
Cancel
Save