add compound keys and iterator--

This commit is contained in:
bert hubert 2018-12-16 15:58:38 +01:00
parent 29aaa63a69
commit bb981d6d31
2 changed files with 125 additions and 33 deletions

View File

@ -39,13 +39,23 @@ void serialize(Archive & ar, DNSResourceRecord& g, const unsigned int version)
}
struct compound
{
std::string operator()(const DNSResourceRecord& rr)
{
std::string ret;
ret.assign((char*)&rr.domain_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<DNSResourceRecord, string, &DNSResourceRecord::ordername>,
index_on<DNSResourceRecord, bool, &DNSResourceRecord::auth>
index_on_function<DNSResourceRecord, string, compound>
> tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records");
{
@ -57,17 +67,17 @@ int main()
else {
cout <<"Did not find id 2" << endl;
}
cout<<"Iterating: "<<endl;
for(auto iter = rotxn.find<0>("powerdns.com"); iter !=rotxn.end(); ++iter)
cout<<"Iterating over name 'powerdns.com': "<<endl;
auto range = rotxn.equal_range<0>("powerdns.com");
for(auto& iter = range.first; iter != range.second; ++iter)
{
cout << iter->qtype << endl;
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;
cout<<" " << rotxn.cardinality<3>() << endl;
}
auto txn = tdbi.getRWTransaction();
@ -78,7 +88,6 @@ int main()
cout<<" " << txn.cardinality<0>() << endl;
cout<<" " << txn.cardinality<1>() << endl;
cout<<" " << txn.cardinality<2>() << endl;
cout<<" " << txn.cardinality<3>() << endl;
DNSResourceRecord rr;
rr.domain_id=11; rr.qtype = 5; rr.ttl = 3600; rr.qname = "www.powerdns.com"; rr.ordername = "www";
@ -87,7 +96,7 @@ int main()
auto id = txn.insert(rr);
cout<<"Inserted as id "<<id<<endl;
rr.qname = "powerdns.com"; rr.qtype = 1; rr.ordername=" "; rr.content = "1.2.3.4";
rr.qname = "powerdns.com"; rr.qtype = 1; rr.ordername=""; rr.content = "1.2.3.4";
id = txn.insert(rr);
cout<<"Inserted as id "<<id<<endl;
@ -100,14 +109,29 @@ int main()
cout<<"Inserted 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.insert(rr);
rr.qname = "ds9a.nl"; rr.content = "ns1.ds9a.nl bert.ds9a.bl 1"; rr.qtype = 6;
rr.qname = "ds9a.nl"; rr.content = "ns1.ds9a.nl bert.ds9a.nl 1"; rr.qtype = 6;
rr.ordername="";
txn.insert(rr);
rr.qname = "ds9a.nl"; rr.content = "25 ns1.ds9a.nl"; rr.qtype = 15;
txn.insert(rr);
rr.qname = "ns1.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
rr.ordername="ns1";
txn.insert(rr);
rr.qname = "ns1.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
txn.insert(rr);
rr.qname = "ns2.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
rr.ordername="ns2";
txn.insert(rr);
rr.qname = "ns2.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
txn.insert(rr);
DNSResourceRecord rr2;
id = txn.get<0>("www.powerdns.com", rr2);
@ -133,16 +157,30 @@ int main()
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
}
cout<<"Going to iterate over everything, ordered by id!"<<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 = "www";
rr3.domain_id = 10;
auto iter = txn.find<2>(c(rr3));
cout <<"Found 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.find<0>("powerdns.com"); iter != txn.end(); ++iter) {
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<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;

View File

@ -19,11 +19,12 @@ using std::endl;
Everything should go into a namespace
What is an error? What is an exception?
Is id=0 still magic?
could id=0 be magic? ('no such id')
Composite keys (powerdns needs them)
functional keys
Insert? Put? Naming matters
Is boost the best serializer?
rename find to equal_range
Perhaps use the separate index concept from multi_index
A dump function would be nice (typed)
*/
@ -92,33 +93,56 @@ void serFromString(const std::string& str, T& ret)
*/
// this only needs methods that must happen for all indexes at once
// so specifically, not size<t> or get<t>, people ask for those
template<class Class,typename Type,Type Class::*PtrToMember>
struct index_on
{
static Type getMember(const Class& c)
{
return c.*PtrToMember;
}
// so specifically, not size<t> or get<t>, people ask for those themselves, and
// should no do that on indexes that don't exist
template<class Class,typename Type, typename Parent>
struct LMDBIndexOps
{
explicit LMDBIndexOps(Parent* parent) : d_parent(parent){}
void put(MDBRWTransaction& txn, const Class& t, uint32_t id)
{
txn.put(d_idx, getMember(t), id);
txn.put(d_idx, d_parent->getMember(t), id);
}
void del(MDBRWTransaction& txn, const Class& t, uint32_t id)
{
txn.del(d_idx, getMember(t), id);
txn.del(d_idx, d_parent->getMember(t), id);
}
void openDB(std::shared_ptr<MDBEnv>& env, string_view str, int flags)
{
d_idx = env->openDB(str, flags);
}
MDBDbi d_idx;
Parent* d_parent;
};
template<class Class,typename Type,Type Class::*PtrToMember>
struct index_on : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>
{
index_on() : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>(this)
{}
static Type getMember(const Class& c)
{
return c.*PtrToMember;
}
typedef Type type;
MDBDbi d_idx;
};
template<class Class, typename Type, class Func>
struct index_on_function : LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func> >
{
index_on_function() : LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func> >(this)
{}
static Type getMember(const Class& c)
{
Func f;
return f(c);
}
typedef Type type;
};
struct nullindex_t
@ -268,10 +292,10 @@ public:
return &d_t;
}
iter_t& operator++()
iter_t& genoperator(MDB_cursor_op dupop, MDB_cursor_op op)
{
MDBOutVal data;
int rc = d_cursor.get(d_key, d_id, d_one_key ? MDB_NEXT_DUP : MDB_NEXT);
int rc = d_cursor.get(d_key, d_id, d_one_key ? dupop : op);
if(rc == MDB_NOTFOUND) {
d_end = true;
}
@ -288,6 +312,15 @@ public:
return *this;
}
iter_t& operator++()
{
return genoperator(MDB_NEXT_DUP, MDB_NEXT);
}
iter_t& operator--()
{
return genoperator(MDB_PREV_DUP, MDB_PREV);
}
uint32_t getID()
{
if(d_on_index)
@ -298,7 +331,7 @@ public:
Parent* d_parent;
typename Parent::cursor_t d_cursor;
MDBOutVal d_key, d_data, d_id;
MDBOutVal d_key{0,0}, d_data{0,0}, d_id{0,0};
bool d_on_index;
bool d_one_key;
bool d_end{false};
@ -312,8 +345,9 @@ public:
MDBOutVal out, id;
if(cursor.get(out, id, MDB_FIRST)) {
return iter_t{&d_parent, std::move(cursor), true, true, true};
if(cursor.get(out, id, MDB_FIRST))
{ // on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), true, false, true};
}
return iter_t{&d_parent, std::move(cursor), true, false};
@ -326,7 +360,8 @@ public:
MDBOutVal out, id;
if(cursor.get(out, id, MDB_FIRST)) {
return iter_t{&d_parent, std::move(cursor), false, true, true};
// on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), false, false, true};
}
return iter_t{&d_parent, std::move(cursor), false, false};
@ -343,11 +378,30 @@ public:
out.d_mdbval = in.d_mdbval;
if(cursor.get(out, id, MDB_SET)) {
return iter_t{&d_parent, std::move(cursor), true, true, true};
// on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), true, false, true};
}
return iter_t{&d_parent, std::move(cursor), true, true};
return iter_t{&d_parent, std::move(cursor), true, false};
};
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);
MDBInVal in(key);
MDBOutVal out, id;
out.d_mdbval = in.d_mdbval;
if(cursor.get(out, id, MDB_SET)) {
// on_index, one_key, end
return {iter_t{&d_parent, std::move(cursor), true, true, true}, eiter_t()};
}
return {iter_t{&d_parent, std::move(cursor), true, true}, eiter_t()};
};
eiter_t end()
{