get now returns an id, making id=0 special, split out our sample code
This commit is contained in:
parent
3277381170
commit
4c1b5e404c
4
Makefile
4
Makefile
|
@ -10,7 +10,7 @@ CFLAGS:= -Wall -O2 -MMD -MP -ggdb
|
||||||
|
|
||||||
|
|
||||||
PROGRAMS = lmdb-test basic-example scale-example multi-example rel-example \
|
PROGRAMS = lmdb-test basic-example scale-example multi-example rel-example \
|
||||||
resize-example lmdb-typed
|
resize-example typed-example
|
||||||
|
|
||||||
all: $(PROGRAMS)
|
all: $(PROGRAMS)
|
||||||
|
|
||||||
|
@ -38,5 +38,5 @@ rel-example: rel-example.o lmdb-safe.o
|
||||||
resize-example: resize-example.o lmdb-safe.o
|
resize-example: resize-example.o lmdb-safe.o
|
||||||
g++ $(CXXVERSIONFLAG) $^ -o $@ -pthread $(LIBS)
|
g++ $(CXXVERSIONFLAG) $^ -o $@ -pthread $(LIBS)
|
||||||
|
|
||||||
lmdb-typed: lmdb-typed.o lmdb-safe.o
|
typed-example: typed-example.o lmdb-typed.o lmdb-safe.o
|
||||||
g++ $(CXXVERSIONFLAG) $^ -o $@ -pthread $(LIBS) -lboost_serialization
|
g++ $(CXXVERSIONFLAG) $^ -o $@ -pthread $(LIBS) -lboost_serialization
|
||||||
|
|
199
lmdb-typed.cc
199
lmdb-typed.cc
|
@ -1,9 +1,7 @@
|
||||||
#include "lmdb-typed.hh"
|
#include "lmdb-typed.hh"
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
unsigned int getMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
|
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
|
||||||
{
|
{
|
||||||
auto cursor = txn.getCursor(dbi);
|
auto cursor = txn.getCursor(dbi);
|
||||||
MDBOutVal maxidval, maxcontent;
|
MDBOutVal maxidval, maxcontent;
|
||||||
|
@ -15,198 +13,3 @@ unsigned int getMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
struct DNSResourceRecord
|
|
||||||
{
|
|
||||||
string qname; // index
|
|
||||||
uint16_t qtype{0};
|
|
||||||
uint32_t domain_id{0}; // index
|
|
||||||
string content;
|
|
||||||
uint32_t ttl{0};
|
|
||||||
string ordername; // index
|
|
||||||
bool auth{true};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Archive>
|
|
||||||
void serialize(Archive & ar, DNSResourceRecord& g, const unsigned int version)
|
|
||||||
{
|
|
||||||
ar & g.qtype;
|
|
||||||
ar & g.qname;
|
|
||||||
ar & g.content;
|
|
||||||
ar & g.ttl;
|
|
||||||
ar & g.domain_id;
|
|
||||||
ar & g.ordername;
|
|
||||||
ar & g.auth;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct compound
|
|
||||||
{
|
|
||||||
std::string operator()(const DNSResourceRecord& rr)
|
|
||||||
{
|
|
||||||
std::string ret;
|
|
||||||
uint32_t id = htonl(rr.domain_id);
|
|
||||||
ret.assign((char*)&id, 4);
|
|
||||||
ret.append(rr.ordername);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
TypedDBI<DNSResourceRecord,
|
|
||||||
index_on<DNSResourceRecord, string, &DNSResourceRecord::qname>,
|
|
||||||
index_on<DNSResourceRecord, uint32_t, &DNSResourceRecord::domain_id>,
|
|
||||||
index_on_function<DNSResourceRecord, string, compound>
|
|
||||||
> 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 over name 'powerdns.com': "<<endl;
|
|
||||||
auto range = rotxn.equal_range<0>("powerdns.com");
|
|
||||||
for(auto iter = std::move(range.first); iter != range.second; ++iter)
|
|
||||||
{
|
|
||||||
cout << iter->qname << " " << iter->qtype << " " <<iter->content <<endl;
|
|
||||||
}
|
|
||||||
cout<<"Currently have "<< rotxn.size()<< " entries"<<endl;
|
|
||||||
cout<<" " << rotxn.size<0>() << " " << rotxn.size<1>() << " " << rotxn.size<2>() << endl;
|
|
||||||
cout<<" " << rotxn.cardinality<0>() << endl;
|
|
||||||
cout<<" " << rotxn.cardinality<1>() << endl;
|
|
||||||
cout<<" " << rotxn.cardinality<2>() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto txn = tdbi.getRWTransaction();
|
|
||||||
txn.clear();
|
|
||||||
|
|
||||||
cout<<"Currently have "<< txn.size()<< " entries after clear"<<endl;
|
|
||||||
cout<<" " << txn.size<0>() << " " << txn.size<1>() << " " << txn.size<2>() << endl;
|
|
||||||
cout<<" " << txn.cardinality<0>() << endl;
|
|
||||||
cout<<" " << txn.cardinality<1>() << endl;
|
|
||||||
cout<<" " << txn.cardinality<2>() << endl;
|
|
||||||
|
|
||||||
DNSResourceRecord rr;
|
|
||||||
rr.domain_id=11; rr.qtype = 5; rr.ttl = 3600; rr.qname = "www.powerdns.com"; rr.ordername = "www";
|
|
||||||
rr.content = "powerdns.com";
|
|
||||||
|
|
||||||
auto id = txn.put(rr);
|
|
||||||
cout<<"Puted as id "<<id<<endl;
|
|
||||||
|
|
||||||
rr.qname = "powerdns.com"; rr.qtype = 1; rr.ordername=""; rr.content = "1.2.3.4";
|
|
||||||
|
|
||||||
id = txn.put(rr);
|
|
||||||
cout<<"Puted as id "<<id<<endl;
|
|
||||||
|
|
||||||
rr.qtype = 2; rr.content = "ns1.powerdns.com"; rr.ordername = "ns1";
|
|
||||||
id = txn.put(rr);
|
|
||||||
cout<<"Puted as id "<<id<<endl;
|
|
||||||
|
|
||||||
rr.content = "ns2.powerdns.com"; rr.ordername = "ns2"; id = txn.put(rr);
|
|
||||||
cout<<"Puted as id "<<id<<endl;
|
|
||||||
|
|
||||||
rr.qname = "www.ds9a.nl"; rr.domain_id = 10; rr.content = "1.2.3.4"; rr.qtype = 1;
|
|
||||||
rr.ordername="www";
|
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
rr.qname = "ds9a.nl"; rr.content = "ns1.ds9a.nl bert.ds9a.nl 1"; rr.qtype = 6;
|
|
||||||
rr.ordername="";
|
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
rr.qname = "ds9a.nl"; rr.content = "25 ns1.ds9a.nl"; rr.qtype = 15;
|
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
rr.qname = "ns1.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
|
||||||
rr.ordername="ns1";
|
|
||||||
txn.put(rr);
|
|
||||||
rr.qname = "ns1.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
rr.qname = "ns2.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
|
||||||
rr.ordername="ns2";
|
|
||||||
txn.put(rr);
|
|
||||||
rr.qname = "ns2.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DNSResourceRecord rr2;
|
|
||||||
id = txn.get<0>("www.powerdns.com", rr2);
|
|
||||||
|
|
||||||
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<endl;
|
|
||||||
|
|
||||||
id = txn.get<0>("powerdns.com", rr2);
|
|
||||||
|
|
||||||
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<endl;
|
|
||||||
|
|
||||||
DNSResourceRecord rr3;
|
|
||||||
id = txn.get<0>("powerdns.com", rr3);
|
|
||||||
cout<< id << endl;
|
|
||||||
|
|
||||||
|
|
||||||
cout<<"Going to iterate over everything, ordered by name!"<<endl;
|
|
||||||
for(auto iter = txn.begin<0>(); iter != txn.end(); ++iter) {
|
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Going to iterate over everything, ordered by domain_id!"<<endl;
|
|
||||||
for(auto iter = txn.begin<1>(); iter != txn.end(); ++iter) {
|
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Going to iterate over everything, ordered by id!"<<endl;
|
|
||||||
for(auto iter = txn.begin(); iter != txn.end(); ++iter) {
|
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Going to iterate over everything, ordered by compound index!"<<endl;
|
|
||||||
for(auto iter = txn.begin<2>(); iter != txn.end(); ++iter) {
|
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<" # "<<iter->ordername << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
compound c;
|
|
||||||
rr3.ordername = "vvv";
|
|
||||||
rr3.domain_id = 10;
|
|
||||||
auto iter = txn.lower_bound<2>(c(rr3));
|
|
||||||
cout <<"Found for '"<<rr3.ordername<<"' using compound index: "<<iter->qname<< " # '" <<iter->ordername<< "'"<<endl;
|
|
||||||
for(int n =0 ; n < 4; ++n) {
|
|
||||||
--iter;
|
|
||||||
cout <<"Found PREV using compound index: "<<iter->qname<< " # '" <<iter->ordername<<"'"<<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Going to iterate over the name powerdns.com!"<<endl;
|
|
||||||
|
|
||||||
for(auto iter = txn.equal_range<0>("powerdns.com"); iter.first != iter.second; ++iter.first) {
|
|
||||||
cout << iter.first.getID()<<": "<<iter.first->qname << " " << iter.first->qtype << " " << iter.first->content <<endl;
|
|
||||||
}
|
|
||||||
cout<<"Done iterating"<<endl;
|
|
||||||
|
|
||||||
cout<<"Going to iterate over the zone ds9a.nl!"<<endl;
|
|
||||||
|
|
||||||
for(auto iter = txn.find<1>(10); iter != txn.end(); ++iter) {
|
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
// id = txn.get3("ns1", rr4);
|
|
||||||
// cout<<"Found "<<id<<": " << rr4.content <<endl;
|
|
||||||
|
|
||||||
txn.commit();
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ using std::endl;
|
||||||
This makes us start everything at ID=1, which might make it possible to
|
This makes us start everything at ID=1, which might make it possible to
|
||||||
treat id 0 as special
|
treat id 0 as special
|
||||||
*/
|
*/
|
||||||
unsigned int getMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
|
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
|
||||||
|
|
||||||
/** This is our serialization interface.
|
/** This is our serialization interface.
|
||||||
We could/should templatize this so you could pick something else
|
We could/should templatize this so you could pick something else
|
||||||
|
@ -175,7 +175,7 @@ public:
|
||||||
uint32_t size()
|
uint32_t size()
|
||||||
{
|
{
|
||||||
MDB_stat stat;
|
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;
|
return stat.ms_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ public:
|
||||||
uint32_t size()
|
uint32_t size()
|
||||||
{
|
{
|
||||||
MDB_stat stat;
|
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;
|
return stat.ms_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ public:
|
||||||
bool get(uint32_t id, T& t)
|
bool get(uint32_t id, T& t)
|
||||||
{
|
{
|
||||||
MDBOutVal data;
|
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;
|
return false;
|
||||||
|
|
||||||
serFromString(data.get<std::string>(), t);
|
serFromString(data.get<std::string>(), t);
|
||||||
|
@ -204,8 +204,10 @@ public:
|
||||||
uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type& key, T& out)
|
uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type& key, T& out)
|
||||||
{
|
{
|
||||||
MDBOutVal id;
|
MDBOutVal id;
|
||||||
if(!d_parent.d_txn.get(std::get<N>(d_parent.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);
|
if(get(id.get<uint32_t>(), out))
|
||||||
|
return id.get<uint32_t>();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ public:
|
||||||
template<int N>
|
template<int N>
|
||||||
uint32_t cardinality()
|
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;
|
bool first = true;
|
||||||
MDBOutVal key, data;
|
MDBOutVal key, data;
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
@ -251,7 +253,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_on_index) {
|
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");
|
throw std::runtime_error("Missing id in constructor");
|
||||||
serFromString(d_data.get<std::string>(), d_t);
|
serFromString(d_data.get<std::string>(), d_t);
|
||||||
}
|
}
|
||||||
|
@ -260,6 +262,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void del()
|
||||||
|
{
|
||||||
|
d_cursor.del();
|
||||||
|
}
|
||||||
|
|
||||||
bool operator!=(const eiter_t& rhs)
|
bool operator!=(const eiter_t& rhs)
|
||||||
{
|
{
|
||||||
return !d_end;
|
return !d_end;
|
||||||
|
@ -290,7 +297,7 @@ public:
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(d_on_index) {
|
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");
|
throw std::runtime_error("Missing id field");
|
||||||
|
|
||||||
serFromString(data.get<std::string>(), d_t);
|
serFromString(data.get<std::string>(), d_t);
|
||||||
|
@ -334,7 +341,7 @@ public:
|
||||||
template<int N>
|
template<int N>
|
||||||
iter_t begin()
|
iter_t begin()
|
||||||
{
|
{
|
||||||
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;
|
MDBOutVal out, id;
|
||||||
|
|
||||||
|
@ -348,7 +355,7 @@ public:
|
||||||
|
|
||||||
iter_t begin()
|
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;
|
MDBOutVal out, id;
|
||||||
|
|
||||||
|
@ -369,7 +376,7 @@ public:
|
||||||
template<int N>
|
template<int N>
|
||||||
iter_t genfind(const typename std::tuple_element<N, tuple_t>::type::type& key, MDB_cursor_op op)
|
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);
|
||||||
|
|
||||||
MDBInVal in(key);
|
MDBInVal in(key);
|
||||||
MDBOutVal out, id;
|
MDBOutVal out, id;
|
||||||
|
@ -400,7 +407,7 @@ public:
|
||||||
template<int N>
|
template<int N>
|
||||||
std::pair<iter_t,eiter_t> equal_range(const typename std::tuple_element<N, tuple_t>::type::type& key)
|
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);
|
||||||
|
|
||||||
MDBInVal in(key);
|
MDBInVal in(key);
|
||||||
MDBOutVal out, id;
|
MDBOutVal out, id;
|
||||||
|
@ -420,10 +427,15 @@ public:
|
||||||
class ROTransaction : public ReadonlyOperations<ROTransaction>
|
class ROTransaction : public ReadonlyOperations<ROTransaction>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(d_parent->d_env->getROTransaction())
|
explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(std::make_shared<MDBROTransaction>(d_parent->d_env->getROTransaction()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit ROTransaction(TypedDBI* parent, std::shared_ptr<MDBROTransaction> txn) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(txn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ROTransaction(ROTransaction&& rhs) :
|
ROTransaction(ROTransaction&& rhs) :
|
||||||
ReadonlyOperations<ROTransaction>(*this), d_parent(rhs.d_parent),d_txn(std::move(rhs.d_txn))
|
ReadonlyOperations<ROTransaction>(*this), d_parent(rhs.d_parent),d_txn(std::move(rhs.d_txn))
|
||||||
|
|
||||||
|
@ -431,20 +443,31 @@ public:
|
||||||
rhs.d_parent = 0;
|
rhs.d_parent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MDBROTransaction> getTransactionHandle()
|
||||||
|
{
|
||||||
|
return d_txn;
|
||||||
|
}
|
||||||
|
|
||||||
typedef MDBROCursor cursor_t;
|
typedef MDBROCursor cursor_t;
|
||||||
|
|
||||||
TypedDBI* d_parent;
|
TypedDBI* d_parent;
|
||||||
MDBROTransaction d_txn;
|
std::shared_ptr<MDBROTransaction> d_txn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RWTransaction : public ReadonlyOperations<RWTransaction>
|
class RWTransaction : public ReadonlyOperations<RWTransaction>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent), d_txn(d_parent->d_env->getRWTransaction())
|
explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent)
|
||||||
|
{
|
||||||
|
d_txn = std::make_shared<MDBRWTransaction>(d_parent->d_env->getRWTransaction());
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit RWTransaction(TypedDBI* parent, std::shared_ptr<MDBRWTransaction> txn) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent), d_txn(txn)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RWTransaction(RWTransaction&& rhs) :
|
RWTransaction(RWTransaction&& rhs) :
|
||||||
ReadonlyOperations<RWTransaction>(*this),
|
ReadonlyOperations<RWTransaction>(*this),
|
||||||
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
|
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
|
||||||
|
@ -456,10 +479,10 @@ public:
|
||||||
uint32_t put(const T& t, uint32_t id=0)
|
uint32_t put(const T& t, uint32_t id=0)
|
||||||
{
|
{
|
||||||
if(!id)
|
if(!id)
|
||||||
id = getMaxID(d_txn, d_parent->d_main) + 1;
|
id = MDBGetMaxID(*d_txn, d_parent->d_main) + 1;
|
||||||
d_txn.put(d_parent->d_main, id, serToString(t));
|
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);
|
#define insertMacro(N) std::get<N>(d_parent->d_tuple).put(*d_txn, t, id);
|
||||||
insertMacro(0);
|
insertMacro(0);
|
||||||
insertMacro(1);
|
insertMacro(1);
|
||||||
insertMacro(2);
|
insertMacro(2);
|
||||||
|
@ -488,14 +511,14 @@ public:
|
||||||
if(!this->get(id, t))
|
if(!this->get(id, t))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d_txn.del(d_parent->d_main, id);
|
d_txn->del(d_parent->d_main, id);
|
||||||
clearIndex(id, t);
|
clearIndex(id, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! clear database & indexes (by hand!)
|
//! clear database & indexes (by hand!)
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
auto cursor = d_txn.getCursor(d_parent->d_main);
|
auto cursor = d_txn->getCursor(d_parent->d_main);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
MDBOutVal key, data;
|
MDBOutVal key, data;
|
||||||
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
|
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
|
||||||
|
@ -510,22 +533,28 @@ public:
|
||||||
//! commit this transaction
|
//! commit this transaction
|
||||||
void commit()
|
void commit()
|
||||||
{
|
{
|
||||||
d_txn.commit();
|
d_txn->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! abort this transaction
|
//! abort this transaction
|
||||||
void abort()
|
void abort()
|
||||||
{
|
{
|
||||||
d_txn.abort();
|
d_txn->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef MDBRWCursor cursor_t;
|
typedef MDBRWCursor cursor_t;
|
||||||
|
|
||||||
|
std::shared_ptr<MDBRWTransaction> getTransactionHandle()
|
||||||
|
{
|
||||||
|
return d_txn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// clear this ID from all indexes
|
// clear this ID from all indexes
|
||||||
void clearIndex(uint32_t id, const T& t)
|
void clearIndex(uint32_t id, const T& t)
|
||||||
{
|
{
|
||||||
#define clearMacro(N) std::get<N>(d_parent->d_tuple).del(d_txn, t, id);
|
#define clearMacro(N) std::get<N>(d_parent->d_tuple).del(*d_txn, t, id);
|
||||||
clearMacro(0);
|
clearMacro(0);
|
||||||
clearMacro(1);
|
clearMacro(1);
|
||||||
clearMacro(2);
|
clearMacro(2);
|
||||||
|
@ -535,7 +564,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypedDBI* d_parent;
|
TypedDBI* d_parent;
|
||||||
MDBRWTransaction d_txn;
|
std::shared_ptr<MDBRWTransaction> d_txn;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Get an RW transaction
|
//! Get an RW transaction
|
||||||
|
@ -550,6 +579,23 @@ public:
|
||||||
return ROTransaction(this);
|
return ROTransaction(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Get an RW transaction
|
||||||
|
RWTransaction getRWTransaction(std::shared_ptr<MDBRWTransaction> txn)
|
||||||
|
{
|
||||||
|
return RWTransaction(this, txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get an RO transaction
|
||||||
|
ROTransaction getROTransaction(std::shared_ptr<MDBROTransaction> txn)
|
||||||
|
{
|
||||||
|
return ROTransaction(this, txn);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MDBEnv> getEnv()
|
||||||
|
{
|
||||||
|
return d_env;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<MDBEnv> d_env;
|
std::shared_ptr<MDBEnv> d_env;
|
||||||
MDBDbi d_main;
|
MDBDbi d_main;
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
#include "lmdb-typed.hh"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct DNSResourceRecord
|
||||||
|
{
|
||||||
|
string qname; // index
|
||||||
|
uint16_t qtype{0};
|
||||||
|
uint32_t domain_id{0}; // index
|
||||||
|
string content;
|
||||||
|
uint32_t ttl{0};
|
||||||
|
string ordername; // index
|
||||||
|
bool auth{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DomainInfo
|
||||||
|
{
|
||||||
|
string qname;
|
||||||
|
string master;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, DomainInfo& g, const unsigned int version)
|
||||||
|
{
|
||||||
|
ar & g.qname & g.master;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, DNSResourceRecord& g, const unsigned int version)
|
||||||
|
{
|
||||||
|
ar & g.qtype;
|
||||||
|
ar & g.qname;
|
||||||
|
ar & g.content;
|
||||||
|
ar & g.ttl;
|
||||||
|
ar & g.domain_id;
|
||||||
|
ar & g.ordername;
|
||||||
|
ar & g.auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct compound
|
||||||
|
{
|
||||||
|
std::string operator()(const DNSResourceRecord& rr)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
uint32_t id = htonl(rr.domain_id);
|
||||||
|
ret.assign((char*)&id, 4);
|
||||||
|
ret.append(rr.ordername);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
TypedDBI<DNSResourceRecord,
|
||||||
|
index_on<DNSResourceRecord, string, &DNSResourceRecord::qname>,
|
||||||
|
index_on<DNSResourceRecord, uint32_t, &DNSResourceRecord::domain_id>,
|
||||||
|
index_on_function<DNSResourceRecord, string, compound>
|
||||||
|
> tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records");
|
||||||
|
|
||||||
|
TypedDBI<DomainInfo,
|
||||||
|
index_on<DomainInfo, string, &DomainInfo::qname>
|
||||||
|
> tdomains(tdbi.getEnv(), "domains");
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
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 over name 'powerdns.com': "<<endl;
|
||||||
|
auto range = rotxn.equal_range<0>("powerdns.com");
|
||||||
|
for(auto iter = std::move(range.first); iter != range.second; ++iter)
|
||||||
|
{
|
||||||
|
cout << iter->qname << " " << iter->qtype << " " <<iter->content <<endl;
|
||||||
|
}
|
||||||
|
cout<<"Currently have "<< rotxn.size()<< " entries"<<endl;
|
||||||
|
cout<<" " << rotxn.size<0>() << " " << rotxn.size<1>() << " " << rotxn.size<2>() << endl;
|
||||||
|
cout<<" " << rotxn.cardinality<0>() << endl;
|
||||||
|
cout<<" " << rotxn.cardinality<1>() << endl;
|
||||||
|
cout<<" " << rotxn.cardinality<2>() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto txn = tdbi.getRWTransaction();
|
||||||
|
auto domtxn = tdomains.getRWTransaction(txn.getTransactionHandle());
|
||||||
|
cout << domtxn.size()<<" domains in table"<<endl;
|
||||||
|
txn.clear();
|
||||||
|
domtxn.clear();
|
||||||
|
|
||||||
|
cout<<"Currently have "<< txn.size()<< " entries after clear"<<endl;
|
||||||
|
cout<<" " << txn.size<0>() << " " << txn.size<1>() << " " << txn.size<2>() << endl;
|
||||||
|
cout<<" " << txn.cardinality<0>() << endl;
|
||||||
|
cout<<" " << txn.cardinality<1>() << endl;
|
||||||
|
cout<<" " << txn.cardinality<2>() << endl;
|
||||||
|
|
||||||
|
DomainInfo di{"powerdns.com", "ns1.powerdns.com"};
|
||||||
|
domtxn.put(di, 11);
|
||||||
|
|
||||||
|
DNSResourceRecord rr;
|
||||||
|
rr.domain_id=11; rr.qtype = 5; rr.ttl = 3600; rr.qname = "www.powerdns.com"; rr.ordername = "www";
|
||||||
|
rr.content = "powerdns.com";
|
||||||
|
|
||||||
|
auto id = txn.put(rr);
|
||||||
|
cout<<"Puted as id "<<id<<endl;
|
||||||
|
|
||||||
|
rr.qname = "powerdns.com"; rr.qtype = 1; rr.ordername=""; rr.content = "1.2.3.4";
|
||||||
|
|
||||||
|
id = txn.put(rr);
|
||||||
|
cout<<"Puted as id "<<id<<endl;
|
||||||
|
|
||||||
|
rr.qtype = 2; rr.content = "ns1.powerdns.com"; rr.ordername = "ns1";
|
||||||
|
id = txn.put(rr);
|
||||||
|
cout<<"Puted as id "<<id<<endl;
|
||||||
|
|
||||||
|
rr.content = "ns2.powerdns.com"; rr.ordername = "ns2"; id = txn.put(rr);
|
||||||
|
cout<<"Puted as id "<<id<<endl;
|
||||||
|
|
||||||
|
DomainInfo di2{"ds9a.nl", "ns1.powerdns.com"};
|
||||||
|
domtxn.put(di, 10);
|
||||||
|
|
||||||
|
|
||||||
|
rr.qname = "www.ds9a.nl"; rr.domain_id = 10; rr.content = "1.2.3.4"; rr.qtype = 1;
|
||||||
|
rr.ordername="www";
|
||||||
|
txn.put(rr);
|
||||||
|
|
||||||
|
rr.qname = "ds9a.nl"; rr.content = "ns1.ds9a.nl bert.ds9a.nl 1"; rr.qtype = 6;
|
||||||
|
rr.ordername="";
|
||||||
|
txn.put(rr);
|
||||||
|
|
||||||
|
rr.qname = "ds9a.nl"; rr.content = "25 ns1.ds9a.nl"; rr.qtype = 15;
|
||||||
|
txn.put(rr);
|
||||||
|
|
||||||
|
rr.qname = "ns1.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
||||||
|
rr.ordername="ns1";
|
||||||
|
txn.put(rr);
|
||||||
|
rr.qname = "ns1.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
||||||
|
txn.put(rr);
|
||||||
|
|
||||||
|
rr.qname = "ns2.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
||||||
|
rr.ordername="ns2";
|
||||||
|
txn.put(rr);
|
||||||
|
rr.qname = "ns2.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
||||||
|
txn.put(rr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DNSResourceRecord rr2;
|
||||||
|
id = txn.get<0>("www.powerdns.com", rr2);
|
||||||
|
|
||||||
|
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<endl;
|
||||||
|
|
||||||
|
id = txn.get<0>("powerdns.com", rr2);
|
||||||
|
|
||||||
|
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<endl;
|
||||||
|
|
||||||
|
DNSResourceRecord rr3;
|
||||||
|
id = txn.get<0>("powerdns.com", rr3);
|
||||||
|
cout<< id << endl;
|
||||||
|
|
||||||
|
|
||||||
|
cout<<"Going to iterate over everything, ordered by name!"<<endl;
|
||||||
|
for(auto iter = txn.begin<0>(); iter != txn.end(); ++iter) {
|
||||||
|
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout<<"Going to iterate over everything, ordered by domain_id!"<<endl;
|
||||||
|
for(auto iter = txn.begin<1>(); iter != txn.end(); ++iter) {
|
||||||
|
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout<<"Going to iterate over everything, ordered by id!"<<endl;
|
||||||
|
for(auto iter = txn.begin(); iter != txn.end(); ++iter) {
|
||||||
|
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout<<"Going to iterate over everything, ordered by compound index!"<<endl;
|
||||||
|
for(auto iter = txn.begin<2>(); iter != txn.end(); ++iter) {
|
||||||
|
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<" # "<<iter->ordername << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
compound c;
|
||||||
|
rr3.ordername = "vvv";
|
||||||
|
rr3.domain_id = 10;
|
||||||
|
auto iter = txn.lower_bound<2>(c(rr3));
|
||||||
|
cout <<"Found for '"<<rr3.ordername<<"' using compound index: "<<iter->qname<< " # '" <<iter->ordername<< "'"<<endl;
|
||||||
|
for(int n =0 ; n < 4; ++n) {
|
||||||
|
--iter;
|
||||||
|
cout <<"Found PREV using compound index: "<<iter->qname<< " # '" <<iter->ordername<<"'"<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout<<"Going to iterate over the name powerdns.com!"<<endl;
|
||||||
|
|
||||||
|
for(auto iter = txn.equal_range<0>("powerdns.com"); iter.first != iter.second; ++iter.first) {
|
||||||
|
cout << iter.first.getID()<<": "<<iter.first->qname << " " << iter.first->qtype << " " << iter.first->content <<endl;
|
||||||
|
}
|
||||||
|
cout<<"Done iterating"<<endl;
|
||||||
|
|
||||||
|
cout<<"Going to iterate over the zone ds9a.nl!"<<endl;
|
||||||
|
|
||||||
|
for(auto iter = txn.find<1>(10); iter != txn.end(); ++iter) {
|
||||||
|
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
// id = txn.get3("ns1", rr4);
|
||||||
|
// cout<<"Found "<<id<<": " << rr4.content <<endl;
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
}
|
Loading…
Reference in New Issue