BerkeleyDB transaction multiple database single file Segfault on open

29 Views Asked by At

My objective is to have a single file containing two BerkeleyDB databases. The first one stores JSON documents index by their id and the second one associates the document ids with some other unique values from that documents. So, I call them "documents" database and "index" database. While adding a document I want to first add the document in the documents database and then add it's parameters into the index database.

I didn't find enough examples for this use case.

First I create the environment in the constructor and Initialize two Db instances. The open function starts the transaction which is ended by commit or abort.

crn::db::db(): _env(0), _opened(false) {
    _env.open("storage", DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN, 0);
    _docs   = new Db(&_env, 0);
    _index  = new Db(&_env, 0);
}
void crn::db::open(){
    _env.txn_begin(NULL, &_transaction, 0);
    _docs->open(_transaction, "storage.db", "docs" , DB_BTREE, DB_CREATE, 0);
    _index->open (_transaction, "storage.db", "indexes", DB_BTREE, DB_CREATE, 0);
    _opened = true;
}
void crn::db::close(){
    if(_opened){
        _docs->sync(0);
        _docs->close(0);
        _index->sync(0);
        _index->close(0);
        _opened = false;
    }
}

void crn::db::commit(){
    _transaction->commit(DB_TXN_SYNC);
    close();
    _transaction = 0x0;
}

void crn::db::abort(){
    _transaction->abort();
    close();
    _transaction = 0x0;
}

For each database operation I first open it, then do the get,put or exists calls and in the end I close it.

bool crn::db::exists(const std::string& id){
    open();
    Dbt key((void*) id.c_str(), id.size());
    int ret = _docs->exists(_transaction, &key, 0);
    commit();
    return ret != DB_NOTFOUND;
}

To add it

bool crn::db::add(const document& doc){
    std::string doc_id = doc.address().id();
    open();
    nlohmann::json json = doc;
    std::string doc_str = json.dump();

    int r_doc, r_addr_param1, r_addr_param2;

    Dbt id((void*) doc_id.c_str(), doc_id.size());
    {
        Dbt value((void*) doc_str.c_str(), doc_str.size());
        r_doc = _docs->put(_transaction, &id, &value, DB_NOOVERWRITE);
    }{
        Dbt key((void*) doc.param1().c_str(),doc.param1().size());
        r_addr_param1 = _index->put(_transaction, &key, &id, DB_NOOVERWRITE);
    }{
        Dbt key((void*) doc.param1().c_str(), doc.param2().size());
        r_addr_param2 = _index->put(_transaction, &key, &id, DB_NOOVERWRITE);
    }

    commit();
    return 0;
}

The problem starts when I call add is called multiple times sequentially in a loop. I get segfault on _docs->open(...) call. But after every add the database is closed.

Also this is the first time I am using BerkeleyDB. I'd appreciate any additional remarks.

https://gist.github.com/neel/23831d97272aff8b05bb725fea343b1e

0

There are 0 best solutions below