https://bugs.openldap.org/show_bug.cgi?id=8447
--- Comment #3 from nicolas.werner@hotmail.de --- I can reproduce this without using any cursors. I am using the lmdb++ header for simplicity (https://github.com/hoytech/lmdbxx), but it also reproduces using the plain C API. Full repro:
#include <iostream> #include <stdlib.h>
#include "lmdb++.h"
#define PROJECT_NAME "mdb-dup-bug"
static int compare_state_key(const MDB_val *a, const MDB_val *b) { auto get_skey = [](const MDB_val *v) { std::string_view data(static_cast<const char *>(v->mv_data), v->mv_size); return data.substr(0, data.find(',')); };
return get_skey(a).compare(get_skey(b)); }
int main(int argc, char **argv) { if(argc != 1) { std::cout << argv[0] << "takes no arguments.\n"; return 1; } std::cout << "This is project " << PROJECT_NAME << ".\n";
auto env = lmdb::env::create(); env.set_max_dbs(10);
char dirname[] = "/tmp/lmdb-bug.XXXXXX"; env.open(mkdtemp(dirname));
lmdb::dbi db;
{ auto txn = lmdb::txn::begin(env); db = lmdb::dbi::open( txn, std::string("dupsort").c_str(), MDB_CREATE | MDB_DUPSORT); lmdb::dbi_set_dupsort(txn, db, compare_state_key);
db.put(txn, "abcd", "ab,cdef"); db.put(txn, "abcd", "a,abc");
txn.commit(); }
{ auto txn = lmdb::txn::begin(env);
std::string_view data; db.get(txn, "abcd", data); std::cout << "Data size: " << data.size() << " expected: 5, data: '" << data << "', expected: 'a,abc'\n";
txn.commit(); }
{ auto txn = lmdb::txn::begin(env); db.put(txn, "abcd", "a,12");
txn.commit(); }
{ auto txn = lmdb::txn::begin(env);
std::string_view data; db.get(txn, "abcd", data); std::cout << "Data size: " << data.size() << " expected: 4, data: '" << data << "', expected: 'a,12'\n";
txn.commit(); }
{ auto txn = lmdb::txn::begin(env); db.put(txn, "abcd", "a,x");
txn.commit(); }
{ auto txn = lmdb::txn::begin(env);
std::string_view data; db.get(txn, "abcd", data); std::cout << "Data size: " << data.size() << " expected: 3, data: '" << data << "', expected: 'a,x'\n";
txn.commit(); }
return 0; }
This prints the following output:
This is project mdb-dup-bug. Data size: 5 expected: 5, data: 'a,abc', expected: 'a,abc' Data size: 5 expected: 4, data: 'a,12c', expected: 'a,12' Data size: 5 expected: 3, data: 'a,x2c', expected: 'a,x'
Commenting out the first put with the different data-key resolves the issue, but certainly you would expect that replacing a duplicate replaces the size too. Doing explicit delete before the put works around this issue.