lmdb_zero/
tx.rs

1// Copyright 2016 FullContact, Inc
2// Copyright 2017 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use std::cell::Cell;
11use std::mem;
12use std::ops::{Deref, DerefMut};
13use std::ptr;
14use libc::c_uint;
15
16use ffi;
17use ffi2;
18use supercow::{Supercow, NonSyncSupercow};
19
20use env::{self, Environment, Stat};
21use dbi::{db, Database};
22use error::{Error, Result};
23use mdb_vals::*;
24use traits::*;
25use cursor::{self, Cursor, StaleCursor};
26
27/// Flags used when calling the various `put` functions.
28pub mod put {
29    use ffi;
30    use libc;
31
32    bitflags! {
33        /// Flags used when calling the various `put` functions.
34        ///
35        /// Note that `RESERVE` and `MULTIPLE` are not exposed in these flags
36        /// because their memory ownership and/or parameter semantics are
37        /// different. `CURRENT` is expressed separately on the cursor
38        /// functions.
39        pub struct Flags : libc::c_uint {
40            /// Enter the new key/data pair only if it does not already appear
41            /// in the database. This flag may only be specified if the
42            /// database was opened with `DUPSORT`. The function will return
43            /// `KEYEXIST` if the key/data pair already appears in the
44            /// database.
45            ///
46            /// ## Example
47            ///
48            /// ```
49            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
50            /// # fn main() {
51            /// # let env = create_env();
52            /// let db = lmdb::Database::open(
53            ///   &env, Some("reversed"),
54            ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
55            ///   .unwrap();
56            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
57            /// {
58            ///   let mut access = txn.access();
59            ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
60            ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
61            ///   // Duplicate, but that's OK by default
62            ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
63            ///   // `NODUPDATA` blocks adding an identical item
64            ///   assert!(access.put(&db, "Fruit", "Apple", lmdb::put::NODUPDATA).is_err());
65            ///   // But doesn't affect pairs not already present
66            ///   access.put(&db, "Fruit", "Durian", lmdb::put::NODUPDATA).unwrap();
67            /// }
68            /// txn.commit().unwrap();
69            /// # }
70            /// ```
71            ///
72            /// When used on a cursor, the cursor is positioned at the
73            /// conflicting key/value pair if this results in a `KEYEXIST`
74            /// error.
75            ///
76            /// ```
77            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
78            /// # fn main() {
79            /// # let env = create_env();
80            /// let db = lmdb::Database::open(
81            ///   &env, Some("reversed"),
82            ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
83            ///   .unwrap();
84            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
85            /// {
86            ///   let mut access = txn.access();
87            ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
88            ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
89            ///   access.put(&db, "Fruit", "Durian", lmdb::put::Flags::empty()).unwrap();
90            ///
91            ///   let mut cursor = txn.cursor(&db).unwrap();
92            ///   assert_eq!(Err(lmdb::Error::Code(lmdb::error::KEYEXIST)),
93            ///              cursor.put(&mut access, "Fruit", "Durian",
94            ///                         lmdb::put::NODUPDATA));
95            ///   assert_eq!(("Fruit", "Durian"), cursor.get_current(&access).unwrap());
96            /// }
97            /// txn.commit().unwrap();
98            /// # }
99            /// ```
100            const NODUPDATA = ffi::MDB_NODUPDATA;
101            /// Enter the new key/data pair only if the key does not already
102            /// appear in the database. The function will return `KEYEXIST` if
103            /// the key already appears in the database, even if the database
104            /// supports duplicates (`DUPSORT`).
105            ///
106            /// ## Examples
107            ///
108            /// ### In a 1:1 database
109            ///
110            /// ```
111            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
112            /// # fn main() {
113            /// # let env = create_env();
114            /// let db = lmdb::Database::open(
115            ///   &env, None, &lmdb::DatabaseOptions::defaults())
116            ///   .unwrap();
117            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
118            /// {
119            ///   let mut access = txn.access();
120            ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
121            ///   // By default, collisions overwrite the old value
122            ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
123            ///   assert_eq!("Orange", access.get::<str,str>(&db, "Fruit").unwrap());
124            ///   // But `NOOVERWRITE` prevents that
125            ///   assert!(access.put(&db, "Fruit", "Durian", lmdb::put::NOOVERWRITE).is_err());
126            ///   assert_eq!("Orange", access.get::<str,str>(&db, "Fruit").unwrap());
127            /// }
128            /// txn.commit().unwrap();
129            /// # }
130            /// ```
131            ///
132            /// ### In a `DUPSORT` database
133            ///
134            /// ```
135            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
136            /// # fn main() {
137            /// # let env = create_env();
138            /// let db = lmdb::Database::open(
139            ///   &env, Some("reversed"),
140            ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
141            ///   .unwrap();
142            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
143            /// {
144            ///   let mut access = txn.access();
145            ///   // Ordinarily, we can add multiple items per key
146            ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
147            ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
148            ///   let mut cursor = txn.cursor(&db).unwrap();
149            ///   cursor.seek_k::<str,str>(&access, "Fruit").unwrap();
150            ///   assert_eq!(2, cursor.count().unwrap());
151            ///
152            ///   // But this can be prevented with `NOOVERWRITE`
153            ///   access.put(&db, "Veggie", "Carrot", lmdb::put::NOOVERWRITE).unwrap();
154            ///   assert!(access.put(&db, "Veggie", "Squash", lmdb::put::NOOVERWRITE).is_err());
155            ///   cursor.seek_k::<str,str>(&access, "Veggie").unwrap();
156            ///   assert_eq!(1, cursor.count().unwrap());
157            /// }
158            /// txn.commit().unwrap();
159            /// # }
160            /// ```
161            // TODO: "The data parameter will be set to point to the existing
162            // item." We should provide functionality to support that.
163            const NOOVERWRITE = ffi::MDB_NOOVERWRITE;
164            /// Append the given key/data pair to the end of the database. This
165            /// option allows fast bulk loading when keys are already known to
166            /// be in the correct order. Loading unsorted keys with this flag
167            /// will cause a `KEYEXIST` error.
168            ///
169            /// ## Example
170            ///
171            /// ```
172            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
173            /// # fn main() {
174            /// # let env = create_env();
175            /// let db = lmdb::Database::open(
176            ///   &env, None, &lmdb::DatabaseOptions::defaults())
177            ///   .unwrap();
178            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
179            /// {
180            ///   let mut access = txn.access();
181            ///   // Load values in ascending order
182            ///   access.put(&db, "France", "Paris", lmdb::put::APPEND).unwrap();
183            ///   access.put(&db, "Germany", "Berlin", lmdb::put::APPEND).unwrap();
184            ///   access.put(&db, "Latvia", "Rīga", lmdb::put::APPEND).unwrap();
185            ///   // Error if you violate ordering
186            ///   assert!(access.put(&db, "Armenia", "Yerevan", lmdb::put::APPEND)
187            ///           .is_err());
188            /// }
189            /// txn.commit().unwrap();
190            /// # }
191            /// ```
192            const APPEND = ffi::MDB_APPEND;
193            /// As with `APPEND` above, but for sorted dup data.
194            const APPENDDUP = ffi::MDB_APPENDDUP;
195        }
196    }
197}
198
199/// Flags used when deleting items.
200pub mod del {
201    use ffi;
202    use libc;
203
204    bitflags! {
205        /// Flags used when deleting items via cursors.
206        pub struct Flags : libc::c_uint {
207            /// Delete all of the data items for the current key instead of
208            /// just the current item. This flag may only be specified if the
209            /// database was opened with `DUPSORT`.
210            ///
211            /// ## Example
212            ///
213            /// ```
214            /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
215            /// # fn main() {
216            /// # let env = create_env();
217            /// let db = lmdb::Database::open(
218            ///   &env, Some("reversed"),
219            ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
220            ///   .unwrap();
221            /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
222            /// {
223            ///   let mut access = txn.access();
224            ///   let f = lmdb::put::Flags::empty();
225            ///   access.put(&db, "Fruit", "Apple", f).unwrap();
226            ///   access.put(&db, "Fruit", "Orange", f).unwrap();
227            ///   access.put(&db, "Fruit", "Durian", f).unwrap();
228            ///
229            ///   let mut cursor = txn.cursor(&db).unwrap();
230            ///   cursor.seek_kv("Fruit", "Durian").unwrap();
231            ///   // By default, only the current item is deleted.
232            ///   cursor.del(&mut access, lmdb::del::Flags::empty()).unwrap();
233            ///   cursor.seek_k::<str,str>(&access, "Fruit").unwrap();
234            ///   assert_eq!(2, cursor.count().unwrap());
235            ///   // But with `NODUPDATA`, they will all go away
236            ///   cursor.del(&mut access, lmdb::del::NODUPDATA).unwrap();
237            ///   assert!(cursor.seek_k::<str,str>(&access, "Fruit").is_err());
238            /// }
239            /// txn.commit().unwrap();
240            /// # }
241            /// ```
242            const NODUPDATA = ffi::MDB_NODUPDATA;
243        }
244    }
245}
246
247// This is internal, but used by other parts of the library
248#[derive(Debug)]
249pub struct TxHandle(pub *mut ffi::MDB_txn);
250
251impl Drop for TxHandle {
252    fn drop(&mut self) {
253        if !self.0.is_null() {
254            unsafe {
255                ffi::mdb_txn_abort(self.0);
256            }
257            self.0 = ptr::null_mut();
258        }
259    }
260}
261
262impl TxHandle {
263    pub unsafe fn commit(&mut self) -> Result<()> {
264        let txn_p = mem::replace(&mut self.0, ptr::null_mut());
265        lmdb_call!(ffi::mdb_txn_commit(txn_p));
266        Ok(())
267    }
268}
269
270/// Base functionality for an LMDB transaction.
271///
272/// The type is "const" in a similar usage to the modifier in C: One cannot use
273/// it to make any modifications, but also cannot rely on it actually being
274/// read-only. `ConstTransaction`s are used to write code that can operate in
275/// either kind of transaction.
276///
277/// Unlike most other LMDB wrappers, transactions here are (indirectly) the
278/// things in control of accessing data behind cursors. This is in order to
279/// correctly express memory semantics: Moving a cursor does not invalidate
280/// memory obtained from the cursor; however, any mutation through the same
281/// transaction does. We therefore model accesses to data in the environment as
282/// borrows of the transaction and the database themselves (possibly mutable on
283/// the latter), which allows the borrow checker to ensure that all references
284/// are dropped before doing a structural modification.
285///
286/// Note that due to limitations in the Rust borrow checker, one actually needs
287/// to use the `*Accessor` structs to access data. Any transaction will yield
288/// at most one accessor, which is implemented with a runtime check that should
289/// in the vast majority of cases get optimised out.
290///
291/// Mutability of a transaction reference does not indicate mutability of the
292/// underlying database, but rather exclusivity for enforcement of child
293/// transaction semantics.
294///
295/// ## Ownership
296///
297/// Transactions support all three ownership modes (but owned mode is not
298/// useful). See `ReadTransaction` and `WriteTransaction` for details.
299///
300/// ## Lifetime
301///
302/// A `ConstTransaction` must be strictly outlived by its `Environment`.
303///
304/// `'env` is covariant: given two lifetimes `'x` and `'y` where `'x: 'y`, a
305/// `&ConstTransaction<'x>` will implicitly coerce to `&ConstTransaction<'y>`.
306///
307/// ```rust,norun
308/// # #![allow(dead_code)]
309/// # extern crate lmdb_zero as lmdb;
310/// # fn main() { }
311/// #
312/// fn convariance<'x, 'y>(db: &lmdb::ConstTransaction<'x>)
313/// where 'x: 'y {
314///   let _db2: &lmdb::ConstTransaction<'y> = db;
315/// }
316/// ```
317///
318/// Because of this property, if you need to hold onto an
319/// `&lmdb::ConstTransaction` and must explicitly name both lifetimes,
320/// it is usually best to use the same lifetime for both the reference and the
321/// parameter, eg `&'x lmdb::ConstTransaction<'x>`.
322#[derive(Debug)]
323pub struct ConstTransaction<'env> {
324    env: NonSyncSupercow<'env, Environment>,
325    tx: TxHandle,
326    has_yielded_accessor: Cell<bool>,
327}
328
329/// A read-only LMDB transaction.
330///
331/// In addition to all operations valid on `ConstTransaction`, a
332/// `ReadTransaction` can additionally operate on cursors with a lifetime
333/// scoped to the environment instead of the transaction.
334///
335/// ## Ownership
336///
337/// `ReadTransaction`s can be created with all three ownership modes (but owned
338/// mode is not useful).
339///
340/// ### Example — Shared mode
341///
342/// ```
343/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
344/// use std::sync::Arc;
345///
346/// # fn main() {
347/// let env = Arc::new(create_env());
348/// let db = Arc::new(lmdb::Database::open(
349///   env.clone(), None, &lmdb::DatabaseOptions::defaults()).unwrap());
350///
351/// // Type and lifetime annotated explicitly for clarity
352/// let txn: lmdb::ReadTransaction<'static> = lmdb::ReadTransaction::new(
353///   env.clone()).unwrap();
354///
355/// // Do stuff with `txn`...
356/// # drop(txn); drop(db);
357/// # }
358/// ```
359///
360/// ## Lifetime
361///
362/// All notes for `ConstTransaction` apply.
363#[derive(Debug)]
364// This MUST be a newtype struct and MUST NOT `impl Drop`
365pub struct ReadTransaction<'env>(ConstTransaction<'env>);
366/// A read-write LMDB transaction.
367///
368/// In addition to all operations valid on `ConstTransaction`, it is also
369/// possible to perform writes to the underlying databases.
370///
371///
372/// ## Ownership
373///
374/// `WriteTransaction`s can be created with all three ownership modes (but
375/// owned mode is not useful).
376///
377/// ### Example — Shared mode
378///
379/// ```
380/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
381/// use std::sync::Arc;
382///
383/// # fn main() {
384/// let env = Arc::new(create_env());
385/// let db = Arc::new(lmdb::Database::open(
386///   env.clone(), None, &lmdb::DatabaseOptions::defaults()).unwrap());
387///
388/// // Type and lifetime annotated explicitly for clarity
389/// let txn: lmdb::WriteTransaction<'static> = lmdb::WriteTransaction::new(
390///   env.clone()).unwrap();
391///
392/// // Do stuff with `txn`...
393///
394/// txn.commit().unwrap();
395/// # }
396/// ```
397///
398/// ## Lifetime
399///
400/// All notes for `ConstTransaction` apply.
401#[derive(Debug)]
402// This MUST be a newtype struct and MUST NOT `impl Drop`
403pub struct WriteTransaction<'env>(ConstTransaction<'env>);
404
405/// A read-only LMDB transaction that has been reset.
406///
407/// It can be renewed by calling `ResetTransaction::renew()`.
408///
409/// ## Lifetime
410///
411/// All notes for `ReadTransaction` apply.
412#[derive(Debug)]
413pub struct ResetTransaction<'env>(ReadTransaction<'env>);
414
415/// A read-only data accessor obtained from a `ConstTransaction`.
416///
417/// There is no corresponding `ReadAccessor`, since there are no additional
418/// operations one can do with a known-read-only accessor.
419///
420/// ## Lifetime
421///
422/// A `ConstAccessor` must be strictly outlived by its parent transaction. The
423/// parent transaction cannot be destroyed (committed, etc) until the borrow
424/// from the accessor ends. This in many cases requires adding an extra scope
425/// (with bare `{ }` braces) in which to obtain the accessor, as can be seen in
426/// many of the examples.
427///
428/// The lifitem of a reference to a `ConstAccessor` dictates the lifetime of
429/// the data accessed via the accessor.
430///
431/// The `'txn` lifetime parameter is covariant. That is, given two lifetimes
432/// `'x` and `'y` where `'x: 'y`, a `&ConstAccessor<'x>` can be implicitly
433/// coerced into a `&ConstAccessor<'y>`.
434///
435/// ```rust,norun
436/// # #![allow(dead_code)]
437/// # extern crate lmdb_zero as lmdb;
438/// # fn main() { }
439/// #
440/// fn convariance<'x, 'y>(db: &lmdb::ConstAccessor<'x>)
441/// where 'x: 'y {
442///   let _db2: &lmdb::ConstAccessor<'y> = db;
443/// }
444/// ```
445///
446/// Because of this property, if you need to hold onto an
447/// `&lmdb::ConstAccessor` and must explicitly name both lifetimes, it
448/// is usually best to use the same lifetime for both the reference and the
449/// parameter, eg `&'x lmdb::ConstAccessor<'x>`.
450#[derive(Debug)]
451pub struct ConstAccessor<'txn>(&'txn ConstTransaction<'txn>);
452
453/// ConstAccessor implements Drop trait so that if it gets
454/// dropped, a new accessor can be safely obtained
455impl<'txn> Drop for ConstAccessor<'txn> {
456    fn drop(&mut self) {
457        self.0.has_yielded_accessor.set(false)
458    }
459}
460
461/// A read-write data accessor obtained from a `WriteTransaction`.
462///
463/// All operations that can be performed on `ConstAccessor` can also be
464/// performed on `WriteAccessor`.
465///
466/// ## Lifetime
467///
468/// Nominally, `WriteAccessor` would behave the same as `ConstAccessor`.
469///
470/// However, there is never any useful reason to explicitly reference a
471/// `&WriteAccessor` (ie, a shared reference). Instead, one talks about a
472/// `&mut WriteAccessor`. The unfortunate consequence here is that the `'txn`
473/// lifetime ends up being _invariant_; that is, the following code will not
474/// compile:
475///
476/// ```rust,ignore
477/// # #![allow(dead_code)]
478/// # extern crate lmdb_zero as lmdb;
479/// # fn main() { }
480/// #
481/// fn convariance<'x, 'y>(db: &mut lmdb::WriteAccessor<'x>)
482/// where 'x: 'y {
483///   let _db2: &mut lmdb::WriteAccessor<'y> = db; // ERROR!
484/// }
485/// ```
486///
487/// The compiler's error messages here tend to be unhelpful. In certain cases,
488/// it will suggest changing the function declaration above to something like
489/// `&'x mut lmdb::WriteAccessor<'x>`. Applying such a fix when it is suggested
490/// _will appear to work_. But what happens is that you end up propagating
491/// `&'txn mut lmdb::WriteAccessor<'txn>` the whole way up your call stack.
492/// Since `'txn` is invariant, it is inferred to be exactly equal to the
493/// lifetime of the transaction, and now you've declared that the borrow from
494/// the transaction exists for the entire lifetime of the transaction. This
495/// means that you cannot actually commit the transaction.
496///
497/// Instead, make sure you always have separate type parameters on the `&mut`
498/// and the `WriteAccessor` itself. This can usually be accomplished by letting
499/// lifetime elision run its course. If you must name both, generally go with
500/// `&'access mut WriteAccessor<'txn>`. The `'access` lifetime is the lifetime
501/// of any data you obtain via the accessor.
502#[derive(Debug)]
503pub struct WriteAccessor<'txn>(ConstAccessor<'txn>);
504
505impl<'env> ConstTransaction<'env> {
506    fn new<'outer: 'env, E>(env: E,
507                            parent: Option<&'env mut ConstTransaction<'outer>>,
508                            flags: c_uint) -> Result<Self>
509    where E : Into<NonSyncSupercow<'env, Environment>> {
510        let env : NonSyncSupercow<'env, Environment> = env.into();
511
512        let mut rawtx: *mut ffi::MDB_txn = ptr::null_mut();
513        unsafe {
514            lmdb_call!(ffi::mdb_txn_begin(
515                env::env_ptr(&env), parent.map_or(ptr::null_mut(), |p| p.tx.0),
516                flags, &mut rawtx));
517        }
518
519        Ok(ConstTransaction {
520            env: env,
521            tx: TxHandle(rawtx),
522            has_yielded_accessor: Cell::new(false),
523        })
524    }
525
526    /// Returns an accessor used to manipulate data in this transaction.
527    ///
528    /// ## Ownership
529    ///
530    /// Unlike most other lmdb-zero APIs, accessors do not support shared
531    /// ownership modes (e.g., where the accessor would hold on to a
532    /// `Rc<ConstTransaction>`). If you need dynamically-managed lifetime,
533    /// instead simply drop the accessor and get a new one the next time one is
534    /// needed.
535    ///
536    /// ## Panics
537    ///
538    /// Panics if this function has already been called on this transaction and
539    /// the returned value has not yet been dropped.
540    ///
541    /// ## Example
542    ///
543    /// ```rust,should_panic
544    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
545    /// # #[allow(unused_vars)]
546    /// # fn main() {
547    /// # let env = create_env();
548    /// let txn = lmdb::ReadTransaction::new(&env).unwrap();
549    /// // Get access the first time
550    /// let access = txn.access();
551    ///
552    /// // You can't get the accessor again in the same scope, since this
553    /// // would create two references to the same logical memory and allow
554    /// // creating aliased mutable references and so forth.
555    /// let access2 = txn.access(); // PANIC!
556    /// # }
557    /// ```
558    #[inline]
559    pub fn access(&self) -> ConstAccessor {
560        assert!(!self.has_yielded_accessor.get(),
561                "Transaction accessor already returned");
562        self.has_yielded_accessor.set(true);
563        ConstAccessor(self)
564    }
565
566    /// Creates a new cursor scoped to this transaction, bound to the given
567    /// database.
568    ///
569    /// This method is functionally equivalent to the method on `CreateCursor`
570    /// and exists for convenience and backwards-compatibility.
571    ///
572    /// If you have an, e.g., `Rc<ReadTransaction>` and want to get a
573    /// `Cursor<'static,'db>`, make sure you have the `CreateCursor` trait
574    /// imported so that the needed alternate implementations of this method
575    /// are available.
576    #[inline]
577    pub fn cursor<'txn, 'db, DB>(&'txn self, db: DB)
578                                 -> Result<Cursor<'txn,'db>>
579    where DB : Into<Supercow<'db, Database<'db>>> {
580        Cursor::construct(Supercow::borrowed(self), db.into())
581    }
582
583    /// Returns the internal id of this transaction.
584    pub fn id(&self) -> usize {
585        unsafe {
586            ffi2::mdb_txn_id(self.tx.0)
587        }
588    }
589
590    /// Retrieves statistics for a database.
591    pub fn db_stat(&self, db: &Database) -> Result<Stat> {
592        try!(db.assert_same_env(&self.env));
593
594        unsafe {
595            let mut raw: ffi::MDB_stat = mem::zeroed();
596            lmdb_call!(ffi::mdb_stat(self.tx.0, db.as_raw(), &mut raw));
597            Ok(raw.into())
598        }
599    }
600
601    /// Retrieve the DB flags for a database handle.
602    pub fn db_flags(&self, db: &Database) -> Result<db::Flags> {
603        try!(db.assert_same_env(&self.env));
604
605        let mut raw: c_uint = 0;
606        unsafe {
607            lmdb_call!(ffi::mdb_dbi_flags(self.tx.0, db.as_raw(), &mut raw));
608        }
609        Ok(db::Flags::from_bits_truncate(raw))
610    }
611
612    #[inline]
613    fn assert_sensible_cursor(&self, cursor: &Cursor)
614                              -> Result<()> {
615        if self as *const ConstTransaction !=
616            cursor::txn_ref(cursor) as *const ConstTransaction
617        {
618            Err(Error::Mismatch)
619        } else {
620            Ok(())
621        }
622    }
623}
624
625// Internally used by other parts of the crate
626#[inline]
627pub fn assert_sensible_cursor(access: &ConstAccessor, cursor: &Cursor)
628                              -> Result<()> {
629    access.0.assert_sensible_cursor(cursor)
630}
631#[inline]
632pub fn assert_same_env(txn: &ConstTransaction, db: &Database)
633                       -> Result<()> {
634    db.assert_same_env(&txn.env)
635}
636#[inline]
637pub fn assert_in_env(txn: &ConstTransaction, env: &Environment)
638                     -> Result<()> {
639    if env as *const Environment != &*txn.env as *const Environment {
640        Err(Error::Mismatch)
641    } else {
642        Ok(())
643    }
644}
645#[inline]
646pub fn txptr(txn: &ConstTransaction) -> *mut ffi::MDB_txn {
647    txn.tx.0
648}
649
650impl<'env> Deref for ReadTransaction<'env> {
651    type Target = ConstTransaction<'env>;
652
653    fn deref(&self) -> &ConstTransaction<'env> {
654        &self.0
655    }
656}
657
658impl<'env> DerefMut for ReadTransaction<'env> {
659    fn deref_mut(&mut self) -> &mut ConstTransaction<'env> {
660        &mut self.0
661    }
662}
663
664impl<'env> ReadTransaction<'env> {
665    /// Opens a new, read-only transaction within the given environment.
666    ///
667    /// ## Note
668    ///
669    /// A transaction and its cursors must only be used by a single thread
670    /// (enforced by the rust compiler), and a thread may only have a single
671    /// transaction at a time. If `NOTLS` is in use, this does not apply to
672    /// read-only transactions. Attempting to open a read-only transaction
673    /// while the current thread holds a read-write transaction will deadlock.
674    pub fn new<E>(env: E) -> Result<Self>
675    where E : Into<NonSyncSupercow<'env, Environment>> {
676        Ok(ReadTransaction(try!(ConstTransaction::new(
677            env, None, ffi::MDB_RDONLY))))
678    }
679
680    /// Dissociates the given cursor from this transaction and its database,
681    /// returning a `StaleCursor` which can be reused later.
682    ///
683    /// This only fails if `cursor` does not belong to this transaction.
684    ///
685    /// ## Example
686    ///
687    /// ```
688    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
689    /// # fn main() {
690    /// # let env = create_env();
691    /// # let db = lmdb::Database::open(
692    /// #   &env, None, &lmdb::DatabaseOptions::defaults())
693    /// #   .unwrap();
694    /// let mut saved_cursor;
695    /// {
696    ///   let txn = lmdb::ReadTransaction::new(&env).unwrap();
697    ///   let cursor = txn.cursor(&db).unwrap();
698    ///   // Do some stuff with `txn` and `cursor`
699    ///
700    ///   // We don't want to realloc `cursor` next time, so save it away
701    ///   saved_cursor = txn.dissoc_cursor(cursor).unwrap();
702    /// } // Read transaction goes away, but our saved cursor remains
703    ///
704    /// {
705    ///   let txn = lmdb::ReadTransaction::new(&env).unwrap();
706    ///   // Rebind the old cursor. It continues operating on `db`.
707    ///   let cursor = txn.assoc_cursor(saved_cursor).unwrap();
708    ///   // Do stuff with txn, cursor
709    ///
710    ///   // We can save the cursor away again
711    ///   saved_cursor = txn.dissoc_cursor(cursor).unwrap();
712    /// }
713    /// # }
714    /// ```
715    ///
716    /// ## Example — Shared ownership mode
717    ///
718    /// Cursors can also be dissociated and reassociated with transactions with
719    /// shared ownership mode. This can also include changing the ownership
720    /// mode. To be able to use shared ownership mode, make sure that the
721    /// `AssocCursor` trait is imported or else you will simply borrow the
722    /// inner transaction instead of taking a copy of the `Rc`, etc.
723    ///
724    /// ```
725    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
726    /// use std::sync::Arc;
727    ///
728    /// use lmdb::traits::{AssocCursor, CreateCursor};
729    ///
730    /// # fn main() {
731    /// // N.B. Unnecessary type and lifetime annotations included for clarity
732    /// let env: Arc<lmdb::Environment> = Arc::new(create_env());
733    /// let db: Arc<lmdb::Database<'static>> = Arc::new(lmdb::Database::open(
734    ///   env.clone(), None, &lmdb::DatabaseOptions::defaults()).unwrap());
735    ///
736    /// let mut saved_cursor: lmdb::StaleCursor<'static>;
737    /// {
738    ///   // `Arc` is unnecessary in this trivial example, but let's pretend
739    ///   // there was good use for this.
740    ///   let txn: Arc<lmdb::ReadTransaction> = Arc::new(
741    ///     lmdb::ReadTransaction::new(env.clone()).unwrap());
742    ///   let cursor: lmdb::Cursor<'static, 'static> =
743    ///     txn.cursor(db.clone()).unwrap();
744    ///
745    ///   // Do some stuff with `txn` and `cursor`
746    ///
747    ///   // We don't want to realloc `cursor` next time, so save it away
748    ///   saved_cursor = txn.dissoc_cursor(cursor).unwrap();
749    /// }
750    ///
751    /// {
752    ///   let txn: Arc<lmdb::ReadTransaction<'static>> =
753    ///     Arc::new(lmdb::ReadTransaction::new(env.clone()).unwrap());
754    ///   // Rebind the old cursor. It continues operating on `db`.
755    ///   let cursor: lmdb::Cursor<'static, 'static> =
756    ///     txn.assoc_cursor(saved_cursor).unwrap();
757    ///   // Do stuff with txn, cursor
758    ///
759    ///   // We can save the cursor away again
760    ///   saved_cursor = txn.dissoc_cursor(cursor).unwrap();
761    /// }
762    /// # }
763    /// ```
764    pub fn dissoc_cursor<'txn,'db>(&self, cursor: Cursor<'txn,'db>)
765                                   -> Result<StaleCursor<'db>>
766    where 'env: 'db {
767        try!(self.assert_sensible_cursor(&cursor));
768        let env = Supercow::clone_non_owned(&self.env)
769            .expect("Cannot use owned `Environment` with `dissoc_cursor`");
770        Ok(cursor::to_stale(cursor, env))
771    }
772
773    /// Associates a saved read-only with this transaction.
774    ///
775    /// The cursor will be rebound to this transaction, but will continue using
776    /// the same database that it was previously.
777    ///
778    /// This method is functionally equivalent to the method on `AssocCursor`
779    /// and exists for convenience and backwards-compatibility.
780    ///
781    /// If you have an, e.g., `Rc<ReadTransaction>` and want to get a
782    /// `Cursor<'static,'db>`, make sure you have the `AssocCursor` trait
783    /// imported so that the needed alternate implementations of this method
784    /// are available.
785    pub fn assoc_cursor<'txn,'db>(&'txn self, cursor: StaleCursor<'db>)
786                                  -> Result<Cursor<'txn,'db>> {
787        let self_as_const: &'txn ConstTransaction = &*self;
788        Cursor::from_stale(cursor,
789                           NonSyncSupercow::borrowed(&*self_as_const))
790    }
791
792    /// Resets this transaction, releasing most of its resources but allowing
793    /// it to be quickly renewed if desired.
794    ///
795    /// ## Example
796    ///
797    /// ```
798    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
799    /// # fn main() {
800    /// # let env = create_env();
801    /// let mut saved_txn;
802    /// {
803    ///   let txn = lmdb::ReadTransaction::new(&env).unwrap();
804    ///   {
805    ///     let access = txn.access();
806    ///     // Do stuff with `txn`, `access`
807    ///   }
808    ///   // Save our transaction so we don't have to reallocate it next time,
809    ///   // but we also don't keep locks around and will later move to the
810    ///   // latest version of the environment.
811    ///   saved_txn = txn.reset();
812    /// }
813    ///
814    /// {
815    ///   // Instead of creating a brand new transaction, renew the one we
816    ///   // saved.
817    ///   let txn = saved_txn.renew().unwrap();
818    ///   {
819    ///     let access = txn.access();
820    ///     // Do stuff with `txn`, `access`
821    ///   }
822    ///
823    ///   // We can save the transaction away again
824    ///   saved_txn = txn.reset();
825    /// }
826    /// # }
827    /// ```
828    pub fn reset(self) -> ResetTransaction<'env> {
829        unsafe { ffi::mdb_txn_reset(self.0.tx.0); }
830        ResetTransaction(self)
831    }
832}
833
834impl<'env> ResetTransaction<'env> {
835    /// Renews this read-only transaction, making it available for more
836    /// reading.
837    pub fn renew(self) -> Result<ReadTransaction<'env>> {
838        unsafe { lmdb_call!(ffi::mdb_txn_renew((self.0).0.tx.0)); }
839        Ok(self.0)
840    }
841}
842
843impl<'env> Deref for WriteTransaction<'env> {
844    type Target = ConstTransaction<'env>;
845
846
847    fn deref(&self) -> &ConstTransaction<'env> {
848        &self.0
849    }
850}
851
852impl<'env> DerefMut for WriteTransaction<'env> {
853    fn deref_mut(&mut self) -> &mut ConstTransaction<'env> {
854        &mut self.0
855    }
856}
857
858impl<'env> WriteTransaction<'env> {
859    /// Creates a new, read-write transaction in the given environment.
860    ///
861    /// ## Note
862    ///
863    /// A transaction and its cursors must only be used by a single thread
864    /// (enforced by the rust compiler), and a thread may only have a single
865    /// read-write transaction at a time (even if `NOTLS` is in use --- trying
866    /// to start two top-level read-write transactions on the same thread will
867    /// deadlock).
868    pub fn new<E>(env: E) -> Result<Self>
869    where E : Into<NonSyncSupercow<'env, Environment>> {
870        Ok(WriteTransaction(try!(ConstTransaction::new(env, None, 0))))
871    }
872
873    /// Opens a new, read-write transaction as a child transaction of the given
874    /// parent. While the new transaction exists, no operations may be
875    /// performed on the parent or any of its cursors. (These bindings are
876    /// actually stricter, and do not permit cursors or other references into
877    /// the parent to coexist with the child transaction.)
878    ///
879    /// After this call, whether or not it succeeds, it is possible to call
880    /// `access()` on the original transaction again one more time, since the
881    /// Rust borrow rules guarantee the old accessor was destroyed by the
882    /// caller already.
883    ///
884    /// ## Note
885    ///
886    /// A transaction and its cursors must only be used by a single thread
887    /// (enforced by the rust compiler).
888    ///
889    /// ## Example
890    ///
891    /// ```
892    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
893    /// # fn main() {
894    /// # let env = create_env();
895    /// let db = lmdb::Database::open(
896    ///   &env, None, &lmdb::DatabaseOptions::defaults()).unwrap();
897    /// let mut txn = lmdb::WriteTransaction::new(&env).unwrap();
898    /// let f = lmdb::put::Flags::empty();
899    /// {
900    ///   let mut access = txn.access();
901    ///   access.put(&db, "Germany", "Berlin", f).unwrap();
902    ///   access.put(&db, "Latvia", "Rīga", f).unwrap();
903    ///   access.put(&db, "France", "Paris", f).unwrap();
904    /// }
905    ///
906    /// {
907    ///   // Open a child transaction and do some more reading and writing.
908    ///   let subtx = txn.child_tx().unwrap();
909    ///   let mut access = subtx.access();
910    ///   assert_eq!("Berlin", access.get::<str,str>(&db, "Germany").unwrap());
911    ///   access.put(&db, "Germany", "Frankfurt", f).unwrap();
912    ///   assert_eq!("Frankfurt", access.get::<str,str>(&db, "Germany").unwrap());
913    ///   // Don't commit --- let the child transaction abort (roll back)
914    /// }
915    ///
916    /// {
917    ///   let mut access = txn.access();
918    ///   // Now we can do some more reading and writing on the original
919    ///   // transaction.
920    ///   // The effect of the aborted child transaction are not visible.
921    ///   access.put(&db, "United Kingdom", "London", f).unwrap();
922    ///   assert_eq!("Berlin", access.get::<str,str>(&db, "Germany").unwrap());
923    /// }
924    ///
925    /// {
926    ///   // Another child.
927    ///   let subtx = txn.child_tx().unwrap();
928    ///   {
929    ///     let mut access = subtx.access();
930    ///     access.put(&db, "Spain", "Madrid", f).unwrap();
931    ///   }
932    ///   // Commit this one this time.
933    ///   subtx.commit().unwrap();
934    /// }
935    ///
936    /// {
937    ///   // Now the changes from the child are visible to this transaction,
938    ///   // but still not outside it.
939    ///   let mut access = txn.access();
940    ///   assert_eq!("Madrid", access.get::<str,str>(&db, "Spain").unwrap());
941    /// }
942    ///
943    /// txn.commit().unwrap();
944    /// # }
945    /// ```
946    pub fn child_tx<'a>(&'a mut self) -> Result<WriteTransaction<'a>>
947    where 'env: 'a {
948        let env = Supercow::share(&mut self.0.env);
949        Ok(WriteTransaction(try!(ConstTransaction::new(
950            env, Some(&mut*self), 0))))
951    }
952
953    /// Commits this write transaction.
954    pub fn commit(mut self) -> Result<()> {
955        unsafe {
956            self.0.tx.commit()
957        }
958    }
959
960    /// Returns a read/write accessor on this transaction.
961    ///
962    /// ## Panics
963    ///
964    /// Panics if an accessor has already been obtained from this transaction
965    /// and not yet dropped.
966    #[inline]
967    pub fn access(&self) -> WriteAccessor {
968        WriteAccessor(self.0.access())
969    }
970}
971
972impl<'txn> ConstAccessor<'txn> {
973    /// Get items from a database.
974    ///
975    /// This function retrieves key/data pairs from the database. A reference
976    /// to the data associated with the given key is returned. If the database
977    /// supports duplicate keys (`DUPSORT`) then the first data item for the
978    /// key will be returned. Retrieval of other items requires the use of
979    /// cursoring.
980    ///
981    /// The returned memory is valid until the next mutation through the
982    /// transaction or the end of the transaction (both are enforced through
983    /// the borrow checker).
984    ///
985    /// ## Errors
986    ///
987    /// This call may return errors for reasons other than the key not being
988    /// found. The easiest way to handle "not found" is generally to use the
989    /// `to_opt` method on `traits::LmdbResultExt` to promote the value into a
990    /// `Result<Option<V>>`. Most important of these other errors is the
991    /// possibility of the key being found, but the value not being convertible
992    /// to a `&V`.
993    #[inline]
994    pub fn get<K : AsLmdbBytes + ?Sized, V : FromLmdbBytes + ?Sized>(
995        &self, db: &Database, key: &K) -> Result<&V>
996    {
997        try!(db.assert_same_env(self.env()));
998
999        let mut mv_key = as_val(key);
1000        let mut out_val = EMPTY_VAL;
1001        unsafe {
1002            lmdb_call!(ffi::mdb_get(
1003                self.txptr(), db.as_raw(), &mut mv_key, &mut out_val));
1004        }
1005
1006        from_val(self, &out_val)
1007    }
1008
1009    fn txptr(&self) -> *mut ffi::MDB_txn {
1010        self.0.tx.0
1011    }
1012
1013    fn env(&self) -> &Environment {
1014        &*self.0.env
1015    }
1016}
1017
1018impl<'txn> Deref for WriteAccessor<'txn> {
1019    type Target = ConstAccessor<'txn>;
1020
1021    fn deref(&self) -> &ConstAccessor<'txn> {
1022        &self.0
1023    }
1024}
1025
1026impl<'txn> WriteAccessor<'txn> {
1027    /// Store items into a database.
1028    ///
1029    /// This function stores key/data pairs in the database. The default
1030    /// behavior is to enter the new key/data pair, replacing any previously
1031    /// existing key if duplicates are disallowed, or adding a duplicate data
1032    /// item if duplicates are allowed (`DUPSORT`).
1033    #[inline]
1034    pub fn put<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>(
1035        &mut self, db: &Database, key: &K, value: &V,
1036        flags: put::Flags) -> Result<()>
1037    {
1038        try!(db.assert_same_env(self.env()));
1039
1040        let mut mv_key = as_val(key);
1041        let mut mv_val = as_val(value);
1042        unsafe {
1043            lmdb_call!(ffi::mdb_put(
1044                self.txptr(), db.as_raw(), &mut mv_key, &mut mv_val,
1045                flags.bits()));
1046        }
1047        Ok(())
1048    }
1049
1050    /// Store items into a database.
1051    ///
1052    /// This function stores key/data pairs in the database. The default
1053    /// behavior is to enter the new key/data pair, replacing any previously
1054    /// existing key if duplicates are disallowed, or adding a duplicate data
1055    /// item if duplicates are allowed (`DUPSORT`).
1056    ///
1057    /// Unlike `put()`, this does not take a value. Instead, it reserves space
1058    /// for the value (equal to the size of `V`) and then returns a mutable
1059    /// reference to it. Be aware that the `FromReservedLmdbBytes` conversion
1060    /// will be invoked on whatever memory happens to be at the destination
1061    /// location.
1062    ///
1063    /// ## Example
1064    ///
1065    /// ```
1066    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1067    /// #[repr(C, packed)]
1068    /// #[derive(Clone,Copy,Debug,PartialEq,Eq)]
1069    /// struct MyStruct {
1070    ///   x: i32,
1071    ///   y: i32,
1072    /// }
1073    /// unsafe impl lmdb::traits::LmdbRaw for MyStruct { }
1074    ///
1075    /// # fn main() {
1076    /// # let env = create_env();
1077    /// # let db = lmdb::Database::open(
1078    /// #   &env, None, &lmdb::DatabaseOptions::defaults())
1079    /// #   .unwrap();
1080    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1081    /// {
1082    ///   let mut access = txn.access();
1083    ///   {
1084    ///     let dst: &mut MyStruct = access.put_reserve(
1085    ///       &db, "foo", lmdb::put::Flags::empty()).unwrap();
1086    ///     // Writing to `dst` actually writes directly into the database.
1087    ///     dst.x = 42;
1088    ///     dst.y = 56;
1089    ///     // Drop `dst` so we can use `access` again
1090    ///   }
1091    ///   assert_eq!(&MyStruct { x: 42, y: 56 },
1092    ///              access.get(&db, "foo").unwrap());
1093    /// }
1094    /// txn.commit().unwrap();
1095    /// # }
1096    /// ```
1097    #[inline]
1098    pub fn put_reserve<K : AsLmdbBytes + ?Sized,
1099                       V : FromReservedLmdbBytes + Sized>(
1100        &mut self, db: &Database, key: &K, flags: put::Flags) -> Result<&mut V>
1101    {
1102        unsafe {
1103            self.put_reserve_unsized(db, key, mem::size_of::<V>(), flags)
1104        }
1105    }
1106
1107    /// Store items into a database.
1108    ///
1109    /// This function stores key/data pairs in the database. The default
1110    /// behavior is to enter the new key/data pair, replacing any previously
1111    /// existing key if duplicates are disallowed, or adding a duplicate data
1112    /// item if duplicates are allowed (`DUPSORT`).
1113    ///
1114    /// Unlike `put()`, this does not take a value. Instead, it reserves space
1115    /// for the value (equal to an array of `count` objects of size `V`) and
1116    /// then returns a mutable reference to it. Be aware that the content of
1117    /// the returned slice is simply whatever happens to be in the destination
1118    /// memory at the time of this call.
1119    ///
1120    /// ## Example
1121    ///
1122    /// ```
1123    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1124    /// # fn main() {
1125    /// # let env = create_env();
1126    /// # let db = lmdb::Database::open(
1127    /// #   &env, None, &lmdb::DatabaseOptions::defaults())
1128    /// #   .unwrap();
1129    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1130    /// {
1131    ///   let mut access = txn.access();
1132    ///   {
1133    ///     let bytes: &mut [u8] = access.put_reserve_array(
1134    ///       &db, "foo", 4, lmdb::put::Flags::empty()).unwrap();
1135    ///     // More realistically, one could zero-copy data from a file/socket
1136    ///     // into `bytes`, for example.
1137    ///     bytes[0] = b'b'; bytes[1] = b'y';
1138    ///     bytes[2] = b't'; bytes[3] = b'e';
1139    ///   }
1140    ///   assert_eq!("byte", access.get::<str,str>(&db, "foo").unwrap());
1141    /// }
1142    /// txn.commit().unwrap();
1143    /// # }
1144    /// ```
1145    #[inline]
1146    pub fn put_reserve_array<K : AsLmdbBytes + ?Sized, V : LmdbRaw>(
1147        &mut self, db: &Database, key: &K, count: usize, flags: put::Flags)
1148        -> Result<&mut [V]>
1149    {
1150        unsafe {
1151            self.put_reserve_unsized(
1152                db, key, mem::size_of::<V>() * count, flags)
1153        }
1154    }
1155
1156    /// Store items into a database.
1157    ///
1158    /// This function stores key/data pairs in the database. The default
1159    /// behavior is to enter the new key/data pair, replacing any previously
1160    /// existing key if duplicates are disallowed, or adding a duplicate data
1161    /// item if duplicates are allowed (`DUPSORT`).
1162    ///
1163    /// Unlike `put()`, this does not take a value. Instead, it reserves space
1164    /// equal to `size` bytes for the value and then returns a mutable
1165    /// reference to it. Be aware that the `FromReservedLmdbBytes` conversion
1166    /// will be invoked on whatever memory happens to be at the destination
1167    /// location.
1168    ///
1169    /// ## Unsafety
1170    ///
1171    /// The caller must ensure that `size` is a valid size for `V`.
1172    #[inline]
1173    pub unsafe fn put_reserve_unsized<K : AsLmdbBytes + ?Sized,
1174                                      V : FromReservedLmdbBytes + ?Sized>(
1175        &mut self, db: &Database, key: &K, size: usize, flags: put::Flags)
1176        -> Result<&mut V>
1177    {
1178        try!(db.assert_same_env(self.env()));
1179
1180        let mut mv_key = as_val(key);
1181        let mut out_val = EMPTY_VAL;
1182        out_val.mv_size = size;
1183        lmdb_call!(ffi::mdb_put(
1184            self.txptr(), db.as_raw(), &mut mv_key, &mut out_val,
1185            flags.bits() | ffi::MDB_RESERVE));
1186
1187        Ok(from_reserved(self, &out_val))
1188    }
1189
1190    /// Delete items from a database by key.
1191    ///
1192    /// This function removes key/data pairs from the database. All values
1193    /// whose key matches `key` are deleted, including in the case of
1194    /// `DUPSORT`. This function will return `NOTFOUND` if the specified
1195    /// key is not in the database.
1196    ///
1197    /// ## Example
1198    ///
1199    /// ```
1200    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1201    /// # fn main() {
1202    /// # let env = create_env();
1203    /// let db = lmdb::Database::open(
1204    ///   &env, Some("example"),
1205    ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
1206    ///   .unwrap();
1207    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1208    /// {
1209    ///   let mut access = txn.access();
1210    ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
1211    ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
1212    ///   assert_eq!("Apple", access.get::<str,str>(&db, "Fruit").unwrap());
1213    ///   access.del_key(&db, "Fruit").unwrap();
1214    ///   assert!(access.get::<str,str>(&db, "Fruit").is_err());
1215    /// }
1216    /// txn.commit().unwrap();
1217    /// # }
1218    /// ```
1219    #[inline]
1220    pub fn del_key<K : AsLmdbBytes + ?Sized>(
1221        &mut self, db: &Database, key: &K) -> Result<()>
1222    {
1223        try!(db.assert_same_env(self.env()));
1224
1225        let mut mv_key = as_val(key);
1226        unsafe {
1227            lmdb_call!(ffi::mdb_del(
1228                self.txptr(), db.as_raw(), &mut mv_key, ptr::null_mut()));
1229        }
1230
1231        Ok(())
1232    }
1233
1234    /// Delete items from a database by key and value.
1235    ///
1236    /// This function removes key/data pairs from the database. If the database
1237    /// does not support sorted duplicate data items (`DUPSORT`) the `val`
1238    /// parameter is ignored and this call behaves like `del()`. Otherwise, if
1239    /// the data item matching both `key` and `val` will be deleted. This
1240    /// function will return `NOTFOUND` if the specified key/data pair is not
1241    /// in the database.
1242    ///
1243    /// ## Example
1244    ///
1245    /// ```
1246    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1247    /// # fn main() {
1248    /// # let env = create_env();
1249    /// let db = lmdb::Database::open(
1250    ///   &env, Some("example"),
1251    ///   &lmdb::DatabaseOptions::create_multimap_unsized::<str,str>())
1252    ///   .unwrap();
1253    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1254    /// {
1255    ///   let mut access = txn.access();
1256    ///   access.put(&db, "Fruit", "Apple", lmdb::put::Flags::empty()).unwrap();
1257    ///   access.put(&db, "Fruit", "Orange", lmdb::put::Flags::empty()).unwrap();
1258    ///   assert_eq!("Apple", access.get::<str,str>(&db, "Fruit").unwrap());
1259    ///   access.del_item(&db, "Fruit", "Apple").unwrap();
1260    ///   assert_eq!("Orange", access.get::<str,str>(&db, "Fruit").unwrap());
1261    /// }
1262    /// txn.commit().unwrap();
1263    /// # }
1264    /// ```
1265    #[inline]
1266    pub fn del_item<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>(
1267        &mut self, db: &Database, key: &K, val: &V) -> Result<()>
1268    {
1269        try!(db.assert_same_env(self.env()));
1270
1271        let mut mv_key = as_val(key);
1272        let mut mv_val = as_val(val);
1273        unsafe {
1274            lmdb_call!(ffi::mdb_del(
1275                self.txptr(), db.as_raw(), &mut mv_key, &mut mv_val));
1276        }
1277
1278        Ok(())
1279    }
1280
1281    /// Completely clears the content of the given database.
1282    ///
1283    /// ## Example
1284    ///
1285    /// ```
1286    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1287    /// # fn main() {
1288    /// # let env = create_env();
1289    /// # let db = lmdb::Database::open(
1290    /// #   &env, None, &lmdb::DatabaseOptions::defaults())
1291    /// #   .unwrap();
1292    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1293    /// {
1294    ///   let mut access = txn.access();
1295    ///   let f = lmdb::put::Flags::empty();
1296    ///   access.put(&db, "Germany", "Berlin", f).unwrap();
1297    ///   access.put(&db, "France", "Paris", f).unwrap();
1298    ///   access.put(&db, "Latvia", "Rīga", f).unwrap();
1299    ///   assert_eq!(3, txn.db_stat(&db).unwrap().entries);
1300    ///
1301    ///   access.clear_db(&db).unwrap();
1302    ///   assert_eq!(0, txn.db_stat(&db).unwrap().entries);
1303    /// }
1304    /// txn.commit().unwrap();
1305    /// # }
1306    /// ```
1307    pub fn clear_db(&mut self, db: &Database) -> Result<()> {
1308        try!(db.assert_same_env(self.env()));
1309        unsafe {
1310            lmdb_call!(ffi::mdb_drop(self.txptr(), db.as_raw(), 0));
1311        }
1312        Ok(())
1313    }
1314}