Merge pull request #10 from mykmelez/merge-danburkert-master

merge danburkert/master
without.crypto
Myk Melez 6 years ago committed by GitHub
commit 6c975fa87a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      .appveyor.yml
  2. 2
      lmdb-sys/Cargo.toml
  3. 17
      lmdb-sys/build.rs
  4. 102
      src/cursor.rs
  5. 6
      src/environment.rs

@ -2,26 +2,22 @@ environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
- TARGET: i686-pc-windows-msvc
# Temporarily disable MinGW builds due to https://github.com/rust-lang/rust/issues/47048.
# Once that issue is fixed, presumably by https://github.com/rust-lang/rust/pull/51989,
# we should reenable them.
# - TARGET: x86_64-pc-windows-gnu
# MSYS_BITS: 64
# - TARGET: i686-pc-windows-gnu
# MSYS_BITS: 32
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- set PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin
- rustc -V
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -Vv
- cargo -V
build_script:
- git submodule -q update --init
- cargo build --target %TARGET% --all -v
test_script:
- SET RUST_BACKTRACE=1
- cargo test --target %TARGET% --all -v
- cargo test --release --target %TARGET% --all -v
cache:
- C:\Users\appveyor\.cargo\registry
- target

@ -19,5 +19,5 @@ build = "build.rs"
libc = "0.2"
[build-dependencies]
pkg-config = "0.3"
pkg-config = "0.3.2"
cc = "1"

@ -11,11 +11,16 @@ fn main() {
lmdb.push("liblmdb");
if !pkg_config::find_library("liblmdb").is_ok() {
cc::Build::new()
.file(lmdb.join("mdb.c"))
.file(lmdb.join("midl.c"))
// https://github.com/LMDB/lmdb/blob/LMDB_0.9.21/libraries/liblmdb/Makefile#L25
.opt_level(2)
.compile("liblmdb.a")
let target = env::var("TARGET").expect("No TARGET found");
let mut build = cc::Build::new();
if target.contains("android") {
build.define("ANDROID", "1");
}
build
.file(lmdb.join("mdb.c"))
.file(lmdb.join("midl.c"))
// https://github.com/LMDB/lmdb/blob/LMDB_0.9.21/libraries/liblmdb/Makefile#L25
.opt_level(2)
.compile("liblmdb.a")
}
}

