drycpp / lmdbxx

C++11 wrapper for the LMDB embedded B+ tree database library.
http://lmdbxx.sourceforge.net
The Unlicense
270 stars 89 forks source link

mdb_del : Invalid argument for simple deletion #24

Open DrissiReda opened 5 years ago

DrissiReda commented 5 years ago

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
hoytech commented 5 years ago

You are calling dbi.del(wtxn, ...) after you are calling wtxn.commit(). Committing (or aborting) a transaction invalidates it. You can't then use it for subsequent operations. Either do the delete in the same transaction, or open a new transaction.

BTW: This repo is not really maintained anymore. I'll try to answer questions as best as possible here, but I have forked it for C++17 and will try to maintain that fork: https://github.com/hoytech/lmdbxx

DrissiReda commented 5 years ago

is your fork compatible with C++11?

hoytech commented 5 years ago

My fork requires a C++17 compiler since it uses std::string_view. However, C++11 code will I believe compile fine with a C++17 compiler.

DrissiReda commented 5 years ago

Thanks, I'll look into it

hoytech commented 5 years ago

Oh, and you asked about docs. You sort of have to use the LMDB C API docs: http://www.lmdb.tech/doc/

For examples of the C++ interface, you can checkout my test code, it has more working C++ examples than does this repo: https://github.com/hoytech/lmdbxx/blob/master/check.cc

DrissiReda commented 5 years ago

Currently I'm limited to C++11, what you told me worked, but I have issues with dbi.get now. If it doesn't find the entry, everything works normally, if it does find the entry, I have a segmentation fault on the call dbi.get

#include <cstdio>
#include <cstdlib>
#include <lmdb++.h>
using namespace lmdb;
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);
    dbi.put(wtxn, "email", "hello");
    wtxn.commit();
  }
  {
    auto rtxn = lmdb::txn::begin(env, nullptr, MDB_RDONLY);
    auto mydb = lmdb::dbi::open(rtxn, nullptr);
    std::string v;
    mydb.get(rtxn, "email", v);
    //std::printf("we found '%s'", v.c_str());
  }

  return EXIT_SUCCESS;
}

A snippet from valgrind:

==80114== Process terminating with default action of signal 11 (SIGSEGV)
==80114==  Access not within mapped region at address 0x106F6C6C6560
==80114==    at 0x510A02C: std::string::assign(std::string const&) (in /usr/lib64/libstdc++.so.6.0.19)
==80114==    by 0x4020A3: bool lmdb::dbi::get<std::string>(MDB_txn*, char const*, std::string&) const (in /home/reda/lmdbxx-master/test)
==80114==    by 0x40155E: main (in /home/reda/lmdbxx-master/test)
==80114==  If you believe this happened as a result of a stack
==80114==  overflow in your program's main thread (unlikely but
==80114==  possible), you can try to increase the size of the
==80114==  main thread stack using the --main-stacksize= flag.
==80114==  The main thread stack size used in this run was 8388608.

A warning printed prior to the error that might be relevant:

==80114== Warning: set address range perms: large range [0x39602000, 0x79602000) (defined)
==80114== Invalid read of size 4
==80114==    at 0x510A02C: std::string::assign(std::string const&) (in /usr/lib64/libstdc++.so.6.0.19)
==80114==    by 0x4020A3: bool lmdb::dbi::get<std::string>(MDB_txn*, char const*, std::string&) const (in /home/reda/lmdbxx-master/test)
==80114==    by 0x40155E: main (in /home/reda/lmdbxx-master/test)
==80114==  Address 0x106f6c6c6560 is not stack'd, malloc'd or (recently) free'd
hoytech commented 5 years ago

You are using the templated get method with std::string. Don't do that: https://github.com/drycpp/lmdbxx/issues/1

Use lmdb::val instead. You can then construct an std::string from that by copying the value from the DB.

DrissiReda commented 5 years ago

using lmdb::val gives an ambiguity error:

EDIT: nevermind, using an lmdb::val object for the key instead of a const char* fixed it.

hoytech commented 5 years ago

You have to use it for the key too. Passing a const char* works in my fork because it implicitly creates a string_view.