Add CMake build system replacing Makefile

* Allow building a shared library with proper exports
* Remove bundled catch2 library in favor of searching for system-provided
  version
* Adapt/fix tests and examples to latest changes
* Fix several warnings
This commit is contained in:
Martchus 2022-01-30 00:05:02 +01:00
parent adcb9338e8
commit b499a201c2
14 changed files with 221 additions and 14415 deletions

78
CMakeLists.txt Normal file
View File

@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR)
project(lmdb-safe)
# define meta data
set(META_PROJECT_NAME lmdb-safe)
set(META_PROJECT_TYPE library)
set(META_PROJECT_VARNAME LMDB_SAFE)
set(META_APP_NAME "LMDB-Safe")
set(META_APP_AUTHOR "Martchus")
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "A safe modern & performant C++ wrapper of LMDB")
set(META_VERSION_MAJOR 0)
set(META_VERSION_MINOR 0)
set(META_VERSION_PATCH 1)
set(META_VERSION_EXACT_SONAME ON)
# add project files
set(HEADER_FILES
lmdb-safe.hh
lmdb-typed.hh
lmdb-reflective.hh
lmdb-boost-serialization.hh)
set(SRC_FILES
lmdb-safe.cc
lmdb-typed.cc)
set(DOC_FILES README.md)
# find c++utilities
set(CONFIGURATION_PACKAGE_SUFFIX
""
CACHE STRING "sets the suffix for find_package() calls to packages configured via c++utilities")
set(PACKAGE_NAMESPACE
""
CACHE STRING "sets the namespace (prefix) for find_package() calls to packages configured via c++utilities")
if (PACKAGE_NAMESPACE)
set(PACKAGE_NAMESPACE_PREFIX "${PACKAGE_NAMESPACE}-")
endif ()
find_package(${PACKAGE_NAMESPACE_PREFIX}c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.5.0 REQUIRED)
use_cpp_utilities(ONLY_HEADERS VISIBILITY PUBLIC)
use_cpp_utilities(LIBRARIES_VARIABLE "TEST_LIBRARIES")
# find lmdb
include(3rdParty)
use_pkg_config_module(PKG_CONFIG_MODULES "lmdb")
# find boost libraries (required by tests)
option(BOOST_STATIC_LINKAGE "${STATIC_LINKAGE}" "link statically against Boost (instead of dynamically)")
set(Boost_USE_MULTITHREADED ON)
if (BOOST_STATIC_LINKAGE)
set(Boost_USE_STATIC_LIBS ON)
endif ()
set(BOOST_ARGS "REQUIRED;COMPONENTS;serialization;iostreams")
use_package(TARGET_NAME Boost::iostreams PACKAGE_NAME Boost PACKAGE_ARGS "${BOOST_ARGS}" LIBRARIES_VARIABLE "TEST_LIBRARIES")
use_package(TARGET_NAME Boost::serialization PACKAGE_NAME Boost PACKAGE_ARGS "${BOOST_ARGS}" LIBRARIES_VARIABLE "TEST_LIBRARIES")
# find catch2 (required by tests)
use_package(TARGET_NAME Catch2::Catch2 PACKAGE_NAME Catch2 LIBRARIES_VARIABLE "TEST_LIBRARIES")
# include modules to apply configuration
include(BasicConfig)
include(WindowsResources)
include(LibraryTarget)
include(Doxygen)
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 multi rel resize scale typed)
foreach (EXAMPLE ${EXAMPLES})
configure_test_target(TEST_NAME "${EXAMPLE}_example" SRC_FILES "examples/${EXAMPLE}.cc" LIBRARIES "${TEST_LIBRARIES}")
endforeach ()

View File

@ -1,4 +1,4 @@
#include "lmdb-safe.hh"
#include "../lmdb-safe.hh"
#include <unistd.h>

View File

