Struct lmdb_zero::Database [] [src]

pub struct Database<'a> { /* fields omitted */ }

A handle on an LMDB database within an environment.

Note that in many respects the RAII aspect of this struct is more a matter of convenience than correctness. In particular, if holding a read transaction open, it is possible to obtain a handle to a database created after that transaction started, but this handle will not point to anything within that transaction.

The library does, however, guarantee that there will be at most one Database object with the same dbi and environment per process.

Lifetime

A Database in borrowed mode must be strictly outlived by its Environment.

'a is covariant: given two lifetimes 'x and 'y where 'x: 'y, a &Database<'x> will implicitly coerce to &Database<'y>.

fn convariance<'x, 'y>(db: &lmdb::Database<'x>)
where 'x: 'y {
  let _db2: &lmdb::Database<'y> = db;
}

Because of this property, if you need to hold onto an &lmdb::Database and must explicitly name both lifetimes, it is usually best to use the same lifetime for both the reference and the parameter, eg &'x lmdb::Database<'x>.

Ownership Modes

All three ownership modes are fully supported. Most examples use borrowed mode, which is used by simply passing an &'env Environment to open.

Owned Mode

Owned mode is useful when your application only uses one Database; this alleviates the need to track both the Environment and the Database.

fn setup() -> lmdb::Database<'static> {
  // N.B. Unneeded type and lifetime annotations included for clarity.
  let env: lmdb::Environment = create_env();
  // Move `env` into the new `Database` because we only want to use the
  // default database. Since it owns the `Environment`, its lifetime
  // parameter is simply `'static`.
  let db: lmdb::Database<'static> = lmdb::Database::open(
    env, None, &lmdb::DatabaseOptions::defaults()).unwrap();
  // And since it owns the `Environment`, we can even return it without
  // worrying about `env`.
  db
}

let db = setup();
// Do stuff with `db`...

// When `db` is dropped, so is the inner `Environment`.

Shared Mode

Shared mode allows to have the Database hold on to the Environment via an Arc instead of a bare reference. This has all the benefits of owned mode and none of the drawbacks, but makes it harder to determine when exactly the Environment gets dropped since this only happens after all referents are (dynamically) dropped.

Without resorting to unsafe, shared mode is also the only way to define a structure which holds both the Environment itself and its child Database values.

use std::sync::Arc;

struct ApplicationContext {
  env: Arc<lmdb::Environment>,
  // You could of course also put these under `Arc`s as well, for example
  // if using shared mode with transactions and/or cursors.
  dict: lmdb::Database<'static>,
  freq: lmdb::Database<'static>,
}

impl ApplicationContext {
  fn into_env(self) -> Arc<lmdb::Environment> { self.env }
}

let env = Arc::new(create_env());
let dict = lmdb::Database::open(
  env.clone(), Some("dict"),
  &lmdb::DatabaseOptions::create_map::<str>()).unwrap();
let freq = lmdb::Database::open(
  env.clone(), Some("freq"),
  &lmdb::DatabaseOptions::create_map::<str>()).unwrap();

let context = ApplicationContext {
  env: env,
  dict: dict,
  freq: freq,
};

// Pass `context` around the application freely...

// We could just let `ApplicationContext` drop, but if we want to be
// absolutely sure we know when the `Environment` drops (by panicking if
// it doesn't do so when we want), we can disassemble the struct and check
// manually.
let env = context.into_env(); // Databases get dropped
Arc::try_unwrap(env).unwrap(); // Regain ownership of `Environment`,
                               // then drop it.

Methods

impl<'a> Database<'a>
[src]

Open a database in the environment.

A database handle denotes the name and parameters of a database, independently of whether such a database exists. The database handle is implicitly closed when the Database object is dropped.

To use named databases (with name != None), EnvBuilder::set_maxdbs() must have been called to reserve space for the extra databases. Database names are keys in the unnamed database, and may be read but not written.

Transaction-local databases are not supported because the resulting ownership semantics are not expressible in rust. This call implicitly creates a write transaction and uses it to create the database, then commits it on success.

One may not open the same database handle multiple times. Attempting to do so will result in the Error::Reopened error.

Examples

Open the default database with default options

{
  let db = lmdb::Database::open(
    &env, None, &lmdb::DatabaseOptions::defaults()).unwrap();
  // Do stuff with `db`
} // The `db` handle is released

Open a named database, creating it if it doesn't exist

// NOT SHOWN: Call `EnvBuilder::set_maxdbs()` with a value greater than
// one so that there is space for the named database(s).
{
  let db = lmdb::Database::open(
    &env, Some("example-db"), &lmdb::DatabaseOptions::new(
      lmdb::db::CREATE)).unwrap();
  // Do stuff with `db`
} // The `db` handle is released

Trying to open the same database more than once

{
  let db = lmdb::Database::open(
    &env, None, &lmdb::DatabaseOptions::defaults()).unwrap();
  // Can't open the same database twice
  assert!(lmdb::Database::open(
    &env, None, &lmdb::DatabaseOptions::defaults()).is_err());
}

Deletes this database.

This call implicitly creates a new write transaction to perform the operation, so that the lifetime of the database handle does not depend on the outcome. The database handle is closed implicitly by this operation.

Note that the other mdb_drop operation which simply clears the database is exposed through WriteAccessor and is transactional.

Example

// NOT SHOWN: Call `EnvBuilder::set_maxdbs()` with a value greater than
// one so that there is space for the named database(s).
{
  let db = lmdb::Database::open(
    &env, Some("example-db"), &lmdb::DatabaseOptions::new(
      lmdb::db::CREATE)).unwrap();
  // Do stuff with `db`

  // Delete the database itself. This also consumes `db`.
  db.delete().unwrap();

  // We can now recreate the database if we so desire.
  // Note that you should not use delete+open to clear a database; use
  // `WriteAccessor::clear_db()` to do that.
  let db = lmdb::Database::open(
    &env, Some("example-db"), &lmdb::DatabaseOptions::new(
      lmdb::db::CREATE)).unwrap();
}

Returns a reference to the Environment to which this Database belongs.

This can be used to elide needing to pass both an &Environment and an &Database around, but is also useful for the use-case wherein the Database owns the Environment.

Because this may borrow an Environment owned by this Database, the lifetime of the returned reference is dependent on self rather than being 'env. (In fact, 'env is usually 'static if the Environment is owned by the Database, so returning &'env Environment is impossible anyway.)

Example

let env: lmdb::Environment = create_env();
// We only want one `Database`, so don't bother keeping both variables
// around and instead let the `Database` own the `Environment`.
let db = lmdb::Database::open(
  env, None, &lmdb::DatabaseOptions::defaults()).unwrap();

// `env` has been consumed, but we can still do useful things by
// getting a reference to the inner value.
let txn = lmdb::ReadTransaction::new(db.env()).unwrap();

// Do stuff with `txn`, etc.

Checks that other_env is the same as the environment on this Database.

If it matches, returns Ok(()); otherwise, returns Err.

Returns the underlying integer handle for this database.

Trait Implementations

impl<'a> Debug for Database<'a>
[src]

Formats the value using the given formatter.