Format tests and examples as well

This commit is contained in:
Martchus 2022-01-30 21:32:08 +01:00
parent 1e393bf3fe
commit ec4a44e4de
10 changed files with 811 additions and 824 deletions

View File

@ -61,6 +61,16 @@ use_package(TARGET_NAME Catch2::Catch2 PACKAGE_NAME Catch2 LIBRARIES_VARIABLE "T
# find threading library (required by examples)
use_package(TARGET_NAME Threads::Threads PACKAGE_NAME Threads LIBRARIES_VARIABLE "TEST_LIBRARIES")
# add test/example files to EXCLUDED_FILES so they're formatted
set(TESTS basic typed)
set(EXAMPLES basic multi rel resize scale typed view)
foreach (TEST ${TESTS})
list(APPEND EXCLUDED_FILES "tests/${TEST}.cc")
endforeach ()
foreach (EXAMPLE ${EXAMPLES})
list(APPEND EXCLUDED_FILES "examples/${EXAMPLE}.cc")
endforeach ()
# include modules to apply configuration
include(BasicConfig)
include(WindowsResources)
@ -71,11 +81,9 @@ include(ConfigHeader)
# configure test targets
include(TestUtilities)
list(APPEND TEST_LIBRARIES ${META_TARGET_NAME})
set(TESTS basic typed)
foreach (TEST ${TESTS})
configure_test_target(TEST_NAME "${TEST}_tests" SRC_FILES "tests/${TEST}.cc" LIBRARIES "${TEST_LIBRARIES}")
endforeach ()
set(EXAMPLES basic multi rel resize scale typed view)
foreach (EXAMPLE ${EXAMPLES})
configure_test_target(TEST_NAME "${EXAMPLE}_example" SRC_FILES "examples/${EXAMPLE}.cc" LIBRARIES "${TEST_LIBRARIES}")
endforeach ()

View File

@ -3,42 +3,40 @@
using namespace std;
using namespace LMDBSafe;
void checkLMDB(MDBEnv* env, MDBDbi dbi)
void checkLMDB(MDBEnv *env, MDBDbi dbi)
{
auto rotxn = env->getROTransaction();
MDBOutVal data;
if(!rotxn->get(dbi, "lmdb", data)) {
cout<< "Outside RW transaction, found that lmdb = " << data.get<string_view>() <<endl;
}
else
cout<<"Outside RW transaction, found nothing" << endl;
auto rotxn = env->getROTransaction();
MDBOutVal data;
if (!rotxn->get(dbi, "lmdb", data)) {
cout << "Outside RW transaction, found that lmdb = " << data.get<string_view>() << endl;
} else
cout << "Outside RW transaction, found nothing" << endl;
}
int main()
{
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB("example", MDB_CREATE);
auto txn = env->getRWTransaction();
mdb_drop(*txn, dbi, 0);
txn->put(dbi, "lmdb", "great");
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB("example", MDB_CREATE);
MDBOutVal data;
if(!txn->get(dbi, "lmdb", data)) {
cout<< "Within RW transaction, found that lmdb = " << data.get<string_view>() <<endl;
}
else
cout<<"Found nothing" << endl;
auto txn = env->getRWTransaction();
mdb_drop(*txn, dbi, 0);
txn->put(dbi, "lmdb", "great");
std::thread elsewhere(checkLMDB, env.get(), dbi);
elsewhere.join();
txn->commit();
cout<<"Committed data"<<endl;
checkLMDB(env.get(), dbi);
txn = env->getRWTransaction();
mdb_drop(*txn, dbi, 0);
txn->commit();
MDBOutVal data;
if (!txn->get(dbi, "lmdb", data)) {
cout << "Within RW transaction, found that lmdb = " << data.get<string_view>() << endl;
} else
cout << "Found nothing" << endl;
std::thread elsewhere(checkLMDB, env.get(), dbi);
elsewhere.join();
txn->commit();
cout << "Committed data" << endl;
checkLMDB(env.get(), dbi);
txn = env->getRWTransaction();
mdb_drop(*txn, dbi, 0);
txn->commit();
}

View File

@ -7,56 +7,53 @@ using namespace LMDBSafe;
int main()
{
unlink("./multi");
auto env = getMDBEnv("multi", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB("qnames", MDB_DUPSORT | MDB_CREATE);
unlink("./multi");
auto env = getMDBEnv("multi", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB("qnames", MDB_DUPSORT | MDB_CREATE);
auto txn = env->getRWTransaction();
txn->clear(dbi);
auto txn = env->getRWTransaction();
txn->clear(dbi);
txn->put(dbi, "bdb", "old");
txn->put(dbi, "lmdb", "hot");
txn->put(dbi, "lmdb", "fast");
txn->put(dbi, "lmdb", "zooms");
txn->put(dbi, "lmdb", "c");
txn->put(dbi, "mdb", "old name");
txn->put(dbi, "bdb", "old");
txn->put(dbi, "lmdb", "hot");
txn->put(dbi, "lmdb", "fast");
txn->put(dbi, "lmdb", "zooms");
txn->put(dbi, "lmdb", "c");
txn->put(dbi, "mdb", "old name");
string_view v1;
if(!txn->get(dbi, "mdb", v1)) {
cout<<v1<<endl;
}
else {
cout << "found nothing" << endl;
}
txn->commit();
txn = env->getRWTransaction();
auto cursor = txn->getRWCursor(dbi);
string_view v1;
if (!txn->get(dbi, "mdb", v1)) {
cout << v1 << endl;
} else {
cout << "found nothing" << endl;
}
txn->commit();
MDBOutVal key, data;
txn = env->getRWTransaction();
auto cursor = txn->getRWCursor(dbi);
for(int rc = cursor.find("lmdb", key, data); !rc; rc = cursor.get(key, data, MDB_NEXT_DUP)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() <<endl;
}
MDBOutVal key, data;
cout<<"Dump of complete database: "<<endl;
for(int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() <<endl;
}
cout << "Done!" <<endl;
for (int rc = cursor.find("lmdb", key, data); !rc; rc = cursor.get(key, data, MDB_NEXT_DUP)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() << endl;
}
cout << "Now going to delete 'lmdb' keys" << endl;
cout << "Dump of complete database: " << endl;
for (int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() << endl;
}
cout << "Done!" << endl;
for(int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
if(key.get<string_view>() == "lmdb")
cursor.del();
}
cout << "Now going to delete 'lmdb' keys" << endl;
cout <<"Complete database after deleting 'lmdb' keys: " << endl;
for(int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() <<endl;
}
for (int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
if (key.get<string_view>() == "lmdb")
cursor.del();
}
cout << "Complete database after deleting 'lmdb' keys: " << endl;
for (int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
cout << key.get<string_view>() << " = " << data.get<string_view>() << endl;
}
}

View File

@ -1,7 +1,7 @@
#include "../lmdb-safe.hh"
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <c++utilities/application/global.h>
@ -10,157 +10,149 @@
using namespace std;
using namespace LMDBSafe;
struct Record
{
struct Record {
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & id & domain_id & name & type & ttl & content & enabled & auth;
}
unsigned int id;
unsigned int domain_id; // needs index
std::string name; // needs index
std::string type;
unsigned int ttl{0};
std::string content;
bool enabled{true};
bool auth{true};
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar &id &domain_id &name &type &ttl &content &enabled &auth;
}
unsigned int id;
unsigned int domain_id; // needs index
std::string name; // needs index
std::string type;
unsigned int ttl{ 0 };
std::string content;
bool enabled{ true };
bool auth{ true };
};
static unsigned int getMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
static unsigned int getMaxID(MDBRWTransaction &txn, MDBDbi &dbi)
{
auto cursor = txn->getRWCursor(dbi);
MDBOutVal maxidval, maxcontent;
unsigned int maxid{0};
if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
maxid = maxidval.get<unsigned int>();
}
return maxid;
auto cursor = txn->getRWCursor(dbi);
MDBOutVal maxidval, maxcontent;
unsigned int maxid{ 0 };
if (!cursor.get(maxidval, maxcontent, MDB_LAST)) {
maxid = maxidval.get<unsigned int>();
}
return maxid;
}
static void store(MDBRWTransaction& txn, MDBDbi& records, MDBDbi& domainidx, MDBDbi&nameidx, const Record& r)
static void store(MDBRWTransaction &txn, MDBDbi &records, MDBDbi &domainidx, MDBDbi &nameidx, const Record &r)
{
ostringstream oss;
boost::archive::binary_oarchive oa(oss,boost::archive::no_header );
oa << r;
txn->put(records, r.id, oss.str(), MDB_APPEND);
txn->put(domainidx, r.domain_id, r.id);
txn->put(nameidx, r.name, r.id);
ostringstream oss;
boost::archive::binary_oarchive oa(oss, boost::archive::no_header);
oa << r;
txn->put(records, r.id, oss.str(), MDB_APPEND);
txn->put(domainidx, r.domain_id, r.id);
txn->put(nameidx, r.name, r.id);
}
int main(int argc, char** argv)
int main(int argc, char **argv)
{
auto env = getMDBEnv("pdns", MDB_NOSUBDIR, 0600);
auto records = env->openDB("records", MDB_INTEGERKEY | MDB_CREATE );
auto domainidx = env->openDB("domainidx", MDB_INTEGERKEY | MDB_DUPFIXED | MDB_DUPSORT | MDB_CREATE);
auto nameidx = env->openDB("nameidx", MDB_DUPFIXED | MDB_DUPSORT | MDB_CREATE);
auto env = getMDBEnv("pdns", MDB_NOSUBDIR, 0600);
auto records = env->openDB("records", MDB_INTEGERKEY | MDB_CREATE);
auto domainidx = env->openDB("domainidx", MDB_INTEGERKEY | MDB_DUPFIXED | MDB_DUPSORT | MDB_CREATE);
auto nameidx = env->openDB("nameidx", MDB_DUPFIXED | MDB_DUPSORT | MDB_CREATE);
auto txn = env->getRWTransaction();
auto txn = env->getRWTransaction();
/*
/*
txn.clear(records);
txn.clear(domainidx);
txn.clear(domainidx);
txn.clear(nameidx);
*/
unsigned int maxid=getMaxID(txn, records);
unsigned int maxdomainid=getMaxID(txn, domainidx);
cout<<"Maxid = "<<maxid<<", Max domain ID = "<<maxdomainid<<endl;
unsigned int maxid = getMaxID(txn, records);
unsigned int maxdomainid = getMaxID(txn, domainidx);
string prefix(argc >= 2 ? argv[1] : "prefix");
auto lim=atoi(argc >= 3 ? argv[2] : "10");
for(int n=0; n < lim; ++n) {
string domain;
if(n)
domain.assign(prefix+std::to_string(n)+".com");
else
domain="powerdns.com";
Record r;
r.id=++maxid;
r.domain_id = ++maxdomainid;
r.name = domain;
r.ttl = 3600;
r.type = "SOA";
r.content = "ns1.powerdns.com ahu.powerdns.com 1";
cout << "Maxid = " << maxid << ", Max domain ID = " << maxdomainid << endl;
store(txn, records, domainidx, nameidx, r);
string prefix(argc >= 2 ? argv[1] : "prefix");
auto lim = atoi(argc >= 3 ? argv[2] : "10");
for (int n = 0; n < lim; ++n) {
string domain;
if (n)
domain.assign(prefix + std::to_string(n) + ".com");
else
domain = "powerdns.com";
Record r;
r.id = ++maxid;
r.domain_id = ++maxdomainid;
r.name = domain;
r.ttl = 3600;
r.type = "SOA";
r.content = "ns1.powerdns.com ahu.powerdns.com 1";
r.id=++maxid;
r.type="NS";
r.content="ns1.powerdns.com";
store(txn, records, domainidx, nameidx, r);
store(txn, records, domainidx, nameidx, r);
r.id = ++maxid;
r.type = "NS";
r.content = "ns1.powerdns.com";
store(txn, records, domainidx, nameidx, r);
r.id=++maxid;
r.type="A";
r.content="1.2.3.4";
store(txn, records, domainidx, nameidx, r);
r.id = ++maxid;
r.type = "A";
r.content = "1.2.3.4";
store(txn, records, domainidx, nameidx, r);
r.id=++maxid;
r.type="AAAA";
r.content="::1";
store(txn, records, domainidx, nameidx, r);
r.id = ++maxid;
r.type = "AAAA";
r.content = "::1";
store(txn, records, domainidx, nameidx, r);
r.id=++maxid;
r.type="CAA";
r.content="letsencrypt.org";
store(txn, records, domainidx, nameidx, r);
r.id = ++maxid;
r.type = "CAA";
r.content = "letsencrypt.org";
store(txn, records, domainidx, nameidx, r);
r.id=++maxid;
r.type="AAAA";
r.name="www."+domain;
r.content="::1";
store(txn, records, domainidx, nameidx, r);
r.id = ++maxid;
r.type = "AAAA";
r.name = "www." + domain;
r.content = "::1";
store(txn, records, domainidx, nameidx, r);
r.id=++maxid;
r.type="A";
r.name="www."+domain;
r.content="127.0.0.1";
store(txn, records, domainidx, nameidx, r);
}
txn->commit();
auto rotxn = env->getROTransaction();
auto rotxn2 = env->getROTransaction();
auto rocursor = rotxn->getCursor(nameidx);
MDBOutVal data;
int count = 0;
MDBOutVal key;
MDBInVal tmp("www.powerdns.com");
key.d_mdbval = tmp.d_mdbval;
// ugh
while(!rocursor.get(key, data, count ? MDB_NEXT_DUP : MDB_SET)) {
unsigned int id = data.get<unsigned int>();
cout<<"Got something: id="<<id<<endl;
MDBOutVal record;
if(!rotxn->get(records, data, record)) {
Record test;
stringstream istr{record.get<string>()};
boost::archive::binary_iarchive oi(istr,boost::archive::no_header );
oi >> test;
cout <<"Record: "<<test.name<<" "<<test.type <<" " <<test.ttl<<" "<<test.content<<endl;
r.id = ++maxid;
r.type = "A";
r.name = "www." + domain;
r.content = "127.0.0.1";
store(txn, records, domainidx, nameidx, r);
}
else {
cout<<"Did not find anything for id "<<id<<endl;
txn->commit();
auto rotxn = env->getROTransaction();
auto rotxn2 = env->getROTransaction();
auto rocursor = rotxn->getCursor(nameidx);
MDBOutVal data;
int count = 0;
MDBOutVal key;
MDBInVal tmp("www.powerdns.com");
key.d_mdbval = tmp.d_mdbval;
// ugh
while (!rocursor.get(key, data, count ? MDB_NEXT_DUP : MDB_SET)) {
unsigned int id = data.get<unsigned int>();
cout << "Got something: id=" << id << endl;
MDBOutVal record;
if (!rotxn->get(records, data, record)) {
Record test;
stringstream istr{ record.get<string>() };
boost::archive::binary_iarchive oi(istr, boost::archive::no_header);
oi >> test;
cout << "Record: " << test.name << " " << test.type << " " << test.ttl << " " << test.content << endl;
} else {
cout << "Did not find anything for id " << id << endl;
}
++count;
}
++count;
}
}

View File

@ -5,87 +5,78 @@
using namespace std;
using namespace LMDBSafe;
template <typename First, typename Second>
struct Pair {
template <typename First, typename Second> struct Pair {
First first;
Second second;
};
int main(int argc, char**)
int main(int argc, char **)
{
auto env = getMDBEnv("resize", MDB_NOSUBDIR | MDB_NOSYNC, 0600);
auto main = env->openDB("ahu", MDB_CREATE );
auto env = getMDBEnv("resize", MDB_NOSUBDIR | MDB_NOSYNC, 0600);
auto main = env->openDB("ahu", MDB_CREATE);
MDBInVal key("counter");
MDBInVal key("counter");
auto rwtxn = env->getRWTransaction();
rwtxn->put(main, "counter", "1234");
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{12,13}), "hoi dan 12,13");
auto rwtxn = env->getRWTransaction();
rwtxn->put(main, "counter", "1234");
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{ 12, 13 }), "hoi dan 12,13");
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{14,15}),
MDBInVal::fromStruct(Pair<int, int>{20,23}));
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{ 14, 15 }), MDBInVal::fromStruct(Pair<int, int>{ 20, 23 }));
MDBOutVal out;
if(!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{12,13}), out))
cout << "Got: " << out.get<string_view>() << endl;
else
cout << "Got nothing!1"<<endl;
if(!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{14,15}), out)) {
auto res = out.get_struct<Pair<int,int>>();
cout << "Got: " << res.first<<", "<<res.second << endl;
}
else
cout << "Got nothing!1"<<endl;
MDBOutVal out;
if (!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{ 12, 13 }), out))
cout << "Got: " << out.get<string_view>() << endl;
else
cout << "Got nothing!1" << endl;
rwtxn->put(main, 12.12, 7.3);
if(!rwtxn->get(main, 12.12, out)) {
cout<<"Got: "<< out.get<double>() <<endl;
}
else
cout << "Got nothing!1"<<endl;
if (!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{ 14, 15 }), out)) {
auto res = out.get_struct<Pair<int, int>>();
cout << "Got: " << res.first << ", " << res.second << endl;
} else
cout << "Got nothing!1" << endl;
rwtxn->commit();
return 0;
if(argc==1) {
for(;;) {
auto rotxn = env->getROTransaction();
MDBOutVal data;
if(!rotxn->get(main, key, data)) {
cout<<"Counter is "<<data.get<unsigned int>() << endl;
cout <<data.get<string>() << endl;
cout<<data.get<string_view>() << endl;
rwtxn->put(main, 12.12, 7.3);
if (!rwtxn->get(main, 12.12, out)) {
cout << "Got: " << out.get<double>() << endl;
} else
cout << "Got nothing!1" << endl;
struct Bert
{
uint16_t x,y;
};
auto b = data.get_struct<Bert>();
cout<<b.x<<" "<<b.y<<endl;
cout<<data.get<unsigned long>() << endl;
}
else
cout<<"Didn't find it"<<endl;
exit(1);
rwtxn->commit();
return 0;
if (argc == 1) {
for (;;) {
auto rotxn = env->getROTransaction();
MDBOutVal data;
if (!rotxn->get(main, key, data)) {
cout << "Counter is " << data.get<unsigned int>() << endl;
cout << data.get<string>() << endl;
cout << data.get<string_view>() << endl;
struct Bert {
uint16_t x, y;
};
auto b = data.get_struct<Bert>();
cout << b.x << " " << b.y << endl;
cout << data.get<unsigned long>() << endl;
} else
cout << "Didn't find it" << endl;
exit(1);
}
} else {
size_t size = 1ULL * 4096 * 244140ULL;
for (unsigned int n = 0;; ++n) {
if (!(n % 16384)) {
size += 16384;
if (int rc = mdb_env_set_mapsize(*env.get(), size))
throw std::runtime_error("Resizing: " + string(mdb_strerror(rc)));
cout << "Did resize" << endl;
}
auto txn = env->getRWTransaction();
txn->put(main, key, MDBInVal(n));
for (unsigned int k = 0; k < 100; ++k)
txn->put(main, MDBInVal(n + 1000 * k), MDBInVal(n + 1000 * k));
txn->commit();
}
}
}
else {
size_t size = 1ULL*4096*244140ULL;
for(unsigned int n=0;;++n) {
if(!(n%16384)) {
size += 16384;
if(int rc=mdb_env_set_mapsize(*env.get(), size))
throw std::runtime_error("Resizing: "+string(mdb_strerror(rc)));
cout<<"Did resize"<<endl;
}
auto txn = env->getRWTransaction();
txn->put(main, key, MDBInVal(n));
for(unsigned int k=0; k < 100; ++k)
txn->put(main, MDBInVal(n+1000*k), MDBInVal(n+1000*k));
txn->commit();
}
}
}

