zero-copy put api.

without.crypto
Dan Burkert 10 years ago
parent b21d5e92a4
commit 22b7a50ac0
  1. 2
      README.md
  2. 2
      lmdb-sys/src/lib.rs
  3. 12
      src/cursor.rs
  4. 2
      src/lib.rs
  5. 64
      src/transaction.rs

@ -23,6 +23,6 @@ cargo build
* [x] lmdb-sys. * [x] lmdb-sys.
* [x] Cursors. * [x] Cursors.
* [ ] Zero-copy put API. * [x] Zero-copy put API.
* [ ] Nested transactions. * [ ] Nested transactions.
* [ ] Database statistics. * [ ] Database statistics.

@ -18,7 +18,7 @@ pub type MDB_cmp_func = extern fn(*const MDB_val, *const MDB_val) -> c_int;
#[repr(C)] #[repr(C)]
pub struct MDB_val { pub struct MDB_val {
pub mv_size: size_t, pub mv_size: size_t,
pub mv_data: *const c_void, pub mv_data: *mut c_void,
} }
#[repr(C)] #[repr(C)]

@ -74,9 +74,9 @@ impl <'txn> Cursor<'txn> {
-> LmdbResult<()> { -> LmdbResult<()> {
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t, let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *const c_void }; mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t, let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *const c_void }; mv_data: data.as_ptr() as *mut c_void };
unsafe { unsafe {
lmdb_result(ffi::mdb_cursor_put(self.cursor(), lmdb_result(ffi::mdb_cursor_put(self.cursor(),
@ -103,10 +103,10 @@ unsafe fn slice_to_val(slice: Option<&[u8]>) -> MDB_val {
match slice { match slice {
Some(slice) => Some(slice) =>
MDB_val { mv_size: slice.len() as size_t, MDB_val { mv_size: slice.len() as size_t,
mv_data: slice.as_ptr() as *const c_void }, mv_data: slice.as_ptr() as *mut c_void },
None => None =>
MDB_val { mv_size: 0, MDB_val { mv_size: 0,
mv_data: ptr::null() }, mv_data: ptr::null_mut() },
} }
} }
@ -238,10 +238,10 @@ mod test {
match slice { match slice {
Some(slice) => Some(slice) =>
MDB_val { mv_size: slice.len() as size_t, MDB_val { mv_size: slice.len() as size_t,
mv_data: slice.as_ptr() as *const c_void }, mv_data: slice.as_ptr() as *mut c_void },
None => None =>
MDB_val { mv_size: 0, MDB_val { mv_size: 0,
mv_data: ptr::null() }, mv_data: ptr::null_mut() },
} }
} }

@ -4,7 +4,7 @@
//! Provides the minimal amount of abstraction necessary to interact with LMDB safely in Rust. In //! Provides the minimal amount of abstraction necessary to interact with LMDB safely in Rust. In
//! general, the API is very similar to the LMDB [C-API](http://symas.com/mdb/doc/). //! general, the API is very similar to the LMDB [C-API](http://symas.com/mdb/doc/).
#![feature(phase, globs, macro_rules, unsafe_destructor, if_let)] #![feature(phase, globs, macro_rules, unsafe_destructor)]
#[phase(plugin, link)] extern crate log; #[phase(plugin, link)] extern crate log;
extern crate libc; extern crate libc;

@ -1,6 +1,7 @@
use libc::{c_uint, c_void, size_t}; use libc::{c_uint, c_void, size_t};
use std::{mem, ptr, raw}; use std::{mem, ptr, raw};
use std::kinds::marker; use std::kinds::marker;
use std::io::BufWriter;
use cursor::Cursor; use cursor::Cursor;
use database::Database; use database::Database;
@ -8,7 +9,7 @@ use environment::Environment;
use error::{LmdbResult, lmdb_result}; use error::{LmdbResult, lmdb_result};
use ffi; use ffi;
use ffi::MDB_txn; use ffi::MDB_txn;
use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags}; use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags, MDB_RESERVE};
/// An LMDB transaction. /// An LMDB transaction.
/// ///
@ -109,9 +110,9 @@ impl <'env> Transaction<'env> {
/// be returned. Retrieval of other items requires the use of `Transaction::cursor_get`. /// be returned. Retrieval of other items requires the use of `Transaction::cursor_get`.
pub fn get<'txn>(&'txn self, database: Database, key: &[u8]) -> LmdbResult<&'txn [u8]> { pub fn get<'txn>(&'txn self, database: Database, key: &[u8]) -> LmdbResult<&'txn [u8]> {
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t, let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *const c_void }; mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: 0, let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: 0,
mv_data: ptr::null() }; mv_data: ptr::null_mut() };
unsafe { unsafe {
try!(lmdb_result(ffi::mdb_get(self.txn(), try!(lmdb_result(ffi::mdb_get(self.txn(),
database.dbi(), database.dbi(),
@ -138,9 +139,9 @@ impl <'env> Transaction<'env> {
flags: WriteFlags) flags: WriteFlags)
-> LmdbResult<()> { -> LmdbResult<()> {
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t, let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *const c_void }; mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t, let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *const c_void }; mv_data: data.as_ptr() as *mut c_void };
unsafe { unsafe {
lmdb_result(ffi::mdb_put(self.txn(), lmdb_result(ffi::mdb_put(self.txn(),
database.dbi(), database.dbi(),
@ -150,6 +151,34 @@ impl <'env> Transaction<'env> {
} }
} }
/// Returns a `BufWriter` which can be used to write a value into the item at the given key
/// and with the given length.
pub fn put_zero_copy<'txn>(&'txn mut self,
database: Database,
key: &[u8],
len: size_t,
flags: WriteFlags)
-> LmdbResult<BufWriter<'txn>> {
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *mut c_void };
let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: len,
mv_data: ptr::null_mut::<c_void>() };
unsafe {
try!(lmdb_result(ffi::mdb_put(self.txn(),
database.dbi(),
&mut key_val,
&mut data_val,
(flags | MDB_RESERVE).bits())));
let slice: &'txn mut [u8] =
mem::transmute(raw::Slice {
data: data_val.mv_data as *const u8,
len: data_val.mv_size as uint
});
Ok(BufWriter::new(slice))
}
}
/// Deletes an item from a database. /// Deletes an item from a database.
/// ///
/// This function removes key/data pairs from the database. If the database does not support /// This function removes key/data pairs from the database. If the database does not support
@ -164,10 +193,10 @@ impl <'env> Transaction<'env> {
data: Option<&[u8]>) data: Option<&[u8]>)
-> LmdbResult<()> { -> LmdbResult<()> {
let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t, let mut key_val: ffi::MDB_val = ffi::MDB_val { mv_size: key.len() as size_t,
mv_data: key.as_ptr() as *const c_void }; mv_data: key.as_ptr() as *mut c_void };
let data_val: Option<ffi::MDB_val> = let data_val: Option<ffi::MDB_val> =
data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t, data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t,
mv_data: data.as_ptr() as *const c_void }); mv_data: data.as_ptr() as *mut c_void });
unsafe { unsafe {
lmdb_result(ffi::mdb_del(self.txn(), lmdb_result(ffi::mdb_del(self.txn(),
database.dbi(), database.dbi(),
@ -240,6 +269,27 @@ mod test {
assert!(txn.get(db, b"key1").is_err()); assert!(txn.get(db, b"key1").is_err());
} }
#[test]
fn test_put_zero_copy() {
let dir = io::TempDir::new("test").unwrap();
let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap();
let mut txn = env.begin_txn(EnvironmentFlags::empty()).unwrap();
let db = txn.open_db(None, DatabaseFlags::empty()).unwrap();
{
let mut writer = txn.put_zero_copy(db, b"key1", 4, WriteFlags::empty()).unwrap();
writer.write(b"val1").unwrap();
}
txn.commit().unwrap();
let mut txn = env.begin_txn(EnvironmentFlags::empty()).unwrap();
assert_eq!(b"val1", txn.get(db, b"key1").unwrap());
assert!(txn.get(db, b"key").is_err());
txn.del(db, b"key1", None).unwrap();
assert!(txn.get(db, b"key1").is_err());
}
#[test] #[test]
fn test_close_database() { fn test_close_database() {
let dir = io::TempDir::new("test").unwrap(); let dir = io::TempDir::new("test").unwrap();

Loading…
Cancel
Save