Coder Social home page Coder Social logo

drycpp / lmdbxx Goto Github PK

View Code? Open in Web Editor NEW
269.0 16.0 89.0 206 KB

C++11 wrapper for the LMDB embedded B+ tree database library.

Home Page: http://lmdbxx.sourceforge.net

License: The Unlicense

C++ 91.53% Makefile 4.21% Shell 2.10% Tcl 2.16%
lmdb cxx

lmdbxx's Introduction

lmdb++: a C++11 wrapper for LMDB

Travis CI build status Coverity Scan build status

This is a comprehensive C++ wrapper for the LMDB embedded database library, offering both an error-checked procedural interface and an object-oriented resource interface with RAII semantics.

Example

Here follows a simple motivating example demonstrating basic use of the object-oriented resource interface:

#include <cstdio>
#include <cstdlib>
#include <lmdb++.h>

int main() {
  /* Create and open the LMDB environment: */
  auto env = lmdb::env::create();
  env.set_mapsize(1UL * 1024UL * 1024UL * 1024UL); /* 1 GiB */
  env.open("./example.mdb", 0, 0664);

  /* Insert some key/value pairs in a write transaction: */
  auto wtxn = lmdb::txn::begin(env);
  auto dbi = lmdb::dbi::open(wtxn, nullptr);
  dbi.put(wtxn, "username", "jhacker");
  dbi.put(wtxn, "email", "[email protected]");
  dbi.put(wtxn, "fullname", "J. Random Hacker");
  wtxn.commit();

  /* Fetch key/value pairs in a read-only transaction: */
  auto rtxn = lmdb::txn::begin(env, nullptr, MDB_RDONLY);
  auto cursor = lmdb::cursor::open(rtxn, dbi);
  std::string key, value;
  while (cursor.get(key, value, MDB_NEXT)) {
    std::printf("key: '%s', value: '%s'\n", key.c_str(), value.c_str());
  }
  cursor.close();
  rtxn.abort();

  /* The enviroment is closed automatically. */

  return EXIT_SUCCESS;
}

Should any operation in the above fail, an lmdb::error exception will be thrown and terminate the program since we don't specify an exception handler. All resources will regardless get automatically cleaned up due to RAII semantics.

Note

In order to run this example, you must first manually create the ./example.mdb directory. This is a basic characteristic of LMDB: the given environment path must already exist, as LMDB will not attempt to automatically create it.

Features

  • Designed to be entirely self-contained as a single <lmdb++.h> header file that can be dropped into a project.
  • Implements a straightforward mapping from C to C++, with consistent naming.
  • Provides both a procedural interface and an object-oriented RAII interface.
  • Simplifies error handling by translating error codes into C++ exceptions.
  • Carefully differentiates logic errors, runtime errors, and fatal errors.
  • Exception strings include the name of the LMDB function that failed.
  • Plays nice with others: all symbols are placed into the lmdb namespace.
  • 100% free and unencumbered public domain software, usable in any context and for any purpose.

Requirements

The <lmdb++.h> header file requires a C++11 compiler and standard library. Recent releases of Clang or GCC will work fine.

In addition, for your application to build and run, the underlying <lmdb.h> header file shipped with LMDB must be available in the preprocessor's include path, and you must link with the liblmdb native library. On Ubuntu Linux 14.04 and newer, these prerequisites can be satisfied by installing the liblmdb-dev package.

Overview

This wrapper offers both an error-checked procedural interface and an object-oriented resource interface with RAII semantics. The former will be useful for easily retrofitting existing projects that currently use the raw C interface, but we recommend the latter for all new projects due to the exception safety afforded by RAII semantics.

Resource Interface

The high-level resource interface wraps LMDB handles in a loving RAII embrace. This way, you can ensure e.g. that a transaction will get automatically aborted when exiting a lexical scope, regardless of whether the escape happened normally or by throwing an exception.

C handle C++ wrapper class
MDB_env* lmdb::env
MDB_txn* lmdb::txn
MDB_dbi lmdb::dbi
MDB_cursor* lmdb::cursor
MDB_val lmdb::val

The methods available on these C++ classes are named consistently with the procedural interface, below, with the obvious difference of omitting the handle type prefix which is already implied by the class in question.

Procedural Interface