View File

@ -5,54 +5,57 @@
using namespace std;
using namespace LMDBSafe;
struct MDBVal
{
MDBVal(unsigned int v) : d_v(v)
{
d_mdbval.mv_size = sizeof(d_v);
d_mdbval.mv_data = &d_v;
}
operator const MDB_val&()
{
return d_mdbval;
}
unsigned int d_v;
MDB_val d_mdbval;
struct MDBVal {
MDBVal(unsigned int v)
: d_v(v)
{
d_mdbval.mv_size = sizeof(d_v);
d_mdbval.mv_data = &d_v;
}
operator const MDB_val &()
{
return d_mdbval;
}
unsigned int d_v;
MDB_val d_mdbval;
};
int main(int argc, char** argv)
int main(int argc, char **argv)
{
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB(std::string_view(), MDB_CREATE | MDB_INTEGERKEY);
auto txn = env->getRWTransaction();
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
auto dbi = env->openDB(std::string_view(), MDB_CREATE | MDB_INTEGERKEY);
auto txn = env->getRWTransaction();
unsigned int limit=20;
if(argc > 1)
limit = CppUtilities::stringToNumber<unsigned int>(argv[1]);
cout<<"Counting records.. "; cout.flush();
auto cursor = txn->getCursor(dbi);
MDBOutVal key, data;
int count=0;
while(!cursor.get(key, data, count ? MDB_NEXT : MDB_FIRST)) {
auto d = data.get<unsigned long>();
if(d==17)
cout <<"Got 17!"<<endl;
count++;
}
cout<<"Have "<<count<<"!"<<endl;
cout<<"Clearing records.. "; cout.flush();
mdb_drop(*txn, dbi, 0); // clear records
cout<<"Done!"<<endl;
unsigned int limit = 20;
if (argc > 1)
limit = CppUtilities::stringToNumber<unsigned int>(argv[1]);
cout << "Adding "<<limit<<" values .. "; cout.flush();
for(unsigned long n = 0 ; n < limit; ++n) {
txn->put(dbi, n, n, MDB_APPEND);
}
cout <<"Done!"<<endl;
cout <<"Calling commit.. "; cout.flush();
txn->commit();
cout<<"Done!"<<endl;
cout << "Counting records.. ";
cout.flush();
auto cursor = txn->getCursor(dbi);
MDBOutVal key, data;
int count = 0;
while (!cursor.get(key, data, count ? MDB_NEXT : MDB_FIRST)) {
auto d = data.get<unsigned long>();
if (d == 17)
cout << "Got 17!" << endl;
count++;
}
cout << "Have " << count << "!" << endl;
cout << "Clearing records.. ";
cout.flush();
mdb_drop(*txn, dbi, 0); // clear records
cout << "Done!" << endl;
cout << "Adding " << limit << " values .. ";
cout.flush();
for (unsigned long n = 0; n < limit; ++n) {
txn->put(dbi, n, n, MDB_APPEND);
}
cout << "Done!" << endl;
cout << "Calling commit.. ";
cout.flush();
txn->commit();
cout << "Done!" << endl;
}

View File

@ -10,225 +10,232 @@
using namespace std;
using namespace LMDBSafe;
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 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;
struct DomainInfo {
string qname;
string master;
};
template<class Archive>
void serialize(Archive & ar, DomainInfo& g, const unsigned int version)
template <class Archive> void serialize(Archive &ar, DomainInfo &g, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & g.qname & g.master;
CPP_UTILITIES_UNUSED(version)
ar &g.qname &g.master;
}
template<class Archive>
void serialize(Archive & ar, DNSResourceRecord& g, const unsigned int version)
template <class Archive> void serialize(Archive &ar, DNSResourceRecord &g, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & g.qtype;
ar & g.qname;
ar & g.content;
ar & g.ttl;
ar & g.domain_id;
ar & g.ordername;
ar & g.auth;
CPP_UTILITIES_UNUSED(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(reinterpret_cast<char *>(&id), 4);
ret.append(rr.ordername);
return ret;
}
struct compound {
std::string operator()(const DNSResourceRecord &rr)
{
std::string ret;
uint32_t id = htonl(rr.domain_id);
ret.assign(reinterpret_cast<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<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");
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;
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;
}
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";
auto txn = tdbi.getRWTransaction();
auto domtxn = tdomains.getRWTransaction(txn.getTransactionHandle());
cout << domtxn.size() << " domains in table" << endl;
txn.clear();
domtxn.clear();
id = txn.put(rr);
cout<<"Puted as id "<<id<<endl;
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;
rr.qtype = 2; rr.content = "ns1.powerdns.com"; rr.ordername = "ns1";
id = txn.put(rr);
cout<<"Puted as id "<<id<<endl;
DomainInfo di{ "powerdns.com", "ns1.powerdns.com" };
domtxn.put(di, 11);
rr.content = "ns2.powerdns.com"; rr.ordername = "ns2"; id = txn.put(rr);
cout<<"Puted as id "<<id<<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";
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);
auto id = txn.put(rr);
cout << "Puted as id " << id << endl;
rr.qname = "ds9a.nl"; rr.content = "ns1.ds9a.nl bert.ds9a.nl 1"; rr.qtype = 6;
rr.ordername="";
txn.put(rr);
rr.qname = "powerdns.com";
rr.qtype = 1;
rr.ordername = "";
rr.content = "1.2.3.4";
rr.qname = "ds9a.nl"; rr.content = "25 ns1.ds9a.nl"; rr.qtype = 15;
txn.put(rr);
id = txn.put(rr);
cout << "Puted as id " << id << endl;
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.qtype = 2;
rr.content = "ns1.powerdns.com";
rr.ordername = "ns1";
id = txn.put(rr);
cout << "Puted as id " << id << endl;
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);
rr.content = "ns2.powerdns.com";
rr.ordername = "ns2";
id = txn.put(rr);
cout << "Puted as id " << id << endl;
DNSResourceRecord rr2;
id = txn.get<0>("www.powerdns.com", rr2);
DomainInfo di2{ "ds9a.nl", "ns1.powerdns.com" };
domtxn.put(di, 10);
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<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);
id = txn.get<0>("powerdns.com", rr2);
rr.qname = "ds9a.nl";
rr.content = "ns1.ds9a.nl bert.ds9a.nl 1";
rr.qtype = 6;
rr.ordername = "";
txn.put(rr);
cout<<"Retrieved id "<< id <<", content: "<<rr2.content<<endl;
rr.qname = "ds9a.nl";
rr.content = "25 ns1.ds9a.nl";
rr.qtype = 15;
txn.put(rr);
DNSResourceRecord rr3;
id = txn.get<0>("powerdns.com", rr3);
cout<< id << endl;
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);
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;
}
DNSResourceRecord rr2;
id = txn.get<0>("www.powerdns.com", rr2);
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 << "Retrieved id " << id << ", content: " << rr2.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;
}
id = txn.get<0>("powerdns.com", rr2);
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;
}
cout << "Retrieved id " << id << ", content: " << rr2.content << 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;
DNSResourceRecord rr3;
id = txn.get<0>("powerdns.com", rr3);
cout << id << endl;
for(auto iter2 = txn.equal_range<0>("powerdns.com"); iter2.first != iter2.second; ++iter2.first) {
cout << iter2.first.getID()<<": "<<iter2.first->qname << " " << iter2.first->qtype << " " << iter2.first->content <<endl;
}
cout<<"Done iterating"<<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 the zone ds9a.nl!"<<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;
}
for(auto iter2 = txn.find<1>(10); iter2 != txn.end(); ++iter2) {
cout << iter2.getID()<<": "<<iter2->qname << " " << iter2->qtype << " " << iter2->content <<endl;
}
cout<<"Done iterating"<<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;
}
DNSResourceRecord change;
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;
txn.modify(1, [](DNSResourceRecord& record) {
record.auth = false;
});
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;
txn.del(1);
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;
}
// DNSResourceRecord rr4;
// id = txn.get3("ns1", rr4);
// cout<<"Found "<<id<<": " << rr4.content <<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;
}
txn.commit();
cout << "Going to iterate over the name powerdns.com!" << endl;
for (auto iter2 = txn.equal_range<0>("powerdns.com"); iter2.first != iter2.second; ++iter2.first) {
cout << iter2.first.getID() << ": " << iter2.first->qname << " " << iter2.first->qtype << " " << iter2.first->content << endl;
}
cout << "Done iterating" << endl;
cout << "Going to iterate over the zone ds9a.nl!" << endl;
for (auto iter2 = txn.find<1>(10); iter2 != txn.end(); ++iter2) {
cout << iter2.getID() << ": " << iter2->qname << " " << iter2->qtype << " " << iter2->content << endl;
}
cout << "Done iterating" << endl;
DNSResourceRecord change;
txn.get(1, change);
cout << "1.auth: " << change.auth << endl;
txn.modify(1, [](DNSResourceRecord &record) { record.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();
}

View File

@ -7,41 +7,38 @@
using namespace std;
using namespace LMDBSafe;
void countDB(MDBEnv& env, MDBROTransaction& txn, const std::string& dbname)
void countDB(MDBEnv &env, MDBROTransaction &txn, const std::string &dbname)
{
CPP_UTILITIES_UNUSED(env)
auto db = txn->openDB(dbname, 0);
auto cursor = txn->getCursor(db);
uint32_t count = 0;
MDBOutVal key, val;
while(!cursor.get(key, val, count ? MDB_NEXT : MDB_FIRST)) {
cout << key.get<string>();
if(key.d_mdbval.mv_size == 4)
cout << " " << key.get<uint32_t>();
cout<<": " << val.get<std::string>();
cout << "\n";
++count;
}
cout <<count<<endl;
auto db = txn->openDB(dbname, 0);
auto cursor = txn->getCursor(db);
uint32_t count = 0;
MDBOutVal key, val;
while (!cursor.get(key, val, count ? MDB_NEXT : MDB_FIRST)) {
cout << key.get<string>();
if (key.d_mdbval.mv_size == 4)
cout << " " << key.get<uint32_t>();
cout << ": " << val.get<std::string>();
cout << "\n";
++count;
}
cout << count << endl;
}
int main(int argc, char** argv)
int main(int argc, char **argv)
{
MDBEnv env(argc >= 2 ? argv[1] : "./database", MDB_RDONLY | MDB_NOSUBDIR, 0600);
auto main = env.openDB("", 0);
auto txn = env.getROTransaction();
MDBEnv env(argc >= 2 ? argv[1] : "./database", MDB_RDONLY | MDB_NOSUBDIR, 0600);
auto main = env.openDB("", 0);
auto txn = env.getROTransaction();
auto cursor = txn->getCursor(main);
auto cursor = txn->getCursor(main);
MDBOutVal key, val;
if(cursor.get(key, val, MDB_FIRST)) {
cout << "Database is empty" <<endl;
}
do {
cout << key.get<string>() << endl;
countDB(env, txn, key.get<string>());
} while(!cursor.get(key, val, MDB_NEXT));
MDBOutVal key, val;
if (cursor.get(key, val, MDB_FIRST)) {
cout << "Database is empty" << endl;
}
do {
cout << key.get<string>() << endl;
countDB(env, txn, key.get<string>());
} while (!cursor.get(key, val, MDB_NEXT));
}

View File

@ -10,326 +10,323 @@
using namespace std;
using namespace LMDBSafe;
TEST_CASE("Most basic tests", "[mostbasic]") {
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
txn->put(main, "lmdb", "hot");
REQUIRE(txn->get(main, "lmdb", out) == 0);
REQUIRE(out.get<std::string>() == "hot");
txn->abort();
auto rotxn = env.getROTransaction();
REQUIRE(rotxn->get(main, "lmdb", out) == MDB_NOTFOUND);
}
TEST_CASE("Range tests", "[range]") {
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
{
auto cursor = txn->getCursor(main);
MDBInVal bert("bert");
MDBOutVal key, val;
REQUIRE(cursor.lower_bound(bert, key, val) == 0);
REQUIRE(key.get<string>() == "bert");
REQUIRE(val.get<string>() == "hubert");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "bert1");
REQUIRE(val.get<string>() == "one");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "berthubert");
REQUIRE(val.get<string>() == "lmdb");
REQUIRE(cursor.lower_bound("kees", key, val) == MDB_NOTFOUND);
txn->commit();
}
auto rotxn = env.getROTransaction();
{
auto cursor = rotxn->getCursor(main);
MDBInVal bert("bert");
MDBOutVal key, val;
REQUIRE(cursor.lower_bound(bert, key, val) == 0);
REQUIRE(key.get<string>() == "bert");
REQUIRE(val.get<string>() == "hubert");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "bert1");
REQUIRE(val.get<string>() == "one");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "berthubert");
REQUIRE(val.get<string>() == "lmdb");
REQUIRE(cursor.lower_bound("kees", key, val) == MDB_NOTFOUND);
}
}
TEST_CASE("moving transactions")
TEST_CASE("Most basic tests", "[mostbasic]")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBDbi main = env.openDB("", MDB_CREATE);
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
auto cursor = txn->getCursor(main);
auto txn2 = std::move(txn);
{
auto cursor2 = std::move(cursor);
}
}
TEST_CASE("transaction inheritance and moving")
{
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBRWCursor cursor;
{
MDBRWTransaction txn = env.getRWTransaction();
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
txn->put(main, "lmdb", "hot");
REQUIRE(txn->get(main, "lmdb", out) == 0);
REQUIRE(out.get<std::string>() == "hot");
txn->abort();
auto rotxn = env.getROTransaction();
REQUIRE(rotxn->get(main, "lmdb", out) == MDB_NOTFOUND);
}
TEST_CASE("Range tests", "[range]")
{
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
// lets just keep this cursor to ensure that it invalidates
cursor = txn->getRWCursor(main);
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
MDBROTransaction ro_txn(std::move(txn));
// despite being moved to an ro_txn (which normally commits instead of
// aborting by default)
}
{
auto cursor = txn->getCursor(main);
MDBInVal bert("bert");
MDBOutVal key, val;
REQUIRE(cursor.lower_bound(bert, key, val) == 0);
REQUIRE(key.get<string>() == "bert");
REQUIRE(val.get<string>() == "hubert");
CHECK(!const_cast<const MDBRWCursor&>(cursor));
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "bert1");
REQUIRE(val.get<string>() == "one");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "berthubert");
REQUIRE(val.get<string>() == "lmdb");
REQUIRE(cursor.lower_bound("kees", key, val) == MDB_NOTFOUND);
txn->commit();
}
auto rotxn = env.getROTransaction();
{
auto cursor = rotxn->getCursor(main);
MDBInVal bert("bert");
MDBOutVal key, val;
REQUIRE(cursor.lower_bound(bert, key, val) == 0);
REQUIRE(key.get<string>() == "bert");
REQUIRE(val.get<string>() == "hubert");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "bert1");
REQUIRE(val.get<string>() == "one");
REQUIRE(cursor.next(key, val) == 0);
REQUIRE(key.get<string>() == "berthubert");
REQUIRE(val.get<string>() == "lmdb");
REQUIRE(cursor.lower_bound("kees", key, val) == MDB_NOTFOUND);
}
}
TEST_CASE("moving transactions")
{
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
auto txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
auto cursor = txn->getCursor(main);
auto txn2 = std::move(txn);
{
auto cursor2 = std::move(cursor);
}
}
TEST_CASE("transaction inheritance and moving")
{
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBRWCursor cursor;
{
MDBRWTransaction txn = env.getRWTransaction();
MDBOutVal out;
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
// lets just keep this cursor to ensure that it invalidates
cursor = txn->getRWCursor(main);
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
MDBROTransaction ro_txn(std::move(txn));
// despite being moved to an ro_txn (which normally commits instead of
// aborting by default)
}
CHECK(!const_cast<const MDBRWCursor &>(cursor));
}
TEST_CASE("nested RW transactions", "[transactions]")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBDbi main = env.openDB("", MDB_CREATE);
/* bootstrap some data */
{
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
/* bootstrap some data */
{
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
}
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
}
/* check that subtransaction got rolled back */
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
/* and that the main changes are still there */
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
/* check that subtransaction got rolled back */
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
/* and that the main changes are still there */
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
/* this time for real! */
sub_txn->commit();
}
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
/* this time for real! */
sub_txn->commit();
}
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
}
TEST_CASE("nesting RW -> RO", "[transactions]")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBDbi main = env.openDB("", MDB_CREATE);
/* bootstrap some data */
{
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
MDBROTransaction sub_txn = main_txn->getROTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
}
/* check that subtransaction got rolled back */
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
/* and that the main changes are still there */
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
/* bootstrap some data */
{
MDBROTransaction sub_sub_txn = sub_txn->getROTransaction();
CHECK(sub_sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
/* this time for real! */
sub_txn->commit();
}
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
MDBROTransaction sub_txn = main_txn->getROTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
}
/* check that subtransaction got rolled back */
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
/* and that the main changes are still there */
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
{
MDBROTransaction sub_sub_txn = sub_txn->getROTransaction();
CHECK(sub_sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
}
/* this time for real! */
sub_txn->commit();
}
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
}
TEST_CASE("try to nest twice", "[transactions]")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
MDBDbi main = env.openDB("", MDB_CREATE);
/* bootstrap some data */
{
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
/* bootstrap some data */
{
auto txn = env.getRWTransaction();
txn->put(main, "bert", "hubert");
txn->put(main, "bertt", "1975");
txn->put(main, "berthubert", "lmdb");
txn->put(main, "bert1", "one");
txn->put(main, "beru", "not");
txn->commit();
}
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
auto main_txn = env.getRWTransaction();
main_txn->del(main, "bertt", "1975");
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
MDBOutVal dummy{};
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
{
auto sub_txn = main_txn->getRWTransaction();
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
sub_txn->del(main, "berthubert", "lmdb");
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
CHECK_THROWS_AS(
main_txn->getRWTransaction(),
std::runtime_error
);
}
CHECK_THROWS_AS(main_txn->getRWTransaction(), std::runtime_error);
}
}
TEST_CASE("transaction counter correctness for RW->RW nesting")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
{
auto txn = env.getRWTransaction();
auto sub_txn = txn->getRWTransaction();
}
{
auto txn = env.getRWTransaction();
auto sub_txn = txn->getRWTransaction();
}
CHECK_NOTHROW(env.getRWTransaction());
CHECK_NOTHROW(env.getROTransaction());
CHECK_NOTHROW(env.getRWTransaction());
CHECK_NOTHROW(env.getROTransaction());
}
TEST_CASE("transaction counter correctness for RW->RO nesting")
{
unlink("./tests");
unlink("./tests");
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
{
auto txn = env.getRWTransaction();
auto sub_txn = txn->getROTransaction();
}
{
auto txn = env.getRWTransaction();
auto sub_txn = txn->getROTransaction();
}
CHECK_NOTHROW(env.getRWTransaction());
CHECK_NOTHROW(env.getROTransaction());
CHECK_NOTHROW(env.getRWTransaction());
CHECK_NOTHROW(env.getROTransaction());
}