@ -1,8 +1,10 @@
#include "lmdb-safe.hh"
#include "../lmdb-safe.hh"
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <c++utilities/application/global.h>
#include <sstream>
using namespace std;
@ -15,6 +17,7 @@ struct Record
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;
}
@ -52,7 +55,7 @@ static void store(MDBRWTransaction& txn, MDBDbi& records, MDBDbi& domainidx, MDB
}
int main(int argc, char** argv)
int main(int, char** argv)
{
auto env = getMDBEnv("pdns", 0, 0600);
auto records = env->openDB("records", MDB_INTEGERKEY | MDB_CREATE );

View File

@ -1,11 +1,17 @@
#include "lmdb-safe.hh"
#include "../lmdb-safe.hh"
#include <cstring>
using namespace std;
using namespace LMDBSafe;
int main(int argc, char** argv)
template <typename First, typename Second>
struct Pair {
First first;
Second second;
};
int main(int argc, char**)
{
auto env = getMDBEnv("resize", MDB_NOSUBDIR | MDB_NOSYNC, 0600);
auto main = env->openDB("ahu", MDB_CREATE );
@ -14,20 +20,20 @@ int main(int argc, char** argv)
auto rwtxn = env->getRWTransaction();
rwtxn->put(main, "counter", "1234");
rwtxn->put(main, MDBInVal::fromStruct(std::make_pair(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(std::make_pair(14,15)),
MDBInVal::fromStruct(std::make_pair(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(std::make_pair(12,13)), 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(std::make_pair(14,15)), out)) {
auto res = out.get_struct<pair<int,int>>();
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
@ -77,7 +83,7 @@ int main(int argc, char** argv)
}
auto txn = env->getRWTransaction();
txn->put(main, key, MDBInVal(n));
for(int k=0; k < 100; ++k)
for(unsigned int k=0; k < 100; ++k)
txn->put(main, MDBInVal(n+1000*k), MDBInVal(n+1000*k));
txn->commit();
}

View File

@ -1,4 +1,6 @@
#include "lmdb-safe.hh"
#include "../lmdb-safe.hh"
#include <c++utilities/conversion/stringconversion.h>
using namespace std;
using namespace LMDBSafe;
@ -22,12 +24,12 @@ struct MDBVal
int main(int argc, char** argv)
{
auto env = getMDBEnv("./database", 0, 0600);
auto dbi = env->openDB(0, MDB_CREATE | MDB_INTEGERKEY);
auto dbi = env->openDB(std::string_view(), MDB_CREATE | MDB_INTEGERKEY);
auto txn = env->getRWTransaction();
unsigned int limit=20000000;
if(argc > 1)
limit = atoi(argv[1]);
limit = CppUtilities::stringToNumber<unsigned int>(argv[1]);
cout<<"Counting records.. "; cout.flush();
auto cursor = txn->getCursor(dbi);

View File

@ -1,4 +1,7 @@
#include "lmdb-typed.hh"
#include "../lmdb-boost-serialization.hh"
#include "../lmdb-typed.hh"
#include <c++utilities/application/global.h>
#include <arpa/inet.h>
@ -27,12 +30,14 @@ struct DomainInfo
template<class Archive>
void serialize(Archive & ar, DomainInfo& g, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & g.qname & g.master;
}
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;
@ -49,7 +54,7 @@ struct compound
{
std::string ret;
uint32_t id = htonl(rr.domain_id);
ret.assign((char*)&id, 4);
ret.assign(reinterpret_cast<char *>(&id), 4);
ret.append(rr.ordername);
return ret;
}
@ -199,23 +204,23 @@ int main()
cout<<"Going to iterate over the name powerdns.com!"<<endl;
for(auto iter = txn.equal_range<0>("powerdns.com"); iter.first != iter.second; ++iter.first) {
cout << iter.first.getID()<<": "<<iter.first->qname << " " << iter.first->qtype << " " << iter.first->content <<endl;
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 iter = txn.find<1>(10); 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;
DNSResourceRecord change;
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;
txn.modify(1, [](DNSResourceRecord& c) {
c.auth = false;
txn.modify(1, [](DNSResourceRecord& record) {
record.auth = false;
});
txn.get(1, change);
cout<<"1.auth: "<<change.auth << endl;

File diff suppressed because it is too large Load Diff

27
global.h Normal file
View File

@ -0,0 +1,27 @@
// Created via CMake from template global.h.in
// WARNING! Any changes to this file will be overwritten by the next CMake run!
#ifndef LMDB_SAFE_GLOBAL
#define LMDB_SAFE_GLOBAL
#include <c++utilities/application/global.h>
#ifdef LMDB_SAFE_STATIC
#define LMDB_SAFE_EXPORT
#define LMDB_SAFE_IMPORT
#else
#define LMDB_SAFE_EXPORT CPP_UTILITIES_GENERIC_LIB_EXPORT
#define LMDB_SAFE_IMPORT CPP_UTILITIES_GENERIC_LIB_IMPORT
#endif
/*!
* \def LMDB_SAFE_EXPORT
* \brief Marks the symbol to be exported by the lmdb-safe library.
*/
/*!
* \def LMDB_SAFE_IMPORT
* \brief Marks the symbol to be imported from the lmdb-safe library.
*/
#endif // LMDB_SAFE_GLOBAL

View File

@ -0,0 +1,38 @@
#pragma once
#include "./lmdb-safe.hh"
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
namespace LMDBSafe {
template<typename T>
std::string serToString(const T& t)
{
auto ret = std::string();
auto inserter = boost::iostreams::back_insert_device<std::string>(ret);
auto stream = boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>>(inserter);
auto oa = boost::archive::binary_oarchive(stream, boost::archive::no_header | boost::archive::no_codecvt);
oa << t;
return ret;
}
template<typename T>
void serFromString(string_view str, T& ret)
{
auto source = boost::iostreams::array_source(str.data(), str.size());
auto stream = boost::iostreams::stream<boost::iostreams::array_source>(source);
auto ia = boost::archive::binary_iarchive(stream, boost::archive::no_header|boost::archive::no_codecvt);
ia >> ret;
}
}

View File

@ -2,7 +2,7 @@
// Example for plugging a (de)serialization implementation using the binary
// (de)serializer provided by https://github.com/Martchus/reflective-rapidjson.
#include "lmdb-safe.hh"
#include "./lmdb-safe.hh"
#include <reflective-rapidjson/lib/binary/reflector.h>

View File

@ -1,5 +1,7 @@
#pragma once
#include "./global.h"
#include <lmdb.h>
#include <iostream>
@ -41,7 +43,7 @@ using string_view = boost::string_ref;
#endif
#endif
class LMDBError : public std::runtime_error
class LMDB_SAFE_EXPORT LMDBError : public std::runtime_error
{
public:
explicit LMDBError(const std::string &error) noexcept
@ -63,7 +65,7 @@ public:
* \brief The MDBDbi class is our only 'value type' object as 1) a dbi is actually an integer
* and 2) per LMDB documentation, we never close it.
*/
class MDBDbi
class LMDB_SAFE_EXPORT MDBDbi
{
public:
MDBDbi()
@ -86,10 +88,10 @@ class MDBROTransactionImpl;
using MDBROTransaction = std::unique_ptr<MDBROTransactionImpl>;
using MDBRWTransaction = std::unique_ptr<MDBRWTransactionImpl>;
class MDBEnv
class LMDB_SAFE_EXPORT MDBEnv
{
public:
MDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs);
MDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 10);
~MDBEnv()
{
@ -122,11 +124,9 @@ private:
std::map<std::thread::id, int> d_ROtransactionsOut;
};
std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 128);
LMDB_SAFE_EXPORT std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 128);
struct MDBOutVal
struct LMDB_SAFE_EXPORT MDBOutVal
{
operator MDB_val&()
{
@ -184,7 +184,7 @@ template<> inline string_view MDBOutVal::get<string_view>() const
return string_view(static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size);
}
class MDBInVal
class LMDB_SAFE_EXPORT MDBInVal
{
public:
MDBInVal(const MDBOutVal& rhs)
@ -226,7 +226,7 @@ public:
{
MDBInVal ret;
ret.d_mdbval.mv_size = sizeof(T);
ret.d_mdbval.mv_data = static_cast<void*>(const_cast<char*>(&t[0]));
ret.d_mdbval.mv_data = static_cast<void*>(&const_cast<T&>(t));
return ret;
}
@ -241,12 +241,9 @@ private:
};
class MDBROCursor;
class MDBROTransactionImpl
class LMDB_SAFE_EXPORT MDBROTransactionImpl
{
protected:
MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn);
@ -495,7 +492,7 @@ public:
}
};
class MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor>
class LMDB_SAFE_EXPORT MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor>
{
public:
MDBROCursor() = default;
@ -510,7 +507,7 @@ public:
class MDBRWCursor;
class MDBRWTransactionImpl: public MDBROTransactionImpl
class LMDB_SAFE_EXPORT MDBRWTransactionImpl: public MDBROTransactionImpl
{
protected:
MDBRWTransactionImpl(MDBEnv* parent, MDB_txn* txn);
@ -610,7 +607,7 @@ public:
* be closed when its transaction ends." This is a problem for us since it may means we are closing
* the cursor twice, which is bad.
*/
class MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>
class LMDB_SAFE_EXPORT MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>
{
public:
MDBRWCursor() = default;

View File

@ -1,5 +1,6 @@
#pragma once
#include "lmdb-safe.hh"
#include "./lmdb-safe.hh"
namespace LMDBSafe {
@ -18,7 +19,7 @@ namespace LMDBSafe {
This makes us start everything at ID=1, which might make it possible to
treat id 0 as special
*/
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
LMDB_SAFE_EXPORT unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
/** This is the serialization interface.
You need to define your these functions for the types you'd like to store.
@ -65,7 +66,7 @@ inline string_view keyConv(string_view t)
* don't exist.
*/
template<class Class,typename Type, typename Parent>
struct LMDBIndexOps
struct LMDB_SAFE_EXPORT LMDBIndexOps
{
explicit LMDBIndexOps(Parent* parent) : d_parent(parent){}
void put(MDBRWTransaction& txn, const Class& t, uint32_t id, unsigned int flags=0)
@ -161,7 +162,7 @@ struct nullindex_t
/** The main class. Templatized only on the indexes and typename right now */
template<typename T, class I1=nullindex_t, class I2=nullindex_t, class I3 = nullindex_t, class I4 = nullindex_t>
class TypedDBI
class LMDB_SAFE_EXPORT TypedDBI
{
public:
TypedDBI(std::shared_ptr<MDBEnv> env, string_view name)
@ -284,7 +285,7 @@ public:
serFromString(d_id.get<string_view>(), d_t);
}
explicit iter_t(Parent* parent, typename Parent::cursor_t&& cursor, const std::string& prefix) :
explicit iter_t(Parent* parent, typename Parent::cursor_t&& cursor, string_view prefix) :
d_parent(parent),
d_cursor(std::move(cursor)),
d_on_index(true), // is this an iterator on main database or on index?
@ -532,7 +533,7 @@ public:
Parent& d_parent;
};
class ROTransaction : public ReadonlyOperations<ROTransaction>
class LMDB_SAFE_EXPORT ROTransaction : public ReadonlyOperations<ROTransaction>
{
public:
explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(std::make_shared<MDBROTransaction>(d_parent->d_env->getROTransaction()))
@ -563,7 +564,7 @@ public:
};
class RWTransaction : public ReadonlyOperations<RWTransaction>
class LMDB_SAFE_EXPORT RWTransaction : public ReadonlyOperations<RWTransaction>
{
public:
explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent)

View File

@ -1,6 +1,9 @@
#include "../lmdb-safe.hh"
#define CATCH_CONFIG_MAIN
#include "lmdb-safe.hh"
#include "catch2/catch.hpp"
#include <catch2/catch.hpp>
#include <c++utilities/application/global.h>
#include <iostream>
@ -146,7 +149,7 @@ TEST_CASE("transaction inheritance and moving")
// aborting by default)
}
CHECK(!cursor);
CHECK(!const_cast<const MDBRWCursor&>(cursor));
}
TEST_CASE("nested RW transactions", "[transactions]")
@ -301,6 +304,7 @@ TEST_CASE("transaction counter correctness for RW->RW nesting")
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
{
auto txn = env.getRWTransaction();
@ -319,6 +323,7 @@ TEST_CASE("transaction counter correctness for RW->RO nesting")
REQUIRE(1);
MDBDbi main = env.openDB("", MDB_CREATE);
CPP_UTILITIES_UNUSED(main)
{
auto txn = env.getRWTransaction();

View File

@ -1,5 +1,10 @@
#include "lmdb-typed.hh"
#include "catch2/catch.hpp"
#include "../lmdb-boost-serialization.hh"
#include "../lmdb-typed.hh"
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include <c++utilities/application/global.h>
#include <time.h>
@ -18,6 +23,7 @@ struct Member
template<class Archive>
void serialize(Archive & ar, Member& g, const unsigned int version)
{
CPP_UTILITIES_UNUSED(version)
ar & g.firstName & g.lastName & g.enrolled;
}