The low-level procedural interface wraps LMDB functions with error-checking code that will throw an instance of a corresponding C++ exception class in case of failure. This interface doesn't offer any convenience overloads as does the resource interface; the parameter types are exactly the same as for the raw C interface offered by LMDB itself. The return type is generally void for these functions since the wrapper eats the error code returned by the underlying C function, throwing an exception in case of failure and otherwise returning values in the same output parameters as the C interface.

This interface is implemented entirely using static inline functions, so there are no hidden extra costs to using these wrapper functions so long as you have a decent compiler capable of basic inlining optimization.

C function C++ wrapper function
mdb_version() N/A
mdb_strerror() N/A
mdb_env_create() lmdb::env_create()
mdb_env_open() lmdb::env_open()
mdb_env_copy() lmdb::env_copy() [1]
mdb_env_copyfd() lmdb::env_copy_fd() [1]
mdb_env_copy2() lmdb::env_copy() [1]
mdb_env_copyfd2() lmdb::env_copy_fd() [1]
mdb_env_stat() lmdb::env_stat()
mdb_env_info() lmdb::env_info()
mdb_env_sync() lmdb::env_sync()
mdb_env_close() lmdb::env_close()
mdb_env_set_flags() lmdb::env_set_flags()
mdb_env_get_flags() lmdb::env_get_flags()
mdb_env_get_path() lmdb::env_get_path()
mdb_env_get_fd() lmdb::env_get_fd()
mdb_env_set_mapsize() lmdb::env_set_mapsize()
mdb_env_set_maxreaders() lmdb::env_set_max_readers()
mdb_env_get_maxreaders() lmdb::env_get_max_readers()
mdb_env_set_maxdbs() lmdb::env_set_max_dbs()
mdb_env_get_maxkeysize() lmdb::env_get_max_keysize()
mdb_env_set_userctx() lmdb::env_set_userctx() [2]
mdb_env_get_userctx() lmdb::env_get_userctx() [2]
mdb_env_set_assert() N/A
mdb_txn_begin() lmdb::txn_begin()
mdb_txn_env() lmdb::txn_env()
mdb_txn_id() lmdb::txn_id() [3]
mdb_txn_commit() lmdb::txn_commit()
mdb_txn_abort() lmdb::txn_abort()
mdb_txn_reset() lmdb::txn_reset()
mdb_txn_renew() lmdb::txn_renew()
mdb_dbi_open() lmdb::dbi_open()
mdb_stat() lmdb::dbi_stat() [4]_
mdb_dbi_flags() lmdb::dbi_flags()
mdb_dbi_close() lmdb::dbi_close()
mdb_drop() lmdb::dbi_drop() [4]_
mdb_set_compare() lmdb::dbi_set_compare() [4]_
mdb_set_dupsort() lmdb::dbi_set_dupsort() [4]_
mdb_set_relfunc() lmdb::dbi_set_relfunc() [4]_
mdb_set_relctx() lmdb::dbi_set_relctx() [4]_
mdb_get() lmdb::dbi_get() [4]_
mdb_put() lmdb::dbi_put() [4]_
mdb_del() lmdb::dbi_del() [4]_
mdb_cursor_open() lmdb::cursor_open()
mdb_cursor_close() lmdb::cursor_close()
mdb_cursor_renew() lmdb::cursor_renew()
mdb_cursor_txn() lmdb::cursor_txn()
mdb_cursor_dbi() lmdb::cursor_dbi()
mdb_cursor_get() lmdb::cursor_get()
mdb_cursor_put() lmdb::cursor_put()
mdb_cursor_del() lmdb::cursor_del()
mdb_cursor_count() lmdb::cursor_count()
mdb_cmp() N/A
mdb_dcmp() N/A
mdb_reader_list() TODO
mdb_reader_check() TODO

Footnotes

[1](1, 2, 3, 4) Three-parameter signature available since LMDB 0.9.14 (2014/09/20).
[2](1, 2) Only available since LMDB 0.9.11 (2014/01/15).
[3]Only available in LMDB HEAD, not yet in any 0.9.x release (as of 0.9.16). Define the LMDBXX_TXN_ID preprocessor symbol to unhide this.
[4]Note the difference in naming. (See below.)

