class LMDB::Environment

The Environment is the root object for all LMDB operations.

An LMDB “environment” is a collection of one or more “databases” (key-value tables), along with transactions to modify those databases and cursors to iterate through them.

An environment – and its collection of databases – is normally stored in a directory. That directory will contain two files:

An environment can contain multiple databases. Each of the databases has a string name (“mydatabase”, “db.3.1982”). You use the database name to open the database within the environment.

@example The normal pattern for using LMDB in Ruby

env = LMDB.new "databasedir"
db = env.database "databasename"
# ... do things to the database ...
env.close

Public Class Methods

new(p1, p2 = {}) click to toggle source

@overload new(path, opts)

Open an LMDB database environment.
The database environment is the root object for all operations on
a collection of databases.  It has to be opened first, before
individual databases can be opened or created in the environment.
The database should be closed when it is no longer needed.

The options hash on this method includes all the flags listed in
{Environment#flags} as well as the options documented here.
@return [Environment]
@param [String] path the path to the files containing the database
@param [Hash] opts options for the database environment
@option opts [Number] :mode The Posix permissions to set on created files.
@option opts [Number] :maxreaders The maximum number of concurrent threads
    that can be executing transactions at once.  Default is 126.
@option opts [Number] :maxdbs The maximum number of named databases in the
    environment.  Not needed if only one database is being used.
@option opts [Number] :mapsize The size of the memory map to be allocated
    for this environment, in bytes.  The memory map size is the
    maximum total size of the database.  The size should be a
    multiple of the OS page size.  The default size is about
    10MiB.
@yield [env] The block to be executed with the environment. The environment is closed afterwards.
@yieldparam env [Environment] The environment
@see #close
@see Environment#flags
@example Open environment and pass options
   env = LMDB.new "dbdir", :maxdbs => 30, :mapasync => true, :writemap => true
@example Pass environment to block
   LMDB.new "dbdir" do |env|
     # ...
   end
static VALUE environment_new(int argc, VALUE *argv, VALUE klass) {
    VALUE path, option_hash;

#ifdef RB_SCAN_ARGS_KEYWORDS
    rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS,
                    argc, argv, "1:", &path, &option_hash);
#else
    rb_scan_args(argc, argv, "1:", &path, &option_hash);
#endif

    EnvironmentOptions options = {
        .flags = MDB_NOTLS,
        .maxreaders = -1,
        .maxdbs = 128,
        .mapsize = 0,
        .mode = 0755,
    };
    if (!NIL_P(option_hash))
        rb_hash_foreach(option_hash, (int (*)(ANYARGS))environment_options,
                        (VALUE)&options);

    MDB_env* env;
    check(mdb_env_create(&env));

    Environment* environment;
    VALUE venv = Data_Make_Struct(cEnvironment, Environment, environment_mark,
                                  environment_free, environment);
    environment->env = env;
    environment->thread_txn_hash = rb_hash_new();
    environment->txn_thread_hash = rb_hash_new();

    if (options.maxreaders > 0)
        check(mdb_env_set_maxreaders(env, options.maxreaders));
    if (options.mapsize > 0)
        check(mdb_env_set_mapsize(env, options.mapsize));

    check(mdb_env_set_maxdbs(env, options.maxdbs <= 0 ? 1 : options.maxdbs));
    VALUE expanded_path = rb_file_expand_path(path, Qnil);
    check(mdb_env_open(env, StringValueCStr(expanded_path), options.flags,
                       options.mode));

    if (rb_block_given_p())
        return rb_ensure(rb_yield, venv, environment_close, venv);

    return venv;
}

Public Instance Methods

active_txn() click to toggle source

@overload active_txn

@return [Transaction] the current active transaction on this thread in the environment.
@example
   env.transaction do |t|
     active = env.active_txn
     # active should equal t
   end
static VALUE environment_active_txn(VALUE self) {
        ENVIRONMENT(self, environment);
        return rb_hash_aref(environment->thread_txn_hash, rb_thread_current());
}
clear_flags(*args) click to toggle source

@overload clear_flags(flags)

