MDBEnv::MDBEnv(const char* fname, int flags, int mode)
{
- mdb_env_create(&d_env);
- uint64_t mapsizeMB = (sizeof(long)==4) ? 100 : 16000;
- // on 32 bit platforms, there is just no room for more
- if(mdb_env_set_mapsize(d_env, mapsizeMB * 1048576))
+ mdb_env_create(&d_env);
+ if(mdb_env_set_mapsize(d_env, 16ULL*4096*244140ULL)) // 4GB
throw std::runtime_error("setting map size");
/*
Various other options may also need to be set before opening the handle, e.g. mdb_env_set_mapsize(), mdb_env_set_maxreaders(), mdb_env_set_maxdbs(),
if(!(envflags & MDB_RDONLY)) {
auto rwt = getRWTransaction();
- MDBDbi ret = rwt.openDB(dbname, flags);
- rwt.commit();
+ MDBDbi ret = rwt->openDB(dbname, flags);
+ rwt->commit();
return ret;
}
MDBDbi ret;
{
auto rwt = getROTransaction();
- ret = rwt.openDB(dbname, flags);
+ ret = rwt->openDB(dbname, flags);
}
return ret;
}
-MDBRWTransaction::MDBRWTransaction(MDBEnv* parent, int flags) : d_parent(parent)
+MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv *parent, MDB_txn *txn):
+ MDBROTransactionImpl(parent, txn)
+
+{
+
+}
+
+MDB_txn *MDBRWTransactionImpl::openRWTransaction(MDBEnv *env, MDB_txn *parent, int flags)
{
- if(d_parent->getROTX() || d_parent->getRWTX())
+ MDB_txn *result;
+ if(env->getROTX() || env->getRWTX())
throw std::runtime_error("Duplicate RW transaction");
for(int tries =0 ; tries < 3; ++tries) { // it might happen twice, who knows
- if(int rc=mdb_txn_begin(d_parent->d_env, 0, flags, &d_txn)) {
+ if(int rc=mdb_txn_begin(env->d_env, parent, flags, &result)) {
if(rc == MDB_MAP_RESIZED && tries < 2) {
// "If the mapsize is increased by another process (..) mdb_txn_begin() will return MDB_MAP_RESIZED.
// call mdb_env_set_mapsize with a size of zero to adopt the new size."
- mdb_env_set_mapsize(d_parent->d_env, 0);
+ mdb_env_set_mapsize(env->d_env, 0);
continue;
}
throw std::runtime_error("Unable to start RW transaction: "+std::string(mdb_strerror(rc)));
}
break;
}
- d_parent->incRWTX();
+ env->incRWTX();
+ return result;
+}
+
+MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv* parent, int flags):
+ MDBRWTransactionImpl(parent, openRWTransaction(parent, nullptr, flags))
+{
+}
+
+MDBRWTransactionImpl::~MDBRWTransactionImpl()
+{
+ abort();
+}
+
+void MDBRWTransactionImpl::commit()
+{
+ closeRORWCursors();
+ if (!d_txn) {
+ return;
+ }
+
+ if(int rc = mdb_txn_commit(d_txn)) {
+ throw std::runtime_error("committing: " + std::string(mdb_strerror(rc)));
+ }
+ environment().decRWTX();
+ d_txn = nullptr;
+}
+
+void MDBRWTransactionImpl::abort()
+{
+ closeRORWCursors();
+ if (!d_txn) {
+ return;
+ }
+
+ mdb_txn_abort(d_txn);
+ // prevent the RO destructor from cleaning up the transaction itself
+ environment().decRWTX();
+ d_txn = nullptr;
+}
+
+MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn):
+ d_parent(parent),
+ d_cursors(),
+ d_txn(txn)
+{
+
}
-MDBROTransaction::MDBROTransaction(MDBEnv* parent, int flags) : d_parent(parent)
+MDB_txn *MDBROTransactionImpl::openROTransaction(MDBEnv *env, MDB_txn *parent, int flags)
{
- if(d_parent->getRWTX())
+ if(env->getRWTX())
throw std::runtime_error("Duplicate RO transaction");
/*
A transaction and its cursors must only be used by a single thread, and a thread may only have a single transaction at a time. If MDB_NOTLS is in use, this does not apply to read-only transactions. */
-
+ MDB_txn *result = nullptr;
for(int tries =0 ; tries < 3; ++tries) { // it might happen twice, who knows
- if(int rc=mdb_txn_begin(d_parent->d_env, 0, MDB_RDONLY | flags, &d_txn)) {
+ if(int rc=mdb_txn_begin(env->d_env, parent, MDB_RDONLY | flags, &result)) {
if(rc == MDB_MAP_RESIZED && tries < 2) {
// "If the mapsize is increased by another process (..) mdb_txn_begin() will return MDB_MAP_RESIZED.
// call mdb_env_set_mapsize with a size of zero to adopt the new size."
- mdb_env_set_mapsize(d_parent->d_env, 0);
+ mdb_env_set_mapsize(env->d_env, 0);
continue;
}
}
break;
}
- d_parent->incROTX();
+ env->incROTX();
+
+ return result;
}
+void MDBROTransactionImpl::closeROCursors()
+{
+ // we need to move the vector away to ensure that the cursors don’t mess with our iteration.
+ std::vector<MDBROCursor*> buf;
+ std::swap(d_cursors, buf);
+ for (auto &cursor: buf) {
+ cursor->close();
+ }
+}
+MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, int flags):
+ MDBROTransactionImpl(parent, openROTransaction(parent, nullptr, flags))
+{
-void MDBRWTransaction::clear(MDB_dbi dbi)
+}
+
+MDBROTransactionImpl::~MDBROTransactionImpl()
+{
+ // this is safe because C++ will not call overrides of virtual methods in destructors.
+ commit();
+}
+
+void MDBROTransactionImpl::abort()
+{
+ closeROCursors();
+ // if d_txn is non-nullptr here, either the transaction object was invalidated earlier (e.g. by moving from it), or it is an RW transaction which has already cleaned up the d_txn pointer (with an abort).
+ if (d_txn) {
+ d_parent->decROTX();
+ mdb_txn_abort(d_txn); // this appears to work better than abort for r/o database opening
+ d_txn = nullptr;
+ }
+}
+
+void MDBROTransactionImpl::commit()
+{
+ closeROCursors();
+ // if d_txn is non-nullptr here, either the transaction object was invalidated earlier (e.g. by moving from it), or it is an RW transaction which has already cleaned up the d_txn pointer (with an abort).
+ if (d_txn) {
+ d_parent->decROTX();
+ mdb_txn_commit(d_txn); // this appears to work better than abort for r/o database opening
+ d_txn = nullptr;
+ }
+}
+
+
+
+void MDBRWTransactionImpl::clear(MDB_dbi dbi)
{
if(int rc = mdb_drop(d_txn, dbi, 0)) {
throw runtime_error("Error clearing database: " + MDBError(rc));
}
}
-MDBRWCursor MDBRWTransaction::getCursor(const MDBDbi& dbi)
+MDBRWCursor MDBRWTransactionImpl::getRWCursor(const MDBDbi& dbi)
{
- return MDBRWCursor(this, dbi);
+ MDB_cursor *cursor;
+ int rc= mdb_cursor_open(d_txn, dbi, &cursor);
+ if(rc) {
+ throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc)));
+ }
+ return MDBRWCursor(d_rw_cursors, cursor);
+}
+
+MDBRWCursor MDBRWTransactionImpl::getCursor(const MDBDbi &dbi)
+{
+ return getRWCursor(dbi);
+}
+
+MDBRWTransaction MDBRWTransactionImpl::getRWTransaction()
+{
+ MDB_txn *txn;
+ if (int rc = mdb_txn_begin(environment(), *this, 0, &txn)) {
+ throw std::runtime_error(std::string("failed to start child transaction: ")+mdb_strerror(rc));
+ }
+ // we need to increase the counter here because commit/abort on the child transaction will decrease it
+ environment().incRWTX();
+ return MDBRWTransaction(new MDBRWTransactionImpl(&environment(), txn));
+}
+
+MDBROTransaction MDBRWTransactionImpl::getROTransaction()
+{
+ return std::move(getRWTransaction());
}
MDBROTransaction MDBEnv::getROTransaction()
{
- return MDBROTransaction(this);
+ return MDBROTransaction(new MDBROTransactionImpl(this));
}
MDBRWTransaction MDBEnv::getRWTransaction()
{
- return MDBRWTransaction(this);
+ return MDBRWTransaction(new MDBRWTransactionImpl(this));
}
-void MDBRWTransaction::closeCursors()
+void MDBRWTransactionImpl::closeRWCursors()
{
- for(auto& c : d_cursors)
- c->close();
- d_cursors.clear();
+ decltype(d_rw_cursors) buf;
+ std::swap(d_rw_cursors, buf);
+ for (auto &cursor: buf) {
+ cursor->close();
+ }
}
-MDBROCursor MDBROTransaction::getCursor(const MDBDbi& dbi)
+MDBROCursor MDBROTransactionImpl::getCursor(const MDBDbi& dbi)
{
- return MDBROCursor(this, dbi);
+ return getROCursor(dbi);
}
-
+MDBROCursor MDBROTransactionImpl::getROCursor(const MDBDbi &dbi)
+{
+ MDB_cursor *cursor;
+ int rc= mdb_cursor_open(d_txn, dbi, &cursor);
+ if(rc) {
+ throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc)));
+ }
+ return MDBROCursor(d_cursors, cursor);
+}
#include <string>
#include <string.h>
#include <mutex>
+#include <vector>
+#include <algorithm>
// apple compiler somehow has string_view even in c++11!
#if __cplusplus < 201703L && !defined(__APPLE__)
#include <boost/version.hpp>
-#if BOOST_VERSION >= 106100
+#if BOOST_VERSION > 105400
#include <boost/utility/string_view.hpp>
using boost::string_view;
#else
class MDBDbi
{
public:
- MDBDbi(): d_dbi(-1)
+ MDBDbi()
{
+ d_dbi = -1;
}
explicit MDBDbi(MDB_env* env, MDB_txn* txn, string_view dbname, int flags);
MDB_dbi d_dbi;
};
-class MDBRWTransaction;
-class MDBROTransaction;
+class MDBRWTransactionImpl;
+class MDBROTransactionImpl;
+
+using MDBROTransaction = std::unique_ptr<MDBROTransactionImpl>;
+using MDBRWTransaction = std::unique_ptr<MDBRWTransactionImpl>;
class MDBEnv
{
memcpy(&ret, d_mdbval.mv_data, sizeof(T));
return ret;
}
+
+ template<class T>
+ const T* get_struct_ptr() const
+ {
+ if(d_mdbval.mv_size != sizeof(T))
+ throw std::runtime_error("MDB data has wrong length for type");
+
+ return reinterpret_cast<const T*>(d_mdbval.mv_data);
+ }
+
MDB_val d_mdbval;
};
class MDBInVal
{
public:
- MDBInVal(const MDBOutVal& rhs): d_mdbval(rhs.d_mdbval)
+ MDBInVal(const MDBOutVal& rhs)
{
+ d_mdbval = rhs.d_mdbval;
}
template <class T,
class MDBROCursor;
-class MDBROTransaction
+class MDBROTransactionImpl
{
+protected:
+ MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn);
+
+private:
+ static MDB_txn *openROTransaction(MDBEnv *env, MDB_txn *parent, int flags=0);
+
+ MDBEnv* d_parent;
+ std::vector<MDBROCursor*> d_cursors;
+
+protected:
+ MDB_txn* d_txn;
+
+ void closeROCursors();
+
public:
- explicit MDBROTransaction(MDBEnv* parent, int flags=0);
+ explicit MDBROTransactionImpl(MDBEnv* parent, int flags=0);
- MDBROTransaction(MDBROTransaction&& rhs)
- {
- d_parent = rhs.d_parent;
- d_txn = rhs.d_txn;
- rhs.d_parent = 0;
- rhs.d_txn = 0;
- }
+ MDBROTransactionImpl(const MDBROTransactionImpl& src) = delete;
+ MDBROTransactionImpl &operator=(const MDBROTransactionImpl& src) = delete;
- void reset()
- {
- // this does not free cursors
- mdb_txn_reset(d_txn);
- d_parent->decROTX();
- }
+ // The move constructor/operator cannot be made safe due to Object Slicing with MDBRWTransaction.
+ MDBROTransactionImpl(MDBROTransactionImpl&& rhs) = delete;
+ MDBROTransactionImpl &operator=(MDBROTransactionImpl &&rhs) = delete;
- void renew()
- {
- if(d_parent->getROTX())
- throw std::runtime_error("Duplicate RO transaction");
- if(int rc = mdb_txn_renew(d_txn))
- throw std::runtime_error("Renewing RO transaction: "+std::string(mdb_strerror(rc)));
- d_parent->incROTX();
- }
-
+ virtual ~MDBROTransactionImpl();
+
+ virtual void abort();
+ virtual void commit();
int get(MDB_dbi dbi, const MDBInVal& key, MDBOutVal& val)
{
}
MDBROCursor getCursor(const MDBDbi&);
+ MDBROCursor getROCursor(const MDBDbi&);
- ~MDBROTransaction()
+ operator MDB_txn*()
{
- if(d_txn) {
- d_parent->decROTX();
- mdb_txn_commit(d_txn); // this appears to work better than abort for r/o database opening
- }
+ return d_txn;
}
- operator MDB_txn*&()
- {
+ inline operator bool() const {
return d_txn;
}
-
- MDBEnv* d_parent;
- MDB_txn* d_txn;
+
+ inline MDBEnv &environment()
+ {
+ return *d_parent;
+ }
};
/*
"If the parent transaction commits, the cursor must not be used again."
*/
-template<class Transaction>
+template<class Transaction, class T>
class MDBGenCursor
{
+private:
+ std::vector<T*> *d_registry;
+ MDB_cursor* d_cursor;
+
+public:
+ MDBGenCursor():
+ d_registry(nullptr),
+ d_cursor(nullptr)
+ {
+
+ }
+
+ MDBGenCursor(std::vector<T*> ®istry, MDB_cursor *cursor):
+ d_registry(®istry),
+ d_cursor(cursor)
+ {
+ registry.emplace_back(static_cast<T*>(this));
+ }
+
+private:
+ void move_from(MDBGenCursor *src)
+ {
+ if (!d_registry) {
+ return;
+ }
+
+ auto iter = std::find(d_registry->begin(),
+ d_registry->end(),
+ src);
+ if (iter != d_registry->end()) {
+ *iter = static_cast<T*>(this);
+ } else {
+ d_registry->emplace_back(static_cast<T*>(this));
+ }
+ }
+
+public:
+ MDBGenCursor(const MDBGenCursor &src) = delete;
+
+ MDBGenCursor(MDBGenCursor &&src) noexcept:
+ d_registry(src.d_registry),
+ d_cursor(src.d_cursor)
+ {
+ move_from(&src);
+ src.d_registry = nullptr;
+ src.d_cursor = nullptr;
+ }
+
+ MDBGenCursor &operator=(const MDBGenCursor &src) = delete;
+
+ MDBGenCursor &operator=(MDBGenCursor &&src) noexcept
+ {
+ d_registry = src.d_registry;
+ d_cursor = src.d_cursor;
+ move_from(&src);
+ src.d_registry = nullptr;
+ src.d_cursor = nullptr;
+ return *this;
+ }
+
+ ~MDBGenCursor()
+ {
+ close();
+ }
+
public:
- MDBGenCursor(Transaction *t) : d_parent(t)
- {}
int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
{
int rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op);
return currentlast(key, data, MDB_FIRST);
}
- operator MDB_cursor*&()
+ operator MDB_cursor*()
{
return d_cursor;
}
- MDB_cursor* d_cursor{nullptr};
- Transaction* d_parent;
-};
-
-class MDBROCursor : public MDBGenCursor<MDBROTransaction>
-{
-public:
- MDBROCursor(MDBROTransaction* parent, const MDB_dbi& dbi) : MDBGenCursor<MDBROTransaction>(parent)
+ operator bool() const
{
- int rc= mdb_cursor_open(d_parent->d_txn, dbi, &d_cursor);
- if(rc) {
- throw std::runtime_error("Error creating RO cursor: "+std::string(mdb_strerror(rc)));
- }
- }
- MDBROCursor(MDBROCursor&& rhs) : MDBGenCursor<MDBROTransaction>(rhs.d_parent)
- {
- d_cursor = rhs.d_cursor;
- rhs.d_cursor = nullptr;
+ return d_cursor;
}
void close()
{
+ if (d_registry) {
+ auto iter = std::find(d_registry->begin(),
+ d_registry->end(),
+ static_cast<T*>(this));
+ if (iter != d_registry->end()) {
+ d_registry->erase(iter);
+ }
+ d_registry = nullptr;
+ }
if (d_cursor) {
mdb_cursor_close(d_cursor);
d_cursor = nullptr;
}
}
-
- ~MDBROCursor()
- {
- if(d_cursor)
- mdb_cursor_close(d_cursor);
- }
+};
+
+class MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor>
+{
+public:
+ MDBROCursor() = default;
+ using MDBGenCursor<MDBROTransactionImpl, MDBROCursor>::MDBGenCursor;
+ MDBROCursor(const MDBROCursor &src) = delete;
+ MDBROCursor(MDBROCursor &&src) = default;
+ MDBROCursor &operator=(const MDBROCursor &src) = delete;
+ MDBROCursor &operator=(MDBROCursor &&src) = default;
+ ~MDBROCursor() = default;
};
class MDBRWCursor;
-class MDBRWTransaction
+class MDBRWTransactionImpl: public MDBROTransactionImpl
{
-public:
- explicit MDBRWTransaction(MDBEnv* parent, int flags=0);
+protected:
+ MDBRWTransactionImpl(MDBEnv* parent, MDB_txn* txn);
- MDBRWTransaction(MDBRWTransaction&& rhs)
- {
- d_parent = rhs.d_parent;
- d_txn = rhs.d_txn;
- rhs.d_parent = 0;
- rhs.d_txn = 0;
- }
+private:
+ static MDB_txn *openRWTransaction(MDBEnv* env, MDB_txn *parent, int flags);
- MDBRWTransaction& operator=(MDBRWTransaction&& rhs)
- {
- if(d_txn)
- abort();
+private:
+ std::vector<MDBRWCursor*> d_rw_cursors;
- d_parent = rhs.d_parent;
- d_txn = rhs.d_txn;
- rhs.d_parent = 0;
- rhs.d_txn = 0;
-
- return *this;
+ void closeRWCursors();
+ inline void closeRORWCursors() {
+ closeROCursors();
+ closeRWCursors();
}
- ~MDBRWTransaction()
- {
- if(d_txn) {
- d_parent->decRWTX();
- closeCursors();
- mdb_txn_abort(d_txn); // XXX check response?
- }
- }
- void closeCursors();
-
- void commit()
- {
- closeCursors();
- if(int rc = mdb_txn_commit(d_txn)) {
- throw std::runtime_error("committing: " + std::string(mdb_strerror(rc)));
- }
- d_parent->decRWTX();
+public:
+ explicit MDBRWTransactionImpl(MDBEnv* parent, int flags=0);
- d_txn=0;
- }
+ MDBRWTransactionImpl(const MDBRWTransactionImpl& rhs) = delete;
+ MDBRWTransactionImpl(MDBRWTransactionImpl&& rhs) = delete;
+ MDBRWTransactionImpl &operator=(const MDBRWTransactionImpl& rhs) = delete;
+ MDBRWTransactionImpl &operator=(MDBRWTransactionImpl&& rhs) = delete;
- void abort()
- {
- closeCursors();
- mdb_txn_abort(d_txn); // XXX check error?
- d_txn = 0;
- d_parent->decRWTX();
- }
+ ~MDBRWTransactionImpl() override;
+
+ void commit() override;
+ void abort() override;
void clear(MDB_dbi dbi);
MDBDbi openDB(string_view dbname, int flags)
{
- return MDBDbi(d_parent->d_env, d_txn, dbname, flags);
+ return MDBDbi(environment().d_env, d_txn, dbname, flags);
}
+ MDBRWCursor getRWCursor(const MDBDbi&);
MDBRWCursor getCursor(const MDBDbi&);
- void reportCursor(MDBRWCursor* child)
- {
- d_cursors.insert(child);
- }
- void unreportCursor(MDBRWCursor* child)
- {
- d_cursors.erase(child);
- }
-
- void reportCursorMove(MDBRWCursor* from, MDBRWCursor* to)
- {
- d_cursors.erase(from);
- d_cursors.insert(to);
- }
-
- operator MDB_txn*&()
- {
- return d_txn;
- }
-
-
-
- std::set<MDBRWCursor*> d_cursors;
- MDBEnv* d_parent;
- MDB_txn* d_txn;
+ MDBRWTransaction getRWTransaction();
+ MDBROTransaction getROTransaction();
};
/* "A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends"
This is a problem for us since it may means we are closing the cursor twice, which is bad
*/
-class MDBRWCursor : public MDBGenCursor<MDBRWTransaction>
+class MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>
{
public:
- MDBRWCursor(MDBRWTransaction* parent, const MDB_dbi& dbi) : MDBGenCursor<MDBRWTransaction>(parent)
- {
- int rc= mdb_cursor_open(d_parent->d_txn, dbi, &d_cursor);
- if(rc) {
- throw std::runtime_error("Error creating RW cursor: "+std::string(mdb_strerror(rc)));
- }
- d_parent->reportCursor(this);
- }
- MDBRWCursor(MDBRWCursor&& rhs) : MDBGenCursor<MDBRWTransaction>(rhs.d_parent)
- {
- d_cursor = rhs.d_cursor;
- rhs.d_cursor = nullptr;
- d_parent->reportCursorMove(&rhs, this);
- }
-
- void close()
- {
- if(d_cursor)
- mdb_cursor_close(d_cursor);
- d_cursor = nullptr;
- }
-
- ~MDBRWCursor()
- {
- if(d_cursor)
- mdb_cursor_close(d_cursor);
- d_parent->unreportCursor(this);
- }
-
+ MDBRWCursor() = default;
+ using MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>::MDBGenCursor;
+ MDBRWCursor(const MDBRWCursor &src) = delete;
+ MDBRWCursor(MDBRWCursor &&src) = default;
+ MDBRWCursor &operator=(const MDBRWCursor &src) = delete;
+ MDBRWCursor &operator=(MDBRWCursor &&src) = default;
+ ~MDBRWCursor() = default;
void put(const MDBOutVal& key, const MDBInVal& data)
{
- int rc = mdb_cursor_put(d_cursor,
- const_cast<MDB_val*>(&key.d_mdbval),
- const_cast<MDB_val*>(&data.d_mdbval), MDB_CURRENT);
+ int rc = mdb_cursor_put(*this,
+ const_cast<MDB_val*>(&key.d_mdbval),
+ const_cast<MDB_val*>(&data.d_mdbval), MDB_CURRENT);
if(rc)
throw std::runtime_error("mdb_cursor_put: " + std::string(mdb_strerror(rc)));
}
int put(const MDBOutVal& key, const MDBOutVal& data, int flags=0)
{
// XXX check errors
- return mdb_cursor_put(d_cursor,
+ return mdb_cursor_put(*this,
const_cast<MDB_val*>(&key.d_mdbval),
const_cast<MDB_val*>(&data.d_mdbval), flags);
}
int del(int flags=0)
{
- return mdb_cursor_del(d_cursor, flags);
+ return mdb_cursor_del(*this, flags);
}
+
};
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
{
- auto cursor = txn.getCursor(dbi);
+ auto cursor = txn->getRWCursor(dbi);
MDBOutVal maxidval, maxcontent;
unsigned int maxid{0};
if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
explicit LMDBIndexOps(Parent* parent) : d_parent(parent){}
void put(MDBRWTransaction& txn, const Class& t, uint32_t id, int flags=0)
{
- txn.put(d_idx, keyConv(d_parent->getMember(t)), id, flags);
+ txn->put(d_idx, keyConv(d_parent->getMember(t)), id, flags);
}
void del(MDBRWTransaction& txn, const Class& t, uint32_t id)
{
- if(int rc = txn.del(d_idx, keyConv(d_parent->getMember(t)), id)) {
+ if(int rc = txn->del(d_idx, keyConv(d_parent->getMember(t)), id)) {
throw std::runtime_error("Error deleting from index: " + std::string(mdb_strerror(rc)));
}
}
uint32_t size()
{
MDB_stat stat;
- mdb_stat(*d_parent.d_txn, d_parent.d_parent->d_main, &stat);
+ mdb_stat(**d_parent.d_txn, d_parent.d_parent->d_main, &stat);
return stat.ms_entries;
}
uint32_t size()
{
MDB_stat stat;
- mdb_stat(*d_parent.d_txn, std::get<N>(d_parent.d_parent->d_tuple).d_idx, &stat);
+ mdb_stat(**d_parent.d_txn, std::get<N>(d_parent.d_parent->d_tuple).d_idx, &stat);
return stat.ms_entries;
}
bool get(uint32_t id, T& t)
{
MDBOutVal data;
- if(d_parent.d_txn->get(d_parent.d_parent->d_main, id, data))
+ if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
return false;
serFromString(data.get<std::string>(), t);
uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type& key, T& out)
{
MDBOutVal id;
- if(!d_parent.d_txn->get(std::get<N>(d_parent.d_parent->d_tuple).d_idx, keyConv(key), id)) {
+ if(!(*d_parent.d_txn)->get(std::get<N>(d_parent.d_parent->d_tuple).d_idx, keyConv(key), id)) {
if(get(id.get<uint32_t>(), out))
return id.get<uint32_t>();
}
template<int N>
uint32_t cardinality()
{
- auto cursor = d_parent.d_txn->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
+ auto cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
bool first = true;
MDBOutVal key, data;
uint32_t count = 0;
return count;
}
- //! End iterator type
+ //! End iderator type
struct eiter_t
{};
}
if(d_on_index) {
- if(d_parent->d_txn->get(d_parent->d_parent->d_main, d_id, d_data))
+ if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
throw std::runtime_error("Missing id in constructor");
serFromString(d_data.get<std::string>(), d_t);
}
}
if(d_on_index) {
- if(d_parent->d_txn->get(d_parent->d_parent->d_main, d_id, d_data))
+ if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
throw std::runtime_error("Missing id in constructor");
serFromString(d_data.get<std::string>(), d_t);
}
}
else {
if(d_on_index) {
- if(d_parent->d_txn->get(d_parent->d_parent->d_main, d_id, data))
+ if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, data))
throw std::runtime_error("Missing id field");
if(filter && !filter(data))
goto next;
template<int N>
iter_t genbegin(MDB_cursor_op op)
{
- typename Parent::cursor_t cursor = d_parent.d_txn->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
+ typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
MDBOutVal out, id;
iter_t begin()
{
- typename Parent::cursor_t cursor = d_parent.d_txn->getCursor(d_parent.d_parent->d_main);
+ typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(d_parent.d_parent->d_main);
MDBOutVal out, id;
template<int N>
iter_t genfind(const typename std::tuple_element<N, tuple_t>::type::type& key, MDB_cursor_op op)
{
- typename Parent::cursor_t cursor = d_parent.d_txn->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
+ typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
std::string keystr = keyConv(key);
MDBInVal in(keystr);
template<int N>
std::pair<iter_t,eiter_t> equal_range(const typename std::tuple_element<N, tuple_t>::type::type& key)
{
- typename Parent::cursor_t cursor = d_parent.d_txn->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
+ typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
std::string keyString=keyConv(key);
MDBInVal in(keyString);
template<int N>
std::pair<iter_t,eiter_t> prefix_range(const typename std::tuple_element<N, tuple_t>::type::type& key)
{
- typename Parent::cursor_t cursor = d_parent.d_txn->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
+ typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
std::string keyString=keyConv(key);
MDBInVal in(keyString);
id = MDBGetMaxID(*d_txn, d_parent->d_main) + 1;
flags = MDB_APPEND;
}
- d_txn->put(d_parent->d_main, id, serToString(t), flags);
+ (*d_txn)->put(d_parent->d_main, id, serToString(t), flags);
#define insertMacro(N) std::get<N>(d_parent->d_tuple).put(*d_txn, t, id);
insertMacro(0);
if(!this->get(id, t))
return;
- d_txn->del(d_parent->d_main, id);
+ (*d_txn)->del(d_parent->d_main, id);
clearIndex(id, t);
}
//! clear database & indexes (by hand!)
void clear()
{
- auto cursor = d_txn->getCursor(d_parent->d_main);
+ auto cursor = (*d_txn)->getRWCursor(d_parent->d_main);
bool first = true;
MDBOutVal key, data;
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
//! commit this transaction
void commit()
{
- d_txn->commit();
+ (*d_txn)->commit();
}
//! abort this transaction
void abort()
{
- d_txn->abort();
+ (*d_txn)->abort();
}
typedef MDBRWCursor cursor_t;
auto pdnsdbi = d_tdomains->getEnv()->openDB("pdns", MDB_CREATE);
auto txn = d_tdomains->getEnv()->getRWTransaction();
MDBOutVal _schemaversion;
- if(!txn.get(pdnsdbi, "schemaversion", _schemaversion)) {
+ if(!txn->get(pdnsdbi, "schemaversion", _schemaversion)) {
auto schemaversion = _schemaversion.get<uint32_t>();
if (schemaversion != SCHEMAVERSION) {
throw std::runtime_error("Expected LMDB schema version "+std::to_string(SCHEMAVERSION)+" but got "+std::to_string(schemaversion));
}
}
else {
- txn.put(pdnsdbi, "schemaversion", SCHEMAVERSION);
+ txn->put(pdnsdbi, "schemaversion", SCHEMAVERSION);
}
MDBOutVal shards;
- if(!txn.get(pdnsdbi, "shards", shards)) {
+ if(!txn->get(pdnsdbi, "shards", shards)) {
d_shards = shards.get<uint32_t>();
if(d_shards != atoi(getArg("shards").c_str())) {
}
else {
d_shards = atoi(getArg("shards").c_str());
- txn.put(pdnsdbi, "shards", d_shards);
+ txn->put(pdnsdbi, "shards", d_shards);
}
- txn.commit();
+ txn->commit();
d_trecords.resize(d_shards);
d_dolog = ::arg().mustDo("query-logging");
}
compoundOrdername co;
string match = co(domain_id);
- auto cursor = txn.txn.getCursor(txn.db->dbi);
+ auto cursor = txn.txn->getCursor(txn.db->dbi);
MDBOutVal key, val;
// cout<<"Match: "<<makeHexDump(match);
if(!cursor.lower_bound(match, key, val) ) {
bool LMDBBackend::commitTransaction()
{
// cout<<"Commit transaction" <<endl;
- d_rwtxn->txn.commit();
+ d_rwtxn->txn->commit();
d_rwtxn.reset();
return true;
}
bool LMDBBackend::abortTransaction()
{
// cout<<"Abort transaction"<<endl;
- d_rwtxn->txn.abort();
+ d_rwtxn->txn->abort();
d_rwtxn.reset();
return true;
rr.disabled = false;
compoundOrdername co;
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, rr.qtype.getCode()), serToString(rr));
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, rr.qtype.getCode()), serToString(rr));
if(ordernameIsNSEC3 && !ordername.empty()) {
MDBOutVal val;
- if(d_rwtxn->txn.get(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, QType::NSEC3), val)) {
+ if(d_rwtxn->txn->get(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, QType::NSEC3), val)) {
rr.ttl = 0;
rr.content=rr.qname.toDNSStringLC();
rr.auth = 0;
string ser = serToString(rr);
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(r.domain_id, ordername, QType::NSEC3), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(r.domain_id, ordername, QType::NSEC3), ser);
rr.ttl = 1;
rr.content = ordername.toDNSString();
ser = serToString(rr);
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, QType::NSEC3), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(r.domain_id, rr.qname, QType::NSEC3), ser);
}
}
return true;
rr.disabled = true;
std::string ser = serToString(rr);
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(domain_id, rr.qname, 0), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, rr.qname, 0), ser);
}
return true;
}
rr.auth = nt.second;
rr.disabled = nt.second;
ser = serToString(rr);
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(domain_id, rr.qname, 0), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, rr.qname, 0), ser);
if(!narrow && rr.auth) {
rr.content = rr.qname.toDNSString();
ser = serToString(rr);
ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3prc, nt.first)));
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(domain_id, ordername, QType::NSEC3), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, ordername, QType::NSEC3), ser);
rr.ttl = 1;
rr.content = ordername.toDNSString();
ser = serToString(rr);
- d_rwtxn->txn.put(d_rwtxn->db->dbi, co(domain_id, rr.qname, QType::NSEC3), ser);
+ d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, rr.qname, QType::NSEC3), ser);
}
}
return true;
}
compoundOrdername co;
- auto cursor = txn->txn.getCursor(txn->db->dbi);
+ auto cursor = txn->txn->getCursor(txn->db->dbi);
MDBOutVal key, val;
string match =co(domain_id, qname.makeRelative(di.zone), qt.getCode());
if(!cursor.find(match, key, val)) {
for(auto rr : rrset) {
rr.content = serializeContent(rr.qtype.getCode(), rr.qname, rr.content);
rr.qname.makeUsRelative(di.zone);
- txn->txn.put(txn->db->dbi, match, serToString(rr));
+ txn->txn->put(txn->db->dbi, match, serToString(rr));
}
if(needCommit)
- txn->txn.commit();
+ txn->txn->commit();
return true;
}
compoundOrdername co;
string match=co(id);
- auto cursor = txn->txn.getCursor(txn->db->dbi);
+ auto cursor = txn->txn->getCursor(txn->db->dbi);
MDBOutVal key, val;
if(!cursor.find(match, key, val)) {
do {
}
if(needCommit)
- txn->txn.commit();
+ txn->txn->commit();
doms.commit();
d_rotxn = getRecordsROTransaction(di.id);
compoundOrdername co;
d_matchkey = co(di.id);
- d_getcursor = std::make_shared<MDBROCursor>(d_rotxn->txn.getCursor(d_rotxn->db->dbi));
+ d_getcursor = std::make_shared<MDBROCursor>(d_rotxn->txn->getCursor(d_rotxn->db->dbi));
MDBOutVal key, val;
d_inlist = true;
d_rotxn = getRecordsROTransaction(zoneId);
compoundOrdername co;
- d_getcursor = std::make_shared<MDBROCursor>(d_rotxn->txn.getCursor(d_rotxn->db->dbi));
+ d_getcursor = std::make_shared<MDBROCursor>(d_rotxn->txn->getCursor(d_rotxn->db->dbi));
MDBOutVal key, val;
if(type.getCode() == QType::ANY) {
d_matchkey = co(zoneId,relqname);
di.id = iter.getID();
auto txn2 = getRecordsROTransaction(iter.getID());
- if(!txn2->txn.get(txn2->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
+ if(!txn2->txn->get(txn2->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
DNSResourceRecord rr;
serFromString(val.get<string_view>(), rr);
compoundOrdername co;
MDBOutVal val;
uint32_t serial = 0;
- if(!txn2->txn.get(txn2->db->dbi, co(iter.getID(), g_rootdnsname, QType::SOA), val)) {
+ if(!txn2->txn->get(txn2->db->dbi, co(iter.getID(), g_rootdnsname, QType::SOA), val)) {
DNSResourceRecord rr;
serFromString(val.get<string_view>(), rr);
struct soatimes st;
compoundOrdername co;
auto txn = getRecordsROTransaction(id);
- auto cursor = txn->txn.getCursor(txn->db->dbi);
+ auto cursor = txn->txn->getCursor(txn->db->dbi);
MDBOutVal key, val;
DNSResourceRecord rr;
compoundOrdername co;
DNSName qname2 = qname.makeRelative(zonename);
string matchkey=co(id,qname2);
- auto cursor = txn->txn.getCursor(txn->db->dbi);
+ auto cursor = txn->txn->getCursor(txn->db->dbi);
MDBOutVal key, val;
// cout<<"Lower_bound for "<<qname2<<endl;
if(cursor.lower_bound(matchkey, key, val)) {
compoundOrdername co;
string matchkey = co(domain_id, rel);
- auto cursor = txn->txn.getCursor(txn->db->dbi);
+ auto cursor = txn->txn->getCursor(txn->db->dbi);
MDBOutVal key, val;
if(cursor.lower_bound(matchkey, key, val)) {
// cout << "Could not find anything"<<endl;
bool del = false;
DNSResourceRecord rr;
matchkey = co(domain_id,rel,QType::NSEC3);
- if(!txn->txn.get(txn->db->dbi, matchkey, val)) {
+ if(!txn->txn->get(txn->db->dbi, matchkey, val)) {
serFromString(val.get<string_view>(), rr);
if(needNSEC3) {
del = true;
}
if(del) {
- txn->txn.del(txn->db->dbi, co(domain_id, DNSName(rr.content.c_str(), rr.content.size(), 0, false), QType::NSEC3));
- txn->txn.del(txn->db->dbi, matchkey);
+ txn->txn->del(txn->db->dbi, co(domain_id, DNSName(rr.content.c_str(), rr.content.size(), 0, false), QType::NSEC3));
+ txn->txn->del(txn->db->dbi, matchkey);
}
} else {
del = true;
rr.content=rel.toDNSStringLC();
string str = serToString(rr);
- txn->txn.put(txn->db->dbi, co(domain_id,ordername,QType::NSEC3), str);
+ txn->txn->put(txn->db->dbi, co(domain_id,ordername,QType::NSEC3), str);
rr.ttl = 1;
rr.content = ordername.toDNSStringLC();
str = serToString(rr);
- txn->txn.put(txn->db->dbi, matchkey, str); // 2
+ txn->txn->put(txn->db->dbi, matchkey, str); // 2
}
if(needCommit)
- txn->txn.commit();
+ txn->txn->commit();
return false;
}
std::string ser = serToString(rr);
- txn->txn.put(txn->db->dbi, co(domain_id, rr.qname, 0), ser);
+ txn->txn->put(txn->db->dbi, co(domain_id, rr.qname, 0), ser);
DNSResourceRecord rr2;
serFromString(ser, rr2);
for(auto n : erase) {
// cout <<" -"<<n<<endl;
n.makeUsRelative(di.zone);
- txn->txn.del(txn->db->dbi, co(domain_id, n, 0));
+ txn->txn->del(txn->db->dbi, co(domain_id, n, 0));
}
}
if(needCommit)
- txn->txn.commit();
+ txn->txn->commit();
return false;
}