Caveats

  • The C++ procedural interface is more strictly and consistently grouped by handle type than is the LMDB native interface. For instance, mdb_put() is wrapped as the C++ function lmdb::dbi_put(), not lmdb::put(). These differences--a handful in number--all concern operations on database handles.
  • The C++ interface takes some care to be const-correct for input-only parameters, something the original C interface largely ignores. Hence occasional use of const_cast in the wrapper code base.
  • lmdb::dbi_put() does not throw an exception if LMDB returns the MDB_KEYEXIST error code; it instead just returns false. This is intended to simplify common usage patterns.
  • lmdb::dbi_get(), lmdb::dbi_del(), and lmdb::cursor_get() do not throw an exception if LMDB returns the MDB_NOTFOUND error code; they instead just return false. This is intended to simplify common usage patterns.
  • lmdb::env_get_max_keysize() returns an unsigned integer, instead of a signed integer as the underlying mdb_env_get_maxkeysize() function does. This conversion is done since the return value cannot in fact be negative.

Error Handling

This wrapper draws a careful distinction between three different classes of possible LMDB error conditions:

  • Logic errors, represented by lmdb::logic_error. Errors of this class are thrown due to programming errors where the function interfaces are used in violation of documented preconditions. A common strategy for handling this class of error conditions is to abort the program with a core dump, facilitating introspection to locate and remedy the bug.
  • Fatal errors, represented by lmdb::fatal_error. Errors of this class are thrown due to the exhaustion of critical system resources, in particular available memory (ENOMEM), or due to attempts to exceed applicable system resource limits. A typical strategy for handling this class of error conditions is to terminate the program with a descriptive error message. More robust programs and shared libraries may wish to implement another strategy, such as retrying the operation after first letting most of the call stack unwind in order to free up scarce resources.
  • Runtime errors, represented by lmdb::runtime_error. Errors of this class are thrown as a matter of course to indicate various exceptional conditions. These conditions are generally recoverable, and robust programs will take care to correctly handle them.

Note

The distinction between logic errors and runtime errors mirrors that found in the C++11 standard library, where the <stdexcept> header defines the standard exception base classes std::logic_error and std::runtime_error. The standard exception class std::bad_alloc, on the other hand, is a representative example of a fatal error.

Error code Exception class Exception type
MDB_KEYEXIST lmdb::key_exist_error runtime
MDB_NOTFOUND lmdb::not_found_error runtime
MDB_CORRUPTED lmdb::corrupted_error fatal
MDB_PANIC lmdb::panic_error fatal
MDB_VERSION_MISMATCH lmdb::version_mismatch_error fatal
MDB_MAP_FULL lmdb::map_full_error runtime
MDB_BAD_DBI lmdb::bad_dbi_error runtime [4]_
(others) lmdb::runtime_error runtime

Footnotes

[4]Available since LMDB 0.9.14 (2014/09/20).

Note

MDB_KEYEXIST and MDB_NOTFOUND are handled specially by some functions.

Versioning Policy

The lmdb++ version tracks the upstream LMDB release (x.y.z) that it is compatible with, and appends a sub-patch-level version (x.y.z.N) to indicate changes to the wrapper itself.

For example, an lmdb++ release of 0.9.14.2 would indicate that it is designed for compatibility with LMDB 0.9.14, and is the third wrapper release (the first being .0, and the second .1) for that upstream target.

Note

To the extent that LMDB will preserve API and ABI compatibility going forward, older versions of the wrapper should work with newer versions of LMDB; and newer versions of the wrapper will generally work with older versions of LMDB by using the preprocessor to conditionalize the visibility of newer symbols--see, for example, the preprocessor guards around the definition of lmdb::env_set_userctx().

Installation

lmdb++ is currently available as a package/port in the following operating system distributions and package management systems:

Distribution Package Name Installation Hint
Arch Linux AUR liblmdb++ yaourt -Sa liblmdb++
Fink [5] lmdb++ sudo fink install lmdb++
MacPorts lmdbxx sudo port install lmdbxx
Portage [6] lmdb++ sudo emerge --ask lmdb++

Footnotes

[5]Still pending review.
[6]Compatible with Gentoo Linux, Funtoo Linux, and Sabayon Linux.

Support

To report a bug or submit a patch for lmdb++, please file an issue in the issue tracker on GitHub.

Questions and discussions about LMDB itself should be directed to the OpenLDAP mailing lists.

Elsewhere

Find this project at: GitHub, Bitbucket, Open Hub, SourceForge, Travis CI, and Coverity Scan.

The API documentation is published at: http://lmdbxx.sourceforge.net/