View File

@ -13,60 +13,57 @@
using namespace std;
using namespace LMDBSafe;
struct Member
{
std::string firstName;
std::string lastName;
time_t enrolled;
struct Member {
std::string firstName;
std::string lastName;
time_t enrolled;
};
template<class Archive>
void serialize(Archive & ar, Member& g, const unsigned int version)
template <class Archive> void serialize(Archive &ar, Member &g, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & g.firstName & g.lastName & g.enrolled;
CPP_UTILITIES_UNUSED(version)
ar &g.firstName &g.lastName &g.enrolled;
}
TEST_CASE("Basic typed tests", "[basictyped]") {
unlink("./tests-typed");
typedef TypedDBI<Member,
index_on<Member, string, &Member::firstName>,
index_on<Member, string, &Member::lastName>,
index_on<Member, time_t, &Member::enrolled>
> tmembers_t;
TEST_CASE("Basic typed tests", "[basictyped]")
{
unlink("./tests-typed");
typedef TypedDBI<Member, index_on<Member, string, &Member::firstName>, index_on<Member, string, &Member::lastName>,
index_on<Member, time_t, &Member::enrolled>>
tmembers_t;
auto tmembers = tmembers_t(getMDBEnv("./tests-typed", MDB_CREATE | MDB_NOSUBDIR, 0600), "members");
REQUIRE(1);
auto tmembers = tmembers_t(getMDBEnv("./tests-typed", MDB_CREATE | MDB_NOSUBDIR, 0600), "members");
auto txn = tmembers.getRWTransaction();
Member m{"bert", "hubert"};
txn.put(m);
m.firstName="bertus";
m.lastName = "testperson";
m.enrolled = time(0);
txn.put(m);
REQUIRE(1);
m.firstName = "other";
txn.put(m);
Member out;
REQUIRE(txn.get(1,out));
REQUIRE(out.firstName == "bert");
REQUIRE(txn.get(2,out));
REQUIRE(out.lastName == "testperson");
auto txn = tmembers.getRWTransaction();
Member m{ "bert", "hubert" };
txn.put(m);
m.firstName = "bertus";
m.lastName = "testperson";
m.enrolled = time(0);
txn.put(m);
REQUIRE(!txn.get(4,out));
m.firstName = "other";
txn.put(m);
auto range = txn.prefix_range<0>("bert");
vector<std::string> names;
for(auto& iter = range.first; iter != range.second; ++iter) {
names.push_back(iter->firstName);
}
REQUIRE(names == vector<std::string>{"bert", "bertus"});
Member out;
REQUIRE(txn.get(1, out));
REQUIRE(out.firstName == "bert");
REQUIRE(txn.get(2, out));
REQUIRE(out.lastName == "testperson");
auto range2 = txn.prefix_range<0>("nosuchperson");
REQUIRE(!(range2.first == range2.second));
txn.abort();
REQUIRE(!txn.get(4, out));
auto range = txn.prefix_range<0>("bert");
vector<std::string> names;
for (auto &iter = range.first; iter != range.second; ++iter) {
names.push_back(iter->firstName);
}
REQUIRE(names == vector<std::string>{ "bert", "bertus" });
auto range2 = txn.prefix_range<0>("nosuchperson");
REQUIRE(!(range2.first == range2.second));
txn.abort();
}