From 5af0bb3e6709542a86a1dc6a4c55195566f6f90f Mon Sep 17 00:00:00 2001 From: bert hubert Date: Sat, 15 Dec 2018 17:53:29 +0100 Subject: [PATCH] readonly transactions, common implementation --- lmdb-typed.cc | 26 +++- lmdb-typed.hh | 327 +++++++++++++++++++++++++++++++------------------- 2 files changed, 226 insertions(+), 127 deletions(-) diff --git a/lmdb-typed.cc b/lmdb-typed.cc index bc36c85..f222465 100644 --- a/lmdb-typed.cc +++ b/lmdb-typed.cc @@ -48,6 +48,22 @@ int main() index_on > tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records"); + { + auto rotxn = tdbi.getROTransaction(); + DNSResourceRecord rr0; + if(rotxn.get(2, rr0)) { + cout << "id 2, found "<("powerdns.com"); iter !=rotxn.end(); ++iter) + { + cout << iter->qtype << endl; + } + } + auto txn = tdbi.getRWTransaction(); cout<<"Currently have "<< txn.size()<< " entries"<() << " " << txn.size<1>() << " " << txn.size<2>() << endl; @@ -113,7 +129,15 @@ int main() cout << iter->qname << " " << iter->qtype << " " << iter->content < tuple_t; tuple_t d_tuple; + + template + struct ReadonlyOperations + { + ReadonlyOperations(Parent& parent) : d_parent(parent) + {} + + uint32_t size() + { + MDB_stat stat; + mdb_stat(d_parent.d_txn, d_parent.d_parent->d_main, &stat); + return stat.ms_entries; + } + + template + uint32_t size() + { + return std::get(d_parent.d_parent->d_tuple).size(d_parent.d_txn); + } + + + bool get(uint32_t id, T& t) + { + MDBOutVal data; + if(d_parent.d_txn.get(d_parent.d_parent->d_main, id, data)) + return false; + + serFromString(data.get(), t); + return true; + } + + template + uint32_t get(const typename std::tuple_element::type::type& key, T& out) + { + MDBOutVal id; + if(!d_parent.d_txn.get(std::get(d_parent.d_parent->d_tuple).d_idx, key, id)) + return get(id.get(), out); + return 0; + } + + + template + uint32_t cardinality() + { + auto cursor = d_parent.d_txn.getCursor(std::get(d_parent.d_parent->d_tuple).d_idx); + bool first = true; + MDBOutVal key, data; + uint32_t count = 0; + while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT_NODUP)) { + ++count; + first=false; + } + return count; + } + + struct eiter_t + {}; + + + template + struct iter_t + { + explicit iter_t(Parent* parent, const typename std::tuple_element::type::type& key) : + d_parent(parent), + d_cursor(d_parent->d_txn.getCursor(std::get(d_parent->d_parent->d_tuple).d_idx)), + d_in(key) + { + d_key.d_mdbval = d_in.d_mdbval; + + MDBOutVal id, data; + if(d_cursor.get(d_key, id, MDB_SET)) { + d_end = true; + return; + } + if(d_parent->d_txn.get(d_parent->d_parent->d_main, id, data)) + throw std::runtime_error("Missing id in constructor"); + + serFromString(data.get(), d_t); + } + + + bool operator!=(const eiter_t& rhs) + { + return !d_end; + } + + bool operator==(const eiter_t& rhs) + { + return d_end; + } + + const T& operator*() + { + return d_t; + } + + const T* operator->() + { + return &d_t; + } + + iter_t& operator++() + { + MDBOutVal id, data; + int rc = d_cursor.get(d_key, id, MDB_NEXT_DUP); + if(rc == MDB_NOTFOUND) { + d_end = true; + } + else { + if(d_parent->d_txn.get(d_parent->d_parent->d_main, id, data)) + throw std::runtime_error("Missing id field"); + + serFromString(data.get(), d_t); + } + return *this; + } + + Parent* d_parent; + typename Parent::cursor_t d_cursor; + MDBOutVal d_key, d_data; + MDBInVal d_in; + bool d_end{false}; + T d_t; + }; + + template + iter_t find(const typename std::tuple_element::type::type& key) + { + iter_t ret{&d_parent, key}; + return ret; + }; + + eiter_t end() + { + return eiter_t(); + } + + + + Parent& d_parent; + }; - class RWTransaction + class ROTransaction : public ReadonlyOperations { public: - explicit RWTransaction(TypedDBI* parent) : d_parent(parent), d_txn(d_parent->d_env->getRWTransaction()) + explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations(*this), d_parent(parent), d_txn(d_parent->d_env->getROTransaction()) + { + } + + ROTransaction(ROTransaction&& rhs) : + ReadonlyOperations(*this), d_parent(rhs.d_parent),d_txn(std::move(rhs.d_txn)) + + { + rhs.d_parent = 0; + } + + typedef MDBROCursor cursor_t; + + TypedDBI* d_parent; + MDBROTransaction d_txn; + }; + + + class RWTransaction : public ReadonlyOperations + { + public: + explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations(*this), d_parent(parent), d_txn(d_parent->d_env->getRWTransaction()) { } RWTransaction(RWTransaction&& rhs) : + ReadonlyOperations(*this), d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn)) { rhs.d_parent = 0; } - uint32_t size() - { - MDB_stat stat; - mdb_stat(d_txn, d_parent->d_main, &stat); - return stat.ms_entries; - } - uint32_t insert(const T& t) + uint32_t insert(const T& t, uint32_t id=0) { - uint32_t id = getMaxID(d_txn, d_parent->d_main) + 1; + if(!id) + id = getMaxID(d_txn, d_parent->d_main) + 1; d_txn.put(d_parent->d_main, id, serToString(t)); #define insertMacro(N) std::get(d_parent->d_tuple).put(d_txn, t, id); @@ -188,21 +363,22 @@ public: return id; } - bool get(uint32_t id, T& t) + void modify(uint32_t id, std::function func) { - MDBOutVal data; - if(d_txn.get(d_parent->d_main, id, data)) - return false; + T t; + if(!this->get(id, t)) + return; // XXX should be exception + func(t); - serFromString(data.get(), t); - return true; + del(id); // this is the lazy way. We could test for changed index fields + insert(t, id); } void del(uint32_t id) { T t; - if(!get(id, t)) + if(!this->get(id, t)) return; d_txn.del(d_parent->d_main, id); @@ -222,35 +398,6 @@ public: cursor.del(); } } - - template - uint32_t get(const typename std::tuple_element::type::type& key, T& out) - { - MDBOutVal id; - if(!d_txn.get(std::get(d_parent->d_tuple).d_idx, key, id)) - return get(id.get(), out); - return 0; - } - - template - uint32_t size() - { - return std::get(d_parent->d_tuple).size(d_txn); - } - - template - uint32_t cardinality() - { - auto cursor = d_txn.getCursor(std::get(d_parent->d_tuple).d_idx); - bool first = true; - MDBOutVal key, data; - uint32_t count = 0; - while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT_NODUP)) { - ++count; - first=false; - } - return count; - } void commit() { @@ -262,86 +409,8 @@ public: d_txn.abort(); } - struct eiter_t - {}; - template - struct iter_t - { - explicit iter_t(RWTransaction* parent, const typename std::tuple_element::type::type& key) : - d_parent(parent), - d_cursor(d_parent->d_txn.getCursor(std::get(d_parent->d_parent->d_tuple).d_idx)), - d_in(key) - { - d_key.d_mdbval = d_in.d_mdbval; - - MDBOutVal id, data; - if(d_cursor.get(d_key, id, MDB_SET)) { - d_end = true; - return; - } - if(d_parent->d_txn.get(d_parent->d_parent->d_main, id, data)) - throw std::runtime_error("Missing id in constructor"); - - serFromString(data.get(), d_t); - } - - - bool operator!=(const eiter_t& rhs) - { - return !d_end; - } - - bool operator==(const eiter_t& rhs) - { - return d_end; - } - - const T& operator*() - { - return d_t; - } - - const T* operator->() - { - return &d_t; - } - - iter_t& operator++() - { - MDBOutVal id, data; - int rc = d_cursor.get(d_key, id, MDB_NEXT_DUP); - if(rc == MDB_NOTFOUND) { - d_end = true; - } - else { - if(d_parent->d_txn.get(d_parent->d_parent->d_main, id, data)) - throw std::runtime_error("Missing id field"); - - serFromString(data.get(), d_t); - } - return *this; - } - - RWTransaction* d_parent; - MDBRWCursor d_cursor; - MDBOutVal d_key, d_data; - MDBInVal d_in; - bool d_end{false}; - T d_t; - }; - - template - iter_t find(const typename std::tuple_element::type::type& key) - { - iter_t ret{this, key}; - return ret; - }; - - eiter_t end() - { - return eiter_t(); - } + typedef MDBRWCursor cursor_t; private: @@ -354,7 +423,8 @@ public: clearMacro(3); #undef clearMacro } - + + public: TypedDBI* d_parent; MDBRWTransaction d_txn; }; @@ -364,6 +434,11 @@ public: return RWTransaction(this); } + ROTransaction getROTransaction() + { + return ROTransaction(this); + } + private: std::shared_ptr d_env; MDBDbi d_main;