Author

Arto Bendiken - http://ar.to/

License

This is free and unencumbered public domain software. For more information, see http://unlicense.org/ or the accompanying UNLICENSE file.

lmdbxx's People

Contributors

artob avatar gregoire-astruc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lmdbxx's Issues

Allow copying of lmdb::dbi instances

It makes sense that the env and txn classes are moveable but not copyable, since they represent resources that are closed on destruction. But dbi isn't like that โ€” the destructor is a no-op. So I don't see a reason for not having a copy constructor and copying assignment.

Having these would make it cleaner to pass dbi instances as parameters, store them in member variables, etc.

Double-free when txn.commit() throws

@core-process noticed and fixed this issue in our C++17 fork of lmdbxx:

If an exception was throw by txn.commit() (ie MDB_MAP_FULL), and this transaction was later aborted (because it went out of scope while unwinding the stack), then a double-free would occur.

You can use the following test to observe this (address sanitizer should be enabled, as it is by default in our Makefile):

https://github.com/hoytech/lmdbxx/blob/5223582ebf92a9b14608ce6768535aef0c65910f/check.cc#L329

I forked this repo for C++17

First of all I want to say thanks, lmdbxx has been very useful to me!

For anyone using C++17 in their projects, std::string_view is a very nice complement to LMDB so I integrated it into lmdbxx. Since Arto hasn't checked in for a while, I just want to let anyone browsing here that I will maintain my fork by answering questions and incorporating bugfixes and so on.

Here's the link to my fork: https://github.com/hoytech/lmdbxx

Querying for different types in key/value pair

In my case, I'm storing key/value pairs as int/string.

The problem arises when I wan't to check if given pair exists in database. Currently I'm only able to check if given key exists via lmdb::cursor::find. Is it somehow possible to do this for key/value pair?

How can I save '0' ?

Hi,
When I try to save orgin image data using lmdb++, I find that I cannot save images containing piexls with gray-level zero. As I have to transform the image data into a string first, the string usually 'breaks' whenever there exits zero pixels. How can I solve this problem ?
Thanks very much!

mdb_del : Invalid argument for simple deletion

I tried to simply delete an entry, and can't really know if I'm wrong or if this is a bug, the only documentation I could find was the api reference, if anyone has better material I'd be glad to take it.

#include <cstdio>
#include <cstdlib>
#include <lmdb++.h>
using namespace lmdb;
int main() {
  auto env = lmdb::env::create();
  env.set_mapsize(1UL * 1024UL * 1024UL); 
  env.open("./example.mdb", 0, 0664);

  auto wtxn = lmdb::txn::begin(env);
  auto dbi = lmdb::dbi::open(wtxn, nullptr);
  dbi.put(wtxn, "key_entry", "value_entry");
  wtxn.commit();
  dbi.del(wtxn, "key_entry");

  return EXIT_SUCCESS;
}

This yields the following error :

terminate called after throwing an instance of 'lmdb::runtime_error'
  what():  mdb_del: Invalid argument

Merge into lmdb

Describe the bug
This is one single header wrapped in an entire package. Maybe it should just be merged into lmdb? They accept pull requests.

problem in lmdb++.h line 1654

in lmdb::dbi_put there is no way to put an element like :
int data[10]
lmdb::val lmdbData((void*)data, sizeof(int)*10 );
...
dbi.put(wtxn, "data", lmdbData))

thread-local storage is not supported for clang7

Error is "lmdb++.h:97:12: error: thread-local storage is not supported for the current target
static thread_local char buffer[1024];"

Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix

Enhance error messages in exceptions

Right now, catching an lmdb::error exception doesn't give much information to aid in troubleshooting incorrect uses of LMDB or runtime errors. For example, mdb_stat: Invalid argument is particularly uninformative and unhelpful. Error messages in exceptions should ideally contain some information on what the parameters passed to the underlying LMDB API function actually were.

Symbol mdb_env_create() doesn't resolve

I tried to compile your example.cc using the latest lmdb++.h in /usr/include like so:

g++ example.cc

But I get the followin error:

