diff --git a/lmdb-sys/src/constants.rs b/lmdb-sys/src/constants.rs index dfc5d69..227c685 100644 --- a/lmdb-sys/src/constants.rs +++ b/lmdb-sys/src/constants.rs @@ -81,66 +81,45 @@ pub const MDB_CP_COMPACT: c_uint = 0x01; /// Successful result. pub const MDB_SUCCESS: c_int = 0; - /// key/data pair already exists. pub const MDB_KEYEXIST: c_int = -30799; - /// key/data pair not found (EOF). pub const MDB_NOTFOUND: c_int = -30798; - /// Requested page not found - this usually indicates corruption. pub const MDB_PAGE_NOTFOUND: c_int = -30797; - /// Located page was wrong type. pub const MDB_CORRUPTED: c_int = -30796; - /// Update of meta page failed or environment had fatal error. -pub const MDB_PANIC : c_int = -30795; - +pub const MDB_PANIC: c_int = -30795; /// Environment version mismatch. pub const MDB_VERSION_MISMATCH: c_int = -30794; - /// File is not a valid LMDB file. pub const MDB_INVALID: c_int = -30793; - /// Environment mapsize reached. pub const MDB_MAP_FULL: c_int = -30792; - /// Environment maxdbs reached. pub const MDB_DBS_FULL: c_int = -30791; - /// Environment maxreaders reached. pub const MDB_READERS_FULL: c_int = -30790; - /// Too many TLS keys in use - Windows only. pub const MDB_TLS_FULL: c_int = -30789; - /// Txn has too many dirty pages. pub const MDB_TXN_FULL: c_int = -30788; - /// Cursor stack too deep - internal error. pub const MDB_CURSOR_FULL: c_int = -30787; - /// Page has not enough space - internal error. pub const MDB_PAGE_FULL: c_int = -30786; - /// Database contents grew beyond environment mapsize. pub const MDB_MAP_RESIZED: c_int = -30785; - /// MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed. pub const MDB_INCOMPATIBLE: c_int = -30784; - /// Invalid reuse of reader locktable slot. pub const MDB_BAD_RSLOT: c_int = -30783; - /// Transaction cannot recover - it must be aborted. pub const MDB_BAD_TXN: c_int = -30782; - /// Unsupported size of key/DB name/data, or wrong DUPFIXED size. pub const MDB_BAD_VALSIZE: c_int = -30781; - /// The specified DBI was changed unexpectedly. pub const MDB_BAD_DBI: c_int = -30780; - /// The last defined error code. pub const MDB_LAST_ERRCODE: c_int = MDB_BAD_DBI; diff --git a/src/cursor.rs b/src/cursor.rs index 6eeec94..35994db 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -147,8 +147,8 @@ impl <'txn> RwCursor<'txn> { /// /// ### Flags /// - /// `MDB_NODUPDATA` may be used to delete all data items for the current key, if the database - /// was opened with `MDB_DUPSORT`. + /// `NO_DUP_DATA` may be used to delete all data items for the current key, if the database + /// was opened with `DUP_SORT`. pub fn del(&self, flags: WriteFlags) -> LmdbResult<()> { unsafe { lmdb_result(ffi::mdb_cursor_del(self.cursor(), flags.bits())) @@ -283,7 +283,7 @@ mod test { fn test_get_dup() { let dir = io::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); - let db = env.create_db(None, MDB_DUPSORT).unwrap(); + let db = env.create_db(None, DUP_SORT).unwrap(); let mut txn = env.begin_write_txn().unwrap(); txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap(); @@ -329,7 +329,7 @@ mod test { fn test_get_dupfixed() { let dir = io::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); - let db = env.create_db(None, MDB_DUPSORT | MDB_DUPFIXED).unwrap(); + let db = env.create_db(None, DUP_SORT | DUP_FIXED).unwrap(); let mut txn = env.begin_write_txn().unwrap(); txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap(); diff --git a/src/environment.rs b/src/environment.rs index 150af44..f0b6efe 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -242,7 +242,7 @@ mod test { let dir = io::TempDir::new("test").unwrap(); // opening non-existent env with read-only should fail - assert!(Environment::new().set_flags(MDB_RDONLY) + assert!(Environment::new().set_flags(READ_ONLY) .open(dir.path(), io::USER_RWX) .is_err()); @@ -250,7 +250,7 @@ mod test { assert!(Environment::new().open(dir.path(), io::USER_RWX).is_ok()); // opening env with read-only should succeed - assert!(Environment::new().set_flags(MDB_RDONLY) + assert!(Environment::new().set_flags(READ_ONLY) .open(dir.path(), io::USER_RWX) .is_ok()); } @@ -267,7 +267,7 @@ mod test { } { // read-only environment - let env = Environment::new().set_flags(MDB_RDONLY) + let env = Environment::new().set_flags(READ_ONLY) .open(dir.path(), io::USER_RWX) .unwrap(); @@ -305,7 +305,7 @@ mod test { let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); assert!(env.sync(true).is_ok()); } { - let env = Environment::new().set_flags(MDB_RDONLY) + let env = Environment::new().set_flags(READ_ONLY) .open(dir.path(), io::USER_RWX) .unwrap(); assert!(env.sync(true).is_ok()); diff --git a/src/error.rs b/src/error.rs index 805da8b..918d43e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,19 +5,108 @@ use std::str; use ffi; #[deriving(Show, Eq, PartialEq, Copy, Clone)] -pub struct LmdbError { - err_code: c_int, +pub enum LmdbError { + /// key/data pair already exists. + KeyExist, + /// key/data pair not found (EOF). + NotFound, + /// Requested page not found - this usually indicates corruption. + PageNotFound, + /// Located page was wrong type. + Corrupted, + /// Update of meta page failed or environment had fatal error. + Panic, + /// Environment version mismatch. + VersionMismatch, + /// File is not a valid LMDB file. + Invalid, + /// Environment mapsize reached. + MapFull, + /// Environment maxdbs reached. + DbsFull, + /// Environment maxreaders reached. + ReadersFull, + /// Too many TLS keys in use - Windows only. + TlsFull, + /// Txn has too many dirty pages. + TxnFull, + /// Cursor stack too deep - internal error. + CursorFull, + /// Page has not enough space - internal error. + PageFull, + /// Database contents grew beyond environment mapsize. + MapResized, + /// MDB_Incompatible: Operation and DB incompatible, or DB flags changed. + Incompatible, + /// Invalid reuse of reader locktable slot. + BadRslot, + /// Transaction cannot recover - it must be aborted. + BadTxn, + /// Unsupported size of key/DB name/data, or wrong DUP_FIXED size. + BadValSize, + /// The specified DBI was changed unexpectedly. + BadDbi, + /// Other error. + Other(c_int), } -impl Error for LmdbError { - fn description(&self) -> &str { - unsafe { str::from_c_str(ffi::mdb_strerror(self.err_code) as *const _) } +impl LmdbError { + pub fn from_err_code(err_code: c_int) -> LmdbError { + match err_code { + ffi::MDB_KEYEXIST => LmdbError::KeyExist, + ffi::MDB_NOTFOUND => LmdbError::NotFound, + ffi::MDB_PAGE_NOTFOUND => LmdbError::PageNotFound, + ffi::MDB_CORRUPTED => LmdbError::Corrupted, + ffi::MDB_PANIC => LmdbError::Panic, + ffi::MDB_VERSION_MISMATCH => LmdbError::VersionMismatch, + ffi::MDB_INVALID => LmdbError::Invalid, + ffi::MDB_MAP_FULL => LmdbError::MapFull, + ffi::MDB_DBS_FULL => LmdbError::DbsFull, + ffi::MDB_READERS_FULL => LmdbError::ReadersFull, + ffi::MDB_TLS_FULL => LmdbError::TlsFull, + ffi::MDB_TXN_FULL => LmdbError::TxnFull, + ffi::MDB_CURSOR_FULL => LmdbError::CursorFull, + ffi::MDB_PAGE_FULL => LmdbError::PageFull, + ffi::MDB_MAP_RESIZED => LmdbError::MapResized, + ffi::MDB_INCOMPATIBLE => LmdbError::Incompatible, + ffi::MDB_BAD_RSLOT => LmdbError::BadRslot, + ffi::MDB_BAD_TXN => LmdbError::BadTxn, + ffi::MDB_BAD_VALSIZE => LmdbError::BadValSize, + ffi::MDB_BAD_DBI => LmdbError::BadDbi, + other => LmdbError::Other(other), + } + } + + pub fn to_err_code(&self) -> c_int { + match *self { + LmdbError::KeyExist => ffi::MDB_KEYEXIST, + LmdbError::NotFound => ffi::MDB_NOTFOUND, + LmdbError::PageNotFound => ffi::MDB_PAGE_NOTFOUND, + LmdbError::Corrupted => ffi::MDB_CORRUPTED, + LmdbError::Panic => ffi::MDB_PANIC, + LmdbError::VersionMismatch => ffi::MDB_VERSION_MISMATCH, + LmdbError::Invalid => ffi::MDB_INVALID, + LmdbError::MapFull => ffi::MDB_MAP_FULL, + LmdbError::DbsFull => ffi::MDB_DBS_FULL, + LmdbError::ReadersFull => ffi::MDB_READERS_FULL, + LmdbError::TlsFull => ffi::MDB_TLS_FULL, + LmdbError::TxnFull => ffi::MDB_TXN_FULL, + LmdbError::CursorFull => ffi::MDB_CURSOR_FULL, + LmdbError::PageFull => ffi::MDB_PAGE_FULL, + LmdbError::MapResized => ffi::MDB_MAP_RESIZED, + LmdbError::Incompatible => ffi::MDB_INCOMPATIBLE, + LmdbError::BadRslot => ffi::MDB_BAD_RSLOT, + LmdbError::BadTxn => ffi::MDB_BAD_TXN, + LmdbError::BadValSize => ffi::MDB_BAD_VALSIZE, + LmdbError::BadDbi => ffi::MDB_BAD_DBI, + LmdbError::Other(err_code) => err_code, + } } } -impl LmdbError { - pub fn from_err_code(err_code: c_int) -> LmdbError { - LmdbError { err_code: err_code} +impl Error for LmdbError { + fn description(&self) -> &str { + unsafe { str::from_c_str(ffi::mdb_strerror(self.to_err_code()) as *const _) } } } @@ -37,14 +126,13 @@ mod test { use std::error::Error; use super::*; - use ffi; #[test] fn test_description() { assert_eq!("Permission denied", LmdbError::from_err_code(13).description()); assert_eq!("MDB_NOTFOUND: No matching key/data pair found", - LmdbError::from_err_code(ffi::MDB_NOTFOUND).description()); + LmdbError::NotFound.description()); } } diff --git a/src/flags.rs b/src/flags.rs index 91ae811..8016aa5 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -1,5 +1,7 @@ use libc::c_uint; +use ffi::*; + bitflags! { #[doc="Environment Options"] #[deriving(Show)] @@ -12,25 +14,25 @@ bitflags! { #[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 FIXED_MAP = 0x01, + const FIXED_MAP = MDB_FIXEDMAP, #[doc="By default, LMDB creates its environment in a directory whose pathname is given in"] #[doc="`path`, and creates its data and lock files under that directory. With this option,"] #[doc="`path` is used as-is for the database main data file. The database lock file is the"] #[doc="`path` with `-lock` appended."] - const NO_SUB_DIR = 0x4000, + const NO_SUB_DIR = MDB_NOSUBDIR, #[doc="Use a writeable memory map unless `READ_ONLY` 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 `WRITEMAP` on the same environment do not cooperate"] + #[doc="Processes with and without `WRITE_MAP` on the same environment do not cooperate"] #[doc="well."] - const WRITEMAP = 0x80000, + const WRITE_MAP = MDB_WRITEMAP, #[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 READ_ONLY = 0x20000, + const READ_ONLY = MDB_RDONLY, #[doc="Flush system buffers to disk only once per transaction, omit the metadata flush."] #[doc="Defer that until the system flushes files to disk, or next non-`READ_ONLY` commit"] @@ -38,26 +40,26 @@ bitflags! { #[doc="system crash may undo the last committed transaction. I.e. it preserves the ACI"] #[doc="(atomicity, consistency, isolation) but not D (durability) database property."] #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."] - const NO_META_SYNC = 0x40000, + const NO_META_SYNC = MDB_NOMETASYNC, #[doc="Don't flush system buffers to disk when committing a transaction. This optimization"] #[doc="means a system crash can corrupt the database or lose the last transactions if"] #[doc="buffers are not yet flushed to disk. The risk is governed by how often the system"] #[doc="flushes dirty buffers to disk and how often `Environment::sync` is called. However,"] - #[doc="if the filesystem preserves write order and the `WRITEMAP` flag is not used,"] + #[doc="if the filesystem preserves write order and the `WRITE_MAP` flag is not used,"] #[doc="transactions exhibit ACI (atomicity, consistency, isolation) properties and only"] #[doc="lose D (durability). I.e. database integrity"] #[doc="is maintained, but a system"] - #[doc="crash may undo the final transactions. Note that (`NO_SYNC | WRITEMAP`) leaves the"] + #[doc="crash may undo the final transactions. Note that (`NO_SYNC | WRITE_MAP`) leaves the"] #[doc="system with no hint for when to write transactions to disk, unless"] - #[doc="`Environment::sync` is called. (`MAP_ASYNC | WRITEMAP`) may be preferable."] + #[doc="`Environment::sync` is called. (`MAP_ASYNC | WRITE_MAP`) may be preferable."] #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."] - const NO_SYNC = 0x10000, + const NO_SYNC = MDB_NOSYNC, - #[doc="When using `WRITEMAP`, use asynchronous flushes to disk. As with `NO_SYNC`, a"] + #[doc="When using `WRITE_MAP`, use asynchronous flushes to disk. As with `NO_SYNC`, a"] #[doc="system crash can then corrupt the database or lose the last transactions. Calling"] #[doc="`Environment::sync` ensures on-disk database integrity until next commit."] #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."] - const MAP_ASYNC = 0x100000, + const MAP_ASYNC = MDB_MAPASYNC, #[doc="Don't use thread-local storage. Tie reader locktable slots to transaction objects"] #[doc="instead of to threads. I.e. `RoTransaction::reset` keeps the slot reseved for the"] @@ -67,20 +69,20 @@ bitflags! { #[doc="threads over individual OS threads need this option. Such an application must also"] #[doc="serialize the write transactions in an OS thread, since LMDB's write locking is"] #[doc="unaware of the user threads."] - const NO_TLS = 0x200000, + const NO_TLS = MDB_NOTLS, #[doc="Do not do any locking. If concurrent access is anticipated, the caller must manage"] #[doc="all concurrency themself. For proper operation the caller must enforce"] #[doc="single-writer semantics, and must ensure that no readers are using old"] #[doc="transactions while a writer is active. The simplest approach is to use an exclusive"] #[doc="lock so that no readers may be active at all when a writer begins."] - const NO_LOCK = 0x400000, + const NO_LOCK = MDB_NOLOCK, #[doc="Turn off readahead. Most operating systems perform readahead on read requests by"] #[doc="default. This option turns it off if the OS supports it. Turning it off may help"] #[doc="random read performance when the DB is larger than RAM and system RAM is full."] #[doc="The option is not implemented on Windows."] - const NO_READAHEAD = 0x800000, + const NO_READAHEAD = MDB_NORDAHEAD, #[doc="Do not initialize malloc'd memory before writing to unused spaces in the data file."] #[doc="By default, memory for pages written to the data file is obtained using malloc."] @@ -92,12 +94,12 @@ bitflags! { #[doc="initialization step has a modest performance cost so some applications may want to"] #[doc="disable it using this flag. This option can be a problem for applications which"] #[doc="handle sensitive data like passwords, and it makes memory checkers like Valgrind"] - #[doc="noisy. This flag is not needed with `WRITEMAP`, which writes directly to the mmap"] + #[doc="noisy. This flag is not needed with `WRITE_MAP`, which writes directly to the mmap"] #[doc="instead of using malloc for pages. The initialization is also skipped if writing"] #[doc="with reserve; the 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 NO_MEM_INIT = 0x1000000, + const NO_MEM_INIT = MDB_NOMEMINIT, } } @@ -109,31 +111,31 @@ bitflags! { #[doc="Keys are strings to be compared in reverse order, from the end of the strings"] #[doc="to the beginning. By default, Keys are treated as strings and compared from"] #[doc="beginning to end."] - const REVERSE_KEY = 0x02, + const REVERSE_KEY = MDB_REVERSEKEY, #[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 DUP_SORT = 0x04, + const DUP_SORT = MDB_DUPSORT, #[doc="Keys are binary integers in native byte order. Setting this option requires all"] #[doc="keys to be the same size, typically 32 or 64 bits."] - const INTEGER_KEY = 0x08, + const INTEGER_KEY = MDB_INTEGERKEY, #[doc="This flag may only be used in combination with `DUP_SORT`. This option tells"] #[doc="the library that the data items for this database are all the same size, which"] #[doc="allows further optimizations in storage and retrieval. When all data items are"] #[doc="the same size, the `GET_MULTIPLE` and `NEXT_MULTIPLE` cursor operations may be"] #[doc="used to retrieve multiple items at once."] - const DUP_FIXED = 0x10, + const DUP_FIXED = MDB_DUPFIXED, #[doc="This option specifies that duplicate data items are also integers, and"] #[doc="should be sorted as such."] - const INTEGER_DUP = 0x20, + const INTEGER_DUP = MDB_INTEGERDUP, #[doc="This option specifies that duplicate data items should be compared as strings"] #[doc="in reverse order."] - const REVERSE_DUP = 0x40, + const REVERSE_DUP = MDB_REVERSEDUP, } } @@ -145,27 +147,27 @@ bitflags! { #[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 (`DUP_SORT`)."] - const NO_OVERWRITE = 0x10, + const NO_OVERWRITE = MDB_NOOVERWRITE, #[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 `DUP_SORT`."] #[doc="The function will return `LmdbError::KeyExist` if the item already appears in the"] #[doc="database."] - const NO_DUP_DATA = 0x20, + const NO_DUP_DATA = MDB_NODUPDATA, #[doc="For `Cursor::put`. Replace the item at the current cursor position. The key"] #[doc="parameter must match the current position. If using sorted duplicates (`DUP_SORT`)"] #[doc="the data item must still sort into the same position. This is intended to be used"] #[doc="when the new data is the same size as the old. Otherwise it will simply perform a"] #[doc="delete of the old record followed by an insert."] - const CURRENT = 0x40, + const CURRENT = MDB_CURRENT, #[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 APPEND = 0x20000, + const APPEND = MDB_APPEND, #[doc="Same as `APPEND`, but for sorted dup data."] - const APPEND_DUP = 0x40000, + const APPEND_DUP = MDB_APPENDDUP, } }