Flag constants for lmdb-sys; move bitflags! to lmdb proper

without.crypto
Dan Burkert 10 years ago
parent b1c1bb5b0b
commit c745961037
  1. 269
      lmdb-sys/src/constants.rs
  2. 48
      src/cursor.rs
  3. 4
      src/database.rs
  4. 42
      src/environment.rs
  5. 183
      src/flags.rs
  6. 3
      src/lib.rs
  7. 30
      src/transaction.rs

@ -1,208 +1,83 @@
use libc::{c_int, c_uint}; use libc::{c_int, c_uint};
bitflags! { ////////////////////////////////////////////////////////////////////////////////////////////////////
#[doc="Environment Options"] //// Environment Flags
#[deriving(Show)] ////////////////////////////////////////////////////////////////////////////////////////////////////
flags EnvironmentFlags: c_uint {
/// mmap at a fixed address (experimental)
#[doc="Use a fixed address for the mmap region. This flag must be specified"] pub const MDB_FIXEDMAP: c_uint = 0x01;
#[doc="when creating the environment, and is stored persistently in the environment."] /// no environment directory
#[doc="If successful, the memory map will always reside at the same virtual address"] pub const MDB_NOSUBDIR: c_uint = 0x4000;
#[doc="and pointers used to reference data items in the database will be constant"] /// don't fsync after commit
#[doc="across multiple invocations. This option may not always work, depending on"] pub const MDB_NOSYNC: c_uint = 0x10000;
#[doc="how the operating system has allocated memory to shared libraries and other uses."] /// read only
#[doc="The feature is highly experimental."] pub const MDB_RDONLY: c_uint = 0x20000;
const MDB_FIXEDMAP = 0x01, /// don't fsync metapage after commit
pub const MDB_NOMETASYNC: c_uint = 0x40000;
#[doc="By default, LMDB creates its environment in a directory whose"] /// use writable mmap
#[doc="pathname is given in *path*, and creates its data and lock files"] pub const MDB_WRITEMAP: c_uint = 0x80000;
#[doc="under that directory. With this option, *path* is used as-is for"] /// use asynchronous msync when #MDB_WRITEMAP is used
#[doc="the database main data file. The database lock file is the *path*"] pub const MDB_MAPASYNC: c_uint = 0x100000;
#[doc="with `-lock` appended."] /// tie reader locktable slots to #MDB_txn objects instead of to threads
const MDB_NOSUBDIR = 0x4000, pub const MDB_NOTLS: c_uint = 0x200000;
/// don't do any locking, caller must manage their own locks
#[doc="Use a writeable memory map unless `MDB_RDONLY` is set. This is faster"] pub const MDB_NOLOCK: c_uint = 0x400000;
#[doc="and uses fewer mallocs, but loses protection from application bugs"] /// don't do readahead (no effect on Windows)
#[doc="like wild pointer writes and other bad updates into the database."] pub const MDB_NORDAHEAD: c_uint = 0x800000;
#[doc="Incompatible with nested transactions."] /// don't initialize malloc'd memory before writing to datafile
#[doc="Processes with and without `MDB_WRITEMAP` on the same environment do"] pub const MDB_NOMEMINIT: c_uint = 0x1000000;
#[doc="not cooperate well."]
const MDB_WRITEMAP = 0x80000, ////////////////////////////////////////////////////////////////////////////////////////////////////
//// Database Flags
#[doc="Open the environment or transaction in read-only mode. No write operations"] ////////////////////////////////////////////////////////////////////////////////////////////////////
#[doc="will be allowed. When opening an environment, LMDB will still modify the lock"]
#[doc="file - except on read-only filesystems, where LMDB does not use locks."] /// use reverse string keys
const MDB_RDONLY = 0x20000, pub const MDB_REVERSEKEY: c_uint = 0x02;
/// use sorted duplicates
#[doc="Flush system buffers to disk only once per transaction, omit the"] pub const MDB_DUPSORT: c_uint = 0x04;
#[doc="metadata flush. Defer that until the system flushes files to disk,"] /// numeric keys in native byte order. The keys must all be of the same size.
#[doc="or next non-`MDB_RDONLY` commit or #mdb_env_sync(). This optimization"] pub const MDB_INTEGERKEY: c_uint = 0x08;
#[doc="maintains database integrity, but a system crash may undo the last"] /// with `MDB_DUPSORT`, sorted dup items have fixed size.
#[doc="committed transaction. I.e. it preserves the ACI (atomicity,"] pub const MDB_DUPFIXED: c_uint = 0x10;
#[doc="consistency, isolation) but not D (durability) database property."] /// with `MDB_DUPSORT`, dups are numeric in native byte order.
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."] pub const MDB_INTEGERDUP: c_uint = 0x20;
const MDB_NOMETASYNC = 0x40000, /// with #MDB_DUPSORT, use reverse string dups.
pub const MDB_REVERSEDUP: c_uint = 0x40;
#[doc="Don't flush system buffers to disk when committing a transaction."] /// create DB if not already existing.
#[doc="This optimization means a system crash can corrupt the database or"]
#[doc="lose the last transactions if buffers are not yet flushed to disk."]
#[doc="The risk is governed by how often the system flushes dirty buffers"]
#[doc="to disk and how often #mdb_env_sync() is called. However, if the"]
#[doc="filesystem preserves write order and the `MDB_WRITEMAP` flag is not"]
#[doc="used, transactions exhibit ACI (atomicity, consistency, isolation)"]
#[doc="properties and only lose D (durability). I.e. database integrity"]
#[doc="is maintained, but a system crash may undo the final transactions."]
#[doc="Note that (`MDB_NOSYNC | MDB_WRITEMAP`) leaves the system with no"]
#[doc="hint for when to write transactions to disk, unless #mdb_env_sync()"]
#[doc="is called. (`MDB_MAPASYNC | MDB_WRITEMAP`) may be preferable."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_NOSYNC = 0x10000,
#[doc="When using `MDB_WRITEMAP`, use asynchronous flushes to disk."]
#[doc="As with `MDB_NOSYNC`, a system crash can then corrupt the"]
#[doc="database or lose the last transactions. Calling #mdb_env_sync()"]
#[doc="ensures on-disk database integrity until next commit."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_MAPASYNC = 0x100000,
#[doc="Don't use Thread-Local Storage. Tie reader locktable slots to"]
#[doc="`MDB_txn` objects instead of to threads. I.e. #mdb_txn_reset() keeps"]
#[doc="the slot reseved for the #MDB_txn object. A thread may use parallel"]
#[doc="read-only transactions. A read-only transaction may span threads if"]
#[doc="the user synchronizes its use. Applications that multiplex many"]
#[doc="user threads over individual OS threads need this option. Such an"]
#[doc="application must also serialize the write transactions in an OS"]
#[doc="thread, since LMDB's write locking is unaware of the user threads."]
const MDB_NOTLS = 0x200000,
#[doc="Don't do any locking. If concurrent access is anticipated, the"]
#[doc="caller must manage all concurrency itself. For proper operation"]
#[doc="the caller must enforce single-writer semantics, and must ensure"]
#[doc="that no readers are using old transactions while a writer is"]
#[doc="active. The simplest approach is to use an exclusive lock so that"]
#[doc="no readers may be active at all when a writer begins."]
const MDB_NOLOCK = 0x400000,
#[doc="Turn off readahead. Most operating systems perform readahead on"]
#[doc="read requests by default. This option turns it off if the OS"]
#[doc="supports it. Turning it off may help random read performance"]
#[doc="when the DB is larger than RAM and system RAM is full."]
#[doc="The option is not implemented on Windows."]
const MDB_NORDAHEAD = 0x800000,
#[doc="Don't initialize malloc'd memory before writing to unused spaces"]
#[doc="in the data file. By default, memory for pages written to the data"]
#[doc="file is obtained using malloc. While these pages may be reused in"]
#[doc="subsequent transactions, freshly malloc'd pages will be initialized"]
#[doc="to zeroes before use. This avoids persisting leftover data from other"]
#[doc="code (that used the heap and subsequently freed the memory) into the"]
#[doc="data file. Note that many other system libraries may allocate"]
#[doc="and free memory from the heap for arbitrary uses. E.g., stdio may"]
#[doc="use the heap for file I/O buffers. This initialization step has a"]
#[doc="modest performance cost so some applications may want to disable"]
#[doc="it using this flag. This option can be a problem for applications"]
#[doc="which handle sensitive data like passwords, and it makes memory"]
#[doc="checkers like Valgrind noisy. This flag is not needed with `MDB_WRITEMAP`,"]
#[doc="which writes directly to the mmap instead of using malloc for pages. The"]
#[doc="initialization is also skipped if `MDB_RESERVE` is used; the"]
#[doc="caller is expected to overwrite all of the memory that was"]
#[doc="reserved in that case."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_NOMEMINIT = 0x1000000,
}
}
bitflags! {
#[doc="Database Options"]
#[deriving(Show)]
flags DatabaseFlags: c_uint {
#[doc="Keys are strings to be compared in reverse order, from the end"]
#[doc="of the strings to the beginning. By default, Keys are treated as strings and"]
#[doc="compared from beginning to end."]
const MDB_REVERSEKEY = 0x02, // 2
#[doc="Duplicate keys may be used in the database. (Or, from another perspective,"]
#[doc="keys may have multiple data items, stored in sorted order.) By default"]
#[doc="keys must be unique and may have only a single data item."]
const MDB_DUPSORT = 0x04, // 4
#[doc="Keys are binary integers in native byte order. Setting this option"]
#[doc="requires all keys to be the same size, typically sizeof(int)"]
#[doc="or sizeof(size_t)."]
const MDB_INTEGERKEY = 0x08, // 8
#[doc="This flag may only be used in combination with `MDB_DUPSORT`. This option"]
#[doc="tells the library that the data items for this database are all the same"]
#[doc="size, which allows further optimizations in storage and retrieval. When"]
#[doc="all data items are the same size, the `MDB_GET_MULTIPLE` and `MDB_NEXT_MULTIPLE`"]
#[doc="cursor operations may be used to retrieve multiple items at once."]
const MDB_DUPFIXED = 0x10, // 16
#[doc="This option specifies that duplicate data items are also integers, and"]
#[doc="should be sorted as such."]
const MDB_INTEGERDUP = 0x20, // 32
#[doc="This option specifies that duplicate data items should be compared as"]
#[doc="strings in reverse order."]
const MDB_REVERSEDUP = 0x40, // 64
}
}
/// Create the named database if it doesn't exist. This option is not
/// allowed in a read-only transaction or a read-only environment.
pub const MDB_CREATE: c_uint = 0x40000; pub const MDB_CREATE: c_uint = 0x40000;
bitflags! { ////////////////////////////////////////////////////////////////////////////////////////////////////
#[doc="Write Options"] //// Write Flags
#[deriving(Show)] ////////////////////////////////////////////////////////////////////////////////////////////////////
flags WriteFlags: c_uint {
/// For put: Don't write if the key already exists.
#[doc="Enter the new key/data pair only if the key"] pub const MDB_NOOVERWRITE: c_uint = 0x10;
#[doc="does not already appear in the database. The function will return"] /// Only for `MDB_DUPSORT`.
#[doc="`KeyExist` if the key already appears in the database, even if"] ///
#[doc="the database supports duplicates (`MDB_DUPSORT`). The `data`"] /// For put: don't write if the key and data pair already exist.
#[doc="parameter will be set to point to the existing item."] /// For `mdb_cursor_del`: remove all duplicate data items.
const MDB_NOOVERWRITE = 0x10, pub const MDB_NODUPDATA: c_uint = 0x20;
/// For `mdb_cursor_put`: overwrite the current key/data pair.
#[doc="Enter the new key/data pair only if it does not"] pub const MDB_CURRENT: c_uint = 0x40;
#[doc="already appear in the database. This flag may only be specified"] /// For put: Just reserve space for data, don't copy it. Return a pointer to the reserved space.
#[doc="if the database was opened with `MDB_DUPSORT`. The function will"]
#[doc="return `MDB_KEYEXIST` if the key/data pair already appears in the"]
#[doc="database."]
const MDB_NODUPDATA = 0x20,
#[doc="For `Cursor::put`. Replace the item at the current cursor position."]
#[doc="The key parameter must match the current position. If using"]
#[doc="sorted duplicates (`MDB_DUPSORT`) the data item must still sort into the"]
#[doc="same position. This is intended to be used when the new data is the same"]
#[doc="size as the old. Otherwise it will simply perform a delete of the old"]
#[doc="record followed by an insert."]
const MDB_CURRENT = 0x40,
#[doc="Append the given key/data pair to the end of the"]
#[doc="database. No key comparisons are performed. This option allows"]
#[doc="fast bulk loading when keys are already known to be in the"]
#[doc="correct order. Loading unsorted keys with this flag will cause"]
#[doc="data corruption."]
const MDB_APPEND = 0x20000,
#[doc="Same as `MDB_APPEND`, but for sorted dup data."]
const MDB_APPENDDUP = 0x40000,
}
}
/// Reserve space for data of the given size, but don't copy the given data. Instead, return a
/// pointer to the reserved space, which the caller can fill in later - before the next update
/// operation or the transaction ends. This saves an extra memcpy if the data is being generated
/// later. LMDB does nothing else with this memory, the caller is expected to modify all of the
/// space requested.
pub const MDB_RESERVE: c_uint = 0x10000; pub const MDB_RESERVE: c_uint = 0x10000;
/// Data is being appended, don't split full pages.
pub const MDB_APPEND: c_uint = 0x20000;
/// Duplicate data is being appended, don't split full pages.
pub const MDB_APPENDDUP: c_uint = 0x40000;
/// Store multiple data items in one call. Only for #MDB_DUPFIXED.
pub const MDB_MULTIPLE: c_uint = 0x80000;
////////////////////////////////////////////////////////////////////////////////////////////////////
//// Copy Flags
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compacting copy: Omit free space from copy, and renumber all pages sequentially.
pub const MDB_CP_COMPACT: c_uint = 0x01;
/////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
//// Return Codes //// Return Codes
/////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
/// Successful result. /// Successful result.
pub const MDB_SUCCESS: c_int = 0; pub const MDB_SUCCESS: c_int = 0;

@ -2,10 +2,11 @@ use libc::{c_void, size_t, c_uint};
use std::{mem, ptr, raw}; use std::{mem, ptr, raw};
use std::kinds::marker; use std::kinds::marker;
use ffi;
use database::Database; use database::Database;
use error::{LmdbResult, lmdb_result, LmdbError}; use error::{LmdbResult, lmdb_result, LmdbError};
use ffi; use flags::WriteFlags;
use ffi::{MDB_cursor, mdb_cursor_open, MDB_val, WriteFlags};
use transaction::Transaction; use transaction::Transaction;
/// An LMDB cursor. /// An LMDB cursor.
@ -13,9 +14,10 @@ pub trait Cursor<'txn> {
/// Returns a raw pointer to the underlying LMDB cursor. /// Returns a raw pointer to the underlying LMDB cursor.
/// ///
/// The caller **must** ensure that the pointer is not used after the lifetime of the cursor. /// The caller **must** ensure that the pointer is not used after the lifetime of the cursor.
fn cursor(&self) -> *mut MDB_cursor; fn cursor(&self) -> *mut ffi::MDB_cursor;
} }
/// Cursor extension methods.
pub trait CursorExt<'txn> : Cursor<'txn> { pub trait CursorExt<'txn> : Cursor<'txn> {
/// Retrieves a key/data pair from the cursor. Depending on the cursor op, the current key is /// Retrieves a key/data pair from the cursor. Depending on the cursor op, the current key is
@ -49,14 +51,14 @@ impl<'txn, T> CursorExt<'txn> for T where T: Cursor<'txn> {}
/// A read-only cursor for navigating items within a database. /// A read-only cursor for navigating items within a database.
pub struct RoCursor<'txn> { pub struct RoCursor<'txn> {
cursor: *mut MDB_cursor, cursor: *mut ffi::MDB_cursor,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
_no_send: marker::NoSend, _no_send: marker::NoSend,
_contravariant: marker::ContravariantLifetime<'txn>, _contravariant: marker::ContravariantLifetime<'txn>,
} }
impl <'txn> Cursor<'txn> for RoCursor<'txn> { impl <'txn> Cursor<'txn> for RoCursor<'txn> {
fn cursor(&self) -> *mut MDB_cursor { fn cursor(&self) -> *mut ffi::MDB_cursor {
self.cursor self.cursor
} }
} }
@ -74,8 +76,8 @@ impl <'txn> RoCursor<'txn> {
/// `Transaction::open_cursor()`. /// `Transaction::open_cursor()`.
#[doc(hidden)] #[doc(hidden)]
pub fn new(txn: &'txn Transaction, db: Database) -> LmdbResult<RoCursor<'txn>> { pub fn new(txn: &'txn Transaction, db: Database) -> LmdbResult<RoCursor<'txn>> {
let mut cursor: *mut MDB_cursor = ptr::null_mut(); let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
unsafe { try!(lmdb_result(mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); } unsafe { try!(lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); }
Ok(RoCursor { Ok(RoCursor {
cursor: cursor, cursor: cursor,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
@ -87,14 +89,14 @@ impl <'txn> RoCursor<'txn> {
/// A read-only cursor for navigating items within a database. /// A read-only cursor for navigating items within a database.
pub struct RwCursor<'txn> { pub struct RwCursor<'txn> {
cursor: *mut MDB_cursor, cursor: *mut ffi::MDB_cursor,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
_no_send: marker::NoSend, _no_send: marker::NoSend,
_contravariant: marker::ContravariantLifetime<'txn>, _contravariant: marker::ContravariantLifetime<'txn>,
} }
impl <'txn> Cursor<'txn> for RwCursor<'txn> { impl <'txn> Cursor<'txn> for RwCursor<'txn> {
fn cursor(&self) -> *mut MDB_cursor { fn cursor(&self) -> *mut ffi::MDB_cursor {
self.cursor self.cursor
} }
} }
@ -112,8 +114,8 @@ impl <'txn> RwCursor<'txn> {
/// `WriteTransaction::open_write_cursor()`. /// `WriteTransaction::open_write_cursor()`.
#[doc(hidden)] #[doc(hidden)]
pub fn new(txn: &'txn Transaction, db: Database) -> LmdbResult<RwCursor<'txn>> { pub fn new(txn: &'txn Transaction, db: Database) -> LmdbResult<RwCursor<'txn>> {
let mut cursor: *mut MDB_cursor = ptr::null_mut(); let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
unsafe { try!(lmdb_result(mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); } unsafe { try!(lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); }
Ok(RwCursor { Ok(RwCursor {
cursor: cursor, cursor: cursor,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
@ -154,18 +156,18 @@ impl <'txn> RwCursor<'txn> {
} }
} }
unsafe fn slice_to_val(slice: Option<&[u8]>) -> MDB_val { unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDB_val {
match slice { match slice {
Some(slice) => Some(slice) =>
MDB_val { mv_size: slice.len() as size_t, ffi::MDB_val { mv_size: slice.len() as size_t,
mv_data: slice.as_ptr() as *mut c_void }, mv_data: slice.as_ptr() as *mut c_void },
None => None =>
MDB_val { mv_size: 0, ffi::MDB_val { mv_size: 0,
mv_data: ptr::null_mut() }, mv_data: ptr::null_mut() },
} }
} }
unsafe fn val_to_slice<'a>(val: MDB_val) -> &'a [u8] { unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
mem::transmute(raw::Slice { mem::transmute(raw::Slice {
data: val.mv_data as *const u8, data: val.mv_data as *const u8,
len: val.mv_size as uint len: val.mv_size as uint
@ -173,7 +175,7 @@ unsafe fn val_to_slice<'a>(val: MDB_val) -> &'a [u8] {
} }
pub struct Items<'txn> { pub struct Items<'txn> {
cursor: *mut MDB_cursor, cursor: *mut ffi::MDB_cursor,
op: c_uint, op: c_uint,
next_op: c_uint, next_op: c_uint,
} }
@ -189,8 +191,8 @@ impl <'txn> Items<'txn> {
impl <'txn> Iterator<(&'txn [u8], &'txn [u8])> for Items<'txn> { impl <'txn> Iterator<(&'txn [u8], &'txn [u8])> for Items<'txn> {
fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> { fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> {
let mut key = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
let mut data = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
unsafe { unsafe {
let err_code = ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op); let err_code = ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, self.op);
@ -216,11 +218,13 @@ mod test {
use std::{io, ptr}; use std::{io, ptr};
use test::{Bencher, black_box}; use test::{Bencher, black_box};
use environment::*;
use ffi::*; use ffi::*;
use environment::*;
use flags::*;
use super::*; use super::*;
use test_utils::*;
use transaction::*; use transaction::*;
use test_utils::setup_bench_db;
#[test] #[test]
fn test_iter() { fn test_iter() {

@ -1,8 +1,10 @@
use std::kinds::marker; use std::kinds::marker;
use std::ptr; use std::ptr;
use error::{LmdbResult, lmdb_result};
use ffi::*; use ffi::*;
use error::{LmdbResult, lmdb_result};
use flags::DatabaseFlags;
use transaction::{RoTransaction, RwTransaction, Transaction}; use transaction::{RoTransaction, RwTransaction, Transaction};
/// A handle to an individual database in an environment. /// A handle to an individual database in an environment.

@ -3,16 +3,18 @@ use std::io::FilePermission;
use std::ptr; use std::ptr;
use std::sync::Mutex; use std::sync::Mutex;
use ffi;
use error::{LmdbResult, lmdb_result}; use error::{LmdbResult, lmdb_result};
use database::Database; use database::Database;
use ffi::*;
use transaction::{RoTransaction, RwTransaction, Transaction, TransactionExt}; use transaction::{RoTransaction, RwTransaction, Transaction, TransactionExt};
use flags::{DatabaseFlags, EnvironmentFlags};
/// An LMDB environment. /// An LMDB environment.
/// ///
/// An environment supports multiple databases, all residing in the same shared-memory map. /// An environment supports multiple databases, all residing in the same shared-memory map.
pub struct Environment { pub struct Environment {
env: *mut MDB_env, env: *mut ffi::MDB_env,
dbi_open_mutex: Mutex<()>, dbi_open_mutex: Mutex<()>,
} }
@ -32,7 +34,7 @@ impl Environment {
/// ///
/// The caller **must** ensure that the pointer is not dereferenced after the lifetime of the /// The caller **must** ensure that the pointer is not dereferenced after the lifetime of the
/// environment. /// environment.
pub fn env(&self) -> *mut MDB_env { pub fn env(&self) -> *mut ffi::MDB_env {
self.env self.env
} }
@ -81,7 +83,7 @@ impl Environment {
let txn = try!(self.begin_read_txn()); let txn = try!(self.begin_read_txn());
let mut flags: c_uint = 0; let mut flags: c_uint = 0;
unsafe { unsafe {
try!(lmdb_result(mdb_dbi_flags(txn.txn(), db.dbi(), &mut flags))); try!(lmdb_result(ffi::mdb_dbi_flags(txn.txn(), db.dbi(), &mut flags)));
} }
Ok(DatabaseFlags::from_bits(flags).unwrap()) Ok(DatabaseFlags::from_bits(flags).unwrap())
} }
@ -104,7 +106,7 @@ impl Environment {
/// the environment was opened with `MDB_NOSYNC` or in part `MDB_NOMETASYNC`. /// the environment was opened with `MDB_NOSYNC` or in part `MDB_NOMETASYNC`.
pub fn sync(&self, force: bool) -> LmdbResult<()> { pub fn sync(&self, force: bool) -> LmdbResult<()> {
unsafe { unsafe {
lmdb_result(mdb_env_sync(self.env(), if force { 1 } else { 0 })) lmdb_result(ffi::mdb_env_sync(self.env(), if force { 1 } else { 0 }))
} }
} }
@ -115,26 +117,26 @@ impl Environment {
/// that value would be large. /// that value would be large.
pub fn close_db(&mut self, name: Option<&str>) -> LmdbResult<()> { pub fn close_db(&mut self, name: Option<&str>) -> LmdbResult<()> {
let db = try!(self.open_db(name)); let db = try!(self.open_db(name));
unsafe { mdb_dbi_close(self.env, db.dbi()) }; unsafe { ffi::mdb_dbi_close(self.env, db.dbi()) };
Ok(()) Ok(())
} }
pub fn clear_db(&mut self, name: Option<&str>) -> LmdbResult<()> { pub fn clear_db(&mut self, name: Option<&str>) -> LmdbResult<()> {
let db = try!(self.open_db(name)); let db = try!(self.open_db(name));
let txn = try!(self.begin_write_txn()); let txn = try!(self.begin_write_txn());
unsafe { lmdb_result(mdb_drop(txn.txn(), db.dbi(), 0)) } unsafe { lmdb_result(ffi::mdb_drop(txn.txn(), db.dbi(), 0)) }
} }
pub fn drop_db(&mut self, name: Option<&str>) -> LmdbResult<()> { pub fn drop_db(&mut self, name: Option<&str>) -> LmdbResult<()> {
let db = try!(self.open_db(name)); let db = try!(self.open_db(name));
let txn = try!(self.begin_write_txn()); let txn = try!(self.begin_write_txn());
unsafe { lmdb_result(mdb_drop(txn.txn(), db.dbi(), 1)) } unsafe { lmdb_result(ffi::mdb_drop(txn.txn(), db.dbi(), 1)) }
} }
} }
impl Drop for Environment { impl Drop for Environment {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { mdb_env_close(self.env) } unsafe { ffi::mdb_env_close(self.env) }
} }
} }
@ -155,26 +157,26 @@ impl EnvironmentBuilder {
/// Open an environment. /// Open an environment.
pub fn open(&self, path: &Path, mode: FilePermission) -> LmdbResult<Environment> { pub fn open(&self, path: &Path, mode: FilePermission) -> LmdbResult<Environment> {
let mut env: *mut MDB_env = ptr::null_mut(); let mut env: *mut ffi::MDB_env = ptr::null_mut();
unsafe { unsafe {
lmdb_try!(mdb_env_create(&mut env)); lmdb_try!(ffi::mdb_env_create(&mut env));
if let Some(max_readers) = self.max_readers { if let Some(max_readers) = self.max_readers {
lmdb_try_with_cleanup!(mdb_env_set_maxreaders(env, max_readers), lmdb_try_with_cleanup!(ffi::mdb_env_set_maxreaders(env, max_readers),
mdb_env_close(env)) ffi::mdb_env_close(env))
} }
if let Some(max_dbs) = self.max_dbs { if let Some(max_dbs) = self.max_dbs {
lmdb_try_with_cleanup!(mdb_env_set_maxdbs(env, max_dbs), lmdb_try_with_cleanup!(ffi::mdb_env_set_maxdbs(env, max_dbs),
mdb_env_close(env)) ffi::mdb_env_close(env))
} }
if let Some(map_size) = self.map_size { if let Some(map_size) = self.map_size {
lmdb_try_with_cleanup!(mdb_env_set_mapsize(env, map_size), lmdb_try_with_cleanup!(ffi::mdb_env_set_mapsize(env, map_size),
mdb_env_close(env)) ffi::mdb_env_close(env))
} }
lmdb_try_with_cleanup!(mdb_env_open(env, lmdb_try_with_cleanup!(ffi::mdb_env_open(env,
path.to_c_str().as_ptr(), path.to_c_str().as_ptr(),
self.flags.bits(), self.flags.bits(),
mode.bits() as mode_t), mode.bits() as mode_t),
mdb_env_close(env)); ffi::mdb_env_close(env));
} }
Ok(Environment { env: env, Ok(Environment { env: env,
dbi_open_mutex: Mutex::new(()) }) dbi_open_mutex: Mutex::new(()) })
@ -232,7 +234,7 @@ mod test {
use std::io; use std::io;
use ffi::*; use flags::*;
use super::*; use super::*;
#[test] #[test]

@ -0,0 +1,183 @@
use libc::c_uint;
bitflags! {
#[doc="Environment Options"]
#[deriving(Show)]
flags EnvironmentFlags: c_uint {
#[doc="Use a fixed address for the mmap region. This flag must be specified"]
#[doc="when creating the environment, and is stored persistently in the environment."]
#[doc="If successful, the memory map will always reside at the same virtual address"]
#[doc="and pointers used to reference data items in the database will be constant"]
#[doc="across multiple invocations. This option may not always work, depending on"]
#[doc="how the operating system has allocated memory to shared libraries and other uses."]
#[doc="The feature is highly experimental."]
const MDB_FIXEDMAP = 0x01,
#[doc="By default, LMDB creates its environment in a directory whose"]
#[doc="pathname is given in `path`, and creates its data and lock files"]
#[doc="under that directory. With this option, `path` is used as-is for"]
#[doc="the database main data file. The database lock file is the `path`"]
#[doc="with `-lock` appended."]
const MDB_NOSUBDIR = 0x4000,
#[doc="Use a writeable memory map unless `MDB_RDONLY` is set. This is faster and uses"]
#[doc="fewer mallocs, but loses protection from application bugs like wild pointer writes"]
#[doc="and other bad updates into the database. Incompatible with nested transactions."]
#[doc="Processes with and without `MDB_WRITEMAP` on the same environment do not cooperate"]
#[doc="well."]
const MDB_WRITEMAP = 0x80000,
#[doc="Open the environment in read-only mode. No write operations will be allowed."]
#[doc="When opening an environment, LMDB will still modify the lock file - except on"]
#[doc="read-only filesystems, where LMDB does not use locks."]
const MDB_RDONLY = 0x20000,
#[doc="Flush system buffers to disk only once per transaction, omit the"]
#[doc="metadata flush. Defer that until the system flushes files to disk,"]
#[doc="or next non-`MDB_RDONLY` commit or #mdb_env_sync(). This optimization"]
#[doc="maintains database integrity, but a system crash may undo the last"]
#[doc="committed transaction. I.e. it preserves the ACI (atomicity,"]
#[doc="consistency, isolation) but not D (durability) database property."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_NOMETASYNC = 0x40000,
#[doc="Don't flush system buffers to disk when committing a transaction."]
#[doc="This optimization means a system crash can corrupt the database or"]
#[doc="lose the last transactions if buffers are not yet flushed to disk."]
#[doc="The risk is governed by how often the system flushes dirty buffers"]
#[doc="to disk and how often `Environment::sync` is called. However, if the"]
#[doc="filesystem preserves write order and the `MDB_WRITEMAP` flag is not"]
#[doc="used, transactions exhibit ACI (atomicity, consistency, isolation)"]
#[doc="properties and only lose D (durability). I.e. database integrity"]
#[doc="is maintained, but a system crash may undo the final transactions."]
#[doc="Note that (`MDB_NOSYNC | MDB_WRITEMAP`) leaves the system with no"]
#[doc="hint for when to write transactions to disk, unless `Environment::sync`"]
#[doc="is called. (`MDB_MAPASYNC | MDB_WRITEMAP`) may be preferable."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_NOSYNC = 0x10000,
#[doc="When using `MDB_WRITEMAP`, use asynchronous flushes to disk."]
#[doc="As with `MDB_NOSYNC`, a system crash can then corrupt the"]
#[doc="database or lose the last transactions. Calling `Environment::sync`"]
#[doc="ensures on-disk database integrity until next commit."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_MAPASYNC = 0x100000,
#[doc="Don't use Thread-Local Storage. Tie reader locktable slots to"]
#[doc="transaction objects instead of to threads. I.e. `RoTransaction::reset` keeps"]
#[doc="the slot reseved for the transaction object. A thread may use parallel"]
#[doc="read-only transactions. A read-only transaction may span threads if"]
#[doc="the user synchronizes its use. Applications that multiplex many"]
#[doc="user threads over individual OS threads need this option. Such an"]
#[doc="application must also serialize the write transactions in an OS"]
#[doc="thread, since LMDB's write locking is unaware of the user threads."]
const MDB_NOTLS = 0x200000,
#[doc="Don't do any locking. If concurrent access is anticipated, the"]
#[doc="caller must manage all concurrency themself. For proper operation"]
#[doc="the caller must enforce single-writer semantics, and must ensure"]
#[doc="that no readers are using old transactions while a writer is"]
#[doc="active. The simplest approach is to use an exclusive lock so that"]
#[doc="no readers may be active at all when a writer begins."]
const MDB_NOLOCK = 0x400000,
#[doc="Turn off readahead. Most operating systems perform readahead on"]
#[doc="read requests by default. This option turns it off if the OS"]
#[doc="supports it. Turning it off may help random read performance"]
#[doc="when the DB is larger than RAM and system RAM is full."]
#[doc="The option is not implemented on Windows."]
const MDB_NORDAHEAD = 0x800000,
#[doc="Don't initialize malloc'd memory before writing to unused spaces"]
#[doc="in the data file. By default, memory for pages written to the data"]
#[doc="file is obtained using malloc. While these pages may be reused in"]
#[doc="subsequent transactions, freshly malloc'd pages will be initialized"]
#[doc="to zeroes before use. This avoids persisting leftover data from other"]
#[doc="code (that used the heap and subsequently freed the memory) into the"]
#[doc="data file. Note that many other system libraries may allocate"]
#[doc="and free memory from the heap for arbitrary uses. E.g., stdio may"]
#[doc="use the heap for file I/O buffers. This initialization step has a"]
#[doc="modest performance cost so some applications may want to disable"]
#[doc="it using this flag. This option can be a problem for applications"]
#[doc="which handle sensitive data like passwords, and it makes memory"]
#[doc="checkers like Valgrind noisy. This flag is not needed with `MDB_WRITEMAP`,"]
#[doc="which writes directly to the mmap instead of using malloc for pages. The"]
#[doc="initialization is also skipped if `MDB_RESERVE` is used; the"]
#[doc="caller is expected to overwrite all of the memory that was"]
#[doc="reserved in that case."]
#[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
const MDB_NOMEMINIT = 0x1000000,
}
}
bitflags! {
#[doc="Database Options"]
#[deriving(Show)]
flags DatabaseFlags: c_uint {
#[doc="Keys are strings to be compared in reverse order, from the end"]
#[doc="of the strings to the beginning. By default, Keys are treated as strings and"]
#[doc="compared from beginning to end."]
const MDB_REVERSEKEY = 0x02,
#[doc="Duplicate keys may be used in the database. (Or, from another perspective,"]
#[doc="keys may have multiple data items, stored in sorted order.) By default"]
#[doc="keys must be unique and may have only a single data item."]
const MDB_DUPSORT = 0x04,
#[doc="Keys are binary integers in native byte order. Setting this option"]
#[doc="requires all keys to be the same size, typically sizeof(int)"]
#[doc="or sizeof(size_t)."]
const MDB_INTEGERKEY = 0x08,
#[doc="This flag may only be used in combination with `MDB_DUPSORT`. This option"]
#[doc="tells the library that the data items for this database are all the same"]
#[doc="size, which allows further optimizations in storage and retrieval. When"]
#[doc="all data items are the same size, the `MDB_GET_MULTIPLE` and `MDB_NEXT_MULTIPLE`"]
#[doc="cursor operations may be used to retrieve multiple items at once."]
const MDB_DUPFIXED = 0x10,
#[doc="This option specifies that duplicate data items are also integers, and"]
#[doc="should be sorted as such."]
const MDB_INTEGERDUP = 0x20,
#[doc="This option specifies that duplicate data items should be compared as"]
#[doc="strings in reverse order."]
const MDB_REVERSEDUP = 0x40,
}
}
bitflags! {
#[doc="Write Options"]
#[deriving(Show)]
flags WriteFlags: c_uint {
#[doc="Insert the new item only if the key does not already appear in the database."]
#[doc="The function will return `LmdbError::KeyExist` if the key already appears in the"]
#[doc="database, even if the database supports duplicates (`MDB_DUPSORT`)."]
const MDB_NOOVERWRITE = 0x10,
#[doc="Insert the new item only if it does not already appear in the database."]
#[doc="This flag may only be specified if the database was opened with `MDB_DUPSORT`."]
#[doc="The function will return `LmdbError::KeyExist` if the item already appears in the"]
#[doc="database."]
const MDB_NODUPDATA = 0x20,
#[doc="For `Cursor::put`. Replace the item at the current cursor position."]
#[doc="The key parameter must match the current position. If using"]
#[doc="sorted duplicates (`MDB_DUPSORT`) the data item must still sort into the"]
#[doc="same position. This is intended to be used when the new data is the same"]
#[doc="size as the old. Otherwise it will simply perform a delete of the old"]
#[doc="record followed by an insert."]
const MDB_CURRENT = 0x40,
#[doc="Append the given item to the end of the database. No key comparisons are performed."]
#[doc="This option allows fast bulk loading when keys are already known to be in the"]
#[doc="correct order. Loading unsorted keys with this flag will cause data corruption."]
const MDB_APPEND = 0x20000,
#[doc="Same as `MDB_APPEND`, but for sorted dup data."]
const MDB_APPENDDUP = 0x40000,
}
}

@ -22,6 +22,7 @@ pub use cursor::{
pub use database::Database; pub use database::Database;
pub use environment::{Environment, EnvironmentBuilder}; pub use environment::{Environment, EnvironmentBuilder};
pub use error::{LmdbResult, LmdbError}; pub use error::{LmdbResult, LmdbError};
pub use flags::*;
pub use transaction::{ pub use transaction::{
InactiveTransaction, InactiveTransaction,
RoTransaction, RoTransaction,
@ -29,7 +30,6 @@ pub use transaction::{
Transaction, Transaction,
TransactionExt, TransactionExt,
}; };
pub use ffi::{DatabaseFlags, EnvironmentFlags, WriteFlags};
macro_rules! lmdb_try { macro_rules! lmdb_try {
($expr:expr) => ({ ($expr:expr) => ({
@ -52,6 +52,7 @@ macro_rules! lmdb_try_with_cleanup {
}) })
} }
mod flags;
mod cursor; mod cursor;
mod database; mod database;
mod environment; mod environment;

@ -3,13 +3,13 @@ use std::{mem, ptr, raw};
use std::kinds::marker; use std::kinds::marker;
use std::io::BufWriter; use std::io::BufWriter;
use ffi;
use cursor::{RoCursor, RwCursor}; use cursor::{RoCursor, RwCursor};
use environment::Environment; use environment::Environment;
use database::Database; use database::Database;
use error::{LmdbError, LmdbResult, lmdb_result}; use error::{LmdbError, LmdbResult, lmdb_result};
use ffi; use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags};
use ffi::MDB_txn;
use ffi::{DatabaseFlags, EnvironmentFlags, WriteFlags, MDB_RDONLY, MDB_RESERVE};
/// An LMDB transaction. /// An LMDB transaction.
/// ///
@ -20,7 +20,7 @@ pub trait Transaction<'env> {
/// ///
/// The caller **must** ensure that the pointer is not used after the lifetime of the /// The caller **must** ensure that the pointer is not used after the lifetime of the
/// transaction. /// transaction.
fn txn(&self) -> *mut MDB_txn; fn txn(&self) -> *mut ffi::MDB_txn;
} }
/// Transaction extension methods. /// Transaction extension methods.
@ -90,7 +90,7 @@ impl<'env, T> TransactionExt<'env> for T where T: Transaction<'env> {}
/// An LMDB read-only transaction. /// An LMDB read-only transaction.
pub struct RoTransaction<'env> { pub struct RoTransaction<'env> {
txn: *mut MDB_txn, txn: *mut ffi::MDB_txn,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
_no_send: marker::NoSend, _no_send: marker::NoSend,
_contravariant: marker::ContravariantLifetime<'env>, _contravariant: marker::ContravariantLifetime<'env>,
@ -109,11 +109,11 @@ impl <'env> RoTransaction<'env> {
/// `Environment::begin_ro_txn`. /// `Environment::begin_ro_txn`.
#[doc(hidden)] #[doc(hidden)]
pub fn new(env: &'env Environment) -> LmdbResult<RoTransaction<'env>> { pub fn new(env: &'env Environment) -> LmdbResult<RoTransaction<'env>> {
let mut txn: *mut MDB_txn = ptr::null_mut(); let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe { unsafe {
try!(lmdb_result(ffi::mdb_txn_begin(env.env(), try!(lmdb_result(ffi::mdb_txn_begin(env.env(),
ptr::null_mut(), ptr::null_mut(),
MDB_RDONLY.bits(), ffi::MDB_RDONLY,
&mut txn))); &mut txn)));
Ok(RoTransaction { Ok(RoTransaction {
txn: txn, txn: txn,
@ -141,13 +141,13 @@ impl <'env> RoTransaction<'env> {
} }
impl <'env> Transaction<'env> for RoTransaction<'env> { impl <'env> Transaction<'env> for RoTransaction<'env> {
fn txn(&self) -> *mut MDB_txn { fn txn(&self) -> *mut ffi::MDB_txn {
self.txn self.txn
} }
} }
pub struct InactiveTransaction<'env> { pub struct InactiveTransaction<'env> {
txn: *mut MDB_txn, txn: *mut ffi::MDB_txn,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
_no_send: marker::NoSend, _no_send: marker::NoSend,
_contravariant: marker::ContravariantLifetime<'env>, _contravariant: marker::ContravariantLifetime<'env>,
@ -179,7 +179,7 @@ impl <'env> InactiveTransaction<'env> {
/// An LMDB read-write transaction. /// An LMDB read-write transaction.
pub struct RwTransaction<'env> { pub struct RwTransaction<'env> {
txn: *mut MDB_txn, txn: *mut ffi::MDB_txn,
_no_sync: marker::NoSync, _no_sync: marker::NoSync,
_no_send: marker::NoSend, _no_send: marker::NoSend,
_contravariant: marker::ContravariantLifetime<'env>, _contravariant: marker::ContravariantLifetime<'env>,
@ -198,7 +198,7 @@ impl <'env> RwTransaction<'env> {
/// `Environment::begin_ro_txn`. /// `Environment::begin_ro_txn`.
#[doc(hidden)] #[doc(hidden)]
pub fn new(env: &'env Environment) -> LmdbResult<RwTransaction<'env>> { pub fn new(env: &'env Environment) -> LmdbResult<RwTransaction<'env>> {
let mut txn: *mut MDB_txn = ptr::null_mut(); let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe { unsafe {
try!(lmdb_result(ffi::mdb_txn_begin(env.env(), try!(lmdb_result(ffi::mdb_txn_begin(env.env(),
ptr::null_mut(), ptr::null_mut(),
@ -259,7 +259,7 @@ impl <'env> RwTransaction<'env> {
database.dbi(), database.dbi(),
&mut key_val, &mut key_val,
&mut data_val, &mut data_val,
flags.bits() | MDB_RESERVE))); flags.bits() | ffi::MDB_RESERVE)));
let slice: &'txn mut [u8] = let slice: &'txn mut [u8] =
mem::transmute(raw::Slice { mem::transmute(raw::Slice {
data: data_val.mv_data as *const u8, data: data_val.mv_data as *const u8,
@ -313,7 +313,7 @@ impl <'env> RwTransaction<'env> {
} }
impl <'env> Transaction<'env> for RwTransaction<'env> { impl <'env> Transaction<'env> for RwTransaction<'env> {
fn txn(&self) -> *mut MDB_txn { fn txn(&self) -> *mut ffi::MDB_txn {
self.txn self.txn
} }
} }
@ -327,8 +327,10 @@ mod test {
use std::sync::{Arc, Barrier, Future}; use std::sync::{Arc, Barrier, Future};
use test::{Bencher, black_box}; use test::{Bencher, black_box};
use environment::*;
use ffi::*; use ffi::*;
use environment::*;
use flags::*;
use super::*; use super::*;
use test_utils::*; use test_utils::*;

Loading…
Cancel
Save