Format tests and examples as well
This commit is contained in:
parent
1e393bf3fe
commit
ec4a44e4de
|
@ -61,6 +61,16 @@ use_package(TARGET_NAME Catch2::Catch2 PACKAGE_NAME Catch2 LIBRARIES_VARIABLE "T
|
||||||
# find threading library (required by examples)
|
# find threading library (required by examples)
|
||||||
use_package(TARGET_NAME Threads::Threads PACKAGE_NAME Threads LIBRARIES_VARIABLE "TEST_LIBRARIES")
|
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 modules to apply configuration
|
||||||
include(BasicConfig)
|
include(BasicConfig)
|
||||||
include(WindowsResources)
|
include(WindowsResources)
|
||||||
|
@ -71,11 +81,9 @@ include(ConfigHeader)
|
||||||
# configure test targets
|
# configure test targets
|
||||||
include(TestUtilities)
|
include(TestUtilities)
|
||||||
list(APPEND TEST_LIBRARIES ${META_TARGET_NAME})
|
list(APPEND TEST_LIBRARIES ${META_TARGET_NAME})
|
||||||
set(TESTS basic typed)
|
|
||||||
foreach (TEST ${TESTS})
|
foreach (TEST ${TESTS})
|
||||||
configure_test_target(TEST_NAME "${TEST}_tests" SRC_FILES "tests/${TEST}.cc" LIBRARIES "${TEST_LIBRARIES}")
|
configure_test_target(TEST_NAME "${TEST}_tests" SRC_FILES "tests/${TEST}.cc" LIBRARIES "${TEST_LIBRARIES}")
|
||||||
endforeach ()
|
endforeach ()
|
||||||
set(EXAMPLES basic multi rel resize scale typed view)
|
|
||||||
foreach (EXAMPLE ${EXAMPLES})
|
foreach (EXAMPLE ${EXAMPLES})
|
||||||
configure_test_target(TEST_NAME "${EXAMPLE}_example" SRC_FILES "examples/${EXAMPLE}.cc" LIBRARIES "${TEST_LIBRARIES}")
|
configure_test_target(TEST_NAME "${EXAMPLE}_example" SRC_FILES "examples/${EXAMPLE}.cc" LIBRARIES "${TEST_LIBRARIES}")
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
|
@ -3,42 +3,40 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
void checkLMDB(MDBEnv* env, MDBDbi dbi)
|
void checkLMDB(MDBEnv *env, MDBDbi dbi)
|
||||||
{
|
{
|
||||||
auto rotxn = env->getROTransaction();
|
auto rotxn = env->getROTransaction();
|
||||||
MDBOutVal data;
|
MDBOutVal data;
|
||||||
if(!rotxn->get(dbi, "lmdb", data)) {
|
if (!rotxn->get(dbi, "lmdb", data)) {
|
||||||
cout<< "Outside RW transaction, found that lmdb = " << data.get<string_view>() <<endl;
|
cout << "Outside RW transaction, found that lmdb = " << data.get<string_view>() << endl;
|
||||||
}
|
} else
|
||||||
else
|
cout << "Outside RW transaction, found nothing" << endl;
|
||||||
cout<<"Outside RW transaction, found nothing" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
|
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
|
||||||
auto dbi = env->openDB("example", MDB_CREATE);
|
auto dbi = env->openDB("example", MDB_CREATE);
|
||||||
|
|
||||||
auto txn = env->getRWTransaction();
|
|
||||||
mdb_drop(*txn, dbi, 0);
|
|
||||||
txn->put(dbi, "lmdb", "great");
|
|
||||||
|
|
||||||
MDBOutVal data;
|
auto txn = env->getRWTransaction();
|
||||||
if(!txn->get(dbi, "lmdb", data)) {
|
mdb_drop(*txn, dbi, 0);
|
||||||
cout<< "Within RW transaction, found that lmdb = " << data.get<string_view>() <<endl;
|
txn->put(dbi, "lmdb", "great");
|
||||||
}
|
|
||||||
else
|
|
||||||
cout<<"Found nothing" << endl;
|
|
||||||
|
|
||||||
std::thread elsewhere(checkLMDB, env.get(), dbi);
|
MDBOutVal data;
|
||||||
elsewhere.join();
|
if (!txn->get(dbi, "lmdb", data)) {
|
||||||
|
cout << "Within RW transaction, found that lmdb = " << data.get<string_view>() << endl;
|
||||||
txn->commit();
|
} else
|
||||||
|
cout << "Found nothing" << endl;
|
||||||
cout<<"Committed data"<<endl;
|
|
||||||
|
std::thread elsewhere(checkLMDB, env.get(), dbi);
|
||||||
checkLMDB(env.get(), dbi);
|
elsewhere.join();
|
||||||
txn = env->getRWTransaction();
|
|
||||||
mdb_drop(*txn, dbi, 0);
|
txn->commit();
|
||||||
txn->commit();
|
|
||||||
|
cout << "Committed data" << endl;
|
||||||
|
|
||||||
|
checkLMDB(env.get(), dbi);
|
||||||
|
txn = env->getRWTransaction();
|
||||||
|
mdb_drop(*txn, dbi, 0);
|
||||||
|
txn->commit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,56 +7,53 @@ using namespace LMDBSafe;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
unlink("./multi");
|
unlink("./multi");
|
||||||
auto env = getMDBEnv("multi", MDB_NOSUBDIR, 0600);
|
auto env = getMDBEnv("multi", MDB_NOSUBDIR, 0600);
|
||||||
auto dbi = env->openDB("qnames", MDB_DUPSORT | MDB_CREATE);
|
auto dbi = env->openDB("qnames", MDB_DUPSORT | MDB_CREATE);
|
||||||
|
|
||||||
auto txn = env->getRWTransaction();
|
auto txn = env->getRWTransaction();
|
||||||
txn->clear(dbi);
|
txn->clear(dbi);
|
||||||
|
|
||||||
txn->put(dbi, "bdb", "old");
|
txn->put(dbi, "bdb", "old");
|
||||||
txn->put(dbi, "lmdb", "hot");
|
txn->put(dbi, "lmdb", "hot");
|
||||||
txn->put(dbi, "lmdb", "fast");
|
txn->put(dbi, "lmdb", "fast");
|
||||||
txn->put(dbi, "lmdb", "zooms");
|
txn->put(dbi, "lmdb", "zooms");
|
||||||
txn->put(dbi, "lmdb", "c");
|
txn->put(dbi, "lmdb", "c");
|
||||||
txn->put(dbi, "mdb", "old name");
|
txn->put(dbi, "mdb", "old name");
|
||||||
|
|
||||||
string_view v1;
|
string_view v1;
|
||||||
if(!txn->get(dbi, "mdb", v1)) {
|
if (!txn->get(dbi, "mdb", v1)) {
|
||||||
cout<<v1<<endl;
|
cout << v1 << endl;
|
||||||
}
|
} else {
|
||||||
else {
|
cout << "found nothing" << endl;
|
||||||
cout << "found nothing" << endl;
|
}
|
||||||
}
|
txn->commit();
|
||||||
txn->commit();
|
|
||||||
|
|
||||||
txn = env->getRWTransaction();
|
|
||||||
auto cursor = txn->getRWCursor(dbi);
|
|
||||||
|
|
||||||
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)) {
|
MDBOutVal key, data;
|
||||||
cout << key.get<string_view>() << " = " << data.get<string_view>() <<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Dump of complete database: "<<endl;
|
for (int rc = cursor.find("lmdb", key, data); !rc; rc = cursor.get(key, data, MDB_NEXT_DUP)) {
|
||||||
for(int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
|
cout << key.get<string_view>() << " = " << data.get<string_view>() << endl;
|
||||||
cout << key.get<string_view>() << " = " << data.get<string_view>() <<endl;
|
}
|
||||||
}
|
|
||||||
cout << "Done!" <<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)) {
|
cout << "Now going to delete 'lmdb' keys" << endl;
|
||||||
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)) {
|
||||||
|
if (key.get<string_view>() == "lmdb")
|
||||||
for(int rc = cursor.first(key, data); !rc; rc = cursor.next(key, data)) {
|
cursor.del();
|
||||||
cout << key.get<string_view>() << " = " << data.get<string_view>() <<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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
240
examples/rel.cc
240
examples/rel.cc
|
@ -1,7 +1,7 @@
|
||||||
#include "../lmdb-safe.hh"
|
#include "../lmdb-safe.hh"
|
||||||
|
|
||||||
#include <boost/archive/binary_oarchive.hpp>
|
|
||||||
#include <boost/archive/binary_iarchive.hpp>
|
#include <boost/archive/binary_iarchive.hpp>
|
||||||
|
#include <boost/archive/binary_oarchive.hpp>
|
||||||
|
|
||||||
#include <c++utilities/application/global.h>
|
#include <c++utilities/application/global.h>
|
||||||
|
|
||||||
|
@ -10,157 +10,149 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
struct Record
|
struct Record {
|
||||||
{
|
|
||||||
|
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
template<class Archive>
|
template <class Archive> void serialize(Archive &ar, const unsigned int version)
|
||||||
void serialize(Archive & ar, const unsigned int version)
|
{
|
||||||
{
|
CPP_UTILITIES_UNUSED(version)
|
||||||
CPP_UTILITIES_UNUSED(version)
|
ar &id &domain_id &name &type &ttl &content &enabled &auth;
|
||||||
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};
|
|
||||||
|
|
||||||
|
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);
|
auto cursor = txn->getRWCursor(dbi);
|
||||||
MDBOutVal maxidval, maxcontent;
|
MDBOutVal maxidval, maxcontent;
|
||||||
unsigned int maxid{0};
|
unsigned int maxid{ 0 };
|
||||||
if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
|
if (!cursor.get(maxidval, maxcontent, MDB_LAST)) {
|
||||||
maxid = maxidval.get<unsigned int>();
|
maxid = maxidval.get<unsigned int>();
|
||||||
}
|
}
|
||||||
return maxid;
|
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;
|
ostringstream oss;
|
||||||
boost::archive::binary_oarchive oa(oss,boost::archive::no_header );
|
boost::archive::binary_oarchive oa(oss, boost::archive::no_header);
|
||||||
oa << r;
|
oa << r;
|
||||||
|
|
||||||
txn->put(records, r.id, oss.str(), MDB_APPEND);
|
txn->put(records, r.id, oss.str(), MDB_APPEND);
|
||||||
txn->put(domainidx, r.domain_id, r.id);
|
txn->put(domainidx, r.domain_id, r.id);
|
||||||
txn->put(nameidx, r.name, 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 env = getMDBEnv("pdns", MDB_NOSUBDIR, 0600);
|
||||||
auto records = env->openDB("records", MDB_INTEGERKEY | MDB_CREATE );
|
auto records = env->openDB("records", MDB_INTEGERKEY | MDB_CREATE);
|
||||||
auto domainidx = env->openDB("domainidx", MDB_INTEGERKEY | MDB_DUPFIXED | MDB_DUPSORT | 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 nameidx = env->openDB("nameidx", MDB_DUPFIXED | MDB_DUPSORT | MDB_CREATE);
|
||||||
|
|
||||||
auto txn = env->getRWTransaction();
|
auto txn = env->getRWTransaction();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
txn.clear(records);
|
txn.clear(records);
|
||||||
txn.clear(domainidx);
|
txn.clear(domainidx);
|
||||||
txn.clear(domainidx);
|
txn.clear(domainidx);
|
||||||
txn.clear(nameidx);
|
txn.clear(nameidx);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int maxid=getMaxID(txn, records);
|
unsigned int maxid = getMaxID(txn, records);
|
||||||
unsigned int maxdomainid=getMaxID(txn, domainidx);
|
unsigned int maxdomainid = getMaxID(txn, domainidx);
|
||||||
|
|
||||||
cout<<"Maxid = "<<maxid<<", Max domain ID = "<<maxdomainid<<endl;
|
|
||||||
|
|
||||||
string prefix(argc >= 2 ? argv[1] : "prefix");
|
cout << "Maxid = " << maxid << ", Max domain ID = " << maxdomainid << endl;
|
||||||
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";
|
|
||||||
|
|
||||||
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;
|
store(txn, records, domainidx, nameidx, r);
|
||||||
r.type="NS";
|
|
||||||
r.content="ns1.powerdns.com";
|
|
||||||
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.id = ++maxid;
|
||||||
r.type="A";
|
r.type = "A";
|
||||||
r.content="1.2.3.4";
|
r.content = "1.2.3.4";
|
||||||
store(txn, records, domainidx, nameidx, r);
|
store(txn, records, domainidx, nameidx, r);
|
||||||
|
|
||||||
r.id=++maxid;
|
r.id = ++maxid;
|
||||||
r.type="AAAA";
|
r.type = "AAAA";
|
||||||
r.content="::1";
|
r.content = "::1";
|
||||||
store(txn, records, domainidx, nameidx, r);
|
store(txn, records, domainidx, nameidx, r);
|
||||||
|
|
||||||
r.id=++maxid;
|
r.id = ++maxid;
|
||||||
r.type="CAA";
|
r.type = "CAA";
|
||||||
r.content="letsencrypt.org";
|
r.content = "letsencrypt.org";
|
||||||
store(txn, records, domainidx, nameidx, r);
|
store(txn, records, domainidx, nameidx, r);
|
||||||
|
|
||||||
|
|
||||||
r.id=++maxid;
|
r.id = ++maxid;
|
||||||
r.type="AAAA";
|
r.type = "AAAA";
|
||||||
r.name="www."+domain;
|
r.name = "www." + domain;
|
||||||
r.content="::1";
|
r.content = "::1";
|
||||||
store(txn, records, domainidx, nameidx, r);
|
store(txn, records, domainidx, nameidx, r);
|
||||||
|
|
||||||
r.id=++maxid;
|
r.id = ++maxid;
|
||||||
r.type="A";
|
r.type = "A";
|
||||||
r.name="www."+domain;
|
r.name = "www." + domain;
|
||||||
r.content="127.0.0.1";
|
r.content = "127.0.0.1";
|
||||||
store(txn, records, domainidx, nameidx, r);
|
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;
|
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,87 +5,78 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
template <typename First, typename Second>
|
template <typename First, typename Second> struct Pair {
|
||||||
struct Pair {
|
|
||||||
First first;
|
First first;
|
||||||
Second second;
|
Second second;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char**)
|
int main(int argc, char **)
|
||||||
{
|
{
|
||||||
auto env = getMDBEnv("resize", MDB_NOSUBDIR | MDB_NOSYNC, 0600);
|
auto env = getMDBEnv("resize", MDB_NOSUBDIR | MDB_NOSYNC, 0600);
|
||||||
auto main = env->openDB("ahu", MDB_CREATE );
|
auto main = env->openDB("ahu", MDB_CREATE);
|
||||||
|
|
||||||
MDBInVal key("counter");
|
MDBInVal key("counter");
|
||||||
|
|
||||||
auto rwtxn = env->getRWTransaction();
|
auto rwtxn = env->getRWTransaction();
|
||||||
rwtxn->put(main, "counter", "1234");
|
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>{ 12, 13 }), "hoi dan 12,13");
|
||||||
|
|
||||||
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{14,15}),
|
rwtxn->put(main, MDBInVal::fromStruct(Pair<int, int>{ 14, 15 }), MDBInVal::fromStruct(Pair<int, int>{ 20, 23 }));
|
||||||
MDBInVal::fromStruct(Pair<int, int>{20,23}));
|
|
||||||
|
|
||||||
|
MDBOutVal out;
|
||||||
MDBOutVal out;
|
if (!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{ 12, 13 }), out))
|
||||||
if(!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{12,13}), out))
|
cout << "Got: " << out.get<string_view>() << endl;
|
||||||
cout << "Got: " << out.get<string_view>() << endl;
|
else
|
||||||
else
|
cout << "Got nothing!1" << endl;
|
||||||
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->put(main, 12.12, 7.3);
|
if (!rwtxn->get(main, MDBInVal::fromStruct(Pair<int, int>{ 14, 15 }), out)) {
|
||||||
if(!rwtxn->get(main, 12.12, out)) {
|
auto res = out.get_struct<Pair<int, int>>();
|
||||||
cout<<"Got: "<< out.get<double>() <<endl;
|
cout << "Got: " << res.first << ", " << res.second << endl;
|
||||||
}
|
} else
|
||||||
else
|
cout << "Got nothing!1" << endl;
|
||||||
cout << "Got nothing!1"<<endl;
|
|
||||||
|
|
||||||
|
rwtxn->put(main, 12.12, 7.3);
|
||||||
rwtxn->commit();
|
if (!rwtxn->get(main, 12.12, out)) {
|
||||||
return 0;
|
cout << "Got: " << out.get<double>() << endl;
|
||||||
|
} else
|
||||||
if(argc==1) {
|
cout << "Got nothing!1" << endl;
|
||||||
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
|
rwtxn->commit();
|
||||||
{
|
return 0;
|
||||||
uint16_t x,y;
|
|
||||||
};
|
if (argc == 1) {
|
||||||
auto b = data.get_struct<Bert>();
|
for (;;) {
|
||||||
cout<<b.x<<" "<<b.y<<endl;
|
auto rotxn = env->getROTransaction();
|
||||||
cout<<data.get<unsigned long>() << endl;
|
MDBOutVal data;
|
||||||
}
|
if (!rotxn->get(main, key, data)) {
|
||||||
else
|
cout << "Counter is " << data.get<unsigned int>() << endl;
|
||||||
cout<<"Didn't find it"<<endl;
|
cout << data.get<string>() << endl;
|
||||||
exit(1);
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,54 +5,57 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
struct MDBVal
|
struct MDBVal {
|
||||||
{
|
MDBVal(unsigned int v)
|
||||||
MDBVal(unsigned int v) : d_v(v)
|
: d_v(v)
|
||||||
{
|
{
|
||||||
d_mdbval.mv_size = sizeof(d_v);
|
d_mdbval.mv_size = sizeof(d_v);
|
||||||
d_mdbval.mv_data = &d_v;
|
d_mdbval.mv_data = &d_v;
|
||||||
}
|
}
|
||||||
operator const MDB_val&()
|
operator const MDB_val &()
|
||||||
{
|
{
|
||||||
return d_mdbval;
|
return d_mdbval;
|
||||||
}
|
}
|
||||||
unsigned int d_v;
|
unsigned int d_v;
|
||||||
MDB_val d_mdbval;
|
MDB_val d_mdbval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
{
|
||||||
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
|
auto env = getMDBEnv("./database", MDB_NOSUBDIR, 0600);
|
||||||
auto dbi = env->openDB(std::string_view(), MDB_CREATE | MDB_INTEGERKEY);
|
auto dbi = env->openDB(std::string_view(), MDB_CREATE | MDB_INTEGERKEY);
|
||||||
auto txn = env->getRWTransaction();
|
auto txn = env->getRWTransaction();
|
||||||
|
|
||||||
unsigned int limit=20;
|
unsigned int limit = 20;
|
||||||
if(argc > 1)
|
if (argc > 1)
|
||||||
limit = CppUtilities::stringToNumber<unsigned int>(argv[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;
|
|
||||||
|
|
||||||
cout << "Adding "<<limit<<" values .. "; cout.flush();
|
cout << "Counting records.. ";
|
||||||
for(unsigned long n = 0 ; n < limit; ++n) {
|
cout.flush();
|
||||||
txn->put(dbi, n, n, MDB_APPEND);
|
auto cursor = txn->getCursor(dbi);
|
||||||
}
|
MDBOutVal key, data;
|
||||||
cout <<"Done!"<<endl;
|
int count = 0;
|
||||||
cout <<"Calling commit.. "; cout.flush();
|
while (!cursor.get(key, data, count ? MDB_NEXT : MDB_FIRST)) {
|
||||||
txn->commit();
|
auto d = data.get<unsigned long>();
|
||||||
cout<<"Done!"<<endl;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,225 +10,232 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
struct DNSResourceRecord
|
struct DNSResourceRecord {
|
||||||
{
|
string qname; // index
|
||||||
string qname; // index
|
uint16_t qtype{ 0 };
|
||||||
uint16_t qtype{0};
|
uint32_t domain_id{ 0 }; // index
|
||||||
uint32_t domain_id{0}; // index
|
string content;
|
||||||
string content;
|
uint32_t ttl{ 0 };
|
||||||
uint32_t ttl{0};
|
string ordername; // index
|
||||||
string ordername; // index
|
bool auth{ true };
|
||||||
bool auth{true};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DomainInfo
|
struct DomainInfo {
|
||||||
{
|
string qname;
|
||||||
string qname;
|
string master;
|
||||||
string master;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Archive>
|
template <class Archive> void serialize(Archive &ar, DomainInfo &g, const unsigned int version)
|
||||||
void serialize(Archive & ar, DomainInfo& g, const unsigned int version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
CPP_UTILITIES_UNUSED(version)
|
||||||
ar & g.qname & g.master;
|
ar &g.qname &g.master;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Archive>
|
template <class Archive> void serialize(Archive &ar, DNSResourceRecord &g, const unsigned int version)
|
||||||
void serialize(Archive & ar, DNSResourceRecord& g, const unsigned int version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
CPP_UTILITIES_UNUSED(version)
|
||||||
ar & g.qtype;
|
ar &g.qtype;
|
||||||
ar & g.qname;
|
ar &g.qname;
|
||||||
ar & g.content;
|
ar &g.content;
|
||||||
ar & g.ttl;
|
ar &g.ttl;
|
||||||
ar & g.domain_id;
|
ar &g.domain_id;
|
||||||
ar & g.ordername;
|
ar &g.ordername;
|
||||||
ar & g.auth;
|
ar &g.auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct compound {
|
||||||
struct compound
|
std::string operator()(const DNSResourceRecord &rr)
|
||||||
{
|
{
|
||||||
std::string operator()(const DNSResourceRecord& rr)
|
std::string ret;
|
||||||
{
|
uint32_t id = htonl(rr.domain_id);
|
||||||
std::string ret;
|
ret.assign(reinterpret_cast<char *>(&id), 4);
|
||||||
uint32_t id = htonl(rr.domain_id);
|
ret.append(rr.ordername);
|
||||||
ret.assign(reinterpret_cast<char *>(&id), 4);
|
return ret;
|
||||||
ret.append(rr.ordername);
|
}
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
TypedDBI<DNSResourceRecord,
|
TypedDBI<DNSResourceRecord, index_on<DNSResourceRecord, string, &DNSResourceRecord::qname>,
|
||||||
index_on<DNSResourceRecord, string, &DNSResourceRecord::qname>,
|
index_on<DNSResourceRecord, uint32_t, &DNSResourceRecord::domain_id>, index_on_function<DNSResourceRecord, string, compound>>
|
||||||
index_on<DNSResourceRecord, uint32_t, &DNSResourceRecord::domain_id>,
|
tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records");
|
||||||
index_on_function<DNSResourceRecord, string, compound>
|
|
||||||
> tdbi(getMDBEnv("./typed.lmdb", MDB_NOSUBDIR, 0600), "records");
|
|
||||||
|
|
||||||
TypedDBI<DomainInfo,
|
TypedDBI<DomainInfo, index_on<DomainInfo, string, &DomainInfo::qname>> tdomains(tdbi.getEnv(), "domains");
|
||||||
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"};
|
auto txn = tdbi.getRWTransaction();
|
||||||
domtxn.put(di, 11);
|
auto domtxn = tdomains.getRWTransaction(txn.getTransactionHandle());
|
||||||
|
cout << domtxn.size() << " domains in table" << endl;
|
||||||
DNSResourceRecord rr;
|
txn.clear();
|
||||||
rr.domain_id=11; rr.qtype = 5; rr.ttl = 3600; rr.qname = "www.powerdns.com"; rr.ordername = "www";
|
domtxn.clear();
|
||||||
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 << "Currently have " << txn.size() << " entries after clear" << endl;
|
||||||
cout<<"Puted as id "<<id<<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";
|
DomainInfo di{ "powerdns.com", "ns1.powerdns.com" };
|
||||||
id = txn.put(rr);
|
domtxn.put(di, 11);
|
||||||
cout<<"Puted as id "<<id<<endl;
|
|
||||||
|
|
||||||
rr.content = "ns2.powerdns.com"; rr.ordername = "ns2"; id = txn.put(rr);
|
DNSResourceRecord rr;
|
||||||
cout<<"Puted as id "<<id<<endl;
|
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"};
|
auto id = txn.put(rr);
|
||||||
domtxn.put(di, 10);
|
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.qname = "powerdns.com";
|
||||||
rr.ordername="";
|
rr.qtype = 1;
|
||||||
txn.put(rr);
|
rr.ordername = "";
|
||||||
|
rr.content = "1.2.3.4";
|
||||||
|
|
||||||
rr.qname = "ds9a.nl"; rr.content = "25 ns1.ds9a.nl"; rr.qtype = 15;
|
id = txn.put(rr);
|
||||||
txn.put(rr);
|
cout << "Puted as id " << id << endl;
|
||||||
|
|
||||||
rr.qname = "ns1.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
rr.qtype = 2;
|
||||||
rr.ordername="ns1";
|
rr.content = "ns1.powerdns.com";
|
||||||
txn.put(rr);
|
rr.ordername = "ns1";
|
||||||
rr.qname = "ns1.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
id = txn.put(rr);
|
||||||
txn.put(rr);
|
cout << "Puted as id " << id << endl;
|
||||||
|
|
||||||
rr.qname = "ns2.ds9a.nl"; rr.content = "1.2.3.4"; rr.qtype = 1;
|
rr.content = "ns2.powerdns.com";
|
||||||
rr.ordername="ns2";
|
rr.ordername = "ns2";
|
||||||
txn.put(rr);
|
id = txn.put(rr);
|
||||||
rr.qname = "ns2.ds9a.nl"; rr.content = "::1"; rr.qtype = 26;
|
cout << "Puted as id " << id << endl;
|
||||||
txn.put(rr);
|
|
||||||
|
|
||||||
|
DomainInfo di2{ "ds9a.nl", "ns1.powerdns.com" };
|
||||||
|
domtxn.put(di, 10);
|
||||||
DNSResourceRecord rr2;
|
|
||||||
id = txn.get<0>("www.powerdns.com", rr2);
|
|
||||||
|
|
||||||
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;
|
rr.qname = "ns1.ds9a.nl";
|
||||||
id = txn.get<0>("powerdns.com", rr3);
|
rr.content = "1.2.3.4";
|
||||||
cout<< id << endl;
|
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;
|
DNSResourceRecord rr2;
|
||||||
for(auto iter = txn.begin<0>(); iter != txn.end(); ++iter) {
|
id = txn.get<0>("www.powerdns.com", rr2);
|
||||||
cout << iter.getID()<<": "<<iter->qname << " " << iter->qtype << " " << iter->content <<endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout<<"Going to iterate over everything, ordered by domain_id!"<<endl;
|
cout << "Retrieved id " << id << ", content: " << rr2.content << 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;
|
id = txn.get<0>("powerdns.com", rr2);
|
||||||
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;
|
cout << "Retrieved id " << id << ", content: " << rr2.content << 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;
|
DNSResourceRecord rr3;
|
||||||
rr3.ordername = "vvv";
|
id = txn.get<0>("powerdns.com", rr3);
|
||||||
rr3.domain_id = 10;
|
cout << id << endl;
|
||||||
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 iter2 = txn.equal_range<0>("powerdns.com"); iter2.first != iter2.second; ++iter2.first) {
|
cout << "Going to iterate over everything, ordered by name!" << endl;
|
||||||
cout << iter2.first.getID()<<": "<<iter2.first->qname << " " << iter2.first->qtype << " " << iter2.first->content <<endl;
|
for (auto iter = txn.begin<0>(); iter != txn.end(); ++iter) {
|
||||||
}
|
cout << iter.getID() << ": " << iter->qname << " " << iter->qtype << " " << iter->content << endl;
|
||||||
cout<<"Done iterating"<<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 << "Going to iterate over everything, ordered by id!" << endl;
|
||||||
cout << iter2.getID()<<": "<<iter2->qname << " " << iter2->qtype << " " << iter2->content <<endl;
|
for (auto iter = txn.begin(); iter != txn.end(); ++iter) {
|
||||||
}
|
cout << iter.getID() << ": " << iter->qname << " " << iter->qtype << " " << iter->content << endl;
|
||||||
cout<<"Done iterating"<<endl;
|
}
|
||||||
|
|
||||||
DNSResourceRecord change;
|
cout << "Going to iterate over everything, ordered by compound index!" << endl;
|
||||||
txn.get(1, change);
|
for (auto iter = txn.begin<2>(); iter != txn.end(); ++iter) {
|
||||||
cout<<"1.auth: "<<change.auth << endl;
|
cout << iter.getID() << ": " << iter->qname << " " << iter->qtype << " " << iter->content << " # " << iter->ordername << endl;
|
||||||
txn.modify(1, [](DNSResourceRecord& record) {
|
}
|
||||||
record.auth = false;
|
|
||||||
});
|
|
||||||
txn.get(1, change);
|
|
||||||
cout<<"1.auth: "<<change.auth << endl;
|
|
||||||
txn.del(1);
|
|
||||||
|
|
||||||
// DNSResourceRecord rr4;
|
compound c;
|
||||||
// id = txn.get3("ns1", rr4);
|
rr3.ordername = "vvv";
|
||||||
// cout<<"Found "<<id<<": " << rr4.content <<endl;
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,41 +7,38 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
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)
|
CPP_UTILITIES_UNUSED(env)
|
||||||
auto db = txn->openDB(dbname, 0);
|
auto db = txn->openDB(dbname, 0);
|
||||||
auto cursor = txn->getCursor(db);
|
auto cursor = txn->getCursor(db);
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
MDBOutVal key, val;
|
MDBOutVal key, val;
|
||||||
while(!cursor.get(key, val, count ? MDB_NEXT : MDB_FIRST)) {
|
while (!cursor.get(key, val, count ? MDB_NEXT : MDB_FIRST)) {
|
||||||
cout << key.get<string>();
|
cout << key.get<string>();
|
||||||
if(key.d_mdbval.mv_size == 4)
|
if (key.d_mdbval.mv_size == 4)
|
||||||
cout << " " << key.get<uint32_t>();
|
cout << " " << key.get<uint32_t>();
|
||||||
cout<<": " << val.get<std::string>();
|
cout << ": " << val.get<std::string>();
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
++count;
|
++count;
|
||||||
|
}
|
||||||
}
|
cout << count << endl;
|
||||||
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);
|
MDBEnv env(argc >= 2 ? argv[1] : "./database", MDB_RDONLY | MDB_NOSUBDIR, 0600);
|
||||||
auto main = env.openDB("", 0);
|
auto main = env.openDB("", 0);
|
||||||
auto txn = env.getROTransaction();
|
auto txn = env.getROTransaction();
|
||||||
|
|
||||||
auto cursor = txn->getCursor(main);
|
auto cursor = txn->getCursor(main);
|
||||||
|
|
||||||
MDBOutVal key, val;
|
MDBOutVal key, val;
|
||||||
if(cursor.get(key, val, MDB_FIRST)) {
|
if (cursor.get(key, val, MDB_FIRST)) {
|
||||||
cout << "Database is empty" <<endl;
|
cout << "Database is empty" << endl;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
cout << key.get<string>() << endl;
|
cout << key.get<string>() << endl;
|
||||||
countDB(env, txn, key.get<string>());
|
countDB(env, txn, key.get<string>());
|
||||||
} while(!cursor.get(key, val, MDB_NEXT));
|
} while (!cursor.get(key, val, MDB_NEXT));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
511
tests/basic.cc
511
tests/basic.cc
|
@ -10,326 +10,323 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
TEST_CASE("Most basic tests", "[mostbasic]") {
|
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")
|
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
|
|
||||||
auto txn = env.getRWTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
MDBOutVal out;
|
MDBOutVal out;
|
||||||
|
|
||||||
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
|
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
|
||||||
|
|
||||||
txn->put(main, "bert", "hubert");
|
txn->put(main, "lmdb", "hot");
|
||||||
txn->put(main, "bertt", "1975");
|
|
||||||
txn->put(main, "berthubert", "lmdb");
|
REQUIRE(txn->get(main, "lmdb", out) == 0);
|
||||||
txn->put(main, "bert1", "one");
|
REQUIRE(out.get<std::string>() == "hot");
|
||||||
txn->put(main, "beru", "not");
|
txn->abort();
|
||||||
|
|
||||||
auto cursor = txn->getCursor(main);
|
auto rotxn = env.getROTransaction();
|
||||||
auto txn2 = std::move(txn);
|
REQUIRE(rotxn->get(main, "lmdb", out) == MDB_NOTFOUND);
|
||||||
{
|
}
|
||||||
auto cursor2 = std::move(cursor);
|
|
||||||
}
|
TEST_CASE("Range tests", "[range]")
|
||||||
}
|
{
|
||||||
|
unlink("./tests");
|
||||||
TEST_CASE("transaction inheritance and moving")
|
|
||||||
{
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
unlink("./tests");
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
|
||||||
|
auto txn = env.getRWTransaction();
|
||||||
MDBRWCursor cursor;
|
|
||||||
{
|
|
||||||
MDBRWTransaction txn = env.getRWTransaction();
|
|
||||||
MDBOutVal out;
|
MDBOutVal out;
|
||||||
|
|
||||||
REQUIRE(txn->get(main, "lmdb", out) == MDB_NOTFOUND);
|
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, "bert", "hubert");
|
||||||
txn->put(main, "bertt", "1975");
|
txn->put(main, "bertt", "1975");
|
||||||
txn->put(main, "berthubert", "lmdb");
|
txn->put(main, "berthubert", "lmdb");
|
||||||
txn->put(main, "bert1", "one");
|
txn->put(main, "bert1", "one");
|
||||||
txn->put(main, "beru", "not");
|
txn->put(main, "beru", "not");
|
||||||
|
|
||||||
MDBROTransaction ro_txn(std::move(txn));
|
{
|
||||||
// despite being moved to an ro_txn (which normally commits instead of
|
auto cursor = txn->getCursor(main);
|
||||||
// aborting by default)
|
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]")
|
TEST_CASE("nested RW transactions", "[transactions]")
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
|
|
||||||
/* bootstrap some data */
|
/* bootstrap some data */
|
||||||
{
|
{
|
||||||
auto txn = env.getRWTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
txn->put(main, "bert", "hubert");
|
txn->put(main, "bert", "hubert");
|
||||||
txn->put(main, "bertt", "1975");
|
txn->put(main, "bertt", "1975");
|
||||||
txn->put(main, "berthubert", "lmdb");
|
txn->put(main, "berthubert", "lmdb");
|
||||||
txn->put(main, "bert1", "one");
|
txn->put(main, "bert1", "one");
|
||||||
txn->put(main, "beru", "not");
|
txn->put(main, "beru", "not");
|
||||||
txn->commit();
|
txn->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto main_txn = env.getRWTransaction();
|
auto main_txn = env.getRWTransaction();
|
||||||
main_txn->del(main, "bertt", "1975");
|
main_txn->del(main, "bertt", "1975");
|
||||||
|
|
||||||
MDBOutVal dummy{};
|
MDBOutVal dummy{};
|
||||||
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto sub_txn = main_txn->getRWTransaction();
|
auto sub_txn = main_txn->getRWTransaction();
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
||||||
sub_txn->del(main, "berthubert", "lmdb");
|
sub_txn->del(main, "berthubert", "lmdb");
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check that subtransaction got rolled back */
|
/* check that subtransaction got rolled back */
|
||||||
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
|
CHECK(main_txn->get(main, "berthubert", dummy) == 0);
|
||||||
/* and that the main changes are still there */
|
/* and that the main changes are still there */
|
||||||
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto sub_txn = main_txn->getRWTransaction();
|
auto sub_txn = main_txn->getRWTransaction();
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
||||||
sub_txn->del(main, "berthubert", "lmdb");
|
sub_txn->del(main, "berthubert", "lmdb");
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
||||||
/* this time for real! */
|
/* this time for real! */
|
||||||
sub_txn->commit();
|
sub_txn->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
||||||
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("nesting RW -> RO", "[transactions]")
|
TEST_CASE("nesting RW -> RO", "[transactions]")
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
|
|
||||||
/* bootstrap some data */
|
/* 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);
|
|
||||||
{
|
{
|
||||||
MDBROTransaction sub_sub_txn = sub_txn->getROTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
CHECK(sub_sub_txn->get(main, "berthubert", dummy) == 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");
|
||||||
|
txn->commit();
|
||||||
}
|
}
|
||||||
/* this time for real! */
|
|
||||||
sub_txn->commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK(main_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
auto main_txn = env.getRWTransaction();
|
||||||
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
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]")
|
TEST_CASE("try to nest twice", "[transactions]")
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
|
|
||||||
/* bootstrap some data */
|
/* bootstrap some data */
|
||||||
{
|
{
|
||||||
auto txn = env.getRWTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
txn->put(main, "bert", "hubert");
|
txn->put(main, "bert", "hubert");
|
||||||
txn->put(main, "bertt", "1975");
|
txn->put(main, "bertt", "1975");
|
||||||
txn->put(main, "berthubert", "lmdb");
|
txn->put(main, "berthubert", "lmdb");
|
||||||
txn->put(main, "bert1", "one");
|
txn->put(main, "bert1", "one");
|
||||||
txn->put(main, "beru", "not");
|
txn->put(main, "beru", "not");
|
||||||
txn->commit();
|
txn->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto main_txn = env.getRWTransaction();
|
auto main_txn = env.getRWTransaction();
|
||||||
main_txn->del(main, "bertt", "1975");
|
main_txn->del(main, "bertt", "1975");
|
||||||
|
|
||||||
MDBOutVal dummy{};
|
MDBOutVal dummy{};
|
||||||
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
CHECK(main_txn->get(main, "bertt", dummy) == MDB_NOTFOUND);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto sub_txn = main_txn->getRWTransaction();
|
auto sub_txn = main_txn->getRWTransaction();
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == 0);
|
||||||
sub_txn->del(main, "berthubert", "lmdb");
|
sub_txn->del(main, "berthubert", "lmdb");
|
||||||
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
CHECK(sub_txn->get(main, "berthubert", dummy) == MDB_NOTFOUND);
|
||||||
|
|
||||||
CHECK_THROWS_AS(
|
CHECK_THROWS_AS(main_txn->getRWTransaction(), std::runtime_error);
|
||||||
main_txn->getRWTransaction(),
|
}
|
||||||
std::runtime_error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("transaction counter correctness for RW->RW nesting")
|
TEST_CASE("transaction counter correctness for RW->RW nesting")
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
CPP_UTILITIES_UNUSED(main)
|
CPP_UTILITIES_UNUSED(main)
|
||||||
|
|
||||||
{
|
{
|
||||||
auto txn = env.getRWTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
auto sub_txn = txn->getRWTransaction();
|
auto sub_txn = txn->getRWTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_NOTHROW(env.getRWTransaction());
|
CHECK_NOTHROW(env.getRWTransaction());
|
||||||
CHECK_NOTHROW(env.getROTransaction());
|
CHECK_NOTHROW(env.getROTransaction());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("transaction counter correctness for RW->RO nesting")
|
TEST_CASE("transaction counter correctness for RW->RO nesting")
|
||||||
{
|
{
|
||||||
unlink("./tests");
|
unlink("./tests");
|
||||||
|
|
||||||
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
MDBEnv env("./tests", MDB_NOSUBDIR, 0600);
|
||||||
REQUIRE(1);
|
REQUIRE(1);
|
||||||
|
|
||||||
MDBDbi main = env.openDB("", MDB_CREATE);
|
MDBDbi main = env.openDB("", MDB_CREATE);
|
||||||
CPP_UTILITIES_UNUSED(main)
|
CPP_UTILITIES_UNUSED(main)
|
||||||
|
|
||||||
{
|
{
|
||||||
auto txn = env.getRWTransaction();
|
auto txn = env.getRWTransaction();
|
||||||
auto sub_txn = txn->getROTransaction();
|
auto sub_txn = txn->getROTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_NOTHROW(env.getRWTransaction());
|
CHECK_NOTHROW(env.getRWTransaction());
|
||||||
CHECK_NOTHROW(env.getROTransaction());
|
CHECK_NOTHROW(env.getROTransaction());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,60 +13,57 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LMDBSafe;
|
using namespace LMDBSafe;
|
||||||
|
|
||||||
struct Member
|
struct Member {
|
||||||
{
|
std::string firstName;
|
||||||
std::string firstName;
|
std::string lastName;
|
||||||
std::string lastName;
|
time_t enrolled;
|
||||||
time_t enrolled;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Archive>
|
template <class Archive> void serialize(Archive &ar, Member &g, const unsigned int version)
|
||||||
void serialize(Archive & ar, Member& g, const unsigned int version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
CPP_UTILITIES_UNUSED(version)
|
||||||
ar & g.firstName & g.lastName & g.enrolled;
|
ar &g.firstName &g.lastName &g.enrolled;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Basic typed tests", "[basictyped]") {
|
TEST_CASE("Basic typed tests", "[basictyped]")
|
||||||
unlink("./tests-typed");
|
{
|
||||||
typedef TypedDBI<Member,
|
unlink("./tests-typed");
|
||||||
index_on<Member, string, &Member::firstName>,
|
typedef TypedDBI<Member, index_on<Member, string, &Member::firstName>, index_on<Member, string, &Member::lastName>,
|
||||||
index_on<Member, string, &Member::lastName>,
|
index_on<Member, time_t, &Member::enrolled>>
|
||||||
index_on<Member, time_t, &Member::enrolled>
|
tmembers_t;
|
||||||
> tmembers_t;
|
|
||||||
|
|
||||||
auto tmembers = tmembers_t(getMDBEnv("./tests-typed", MDB_CREATE | MDB_NOSUBDIR, 0600), "members");
|
auto tmembers = tmembers_t(getMDBEnv("./tests-typed", MDB_CREATE | MDB_NOSUBDIR, 0600), "members");
|
||||||
|
|
||||||
REQUIRE(1);
|
|
||||||
|
|
||||||
auto txn = tmembers.getRWTransaction();
|
REQUIRE(1);
|
||||||
Member m{"bert", "hubert"};
|
|
||||||
txn.put(m);
|
|
||||||
m.firstName="bertus";
|
|
||||||
m.lastName = "testperson";
|
|
||||||
m.enrolled = time(0);
|
|
||||||
txn.put(m);
|
|
||||||
|
|
||||||
m.firstName = "other";
|
auto txn = tmembers.getRWTransaction();
|
||||||
txn.put(m);
|
Member m{ "bert", "hubert" };
|
||||||
|
txn.put(m);
|
||||||
Member out;
|
m.firstName = "bertus";
|
||||||
REQUIRE(txn.get(1,out));
|
m.lastName = "testperson";
|
||||||
REQUIRE(out.firstName == "bert");
|
m.enrolled = time(0);
|
||||||
REQUIRE(txn.get(2,out));
|
txn.put(m);
|
||||||
REQUIRE(out.lastName == "testperson");
|
|
||||||
|
|
||||||
REQUIRE(!txn.get(4,out));
|
m.firstName = "other";
|
||||||
|
txn.put(m);
|
||||||
|
|
||||||
auto range = txn.prefix_range<0>("bert");
|
Member out;
|
||||||
vector<std::string> names;
|
REQUIRE(txn.get(1, out));
|
||||||
for(auto& iter = range.first; iter != range.second; ++iter) {
|
REQUIRE(out.firstName == "bert");
|
||||||
names.push_back(iter->firstName);
|
REQUIRE(txn.get(2, out));
|
||||||
}
|
REQUIRE(out.lastName == "testperson");
|
||||||
REQUIRE(names == vector<std::string>{"bert", "bertus"});
|
|
||||||
|
|
||||||
auto range2 = txn.prefix_range<0>("nosuchperson");
|
REQUIRE(!txn.get(4, out));
|
||||||
REQUIRE(!(range2.first == range2.second));
|
|
||||||
|
auto range = txn.prefix_range<0>("bert");
|
||||||
txn.abort();
|
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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue