readonly transactions, common implementation

This commit is contained in:
bert hubert 2018-12-15 17:53:29 +01:00
parent f11d89dd4a
commit 5af0bb3e67
2 changed files with 226 additions and 127 deletions

View File

@ -48,6 +48,22 @@ int main()
index_on<DNSResourceRecord, bool, &DNSResourceRecord::auth>
> tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records");
{
auto rotxn = tdbi.getROTransaction();
DNSResourceRecord rr0;
if(rotxn.get(2, rr0)) {
cout << "id 2, found "<<rr0.qname<<endl;
}
else {
cout <<"Did not find id 2" << endl;
}
cout<<"Iterating: "<<endl;
for(auto iter = rotxn.find<0>("powerdns.com"); iter !=rotxn.end(); ++iter)
{
cout << iter->qtype << endl;
}
}
auto txn = tdbi.getRWTransaction();
cout<<"Currently have "<< txn.size()<< " entries"<<endl;
cout<<" " << txn.size<0>() << " " << txn.size<1>() << " " << txn.size<2>() << endl;
@ -114,6 +130,14 @@ int main()
}
cout<<"Done iterating"<<endl;
DNSResourceRecord change;
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;
txn.modify(1, [](DNSResourceRecord& c) {
c.auth = false;
});
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;
txn.del(1);
// DNSResourceRecord rr4;

View File

@ -13,6 +13,23 @@
using std::cout;
using std::endl;
/*
Open issues:
Everything should go into a namespace
What is an error? What is an exception?
Is id=0 still magic?
Composite keys (powerdns needs them)
Insert? Put? Naming matters
Is boost the best serializer?
Iterator on main table
begin() and end()
Perhaps use the separate index concept from multi_index
A dump function would be nice (typed)
Need a read-only transaction (without duplicating all the things)
*/
unsigned int getMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
@ -153,95 +170,50 @@ public:
typedef std::tuple<I1, I2, I3, I4> tuple_t;
tuple_t d_tuple;
class RWTransaction
template<class Parent>
struct ReadonlyOperations
{
public:
explicit RWTransaction(TypedDBI* parent) : d_parent(parent), d_txn(d_parent->d_env->getRWTransaction())
{
}
RWTransaction(RWTransaction&& rhs) :
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
{
rhs.d_parent = 0;
}
ReadonlyOperations(Parent& parent) : d_parent(parent)
{}
uint32_t size()
{
MDB_stat stat;
mdb_stat(d_txn, d_parent->d_main, &stat);
mdb_stat(d_parent.d_txn, d_parent.d_parent->d_main, &stat);
return stat.ms_entries;
}
uint32_t insert(const T& t)
template<int N>
uint32_t size()
{
uint32_t id = getMaxID(d_txn, d_parent->d_main) + 1;
d_txn.put(d_parent->d_main, id, serToString(t));
#define insertMacro(N) std::get<N>(d_parent->d_tuple).put(d_txn, t, id);
insertMacro(0);
insertMacro(1);
insertMacro(2);
insertMacro(3);
#undef insertMacro
return id;
return std::get<N>(d_parent.d_parent->d_tuple).size(d_parent.d_txn);
}
bool get(uint32_t id, T& t)
{
MDBOutVal data;
if(d_txn.get(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);
return true;
}
void del(uint32_t id)
{
T t;
if(!get(id, t))
return;
d_txn.del(d_parent->d_main, id);
clearIndex(id, t);
}
void clear()
{
auto cursor = d_txn.getCursor(d_parent->d_main);
bool first = true;
MDBOutVal key, data;
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
first = false;
T t;
serFromString(data.get<std::string>(), t);
clearIndex(key.get<uint32_t>(), t);
cursor.del();
}
}
template<int N>
uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type& key, T& out)
{
MDBOutVal id;
if(!d_txn.get(std::get<N>(d_parent->d_tuple).d_idx, key, id))
if(!d_parent.d_txn.get(std::get<N>(d_parent.d_parent->d_tuple).d_idx, key, id))
return get(id.get<uint32_t>(), out);
return 0;
}
template<int N>
uint32_t size()
{
return std::get<N>(d_parent->d_tuple).size(d_txn);
}
template<int N>
uint32_t cardinality()
{
auto cursor = d_txn.getCursor(std::get<N>(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;
@ -252,23 +224,14 @@ public:
return count;
}
void commit()
{
d_txn.commit();
}
void abort()
{
d_txn.abort();
}
struct eiter_t
{};
template<int N>
struct iter_t
{
explicit iter_t(RWTransaction* parent, const typename std::tuple_element<N, tuple_t>::type::type& key) :
explicit iter_t(Parent* parent, const typename std::tuple_element<N, tuple_t>::type::type& key) :
d_parent(parent),
d_cursor(d_parent->d_txn.getCursor(std::get<N>(d_parent->d_parent->d_tuple).d_idx)),
d_in(key)
@ -323,8 +286,8 @@ public:
return *this;
}
RWTransaction* d_parent;
MDBRWCursor d_cursor;
Parent* d_parent;
typename Parent::cursor_t d_cursor;
MDBOutVal d_key, d_data;
MDBInVal d_in;
bool d_end{false};
@ -334,7 +297,7 @@ public:
template<int N>
iter_t<N> find(const typename std::tuple_element<N, tuple_t>::type::type& key)
{
iter_t<N> ret{this, key};
iter_t<N> ret{&d_parent, key};
return ret;
};
@ -344,6 +307,112 @@ public:
}
Parent& d_parent;
};
class ROTransaction : public ReadonlyOperations<ROTransaction>
{
public:
explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(d_parent->d_env->getROTransaction())
{
}
ROTransaction(ROTransaction&& rhs) :
ReadonlyOperations<ROTransaction>(*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<RWTransaction>
{
public:
explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent), d_txn(d_parent->d_env->getRWTransaction())
{
}
RWTransaction(RWTransaction&& rhs) :
ReadonlyOperations<RWTransaction>(*this),
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
{
rhs.d_parent = 0;
}
uint32_t insert(const T& t, uint32_t id=0)
{
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<N>(d_parent->d_tuple).put(d_txn, t, id);
insertMacro(0);
insertMacro(1);
insertMacro(2);
insertMacro(3);
#undef insertMacro
return id;
}
void modify(uint32_t id, std::function<void(T&)> func)
{
T t;
if(!this->get(id, t))
return; // XXX should be exception
func(t);
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(!this->get(id, t))
return;
d_txn.del(d_parent->d_main, id);
clearIndex(id, t);
}
void clear()
{
auto cursor = d_txn.getCursor(d_parent->d_main);
bool first = true;
MDBOutVal key, data;
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
first = false;
T t;
serFromString(data.get<std::string>(), t);
clearIndex(key.get<uint32_t>(), t);
cursor.del();
}
}
void commit()
{
d_txn.commit();
}
void abort()
{
d_txn.abort();
}
typedef MDBRWCursor cursor_t;
private:
void clearIndex(uint32_t id, const T& t)
{
@ -355,6 +424,7 @@ public:
#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<MDBEnv> d_env;
MDBDbi d_main;