@ -1,6 +1,7 @@
use libc::{c_void, size_t, c_uint};
use std::{fmt, ptr, result, slice};
use std::marker::PhantomData;
use std::{fmt, mem, ptr, result, slice};
use libc::{EINVAL, c_void, size_t, c_uint};
use database::Database;
use error::{Error, Result, lmdb_result};
@ -19,11 +20,7 @@ pub trait Cursor<'txn> {
/// Retrieves a key/data pair from the cursor. Depending on the cursor op,
/// the current key may be returned.
fn get(&self,
key: Option<&[u8]>,
data: Option<&[u8]>,
op: c_uint)
-> Result<(Option<&'txn [u8]>, &'txn [u8])> {
fn get(&self, key: Option<&[u8]>, data: Option<&[u8]>, op: c_uint) -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
unsafe {
let mut key_val = slice_to_val(key);
let mut data_val = slice_to_val(data);
@ -52,8 +49,7 @@ pub trait Cursor<'txn> {
/// duplicate data items of each key will be returned before moving on to
/// the next key.
fn iter_start(&mut self) -> Iter<'txn> {
self.get(None, None, ffi::MDB_FIRST).unwrap();
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
}
/// Iterate over database items starting from the given key.
@ -63,10 +59,9 @@ pub trait Cursor<'txn> {
/// the next key.
fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
Err(Error::NotFound) => Ok(()),
Err(error) => Err(error),
Ok(_) => Ok(()),
}.unwrap();
Ok(_) | Err(Error::NotFound) => (),
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
};
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
}
@ -80,27 +75,26 @@ pub trait Cursor<'txn> {
/// Iterate over duplicate database items starting from the beginning of the
/// database. Each item will be returned as an iterator of its duplicates.
fn iter_dup_start(&mut self) -> IterDup<'txn> {
self.get(None, None, ffi::MDB_FIRST).unwrap();
IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
IterDup::new(self.cursor(), ffi::MDB_FIRST)
}
/// Iterate over duplicate items in the database starting from the given
/// key. Each item will be returned as an iterator of its duplicates.
fn iter_dup_from<K>(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> {
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
Err(Error::NotFound) => Ok(()),
Err(error) => Err(error),
Ok(_) => Ok(()),
}.unwrap();
Ok(_) | Err(Error::NotFound) => (),
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
};
IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
}
/// Iterate over the duplicates of the item in the database with the given
/// key.
fn iter_dup_of<K>(&mut self, key: &K) -> Result<Iter<'txn>> where K:
AsRef<[u8]> {
self.get(Some(key.as_ref()), None, ffi::MDB_SET)?;
Ok(Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
/// Iterate over the duplicates of the item in the database with the given key.
fn iter_dup_of<K>(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> {
match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
Ok(_) | Err(Error::NotFound) => (),
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
};
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
}
}
@ -249,20 +243,14 @@ impl <'txn> Iterator for Iter<'txn> {
fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> {
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let op = mem::replace(&mut self.op, self.next_op);
unsafe {
let err_code = ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op);
// Set the operation for the next get
self.op = self.next_op;
if err_code == ffi::MDB_SUCCESS {
Some((val_to_slice(key), val_to_slice(data)))
} else {
// The documentation for mdb_cursor_get specifies that it may fail with MDB_NOTFOUND
// and MDB_EINVAL (and we shouldn't be passing in invalid parameters).
// TODO: validate that these are the only failures possible.
debug_assert!(err_code == ffi::MDB_NOTFOUND,
"Unexpected LMDB error {:?}.", Error::from_err_code(err_code));
None
match ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op) {
ffi::MDB_SUCCESS => Some((val_to_slice(key), val_to_slice(data))),
// EINVAL can occur when the cursor was previously seeked to a non-existent value,
// e.g. iter_from with a key greater than all values in the database.
ffi::MDB_NOTFOUND | EINVAL => None,
error => panic!("mdb_cursor_get returned an unexpected error: {}", error),
}
}
}
@ -299,12 +287,12 @@ impl <'txn> Iterator for IterDup<'txn> {
fn next(&mut self) -> Option<Iter<'txn>> {
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let op = mem::replace(&mut self.op, ffi::MDB_NEXT_NODUP);
let err_code = unsafe {
ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op)
ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op)
};
if err_code == ffi::MDB_SUCCESS {
self.op = ffi::MDB_NEXT;
Some(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
} else {
None
@ -463,6 +451,36 @@ mod test {
cursor.iter_from(b"key6").collect::<Vec<_>>());
}
#[test]
fn test_iter_empty_database() {
let dir = TempDir::new("test").unwrap();
let env = Environment::new().open(dir.path()).unwrap();
let db = env.open_db(None).unwrap();
let txn = env.begin_ro_txn().unwrap();
let mut cursor = txn.open_ro_cursor(db).unwrap();
assert_eq!(0, cursor.iter().count());
assert_eq!(0, cursor.iter_start().count());
assert_eq!(0, cursor.iter_from(b"foo").count());
}
#[test]
fn test_iter_empty_dup_database() {
let dir = TempDir::new("test").unwrap();
let env = Environment::new().open(dir.path()).unwrap();
let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
let txn = env.begin_ro_txn().unwrap();
let mut cursor = txn.open_ro_cursor(db).unwrap();
assert_eq!(0, cursor.iter().count());
assert_eq!(0, cursor.iter_start().count());
assert_eq!(0, cursor.iter_from(b"foo").count());
assert_eq!(0, cursor.iter_dup().count());
assert_eq!(0, cursor.iter_dup_start().count());
assert_eq!(0, cursor.iter_dup_from(b"foo").count());
assert_eq!(0, cursor.iter_dup_of(b"foo").count());
}
#[test]
fn test_iter_dup() {
let dir = TempDir::new("test").unwrap();
@ -514,9 +532,9 @@ mod test {
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Vec<_>>());
assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
cursor.iter_dup_of(b"b").unwrap().collect::<Vec<_>>());
cursor.iter_dup_of(b"b").collect::<Vec<_>>());
assert!(cursor.iter_dup_of(b"foo").is_err());
assert_eq!(0, cursor.iter_dup_of(b"foo").count());
}
#[test]

@ -242,7 +242,8 @@ impl EnvironmentBuilder {
///
/// On UNIX, the database files will be opened with 644 permissions.
///
/// The path may not contain the null character.
/// The path may not contain the null character, Windows UNC (Uniform Naming Convention)
/// paths are not supported either.
pub fn open(&self, path: &Path) -> Result<Environment> {
self.open_with_permissions(path, 0o644)
}
@ -251,7 +252,8 @@ impl EnvironmentBuilder {
///
/// On Windows, the permissions will be ignored.
///
/// The path may not contain the null character.
/// The path may not contain the null character, Windows UNC (Uniform Naming Convention)
/// paths are not supported either.
pub fn open_with_permissions(&self, path: &Path, mode: ffi::mode_t) -> Result<Environment> {
let mut env: *mut ffi::MDB_env = ptr::null_mut();
unsafe {

Loading…
Cancel
Save