/tmp/ccUhugbK.o: In function `lmdb::env_create(MDB_env**)':
example.cc:(.text+0x14): undefined reference to `mdb_env_create'
/tmp/ccUhugbK.o: In function `lmdb::env_open(MDB_env*, char const*, unsigned int, unsigned int)':
example.cc:(.text+0x5b): undefined reference to `mdb_env_open'
/tmp/ccUhugbK.o: In function `lmdb::env_close(MDB_env*)':
example.cc:(.text+0x8e): undefined reference to `mdb_env_close'
/tmp/ccUhugbK.o: In function `lmdb::env_set_flags(MDB_env*, unsigned int, bool)':
example.cc:(.text+0xc8): undefined reference to `mdb_env_set_flags'
/tmp/ccUhugbK.o: In function `lmdb::env_set_mapsize(MDB_env*, unsigned long)':
example.cc:(.text+0x106): undefined reference to `mdb_env_set_mapsize'
/tmp/ccUhugbK.o: In function `lmdb::txn_begin(MDB_env*, MDB_txn*, unsigned int, MDB_txn**)':
example.cc:(.text+0x14f): undefined reference to `mdb_txn_begin'
/tmp/ccUhugbK.o: In function `lmdb::txn_commit(MDB_txn*)':
example.cc:(.text+0x182): undefined reference to `mdb_txn_commit'
/tmp/ccUhugbK.o: In function `lmdb::txn_abort(MDB_txn*)':
example.cc:(.text+0x1b5): undefined reference to `mdb_txn_abort'
/tmp/ccUhugbK.o: In function `lmdb::dbi_open(MDB_txn*, char const*, unsigned int, unsigned int*)':
example.cc:(.text+0x1e6): undefined reference to `mdb_dbi_open'
/tmp/ccUhugbK.o: In function `lmdb::dbi_put(MDB_txn*, unsigned int, MDB_val const*, MDB_val*, unsigned int)':
example.cc:(.text+0x239): undefined reference to `mdb_put'
/tmp/ccUhugbK.o: In function `lmdb::cursor_open(MDB_txn*, unsigned int, MDB_cursor**)':
example.cc:(.text+0x28b): undefined reference to `mdb_cursor_open'
/tmp/ccUhugbK.o: In function `lmdb::cursor_close(MDB_cursor*)':
example.cc:(.text+0x2be): undefined reference to `mdb_cursor_close'
/tmp/ccUhugbK.o: In function `lmdb::cursor_get(MDB_cursor*, MDB_val*, MDB_val*, MDB_cursor_op)':
example.cc:(.text+0x2ef): undefined reference to `mdb_cursor_get'
/tmp/ccUhugbK.o: In function `lmdb::error::what() const':
example.cc:(.text._ZNK4lmdb5error4whatEv[_ZNK4lmdb5error4whatEv]+0x1c): undefined reference to `mdb_strerror'
collect2: error: ld returned 1 exit status

Looking inside lmdb++.h it seems that mdb_env_create hasn't been defined anywhere, but it IS referenced.

PS: Thanks for this great library, I hope to make use of it.

Example uses the same dbi instance with a different transaction

In the example code provided in your Readme.MD, the second transaction uses the "dbi" instance that was opened using the first transaction:

auto dbi = lmdb::dbi::open(wtxn, nullptr);
...
auto cursor = lmdb::cursor::open(rtxn, dbi);

Is this recommended? Or should one open a new database for every transaction?

Cursor.get returns key and value concatenated into key variable

Weird output from cursor get: I would get both key and value inside the key variable, then the value inside the value variable :

#include <cstdio>
#include <cstdlib>
#include <lmdb++.h>
using namespace lmdb;
int getsize(const lmdb::env& e){
    auto t = lmdb::txn::begin(e.handle(), nullptr, MDB_RDONLY);
    auto d = lmdb::dbi::open(t, nullptr);
    int r=d.size(t);
    t.abort();
    return r;
}


int main() {
  auto env = lmdb::env::create();
  env.set_mapsize(1UL * 1024UL * 1024UL * 1024UL); /* 1 GiB */
  env.open("./example.mdb", 0, 0664);
  {
    auto wtxn = lmdb::txn::begin(env);
    auto dbi = lmdb::dbi::open(wtxn, nullptr);
    char a[6] = "hello";
    dbi.put(wtxn, "email", "hello");
    dbi.put(wtxn, "key", "value");
    dbi.put(wtxn, "user", "johndoe");
    wtxn.commit();
  }
  {
      auto rtxn = lmdb::txn::begin(env);
      auto dbi = lmdb::dbi::open(rtxn, nullptr);
      auto cursor = lmdb::cursor::open(rtxn, dbi);
      lmdb::val k, v;
      while(cursor.get(k, v, MDB_NEXT)){
        printf("We got '%s'\nValue '%s'\n", k.data(), v.data());
      }
  }
  {
    std::printf("size is %d\n", getsize(env));
  }
return EXIT_SUCCESS;
}