Clear one or more flags in the environment. The available flags are defined in {Environment#flags}.
@see Environment#flags
@param [Array] flags Array of flag names (symbols) to clear
@return nil
@raise [Error] if an invalid flag name is specified
@example
  env.clear_flags :nosync, :writemap
static VALUE environment_clear_flags(int argc, VALUE* argv, VALUE self) {
        environment_change_flags(argc, argv, self, 0);
        return Qnil;
}
close() click to toggle source

@overload close

Close an environment, completing all IOs and cleaning up database
state if needed.
@example
   env = LMDB.new('abc')
   # ...various operations on the environment...
   env.close
static VALUE environment_close(VALUE self) {
        ENVIRONMENT(self, environment);
        mdb_env_close(environment->env);
        environment->env = 0;
        return Qnil;
}
copy(p1) click to toggle source

@overload copy(path)

Create a copy (snapshot) of an environment.  The copy can be used
as a backup.  The copy internally uses a read-only transaction to
ensure that the copied data is serialized with respect to database
updates.
@param [String] path The directory in which the copy will
    reside. This directory must already exist and be writable but
    must otherwise be empty.
@return nil
@raise [Error] when there is an error creating the copy.
static VALUE environment_copy(VALUE self, VALUE path) {
        ENVIRONMENT(self, environment);
        VALUE expanded_path = rb_file_expand_path(path, Qnil);
        check(mdb_env_copy(environment->env, StringValueCStr(expanded_path)));
        return Qnil;
}
database(p1 = v1, p2 = {}) click to toggle source

@overload database(name, options)

Opens a database within the environment.

Note that a database is opened or created within a transaction.  If
the open creates a new database, the database is not available for
other operations in other transactions until the transaction that
is creating the database commits.  If the transaction creating the
database aborts, the database is not created.
@return [Database] newly-opened database
@raise [Error] if there is an error opening the database
@param [String] name Optional name for the database to be opened.
@param [Hash] options Options for the database.
@option options [Boolean] :reversekey Keys are strings to be
    compared in reverse order, from the end of the strings to the
    beginning. By default, Keys are treated as strings and
    compared from beginning to end.
@option options [Boolean] :dupsort Duplicate keys may be used in
    the database. (Or, from another perspective, keys may have
    multiple data items, stored in sorted order.) By default keys
    must be unique and may have only a single data item.
@option options [Boolean] :integerkey Keys are binary integers in
    native byte order.
@option options [Boolean] :dupfixed This flag may only be used in
    combination with +:dupsort+. This option tells the library
    that the data items for this database are all the same size,
    which allows further optimizations in storage and retrieval.
@option options [Boolean] :integerdup This option specifies that
    duplicate data items are also integers, and should be sorted
    as such.
@option options [Boolean] :reversedup This option specifies that
    duplicate data items should be compared as strings in reverse
    order.
@option options [Boolean] :create Create the named database if it
    doesn't exist. This option is not allowed in a read-only
    transaction or a read-only environment.
static VALUE environment_database(int argc, VALUE *argv, VALUE self) {
    ENVIRONMENT(self, environment);
    if (!active_txn(self))
        return call_with_transaction(self, self, "database", argc, argv, 0);

    VALUE name, option_hash;
#ifdef RB_SCAN_ARGS_KEYWORDS
    rb_scan_args_kw(RB_SCAN_ARGS_KEYWORDS,
                    argc, argv, "01:", &name, &option_hash);
#else
    rb_scan_args(argc, argv, "01:", &name, &option_hash);
#endif


    int flags = 0;
    if (!NIL_P(option_hash))
        rb_hash_foreach(option_hash, (int (*)(ANYARGS))database_flags,
                        (VALUE)&flags);

    MDB_dbi dbi;
    check(mdb_dbi_open(need_txn(self), NIL_P(name) ? 0 : StringValueCStr(name),
                       flags, &dbi));

    Database* database;
    VALUE vdb = Data_Make_Struct(cDatabase, Database, database_mark, free,
                                 database);
    database->dbi = dbi;
    database->env = self;

    return vdb;
}
flags() click to toggle source

@overload flags

Return the flags that are set in this environment.
@return [Array] Array of flag symbols
The environment flags are:
* +:fixedmap+ Use a fixed address for the mmap region.
* +:nosubdir+ By default, MDB creates its environment in a directory whose pathname is given in +path+, and creates its data and lock files under that directory. With this option, path is used as-is for the database main data file. The database lock file is the path with "-lock" appended.
* +:nosync+ Don't flush system buffers to disk when committing a transaction. This optimization means a system crash can corrupt the database or lose the last transactions if buffers are not yet flushed to disk. The risk is governed by how often the system flushes dirty buffers to disk and how often {Environment#sync} is called. However, if the filesystem preserves write order and the +:writemap+ flag is not used, transactions exhibit ACI (atomicity, consistency, isolation) properties and only lose D (durability). That is, database integrity is maintained, but a system crash may undo the final transactions. Note that +:nosync + :writemap+ leaves the system with no hint for when to write transactions to disk, unless {Environment#sync} is called. +:mapasync + :writemap+ may be preferable.
* +:rdonly+ Open the environment in read-only mode. No write operations will be allowed. MDB will still modify the lock file - except on read-only filesystems, where MDB does not use locks.
* +:nometasync+ Flush system buffers to disk only once per transaction, omit the metadata flush. Defer that until the system flushes files to disk, or next  non-MDB_RDONLY commit or {Environment#sync}. This optimization maintains database integrity, but a system crash may undo the last committed transaction. That is, it preserves the ACI (atomicity, consistency, isolation) but not D (durability) database property.
* +:writemap+ Use a writeable memory map unless +:rdonly+ is set. This is faster and uses fewer mallocs, but loses protection from application bugs like wild pointer writes and other bad updates into the database. Incompatible with nested transactions.
* +:mapasync+ When using +:writemap+, use asynchronous flushes to disk. As with +:nosync+, a system crash can then corrupt the database or lose the last transactions. Calling {Environment#sync} ensures on-disk database integrity until next commit.
* +:notls+ Don't use thread-local storage.
@example
    env = LMDB.new "abc", :writemap => true, :nometasync => true
    env.flags           #=> [:writemap, :nometasync]
static VALUE environment_flags(VALUE self) {
        unsigned int flags;
        ENVIRONMENT(self, environment);
        check(mdb_env_get_flags(environment->env, &flags));

        VALUE ret = rb_ary_new();
#define FLAG(const, name) if (flags & MDB_##const) rb_ary_push(ret, ID2SYM(rb_intern(#name)));
#include "env_flags.h"
#undef FLAG

        return ret;
}
info() click to toggle source

@overload info

Return useful information about an environment.
@return [Hash]
* +:mapaddr+ The memory address at which the database is mapped, if fixed
* +:mapsize+ The size of the data memory map
* +:last_pgno+ ID of the last used page
* +:last_txnid+ ID of the last committed transaction
* +:maxreaders+ Max reader slots in the environment
* +:numreaders+ Max readers slots in the environment
static VALUE environment_info(VALUE self) {
        MDB_envinfo info;

        ENVIRONMENT(self, environment);
        check(mdb_env_info(environment->env, &info));

        VALUE ret = rb_hash_new();

#define INFO_SET(name) rb_hash_aset(ret, ID2SYM(rb_intern(#name)), SIZET2NUM((size_t)info.me_##name));
        INFO_SET(mapaddr);
        INFO_SET(mapsize);
        INFO_SET(last_pgno);
        INFO_SET(last_txnid);
        INFO_SET(maxreaders);
        INFO_SET(numreaders);
#undef INFO_SET

        return ret;
}
mapsize=(p1) click to toggle source
static VALUE environment_set_mapsize(VALUE self, VALUE size) {
        ENVIRONMENT(self, environment);
        check(mdb_env_set_mapsize(environment->env, NUM2LONG(size)));
        return Qnil;
}
path() click to toggle source

@overload path

Return the path to the database environment files
@return [String] the path that was used to open the environment.
static VALUE environment_path(VALUE self) {
        const char* path;
        ENVIRONMENT(self, environment);
        check(mdb_env_get_path(environment->env, &path));
        return rb_str_new2(path);
}
set_flags(*args) click to toggle source

@overload set_flags(flags)

Set one or more flags in the environment. The available flags are defined in {Environment#flags}.
@see Environment#flags
@param [Array] flags Array of flag names (symbols) to set
@return nil
@raise [Error] if an invalid flag name is specified
@example
 env.set_flags :nosync, :writemap
static VALUE environment_set_flags(int argc, VALUE* argv, VALUE self) {
        environment_change_flags(argc, argv, self, 1);
        return Qnil;
}
stat() click to toggle source

@overload stat

Return useful statistics about an environment.
@return [Hash] the statistics
* +:psize+ Size of a database page
* +:depth+ Depth (height) of the B-tree
* +:branch_pages+ Number of internal (non-leaf) pages
* +:leaf_pages+ Number of leaf pages
* +:overflow_pages+ Number of overflow pages
* +:entries+ Number of data items
static VALUE environment_stat(VALUE self) {
        ENVIRONMENT(self, environment);
        MDB_stat stat;
        check(mdb_env_stat(environment->env, &stat));
        return stat2hash(&stat);
}
sync(p1 = v1) click to toggle source

@overload sync(force)

Flush the data buffers to disk.

Data is always written to disk when {Transaction#commit} is called, but
the operating system may keep it buffered. MDB always flushes the
OS buffers upon commit as well, unless the environment was opened
with +:nosync+ or in part +:nometasync+.
@param [Boolean] force If true, force a synchronous
  flush. Otherwise if the environment has the +:nosync+ flag set
  the flushes will be omitted, and with +:mapasync+ they will be
  asynchronous.
static VALUE environment_sync(int argc, VALUE *argv, VALUE self) {
        ENVIRONMENT(self, environment);

        VALUE force;
        rb_scan_args(argc, argv, "01", &force);

        check(mdb_env_sync(environment->env, RTEST(force)));
        return Qnil;
}
transaction(p1 = v1) click to toggle source

@overload transaction(readonly)

Begin a transaction.  Takes a block to run the body of the
transaction.  A transaction commits when it exits the block successfully.
A transaction aborts when it raises an exception or calls
{Transaction#abort}.
@param [Boolean] readonly This transaction will not perform any
   write operations
@note Transactions can be nested.
@yield [txn] The block to be executed with the body of the transaction.
@yieldparam txn [Transaction] An optional transaction argument
@example
   db = env.database "mydata"
   env.transaction do |txn1|
     db['a'] = 1
     env.transaction do |txn2|
       # txn2 is nested in txn1
       db['a'] = 2
       db['a']                    #=> 2
       txn2.abort
     end
     db['a']                      #=> 1
     env.transaction do
       db['a'] = 3
     end
   end
   db['a']                        #=> 3
static VALUE environment_transaction(int argc, VALUE *argv, VALUE self) {
        rb_need_block();

        VALUE readonly;
        rb_scan_args(argc, argv, "01", &readonly);
        unsigned int flags = RTEST(readonly) ? MDB_RDONLY : 0;

        return with_transaction(self, rb_yield, Qnil, flags);
}