Expected Output:

We got 'email'
Value 'hello'
We got 'key'
Value 'value'
We got 'user'
Value 'johndoe'
size is 3

Output :

We got 'emailhello'
Value 'hello'
We got 'keyvalue'
Value 'value'
We got 'userjohndoe'
Value 'johndoe'
size is 3

No updating value when key exists

Why is it that when I do a put with a key that already exists, it doesn't update the value for that key? Do I have to delete the old key/value before adding the new key/value?

Help needed cursor_put and MDB_MULTIPLE

Hi, I am trying yo use lmdb++ to work with LMDB. I have it working via the example you provided. I have a problem when trying to use cursor_put with MDB_MULTIPLE. I cant seem to get it to work right. Here is the code:

`std::vector rawData(1000000, std::rand());
MDB_val value1, value2, key;
value1.mv_size = sizeof(int);
value1.mv_data = const_cast<void*> (static_cast<const void*> (&rawData[0]));;
value2.mv_size = 1000000;
MDB_val mData[2] = { value1, value2 };
int i = 0;

auto env = lmdb::env::create();
env.set_mapsize(1UL * 1024UL * 1024UL * 1024UL); /* 1 GiB */
env.open(path.c_str(), 0, 0664);
auto wtxn = lmdb::txn::begin(env);
auto dbi = lmdb::dbi::open(wtxn, nullptr, MDB_DUPSORT | MDB_DUPFIXED | MDB_INTEGERDUP | MDB_CREATE);
auto cursor = lmdb::cursor::open(wtxn, dbi);
key.mv_size = sizeof(i);
key.mv_data = &i;
cursor_put(cursor, &key, mData, MDB_MULTIPLE);`

I think I am probably misusing the lib or some part of it. So any advice would be good.

Feature Request: remove dependency on pthreads?

I'd like to use lmdb++ but as it stands I cannot because of it's dependency on pthreads... The real problem is that on Windows it looks like the current code requires pthread_t from mingw and I am using Visual Studio on Windows. Since it requires a modern implementation of C++ anyway, might it be possible to use only standard features?

Cursor double free on write tx

Not really sure if this is an issue as I don't think there is any fix for this given the available lmdb library, but I think it is worth noting on github wiki.

As per the lmdb documents for commiting a tx "Earlier documentation incorrectly said all cursors would be freed. Only write-transactions free cursors.".

So when a wite tx is committed AND a cursor object live, the underlying MDB_cursor* is freed during the commit, then freed when the cursor object is destroyed resulting in memory violation. As such the ordering of committing and destroying (or closing) below will crash.

wtxn.commit(); cursor.close();

I do not think there is a way for a cursor to know if the tx has been committed, so there seems to be no trivial fix if one at all.

An easy solution from a users perspective is just to make sure you actively close all cursors of a write tx before before committing. Its pretty simple but it took me a while to figure out where the memory violation was coming from. Perhaps this could be added somewhere to your wiki to warn users of this.

cursor.close(); wtxn.commit();

How to get an specific value with lmdb++

I have already tried to use lmdb++ but I failed.
What I want to do is simple, it is like the example.cc but I want to get an specific value of a key of the data base instead of go over all the values that have been saved on it with cursors.

For example:

int main() {
  auto env = lmdb::env::create();
  env.open("./example.mdb", 0, 0664);

  auto wtxn = lmdb::txn::begin(env);
  auto dbi = lmdb::dbi::open(wtxn, nullptr);
  dbi.put(wtxn, "username", "jhacker");
  dbi.put(wtxn, "email", "[email protected]");
  dbi.put(wtxn, "fullname", "J. Random Hacker");
  wtxn.commit();

  auto rtxn = lmdb::txn::begin(env);

  std::string value;
  dbi.get(rtxn, "username", value);
  std::printf("value: '%s'\n",value.c_str());

  rtxn.abort();

  return EXIT_SUCCESS;
}

But it returns me:
Segmentation fault (core dumped)

How can I do this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.