Apply uniform formatting via clang-format
This commit is contained in:
parent
ff1fc3ebd4
commit
2e7d278c9b
|
@ -30,3 +30,6 @@
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Misc
|
||||
.clang-format
|
||||
|
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
#include "./lmdb-safe.hh"
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
|
||||
#include <boost/iostreams/device/back_inserter.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)
|
||||
template <typename T> std::string serToString(const T &t)
|
||||
{
|
||||
auto ret = std::string();
|
||||
auto inserter = boost::iostreams::back_insert_device<std::string>(ret);
|
||||
|
@ -26,13 +25,12 @@ std::string serToString(const T& t)
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void serFromString(string_view str, T& 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);
|
||||
auto ia = boost::archive::binary_iarchive(stream, boost::archive::no_header | boost::archive::no_codecvt);
|
||||
ia >> ret;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
|
||||
#include <reflective-rapidjson/lib/binary/reflector.h>
|
||||
|
||||
#include <boost/iostreams/device/back_inserter.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)
|
||||
template <typename T> std::string serToString(const T &t)
|
||||
{
|
||||
auto ret = std::string();
|
||||
auto inserter = boost::iostreams::back_insert_device<std::string>(ret);
|
||||
|
@ -23,8 +22,7 @@ std::string serToString(const T& t)
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void serFromString(string_view str, T& 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);
|
||||
|
@ -33,4 +31,4 @@ void serFromString(string_view str, T& ret)
|
|||
serializer.read(ret);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
107
lmdb-safe.cc
107
lmdb-safe.cc
|
@ -3,30 +3,30 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace LMDBSafe {
|
||||
|
||||
MDBDbi::MDBDbi(MDB_env* env, MDB_txn* txn, const string_view dbname, unsigned int flags)
|
||||
MDBDbi::MDBDbi(MDB_env *env, MDB_txn *txn, const string_view dbname, unsigned int flags)
|
||||
{
|
||||
(void)env;
|
||||
// A transaction that uses this function must finish (either commit or abort) before any other transaction in the process may use this function.
|
||||
|
||||
if(const auto rc = mdb_dbi_open(txn, dbname.empty() ? 0 : &dbname[0], flags, &d_dbi))
|
||||
if (const auto rc = mdb_dbi_open(txn, dbname.empty() ? 0 : &dbname[0], flags, &d_dbi))
|
||||
throw LMDBError("Unable to open named database: ", rc);
|
||||
|
||||
// Database names are keys in the unnamed database, and may be read but not written.
|
||||
}
|
||||
|
||||
MDBEnv::MDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs)
|
||||
MDBEnv::MDBEnv(const char *fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs)
|
||||
{
|
||||
mdb_env_create(&d_env);
|
||||
if(const auto rc = mdb_env_set_mapsize(d_env, 16ULL * 4096 * 244140ULL)) { // 4GB
|
||||
if (const auto rc = mdb_env_set_mapsize(d_env, 16ULL * 4096 * 244140ULL)) { // 4GB
|
||||
throw LMDBError("Setting map size: ", rc);
|
||||
}
|
||||
// Various other options may also need to be set before opening the handle, e.g. mdb_env_set_mapsize(), mdb_env_set_maxreaders(), mdb_env_set_maxdbs(),
|
||||
|
@ -35,7 +35,7 @@ MDBEnv::MDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi m
|
|||
}
|
||||
|
||||
// we need MDB_NOTLS since we rely on its semantics
|
||||
if(const auto rc = mdb_env_open(d_env, fname, flags | MDB_NOTLS, mode)) {
|
||||
if (const auto rc = mdb_env_open(d_env, fname, flags | MDB_NOTLS, mode)) {
|
||||
// If this function fails, mdb_env_close() must be called to discard the MDB_env handle.
|
||||
mdb_env_close(d_env);
|
||||
throw LMDBError("Unable to open database file " + std::string(fname) + ": ", rc);
|
||||
|
@ -77,11 +77,9 @@ int MDBEnv::getROTX()
|
|||
return d_ROtransactionsOut[std::this_thread::get_id()];
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs)
|
||||
std::shared_ptr<MDBEnv> getMDBEnv(const char *fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs)
|
||||
{
|
||||
struct Value
|
||||
{
|
||||
struct Value {
|
||||
weak_ptr<MDBEnv> wp;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
@ -90,16 +88,16 @@ std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, unsigned int flags, mdb_mod
|
|||
static std::mutex mut;
|
||||
|
||||
struct stat statbuf;
|
||||
if(stat(fname, &statbuf)) {
|
||||
if(errno != ENOENT)
|
||||
if (stat(fname, &statbuf)) {
|
||||
if (errno != ENOENT)
|
||||
throw LMDBError("Unable to stat prospective mdb database: " + string(strerror(errno)));
|
||||
else {
|
||||
std::lock_guard<std::mutex> l(mut);
|
||||
auto fresh = std::make_shared<MDBEnv>(fname, flags, mode, maxDBs);
|
||||
if(stat(fname, &statbuf))
|
||||
if (stat(fname, &statbuf))
|
||||
throw LMDBError("Unable to stat prospective mdb database: " + string(strerror(errno)));
|
||||
auto key = std::tie(statbuf.st_dev, statbuf.st_ino);
|
||||
s_envs[key] = {fresh, flags};
|
||||
s_envs[key] = { fresh, flags };
|
||||
return fresh;
|
||||
}
|
||||
}
|
||||
|
@ -107,26 +105,24 @@ std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, unsigned int flags, mdb_mod
|
|||
std::lock_guard<std::mutex> l(mut);
|
||||
auto key = std::tie(statbuf.st_dev, statbuf.st_ino);
|
||||
auto iter = s_envs.find(key);
|
||||
if(iter != s_envs.end()) {
|
||||
if (iter != s_envs.end()) {
|
||||
auto sp = iter->second.wp.lock();
|
||||
if(sp) {
|
||||
if(iter->second.flags != flags)
|
||||
if (sp) {
|
||||
if (iter->second.flags != flags)
|
||||
throw LMDBError("Can't open mdb with differing flags");
|
||||
|
||||
return sp;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
s_envs.erase(iter); // useful if make_shared fails
|
||||
}
|
||||
}
|
||||
|
||||
auto fresh = std::make_shared<MDBEnv>(fname, flags, mode, maxDBs);
|
||||
s_envs[key] = {fresh, flags};
|
||||
s_envs[key] = { fresh, flags };
|
||||
|
||||
return fresh;
|
||||
}
|
||||
|
||||
|
||||
MDBDbi MDBEnv::openDB(const string_view dbname, unsigned int flags)
|
||||
{
|
||||
unsigned int envflags;
|
||||
|
@ -136,7 +132,7 @@ MDBDbi MDBEnv::openDB(const string_view dbname, unsigned int flags)
|
|||
*/
|
||||
std::lock_guard<std::mutex> l(d_openmut);
|
||||
|
||||
if(!(envflags & MDB_RDONLY)) {
|
||||
if (!(envflags & MDB_RDONLY)) {
|
||||
auto rwt = getRWTransaction();
|
||||
MDBDbi ret = rwt->openDB(dbname, flags);
|
||||
rwt->commit();
|
||||
|
@ -151,22 +147,21 @@ MDBDbi MDBEnv::openDB(const string_view dbname, unsigned int flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv *parent, MDB_txn *txn):
|
||||
MDBROTransactionImpl(parent, txn)
|
||||
MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv *parent, MDB_txn *txn)
|
||||
: MDBROTransactionImpl(parent, txn)
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MDB_txn *MDBRWTransactionImpl::openRWTransaction(MDBEnv *env, MDB_txn *parent, unsigned int flags)
|
||||
{
|
||||
MDB_txn *result;
|
||||
if(env->getRWTX())
|
||||
if (env->getRWTX())
|
||||
throw LMDBError("Duplicate RW transaction");
|
||||
|
||||
for(int tries =0 ; tries < 3; ++tries) { // it might happen twice, who knows
|
||||
if(int rc=mdb_txn_begin(env->d_env, parent, flags, &result)) {
|
||||
if(rc == MDB_MAP_RESIZED && tries < 2) {
|
||||
for (int tries = 0; tries < 3; ++tries) { // it might happen twice, who knows
|
||||
if (int rc = mdb_txn_begin(env->d_env, parent, flags, &result)) {
|
||||
if (rc == MDB_MAP_RESIZED && tries < 2) {
|
||||
// "If the mapsize is increased by another process (..) mdb_txn_begin() will return MDB_MAP_RESIZED.
|
||||
// call mdb_env_set_mapsize with a size of zero to adopt the new size."
|
||||
mdb_env_set_mapsize(env->d_env, 0);
|
||||
|
@ -180,8 +175,8 @@ MDB_txn *MDBRWTransactionImpl::openRWTransaction(MDBEnv *env, MDB_txn *parent, u
|
|||
return result;
|
||||
}
|
||||
|
||||
MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv* parent, unsigned int flags):
|
||||
MDBRWTransactionImpl(parent, openRWTransaction(parent, nullptr, flags))
|
||||
MDBRWTransactionImpl::MDBRWTransactionImpl(MDBEnv *parent, unsigned int flags)
|
||||
: MDBRWTransactionImpl(parent, openRWTransaction(parent, nullptr, flags))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -197,7 +192,7 @@ void MDBRWTransactionImpl::commit()
|
|||
return;
|
||||
}
|
||||
|
||||
if(const auto rc = mdb_txn_commit(d_txn)) {
|
||||
if (const auto rc = mdb_txn_commit(d_txn)) {
|
||||
throw LMDBError("Committing transaction: ", rc);
|
||||
}
|
||||
environment().decRWTX();
|
||||
|
@ -217,25 +212,24 @@ void MDBRWTransactionImpl::abort()
|
|||
d_txn = nullptr;
|
||||
}
|
||||
|
||||
MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn):
|
||||
d_parent(parent),
|
||||
d_cursors(),
|
||||
d_txn(txn)
|
||||
MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn)
|
||||
: d_parent(parent)
|
||||
, d_cursors()
|
||||
, d_txn(txn)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MDB_txn *MDBROTransactionImpl::openROTransaction(MDBEnv *env, MDB_txn *parent, unsigned int flags)
|
||||
{
|
||||
if(env->getRWTX())
|
||||
if (env->getRWTX())
|
||||
throw LMDBError("Duplicate RO transaction");
|
||||
|
||||
/*
|
||||
A transaction and its cursors must only be used by a single thread, and a thread may only have a single transaction at a time. If MDB_NOTLS is in use, this does not apply to read-only transactions. */
|
||||
MDB_txn *result = nullptr;
|
||||
for(int tries = 0; tries < 3; ++tries) { // it might happen twice, who knows
|
||||
if(const auto rc = mdb_txn_begin(env->d_env, parent, MDB_RDONLY | flags, &result)) {
|
||||
if(rc == MDB_MAP_RESIZED && tries < 2) {
|
||||
for (int tries = 0; tries < 3; ++tries) { // it might happen twice, who knows
|
||||
if (const auto rc = mdb_txn_begin(env->d_env, parent, MDB_RDONLY | flags, &result)) {
|
||||
if (rc == MDB_MAP_RESIZED && tries < 2) {
|
||||
// "If the mapsize is increased by another process (..) mdb_txn_begin() will return MDB_MAP_RESIZED.
|
||||
// call mdb_env_set_mapsize with a size of zero to adopt the new size."
|
||||
mdb_env_set_mapsize(env->d_env, 0);
|
||||
|
@ -253,17 +247,16 @@ MDB_txn *MDBROTransactionImpl::openROTransaction(MDBEnv *env, MDB_txn *parent, u
|
|||
void MDBROTransactionImpl::closeROCursors()
|
||||
{
|
||||
// we need to move the vector away to ensure that the cursors don’t mess with our iteration.
|
||||
std::vector<MDBROCursor*> buf;
|
||||
std::vector<MDBROCursor *> buf;
|
||||
std::swap(d_cursors, buf);
|
||||
for (auto &cursor: buf) {
|
||||
for (auto &cursor : buf) {
|
||||
cursor->close();
|
||||
}
|
||||
}
|
||||
|
||||
MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, unsigned int flags):
|
||||
MDBROTransactionImpl(parent, openROTransaction(parent, nullptr, flags))
|
||||
MDBROTransactionImpl::MDBROTransactionImpl(MDBEnv *parent, unsigned int flags)
|
||||
: MDBROTransactionImpl(parent, openROTransaction(parent, nullptr, flags))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MDBROTransactionImpl::~MDBROTransactionImpl()
|
||||
|
@ -296,19 +289,18 @@ void MDBROTransactionImpl::commit()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MDBRWTransactionImpl::clear(MDB_dbi dbi)
|
||||
{
|
||||
if(const auto rc = mdb_drop(d_txn, dbi, 0)) {
|
||||
if (const auto rc = mdb_drop(d_txn, dbi, 0)) {
|
||||
throw LMDBError("Error clearing database: ", rc);
|
||||
}
|
||||
}
|
||||
|
||||
MDBRWCursor MDBRWTransactionImpl::getRWCursor(const MDBDbi& dbi)
|
||||
MDBRWCursor MDBRWTransactionImpl::getRWCursor(const MDBDbi &dbi)
|
||||
{
|
||||
MDB_cursor *cursor;;
|
||||
if(const auto rc = mdb_cursor_open(d_txn, dbi, &cursor)) {
|
||||
MDB_cursor *cursor;
|
||||
;
|
||||
if (const auto rc = mdb_cursor_open(d_txn, dbi, &cursor)) {
|
||||
throw LMDBError("Error creating RO cursor: ", rc);
|
||||
}
|
||||
return MDBRWCursor(d_rw_cursors, cursor);
|
||||
|
@ -344,17 +336,16 @@ MDBRWTransaction MDBEnv::getRWTransaction()
|
|||
return MDBRWTransaction(new MDBRWTransactionImpl(this));
|
||||
}
|
||||
|
||||
|
||||
void MDBRWTransactionImpl::closeRWCursors()
|
||||
{
|
||||
decltype(d_rw_cursors) buf;
|
||||
std::swap(d_rw_cursors, buf);
|
||||
for (auto &cursor: buf) {
|
||||
for (auto &cursor : buf) {
|
||||
cursor->close();
|
||||
}
|
||||
}
|
||||
|
||||
MDBROCursor MDBROTransactionImpl::getCursor(const MDBDbi& dbi)
|
||||
MDBROCursor MDBROTransactionImpl::getCursor(const MDBDbi &dbi)
|
||||
{
|
||||
return getROCursor(dbi);
|
||||
}
|
||||
|
@ -362,10 +353,10 @@ MDBROCursor MDBROTransactionImpl::getCursor(const MDBDbi& dbi)
|
|||
MDBROCursor MDBROTransactionImpl::getROCursor(const MDBDbi &dbi)
|
||||
{
|
||||
MDB_cursor *cursor;
|
||||
if(const auto rc = mdb_cursor_open(d_txn, dbi, &cursor)) {
|
||||
if (const auto rc = mdb_cursor_open(d_txn, dbi, &cursor)) {
|
||||
throw LMDBError("Error creating RO cursor: ", rc);
|
||||
}
|
||||
return MDBROCursor(d_cursors, cursor);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
328
lmdb-safe.hh
328
lmdb-safe.hh
|
@ -4,19 +4,19 @@
|
|||
|
||||
#include <lmdb.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
/*!
|
||||
* \brief The LMDBSafe namespace contains all classes/types contained by the lmdb-safe and
|
||||
|
@ -43,8 +43,7 @@ using string_view = boost::string_ref;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
class LMDB_SAFE_EXPORT LMDBError : public std::runtime_error
|
||||
{
|
||||
class LMDB_SAFE_EXPORT LMDBError : public std::runtime_error {
|
||||
public:
|
||||
explicit LMDBError(const std::string &error) noexcept
|
||||
: std::runtime_error(error)
|
||||
|
@ -65,16 +64,15 @@ 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 LMDB_SAFE_EXPORT MDBDbi
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBDbi {
|
||||
public:
|
||||
MDBDbi()
|
||||
{
|
||||
d_dbi = std::numeric_limits<decltype (d_dbi)>::max();
|
||||
d_dbi = std::numeric_limits<decltype(d_dbi)>::max();
|
||||
}
|
||||
explicit MDBDbi(MDB_env* env, MDB_txn* txn, string_view dbname, unsigned int flags);
|
||||
explicit MDBDbi(MDB_env *env, MDB_txn *txn, string_view dbname, unsigned int flags);
|
||||
|
||||
operator const MDB_dbi&() const
|
||||
operator const MDB_dbi &() const
|
||||
{
|
||||
return d_dbi;
|
||||
}
|
||||
|
@ -88,10 +86,9 @@ class MDBROTransactionImpl;
|
|||
using MDBROTransaction = std::unique_ptr<MDBROTransactionImpl>;
|
||||
using MDBRWTransaction = std::unique_ptr<MDBRWTransactionImpl>;
|
||||
|
||||
class LMDB_SAFE_EXPORT MDBEnv
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBEnv {
|
||||
public:
|
||||
MDBEnv(const char* fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 10);
|
||||
MDBEnv(const char *fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 10);
|
||||
|
||||
~MDBEnv()
|
||||
{
|
||||
|
@ -105,11 +102,11 @@ public:
|
|||
MDBRWTransaction getRWTransaction();
|
||||
MDBROTransaction getROTransaction();
|
||||
|
||||
operator MDB_env*& ()
|
||||
operator MDB_env *&()
|
||||
{
|
||||
return d_env;
|
||||
}
|
||||
MDB_env* d_env;
|
||||
MDB_env *d_env;
|
||||
|
||||
int getRWTX();
|
||||
void incRWTX();
|
||||
|
@ -117,6 +114,7 @@ public:
|
|||
int getROTX();
|
||||
void incROTX();
|
||||
void decROTX();
|
||||
|
||||
private:
|
||||
std::mutex d_openmut;
|
||||
std::mutex d_countmutex;
|
||||
|
@ -124,149 +122,136 @@ private:
|
|||
std::map<std::thread::id, int> d_ROtransactionsOut;
|
||||
};
|
||||
|
||||
LMDB_SAFE_EXPORT 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 LMDB_SAFE_EXPORT MDBOutVal
|
||||
{
|
||||
operator MDB_val&()
|
||||
struct LMDB_SAFE_EXPORT MDBOutVal {
|
||||
operator MDB_val &()
|
||||
{
|
||||
return d_mdbval;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value,
|
||||
T>::type* = nullptr> const
|
||||
T get()
|
||||
template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type * = nullptr> const T get()
|
||||
{
|
||||
T ret;
|
||||
if(d_mdbval.mv_size != sizeof(T))
|
||||
if (d_mdbval.mv_size != sizeof(T))
|
||||
throw LMDBError("MDB data has wrong length for type");
|
||||
|
||||
memcpy(&ret, d_mdbval.mv_data, sizeof(T));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_class<T>::value,T>::type* = nullptr>
|
||||
T get() const;
|
||||
template <class T, typename std::enable_if<std::is_class<T>::value, T>::type * = nullptr> T get() const;
|
||||
|
||||
template<class T>
|
||||
T get_struct() const
|
||||
template <class T> T get_struct() const
|
||||
{
|
||||
T ret;
|
||||
if(d_mdbval.mv_size != sizeof(T))
|
||||
if (d_mdbval.mv_size != sizeof(T))
|
||||
throw LMDBError("MDB data has wrong length for type");
|
||||
|
||||
memcpy(&ret, d_mdbval.mv_data, sizeof(T));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T* get_struct_ptr() const
|
||||
template <class T> const T *get_struct_ptr() const
|
||||
{
|
||||
if(d_mdbval.mv_size != sizeof(T))
|
||||
if (d_mdbval.mv_size != sizeof(T))
|
||||
throw LMDBError("MDB data has wrong length for type");
|
||||
|
||||
return reinterpret_cast<const T*>(d_mdbval.mv_data);
|
||||
return reinterpret_cast<const T *>(d_mdbval.mv_data);
|
||||
}
|
||||
|
||||
|
||||
MDB_val d_mdbval;
|
||||
};
|
||||
|
||||
template<> inline std::string MDBOutVal::get<std::string>() const
|
||||
template <> inline std::string MDBOutVal::get<std::string>() const
|
||||
{
|
||||
return std::string(static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size);
|
||||
return std::string(static_cast<char *>(d_mdbval.mv_data), d_mdbval.mv_size);
|
||||
}
|
||||
|
||||
template<> inline string_view MDBOutVal::get<string_view>() const
|
||||
template <> inline string_view MDBOutVal::get<string_view>() const
|
||||
{
|
||||
return string_view(static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size);
|
||||
return string_view(static_cast<char *>(d_mdbval.mv_data), d_mdbval.mv_size);
|
||||
}
|
||||
|
||||
class LMDB_SAFE_EXPORT MDBInVal
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBInVal {
|
||||
public:
|
||||
MDBInVal(const MDBOutVal& rhs)
|
||||
MDBInVal(const MDBOutVal &rhs)
|
||||
{
|
||||
d_mdbval = rhs.d_mdbval;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value,
|
||||
T>::type* = nullptr>
|
||||
MDBInVal(T i)
|
||||
template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type * = nullptr> MDBInVal(T i)
|
||||
{
|
||||
memcpy(&d_memory[0], &i, sizeof(i));
|
||||
d_mdbval.mv_size = sizeof(T);
|
||||
d_mdbval.mv_data = d_memory;;
|
||||
d_mdbval.mv_data = d_memory;
|
||||
;
|
||||
}
|
||||
|
||||
MDBInVal(const char* s)
|
||||
MDBInVal(const char *s)
|
||||
{
|
||||
d_mdbval.mv_size = strlen(s);
|
||||
d_mdbval.mv_data = static_cast<void*>(const_cast<char*>(s));
|
||||
d_mdbval.mv_data = static_cast<void *>(const_cast<char *>(s));
|
||||
}
|
||||
|
||||
MDBInVal(string_view v)
|
||||
{
|
||||
d_mdbval.mv_size = v.size();
|
||||
d_mdbval.mv_data = static_cast<void*>(const_cast<char*>(v.data()));
|
||||
d_mdbval.mv_data = static_cast<void *>(const_cast<char *>(v.data()));
|
||||
}
|
||||
|
||||
MDBInVal(const std::string& v)
|
||||
MDBInVal(const std::string &v)
|
||||
{
|
||||
d_mdbval.mv_size = v.size();
|
||||
d_mdbval.mv_data = static_cast<void*>(const_cast<char*>(v.data()));
|
||||
d_mdbval.mv_data = static_cast<void *>(const_cast<char *>(v.data()));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static MDBInVal fromStruct(const T& t)
|
||||
template <typename T> static MDBInVal fromStruct(const T &t)
|
||||
{
|
||||
MDBInVal ret;
|
||||
ret.d_mdbval.mv_size = sizeof(T);
|
||||
ret.d_mdbval.mv_data = static_cast<void*>(&const_cast<T&>(t));
|
||||
ret.d_mdbval.mv_data = static_cast<void *>(&const_cast<T &>(t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
operator MDB_val&()
|
||||
operator MDB_val &()
|
||||
{
|
||||
return d_mdbval;
|
||||
}
|
||||
MDB_val d_mdbval;
|
||||
private:
|
||||
MDBInVal(){}
|
||||
char d_memory[sizeof(double)];
|
||||
|
||||
private:
|
||||
MDBInVal()
|
||||
{
|
||||
}
|
||||
char d_memory[sizeof(double)];
|
||||
};
|
||||
|
||||
class MDBROCursor;
|
||||
|
||||
class LMDB_SAFE_EXPORT MDBROTransactionImpl
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBROTransactionImpl {
|
||||
protected:
|
||||
MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn);
|
||||
|
||||
private:
|
||||
static MDB_txn *openROTransaction(MDBEnv *env, MDB_txn *parent, unsigned int flags=0);
|
||||
static MDB_txn *openROTransaction(MDBEnv *env, MDB_txn *parent, unsigned int flags = 0);
|
||||
|
||||
MDBEnv* d_parent;
|
||||
std::vector<MDBROCursor*> d_cursors;
|
||||
MDBEnv *d_parent;
|
||||
std::vector<MDBROCursor *> d_cursors;
|
||||
|
||||
protected:
|
||||
MDB_txn* d_txn;
|
||||
MDB_txn *d_txn;
|
||||
|
||||
void closeROCursors();
|
||||
|
||||
public:
|
||||
explicit MDBROTransactionImpl(MDBEnv* parent, unsigned int flags=0);
|
||||
explicit MDBROTransactionImpl(MDBEnv *parent, unsigned int flags = 0);
|
||||
|
||||
MDBROTransactionImpl(const MDBROTransactionImpl& src) = delete;
|
||||
MDBROTransactionImpl &operator=(const MDBROTransactionImpl& src) = delete;
|
||||
MDBROTransactionImpl(const MDBROTransactionImpl &src) = delete;
|
||||
MDBROTransactionImpl &operator=(const MDBROTransactionImpl &src) = delete;
|
||||
|
||||
// The move constructor/operator cannot be made safe due to Object Slicing with MDBRWTransaction.
|
||||
MDBROTransactionImpl(MDBROTransactionImpl&& rhs) = delete;
|
||||
MDBROTransactionImpl(MDBROTransactionImpl &&rhs) = delete;
|
||||
MDBROTransactionImpl &operator=(MDBROTransactionImpl &&rhs) = delete;
|
||||
|
||||
virtual ~MDBROTransactionImpl();
|
||||
|
@ -274,44 +259,43 @@ public:
|
|||
virtual void abort();
|
||||
virtual void commit();
|
||||
|
||||
int get(MDB_dbi dbi, const MDBInVal& key, MDBOutVal& val)
|
||||
int get(MDB_dbi dbi, const MDBInVal &key, MDBOutVal &val)
|
||||
{
|
||||
if(!d_txn)
|
||||
if (!d_txn)
|
||||
throw LMDBError("Attempt to use a closed RO transaction for get");
|
||||
|
||||
const auto rc = mdb_get(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval),
|
||||
&val.d_mdbval);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_get(d_txn, dbi, const_cast<MDB_val *>(&key.d_mdbval), &val.d_mdbval);
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Getting data: ", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int get(MDB_dbi dbi, const MDBInVal& key, string_view& val)
|
||||
int get(MDB_dbi dbi, const MDBInVal &key, string_view &val)
|
||||
{
|
||||
MDBOutVal out;
|
||||
int rc = get(dbi, key, out);
|
||||
if(!rc)
|
||||
if (!rc)
|
||||
val = out.get<string_view>();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// this is something you can do, readonly
|
||||
MDBDbi openDB(string_view dbname, unsigned int flags)
|
||||
{
|
||||
return MDBDbi( d_parent->d_env, d_txn, dbname, flags);
|
||||
return MDBDbi(d_parent->d_env, d_txn, dbname, flags);
|
||||
}
|
||||
|
||||
MDBROCursor getCursor(const MDBDbi&);
|
||||
MDBROCursor getROCursor(const MDBDbi&);
|
||||
MDBROCursor getCursor(const MDBDbi &);
|
||||
MDBROCursor getROCursor(const MDBDbi &);
|
||||
|
||||
operator MDB_txn*()
|
||||
operator MDB_txn *()
|
||||
{
|
||||
return d_txn;
|
||||
}
|
||||
|
||||
inline operator bool() const {
|
||||
inline operator bool() const
|
||||
{
|
||||
return d_txn;
|
||||
}
|
||||
|
||||
|
@ -328,26 +312,23 @@ public:
|
|||
* It can be reused with mdb_cursor_renew() before finally closing it.
|
||||
* - "If the parent transaction commits, the cursor must not be used again."
|
||||
*/
|
||||
template<class Transaction, class T>
|
||||
class MDBGenCursor
|
||||
{
|
||||
template <class Transaction, class T> class MDBGenCursor {
|
||||
private:
|
||||
std::vector<T*> *d_registry;
|
||||
MDB_cursor* d_cursor;
|
||||
std::vector<T *> *d_registry;
|
||||
MDB_cursor *d_cursor;
|
||||
|
||||
public:
|
||||
MDBGenCursor():
|
||||
d_registry(nullptr),
|
||||
d_cursor(nullptr)
|
||||
MDBGenCursor()
|
||||
: d_registry(nullptr)
|
||||
, d_cursor(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MDBGenCursor(std::vector<T*> ®istry, MDB_cursor *cursor):
|
||||
d_registry(®istry),
|
||||
d_cursor(cursor)
|
||||
MDBGenCursor(std::vector<T *> ®istry, MDB_cursor *cursor)
|
||||
: d_registry(®istry)
|
||||
, d_cursor(cursor)
|
||||
{
|
||||
registry.emplace_back(static_cast<T*>(this));
|
||||
registry.emplace_back(static_cast<T *>(this));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -357,22 +338,20 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
auto iter = std::find(d_registry->begin(),
|
||||
d_registry->end(),
|
||||
src);
|
||||
auto iter = std::find(d_registry->begin(), d_registry->end(), src);
|
||||
if (iter != d_registry->end()) {
|
||||
*iter = static_cast<T*>(this);
|
||||
*iter = static_cast<T *>(this);
|
||||
} else {
|
||||
d_registry->emplace_back(static_cast<T*>(this));
|
||||
d_registry->emplace_back(static_cast<T *>(this));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
MDBGenCursor(const MDBGenCursor &src) = delete;
|
||||
|
||||
MDBGenCursor(MDBGenCursor &&src) noexcept:
|
||||
d_registry(src.d_registry),
|
||||
d_cursor(src.d_cursor)
|
||||
MDBGenCursor(MDBGenCursor &&src) noexcept
|
||||
: d_registry(src.d_registry)
|
||||
, d_cursor(src.d_cursor)
|
||||
{
|
||||
move_from(&src);
|
||||
src.d_registry = nullptr;
|
||||
|
@ -397,74 +376,73 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
|
||||
int get(MDBOutVal &key, MDBOutVal &data, MDB_cursor_op op)
|
||||
{
|
||||
const auto rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Unable to get from cursor: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
|
||||
int find(const MDBInVal &in, MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
key.d_mdbval = in.d_mdbval;
|
||||
const auto rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_cursor_get(d_cursor, const_cast<MDB_val *>(&key.d_mdbval), &data.d_mdbval, MDB_SET);
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Unable to find from cursor: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
|
||||
int lower_bound(const MDBInVal &in, MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
key.d_mdbval = in.d_mdbval;
|
||||
|
||||
const auto rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_cursor_get(d_cursor, const_cast<MDB_val *>(&key.d_mdbval), &data.d_mdbval, MDB_SET_RANGE);
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Unable to lower_bound from cursor: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int nextprev(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
|
||||
int nextprev(MDBOutVal &key, MDBOutVal &data, MDB_cursor_op op)
|
||||
{
|
||||
const auto rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Unable to prevnext from cursor: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int next(MDBOutVal& key, MDBOutVal& data)
|
||||
int next(MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
return nextprev(key, data, MDB_NEXT);
|
||||
}
|
||||
|
||||
int prev(MDBOutVal& key, MDBOutVal& data)
|
||||
int prev(MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
return nextprev(key, data, MDB_PREV);
|
||||
}
|
||||
|
||||
int currentlast(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
|
||||
int currentlast(MDBOutVal &key, MDBOutVal &data, MDB_cursor_op op)
|
||||
{
|
||||
const auto rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Unable to next from cursor: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int current(MDBOutVal& key, MDBOutVal& data)
|
||||
int current(MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
return currentlast(key, data, MDB_GET_CURRENT);
|
||||
}
|
||||
int last(MDBOutVal& key, MDBOutVal& data)
|
||||
int last(MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
return currentlast(key, data, MDB_LAST);
|
||||
}
|
||||
int first(MDBOutVal& key, MDBOutVal& data)
|
||||
int first(MDBOutVal &key, MDBOutVal &data)
|
||||
{
|
||||
return currentlast(key, data, MDB_FIRST);
|
||||
}
|
||||
|
||||
operator MDB_cursor*()
|
||||
operator MDB_cursor *()
|
||||
{
|
||||
return d_cursor;
|
||||
}
|
||||
|
@ -477,9 +455,7 @@ public:
|
|||
void close()
|
||||
{
|
||||
if (d_registry) {
|
||||
auto iter = std::find(d_registry->begin(),
|
||||
d_registry->end(),
|
||||
static_cast<T*>(this));
|
||||
auto iter = std::find(d_registry->begin(), d_registry->end(), static_cast<T *>(this));
|
||||
if (iter != d_registry->end()) {
|
||||
d_registry->erase(iter);
|
||||
}
|
||||
|
@ -492,8 +468,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class LMDB_SAFE_EXPORT MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor>
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor> {
|
||||
public:
|
||||
MDBROCursor() = default;
|
||||
using MDBGenCursor<MDBROTransactionImpl, MDBROCursor>::MDBGenCursor;
|
||||
|
@ -502,35 +477,34 @@ public:
|
|||
MDBROCursor &operator=(const MDBROCursor &src) = delete;
|
||||
MDBROCursor &operator=(MDBROCursor &&src) = default;
|
||||
~MDBROCursor() = default;
|
||||
|
||||
};
|
||||
|
||||
class MDBRWCursor;
|
||||
|
||||
class LMDB_SAFE_EXPORT MDBRWTransactionImpl: public MDBROTransactionImpl
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBRWTransactionImpl : public MDBROTransactionImpl {
|
||||
protected:
|
||||
MDBRWTransactionImpl(MDBEnv* parent, MDB_txn* txn);
|
||||
MDBRWTransactionImpl(MDBEnv *parent, MDB_txn *txn);
|
||||
|
||||
private:
|
||||
static MDB_txn *openRWTransaction(MDBEnv* env, MDB_txn *parent, unsigned int flags);
|
||||
static MDB_txn *openRWTransaction(MDBEnv *env, MDB_txn *parent, unsigned int flags);
|
||||
|
||||
private:
|
||||
std::vector<MDBRWCursor*> d_rw_cursors;
|
||||
std::vector<MDBRWCursor *> d_rw_cursors;
|
||||
|
||||
void closeRWCursors();
|
||||
inline void closeRORWCursors() {
|
||||
inline void closeRORWCursors()
|
||||
{
|
||||
closeROCursors();
|
||||
closeRWCursors();
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MDBRWTransactionImpl(MDBEnv* parent, unsigned int flags=0);
|
||||
explicit MDBRWTransactionImpl(MDBEnv *parent, unsigned int flags = 0);
|
||||
|
||||
MDBRWTransactionImpl(const MDBRWTransactionImpl& rhs) = delete;
|
||||
MDBRWTransactionImpl(MDBRWTransactionImpl&& rhs) = delete;
|
||||
MDBRWTransactionImpl &operator=(const MDBRWTransactionImpl& rhs) = delete;
|
||||
MDBRWTransactionImpl &operator=(MDBRWTransactionImpl&& rhs) = delete;
|
||||
MDBRWTransactionImpl(const MDBRWTransactionImpl &rhs) = delete;
|
||||
MDBRWTransactionImpl(MDBRWTransactionImpl &&rhs) = delete;
|
||||
MDBRWTransactionImpl &operator=(const MDBRWTransactionImpl &rhs) = delete;
|
||||
MDBRWTransactionImpl &operator=(MDBRWTransactionImpl &&rhs) = delete;
|
||||
|
||||
~MDBRWTransactionImpl() override;
|
||||
|
||||
|
@ -539,51 +513,46 @@ public:
|
|||
|
||||
void clear(MDB_dbi dbi);
|
||||
|
||||
void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, unsigned int flags=0)
|
||||
void put(MDB_dbi dbi, const MDBInVal &key, const MDBInVal &val, unsigned int flags = 0)
|
||||
{
|
||||
if(!d_txn)
|
||||
if (!d_txn)
|
||||
throw LMDBError("Attempt to use a closed RW transaction for put");
|
||||
if(const auto rc = mdb_put(d_txn, dbi,
|
||||
const_cast<MDB_val*>(&key.d_mdbval),
|
||||
const_cast<MDB_val*>(&val.d_mdbval), flags))
|
||||
if (const auto rc = mdb_put(d_txn, dbi, const_cast<MDB_val *>(&key.d_mdbval), const_cast<MDB_val *>(&val.d_mdbval), flags))
|
||||
throw LMDBError("Putting data: ", rc);
|
||||
}
|
||||
|
||||
|
||||
int del(MDBDbi& dbi, const MDBInVal& key, const MDBInVal& val)
|
||||
int del(MDBDbi &dbi, const MDBInVal &key, const MDBInVal &val)
|
||||
{
|
||||
const auto rc = mdb_del(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval), const_cast<MDB_val*>(&val.d_mdbval));
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_del(d_txn, dbi, const_cast<MDB_val *>(&key.d_mdbval), const_cast<MDB_val *>(&val.d_mdbval));
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Deleting data: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int del(MDBDbi& dbi, const MDBInVal& key)
|
||||
int del(MDBDbi &dbi, const MDBInVal &key)
|
||||
{
|
||||
const auto rc = mdb_del(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval), 0);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_del(d_txn, dbi, const_cast<MDB_val *>(&key.d_mdbval), 0);
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Deleting data: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int get(MDBDbi& dbi, const MDBInVal& key, MDBOutVal& val)
|
||||
int get(MDBDbi &dbi, const MDBInVal &key, MDBOutVal &val)
|
||||
{
|
||||
if(!d_txn)
|
||||
if (!d_txn)
|
||||
throw LMDBError("Attempt to use a closed RW transaction for get");
|
||||
|
||||
const auto rc = mdb_get(d_txn, dbi, const_cast<MDB_val*>(&key.d_mdbval),
|
||||
&val.d_mdbval);
|
||||
if(rc && rc != MDB_NOTFOUND)
|
||||
const auto rc = mdb_get(d_txn, dbi, const_cast<MDB_val *>(&key.d_mdbval), &val.d_mdbval);
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
throw LMDBError("Getting data: ", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int get(MDBDbi& dbi, const MDBInVal& key, string_view& val)
|
||||
int get(MDBDbi &dbi, const MDBInVal &key, string_view &val)
|
||||
{
|
||||
MDBOutVal out;
|
||||
const auto rc = get(dbi, key, out);
|
||||
if(!rc)
|
||||
if (!rc)
|
||||
val = out.get<string_view>();
|
||||
return rc;
|
||||
}
|
||||
|
@ -593,8 +562,8 @@ public:
|
|||
return MDBDbi(environment().d_env, d_txn, dbname, flags);
|
||||
}
|
||||
|
||||
MDBRWCursor getRWCursor(const MDBDbi&);
|
||||
MDBRWCursor getCursor(const MDBDbi&);
|
||||
MDBRWCursor getRWCursor(const MDBDbi &);
|
||||
MDBRWCursor getCursor(const MDBDbi &);
|
||||
|
||||
MDBRWTransaction getRWTransaction();
|
||||
MDBROTransaction getROTransaction();
|
||||
|
@ -607,8 +576,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 LMDB_SAFE_EXPORT MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>
|
||||
{
|
||||
class LMDB_SAFE_EXPORT MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor> {
|
||||
public:
|
||||
MDBRWCursor() = default;
|
||||
using MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>::MDBGenCursor;
|
||||
|
@ -618,29 +586,23 @@ public:
|
|||
MDBRWCursor &operator=(MDBRWCursor &&src) = default;
|
||||
~MDBRWCursor() = default;
|
||||
|
||||
void put(const MDBOutVal& key, const MDBInVal& data)
|
||||
void put(const MDBOutVal &key, const MDBInVal &data)
|
||||
{
|
||||
if(const auto rc = mdb_cursor_put(*this,
|
||||
const_cast<MDB_val*>(&key.d_mdbval),
|
||||
const_cast<MDB_val*>(&data.d_mdbval), MDB_CURRENT))
|
||||
if (const auto rc = mdb_cursor_put(*this, const_cast<MDB_val *>(&key.d_mdbval), const_cast<MDB_val *>(&data.d_mdbval), MDB_CURRENT))
|
||||
throw LMDBError("Putting data via mdb_cursor_put: ", rc);
|
||||
}
|
||||
|
||||
|
||||
void put(const MDBOutVal& key, const MDBOutVal& data, unsigned int flags=0)
|
||||
void put(const MDBOutVal &key, const MDBOutVal &data, unsigned int flags = 0)
|
||||
{
|
||||
if (const auto rc = mdb_cursor_put(*this,
|
||||
const_cast<MDB_val*>(&key.d_mdbval),
|
||||
const_cast<MDB_val*>(&data.d_mdbval), flags))
|
||||
if (const auto rc = mdb_cursor_put(*this, const_cast<MDB_val *>(&key.d_mdbval), const_cast<MDB_val *>(&data.d_mdbval), flags))
|
||||
throw LMDBError("Putting data via mdb_cursor_put: ", rc);
|
||||
}
|
||||
|
||||
void del(unsigned int flags=0)
|
||||
void del(unsigned int flags = 0)
|
||||
{
|
||||
if (const auto rc = mdb_cursor_del(*this, flags))
|
||||
throw LMDBError("Deleting data via mdb_cursor_del: ", rc);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
namespace LMDBSafe {
|
||||
|
||||
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
|
||||
unsigned int MDBGetMaxID(MDBRWTransaction &txn, MDBDbi &dbi)
|
||||
{
|
||||
auto cursor = txn->getRWCursor(dbi);
|
||||
MDBOutVal maxidval, maxcontent;
|
||||
unsigned int maxid{0};
|
||||
if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
|
||||
unsigned int maxid{ 0 };
|
||||
if (!cursor.get(maxidval, maxcontent, MDB_LAST)) {
|
||||
maxid = maxidval.get<unsigned int>();
|
||||
}
|
||||
return maxid;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
348
lmdb-typed.hh
348
lmdb-typed.hh
|
@ -19,37 +19,31 @@ namespace LMDBSafe {
|
|||
This makes us start everything at ID=1, which might make it possible to
|
||||
treat id 0 as special
|
||||
*/
|
||||
LMDB_SAFE_EXPORT 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.
|
||||
*/
|
||||
template<typename T>
|
||||
std::string serToString(const T& t);
|
||||
template <typename T> std::string serToString(const T &t);
|
||||
|
||||
template<typename T>
|
||||
void serFromString(string_view str, T& ret);
|
||||
template <typename T> void serFromString(string_view str, T &ret);
|
||||
|
||||
/** This is the serialization interface for keys.
|
||||
You need to define your these functions for the types you'd like to use as keys.
|
||||
*/
|
||||
template <class T, class Enable>
|
||||
inline std::string keyConv(const T& t);
|
||||
template <class T, class Enable> inline std::string keyConv(const T &t);
|
||||
|
||||
template <class T, typename std::enable_if<std::is_arithmetic<T>::value,T>::type* = nullptr>
|
||||
inline string_view keyConv(const T& t)
|
||||
template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type * = nullptr> inline string_view keyConv(const T &t)
|
||||
{
|
||||
return string_view(reinterpret_cast<const char *>(&t), sizeof(t));
|
||||
}
|
||||
|
||||
template<class T, typename std::enable_if<std::is_same<T, std::string>::value,T>::type* = nullptr>
|
||||
inline string_view keyConv(const T& t)
|
||||
template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type * = nullptr> inline string_view keyConv(const T &t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template<class T, typename std::enable_if<std::is_same<T, string_view>::value,T>::type* = nullptr>
|
||||
inline string_view keyConv(string_view t)
|
||||
template <class T, typename std::enable_if<std::is_same<T, string_view>::value, T>::type * = nullptr> inline string_view keyConv(string_view t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
@ -65,45 +59,46 @@ inline string_view keyConv(string_view t)
|
|||
* size<t> or get<t>. People ask for those themselves, and should no do that on indexes that
|
||||
* don't exist.
|
||||
*/
|
||||
template<class Class,typename Type, typename Parent>
|
||||
struct 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)
|
||||
template <class Class, typename Type, typename Parent> 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)
|
||||
{
|
||||
txn->put(d_idx, keyConv(d_parent->getMember(t)), id, flags);
|
||||
}
|
||||
|
||||
void del(MDBRWTransaction& txn, const Class& t, uint32_t id)
|
||||
void del(MDBRWTransaction &txn, const Class &t, uint32_t id)
|
||||
{
|
||||
if(const auto rc = txn->del(d_idx, keyConv(d_parent->getMember(t)), id)) {
|
||||
if (const auto rc = txn->del(d_idx, keyConv(d_parent->getMember(t)), id)) {
|
||||
throw LMDBError("Error deleting from index: ", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void clear(MDBRWTransaction& txn)
|
||||
void clear(MDBRWTransaction &txn)
|
||||
{
|
||||
if (const auto rc = mdb_drop(*txn, d_idx, 0)) {
|
||||
throw LMDBError("Error clearing index: ", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void openDB(std::shared_ptr<MDBEnv>& env, string_view str, unsigned int flags)
|
||||
void openDB(std::shared_ptr<MDBEnv> &env, string_view str, unsigned int flags)
|
||||
{
|
||||
d_idx = env->openDB(str, flags);
|
||||
}
|
||||
MDBDbi d_idx;
|
||||
Parent* d_parent;
|
||||
Parent *d_parent;
|
||||
};
|
||||
|
||||
/** This is an index on a field in a struct, it derives from the LMDBIndexOps */
|
||||
|
||||
template<class Class,typename Type,Type Class::*PtrToMember>
|
||||
struct index_on : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>
|
||||
{
|
||||
index_on() : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>(this)
|
||||
{}
|
||||
static Type getMember(const Class& c)
|
||||
template <class Class, typename Type, Type Class::*PtrToMember> struct index_on : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>> {
|
||||
index_on()
|
||||
: LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>(this)
|
||||
{
|
||||
}
|
||||
static Type getMember(const Class &c)
|
||||
{
|
||||
return c.*PtrToMember;
|
||||
}
|
||||
|
@ -112,12 +107,12 @@ struct index_on : LMDBIndexOps<Class, Type, index_on<Class, Type, PtrToMember>>
|
|||
};
|
||||
|
||||
/** This is a calculated index */
|
||||
template<class Class, typename Type, class Func>
|
||||
struct index_on_function : LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func> >
|
||||
{
|
||||
index_on_function() : LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func> >(this)
|
||||
{}
|
||||
static Type getMember(const Class& c)
|
||||
template <class Class, typename Type, class Func> struct index_on_function : LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func>> {
|
||||
index_on_function()
|
||||
: LMDBIndexOps<Class, Type, index_on_function<Class, Type, Func>>(this)
|
||||
{
|
||||
}
|
||||
static Type getMember(const Class &c)
|
||||
{
|
||||
Func f;
|
||||
return f(c);
|
||||
|
@ -127,30 +122,26 @@ struct index_on_function : LMDBIndexOps<Class, Type, index_on_function<Class, Ty
|
|||
};
|
||||
|
||||
/** nop index, so we can fill our N indexes, even if you don't use them all */
|
||||
struct nullindex_t
|
||||
{
|
||||
template<typename Class>
|
||||
void put(MDBRWTransaction& txn, const Class& t, uint32_t id, unsigned int flags=0)
|
||||
struct nullindex_t {
|
||||
template <typename Class> void put(MDBRWTransaction &txn, const Class &t, uint32_t id, unsigned int flags = 0)
|
||||
{
|
||||
(void)txn;
|
||||
(void)t;
|
||||
(void)id;
|
||||
(void)flags;
|
||||
}
|
||||
template<typename Class>
|
||||
void del(MDBRWTransaction& txn, const Class& t, uint32_t id)
|
||||
template <typename Class> void del(MDBRWTransaction &txn, const Class &t, uint32_t id)
|
||||
{
|
||||
(void)txn;
|
||||
(void)t;
|
||||
(void)id;
|
||||
}
|
||||
template<typename Class>
|
||||
void clear(Class& txn)
|
||||
template <typename Class> void clear(Class &txn)
|
||||
{
|
||||
(void)txn;
|
||||
}
|
||||
|
||||
void openDB(std::shared_ptr<MDBEnv>& env, string_view str, unsigned int flags)
|
||||
void openDB(std::shared_ptr<MDBEnv> &env, string_view str, unsigned int flags)
|
||||
{
|
||||
(void)env;
|
||||
(void)str;
|
||||
|
@ -159,21 +150,20 @@ struct nullindex_t
|
|||
typedef uint32_t type; // dummy
|
||||
};
|
||||
|
||||
|
||||
/** 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 LMDB_SAFE_EXPORT TypedDBI
|
||||
{
|
||||
template <typename T, class I1 = nullindex_t, class I2 = nullindex_t, class I3 = nullindex_t, class I4 = nullindex_t>
|
||||
class LMDB_SAFE_EXPORT TypedDBI {
|
||||
public:
|
||||
TypedDBI(std::shared_ptr<MDBEnv> env, string_view name)
|
||||
: d_env(env), d_name(name)
|
||||
: d_env(env)
|
||||
, d_name(name)
|
||||
{
|
||||
d_main = d_env->openDB(name, MDB_CREATE | MDB_INTEGERKEY);
|
||||
|
||||
// now you might be tempted to go all MPL on this so we can get rid of the
|
||||
// ugly macro. I'm not very receptive to that idea since it will make things
|
||||
// EVEN uglier.
|
||||
#define openMacro(N) std::get<N>(d_tuple).openDB(d_env, std::string(name)+"_"#N, MDB_CREATE | MDB_DUPFIXED | MDB_DUPSORT);
|
||||
#define openMacro(N) std::get<N>(d_tuple).openDB(d_env, std::string(name) + "_" #N, MDB_CREATE | MDB_DUPFIXED | MDB_DUPSORT);
|
||||
openMacro(0);
|
||||
openMacro(1);
|
||||
openMacro(2);
|
||||
|
@ -181,18 +171,17 @@ public:
|
|||
#undef openMacro
|
||||
}
|
||||
|
||||
|
||||
// we get a lot of our smarts from this tuple, it enables get<0> etc
|
||||
typedef std::tuple<I1, I2, I3, I4> tuple_t;
|
||||
tuple_t d_tuple;
|
||||
|
||||
// We support readonly and rw transactions. Here we put the Readonly operations
|
||||
// which get sourced by both kinds of transactions
|
||||
template<class Parent>
|
||||
struct ReadonlyOperations
|
||||
template <class Parent> struct ReadonlyOperations {
|
||||
ReadonlyOperations(Parent &parent)
|
||||
: d_parent(parent)
|
||||
{
|
||||
ReadonlyOperations(Parent& parent) : d_parent(parent)
|
||||
{}
|
||||
}
|
||||
|
||||
//! Number of entries in main database
|
||||
size_t size()
|
||||
|
@ -203,8 +192,7 @@ public:
|
|||
}
|
||||
|
||||
//! Number of entries in the various indexes - should be the same
|
||||
template<int N>
|
||||
size_t size()
|
||||
template <int N> size_t size()
|
||||
{
|
||||
MDB_stat stat;
|
||||
mdb_stat(**d_parent.d_txn, std::get<N>(d_parent.d_parent->d_tuple).d_idx, &stat);
|
||||
|
@ -212,10 +200,10 @@ public:
|
|||
}
|
||||
|
||||
//! Get item with id, from main table directly
|
||||
bool get(uint32_t id, T& t)
|
||||
bool get(uint32_t id, T &t)
|
||||
{
|
||||
MDBOutVal data;
|
||||
if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
|
||||
if ((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
|
||||
return false;
|
||||
|
||||
serFromString(data.get<string_view>(), t);
|
||||
|
@ -223,116 +211,113 @@ public:
|
|||
}
|
||||
|
||||
//! Get item through index N, then via the main database
|
||||
template<std::size_t N>
|
||||
uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type& key, T& out)
|
||||
template <std::size_t N> uint32_t get(const typename std::tuple_element<N, tuple_t>::type::type &key, T &out)
|
||||
{
|
||||
MDBOutVal id;
|
||||
if(!(*d_parent.d_txn)->get(std::get<N>(d_parent.d_parent->d_tuple).d_idx, keyConv(key), id)) {
|
||||
if(get(id.get<uint32_t>(), out))
|
||||
if (!(*d_parent.d_txn)->get(std::get<N>(d_parent.d_parent->d_tuple).d_idx, keyConv(key), id)) {
|
||||
if (get(id.get<uint32_t>(), out))
|
||||
return id.get<uint32_t>();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Cardinality of index N
|
||||
template<std::size_t N>
|
||||
uint32_t cardinality()
|
||||
template <std::size_t N> uint32_t cardinality()
|
||||
{
|
||||
auto cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
|
||||
bool first = true;
|
||||
MDBOutVal key, data;
|
||||
uint32_t count = 0;
|
||||
while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT_NODUP)) {
|
||||
while (!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT_NODUP)) {
|
||||
++count;
|
||||
first=false;
|
||||
first = false;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! End iderator type
|
||||
struct eiter_t
|
||||
{};
|
||||
struct eiter_t {
|
||||
};
|
||||
|
||||
// can be on main, or on an index
|
||||
// when on main, return data directly
|
||||
// when on index, indirect
|
||||
// we can be limited to one key, or iterate over entire database
|
||||
// iter requires you to put the cursor in the right place first!
|
||||
struct iter_t
|
||||
{
|
||||
explicit iter_t(Parent* parent, typename Parent::cursor_t&& cursor, bool on_index, bool one_key, bool end=false) :
|
||||
d_parent(parent),
|
||||
d_cursor(std::move(cursor)),
|
||||
d_on_index(on_index), // is this an iterator on main database or on index?
|
||||
d_one_key(one_key), // should we stop at end of key? (equal range)
|
||||
struct iter_t {
|
||||
explicit iter_t(Parent *parent, typename Parent::cursor_t &&cursor, bool on_index, bool one_key, bool end = false)
|
||||
: d_parent(parent)
|
||||
, d_cursor(std::move(cursor))
|
||||
, d_on_index(on_index)
|
||||
, // is this an iterator on main database or on index?
|
||||
d_one_key(one_key)
|
||||
, // should we stop at end of key? (equal range)
|
||||
d_end(end)
|
||||
{
|
||||
if(d_end)
|
||||
if (d_end)
|
||||
return;
|
||||
d_prefix.clear();
|
||||
|
||||
if(d_cursor.get(d_key, d_id, MDB_GET_CURRENT)) {
|
||||
if (d_cursor.get(d_key, d_id, MDB_GET_CURRENT)) {
|
||||
d_end = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(d_on_index) {
|
||||
if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
|
||||
if (d_on_index) {
|
||||
if ((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
|
||||
throw LMDBError("Missing id in constructor");
|
||||
serFromString(d_data.get<string_view>(), d_t);
|
||||
}
|
||||
else
|
||||
} else
|
||||
serFromString(d_id.get<string_view>(), d_t);
|
||||
}
|
||||
|
||||
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?
|
||||
d_one_key(false),
|
||||
d_prefix(prefix),
|
||||
d_end(false)
|
||||
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?
|
||||
d_one_key(false)
|
||||
, d_prefix(prefix)
|
||||
, d_end(false)
|
||||
{
|
||||
if(d_end)
|
||||
if (d_end)
|
||||
return;
|
||||
|
||||
if(d_cursor.get(d_key, d_id, MDB_GET_CURRENT)) {
|
||||
if (d_cursor.get(d_key, d_id, MDB_GET_CURRENT)) {
|
||||
d_end = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(d_on_index) {
|
||||
if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
|
||||
if (d_on_index) {
|
||||
if ((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
|
||||
throw LMDBError("Missing id in constructor");
|
||||
serFromString(d_data.get<string_view>(), d_t);
|
||||
}
|
||||
else
|
||||
} else
|
||||
serFromString(d_id.get<string_view>(), d_t);
|
||||
}
|
||||
|
||||
|
||||
std::function<bool(const MDBOutVal&)> filter;
|
||||
std::function<bool(const MDBOutVal &)> filter;
|
||||
void del()
|
||||
{
|
||||
d_cursor.del();
|
||||
}
|
||||
|
||||
bool operator!=(const eiter_t&) const
|
||||
bool operator!=(const eiter_t &) const
|
||||
{
|
||||
return !d_end;
|
||||
}
|
||||
|
||||
bool operator==(const eiter_t&) const
|
||||
bool operator==(const eiter_t &) const
|
||||
{
|
||||
return d_end;
|
||||
}
|
||||
|
||||
const T& operator*()
|
||||
const T &operator*()
|
||||
{
|
||||
return d_t;
|
||||
}
|
||||
|
||||
const T* operator->()
|
||||
const T *operator->()
|
||||
{
|
||||
return &d_t;
|
||||
}
|
||||
|
@ -343,31 +328,27 @@ public:
|
|||
}
|
||||
|
||||
// implements generic ++ or --
|
||||
iter_t& genoperator(MDB_cursor_op dupop, MDB_cursor_op op)
|
||||
iter_t &genoperator(MDB_cursor_op dupop, MDB_cursor_op op)
|
||||
{
|
||||
MDBOutVal data;
|
||||
next:;
|
||||
const auto rc = d_cursor.get(d_key, d_id, d_one_key ? dupop : op);
|
||||
if(rc == MDB_NOTFOUND) {
|
||||
if (rc == MDB_NOTFOUND) {
|
||||
d_end = true;
|
||||
}
|
||||
else if(rc) {
|
||||
} else if (rc) {
|
||||
throw LMDBError("Unable to get in genoperator: ", rc);
|
||||
}
|
||||
else if(!d_prefix.empty() && d_key.get<std::string>().rfind(d_prefix, 0)!=0) {
|
||||
} else if (!d_prefix.empty() && d_key.get<std::string>().rfind(d_prefix, 0) != 0) {
|
||||
d_end = true;
|
||||
}
|
||||
else {
|
||||
if(d_on_index) {
|
||||
if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, data))
|
||||
} else {
|
||||
if (d_on_index) {
|
||||
if ((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, data))
|
||||
throw LMDBError("Missing id field in genoperator");
|
||||
if(filter && !filter(data))
|
||||
if (filter && !filter(data))
|
||||
goto next;
|
||||
|
||||
serFromString(data.get<string_view>(), d_t);
|
||||
}
|
||||
else {
|
||||
if(filter && !filter(data))
|
||||
} else {
|
||||
if (filter && !filter(data))
|
||||
goto next;
|
||||
|
||||
serFromString(d_id.get<string_view>(), d_t);
|
||||
|
@ -376,11 +357,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
iter_t& operator++()
|
||||
iter_t &operator++()
|
||||
{
|
||||
return genoperator(MDB_NEXT_DUP, MDB_NEXT);
|
||||
}
|
||||
iter_t& operator--()
|
||||
iter_t &operator--()
|
||||
{
|
||||
return genoperator(MDB_PREV_DUP, MDB_PREV);
|
||||
}
|
||||
|
@ -388,54 +369,50 @@ public:
|
|||
// get ID this iterator points to
|
||||
uint32_t getID()
|
||||
{
|
||||
if(d_on_index)
|
||||
if (d_on_index)
|
||||
return d_id.get<uint32_t>();
|
||||
else
|
||||
return d_key.get<uint32_t>();
|
||||
}
|
||||
|
||||
const MDBOutVal& getKey()
|
||||
const MDBOutVal &getKey()
|
||||
{
|
||||
return d_key;
|
||||
}
|
||||
|
||||
|
||||
// transaction we are part of
|
||||
Parent* d_parent;
|
||||
Parent *d_parent;
|
||||
typename Parent::cursor_t d_cursor;
|
||||
|
||||
// gcc complains if I don't zero-init these, which is worrying XXX
|
||||
MDBOutVal d_key{{0,0}}, d_data{{0,0}}, d_id{{0,0}};
|
||||
MDBOutVal d_key{ { 0, 0 } }, d_data{ { 0, 0 } }, d_id{ { 0, 0 } };
|
||||
bool d_on_index;
|
||||
bool d_one_key;
|
||||
std::string d_prefix;
|
||||
bool d_end{false};
|
||||
bool d_end{ false };
|
||||
T d_t;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
iter_t genbegin(MDB_cursor_op op)
|
||||
template <int N> iter_t genbegin(MDB_cursor_op op)
|
||||
{
|
||||
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
|
||||
|
||||
MDBOutVal out, id;
|
||||
|
||||
if(cursor.get(out, id, op)) {
|
||||
if (cursor.get(out, id, op)) {
|
||||
// on_index, one_key, end
|
||||
return iter_t{&d_parent, std::move(cursor), true, false, true};
|
||||
return iter_t{ &d_parent, std::move(cursor), true, false, true };
|
||||
}
|
||||
|
||||
return iter_t{&d_parent, std::move(cursor), true, false};
|
||||
return iter_t{ &d_parent, std::move(cursor), true, false };
|
||||
};
|
||||
|
||||
template<int N>
|
||||
iter_t begin()
|
||||
template <int N> iter_t begin()
|
||||
{
|
||||
return genbegin<N>(MDB_FIRST);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
iter_t rbegin()
|
||||
template <int N> iter_t rbegin()
|
||||
{
|
||||
return genbegin<N>(MDB_LAST);
|
||||
}
|
||||
|
@ -446,12 +423,12 @@ public:
|
|||
|
||||
MDBOutVal out, id;
|
||||
|
||||
if(cursor.get(out, id, MDB_FIRST)) {
|
||||
if (cursor.get(out, id, MDB_FIRST)) {
|
||||
// on_index, one_key, end
|
||||
return iter_t{&d_parent, std::move(cursor), false, false, true};
|
||||
return iter_t{ &d_parent, std::move(cursor), false, false, true };
|
||||
}
|
||||
|
||||
return iter_t{&d_parent, std::move(cursor), false, false};
|
||||
return iter_t{ &d_parent, std::move(cursor), false, false };
|
||||
};
|
||||
|
||||
eiter_t end()
|
||||
|
@ -460,8 +437,7 @@ public:
|
|||
}
|
||||
|
||||
// basis for find, lower_bound
|
||||
template<std::size_t N>
|
||||
iter_t genfind(const typename std::tuple_element<N, tuple_t>::type::type& key, MDB_cursor_op op)
|
||||
template <std::size_t N> iter_t genfind(const typename std::tuple_element<N, tuple_t>::type::type &key, MDB_cursor_op op)
|
||||
{
|
||||
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
|
||||
|
||||
|
@ -470,83 +446,83 @@ public:
|
|||
MDBOutVal out, id;
|
||||
out.d_mdbval = in.d_mdbval;
|
||||
|
||||
if(cursor.get(out, id, op)) {
|
||||
if (cursor.get(out, id, op)) {
|
||||
// on_index, one_key, end
|
||||
return iter_t{&d_parent, std::move(cursor), true, false, true};
|
||||
return iter_t{ &d_parent, std::move(cursor), true, false, true };
|
||||
}
|
||||
|
||||
return iter_t{&d_parent, std::move(cursor), true, false};
|
||||
return iter_t{ &d_parent, std::move(cursor), true, false };
|
||||
};
|
||||
|
||||
template<std::size_t N>
|
||||
iter_t find(const typename std::tuple_element<N, tuple_t>::type::type& key)
|
||||
template <std::size_t N> iter_t find(const typename std::tuple_element<N, tuple_t>::type::type &key)
|
||||
{
|
||||
return genfind<N>(key, MDB_SET);
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
iter_t lower_bound(const typename std::tuple_element<N, tuple_t>::type::type& key)
|
||||
template <std::size_t N> iter_t lower_bound(const typename std::tuple_element<N, tuple_t>::type::type &key)
|
||||
{
|
||||
return genfind<N>(key, MDB_SET_RANGE);
|
||||
}
|
||||
|
||||
|
||||
//! equal range - could possibly be expressed through genfind
|
||||
template<std::size_t N>
|
||||
std::pair<iter_t,eiter_t> equal_range(const typename std::tuple_element<N, tuple_t>::type::type& key)
|
||||
template <std::size_t N> std::pair<iter_t, eiter_t> equal_range(const typename std::tuple_element<N, tuple_t>::type::type &key)
|
||||
{
|
||||
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
|
||||
|
||||
const auto keyString=keyConv(key);
|
||||
const auto keyString = keyConv(key);
|
||||
MDBInVal in(keyString);
|
||||
MDBOutVal out, id;
|
||||
out.d_mdbval = in.d_mdbval;
|
||||
|
||||
if(cursor.get(out, id, MDB_SET)) {
|
||||
if (cursor.get(out, id, MDB_SET)) {
|
||||
// on_index, one_key, end
|
||||
return {iter_t{&d_parent, std::move(cursor), true, true, true}, eiter_t()};
|
||||
return { iter_t{ &d_parent, std::move(cursor), true, true, true }, eiter_t() };
|
||||
}
|
||||
|
||||
return {iter_t{&d_parent, std::move(cursor), true, true}, eiter_t()};
|
||||
return { iter_t{ &d_parent, std::move(cursor), true, true }, eiter_t() };
|
||||
};
|
||||
|
||||
//! equal range - could possibly be expressed through genfind
|
||||
template<std::size_t N>
|
||||
std::pair<iter_t,eiter_t> prefix_range(const typename std::tuple_element<N, tuple_t>::type::type& key)
|
||||
template <std::size_t N> std::pair<iter_t, eiter_t> prefix_range(const typename std::tuple_element<N, tuple_t>::type::type &key)
|
||||
{
|
||||
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
|
||||
|
||||
const auto keyString=keyConv(key);
|
||||
const auto keyString = keyConv(key);
|
||||
MDBInVal in(keyString);
|
||||
MDBOutVal out, id;
|
||||
out.d_mdbval = in.d_mdbval;
|
||||
|
||||
if(cursor.get(out, id, MDB_SET_RANGE)) {
|
||||
if (cursor.get(out, id, MDB_SET_RANGE)) {
|
||||
// on_index, one_key, end
|
||||
return {iter_t{&d_parent, std::move(cursor), true, true, true}, eiter_t()};
|
||||
return { iter_t{ &d_parent, std::move(cursor), true, true, true }, eiter_t() };
|
||||
}
|
||||
|
||||
return {iter_t(&d_parent, std::move(cursor), keyString), eiter_t()};
|
||||
return { iter_t(&d_parent, std::move(cursor), keyString), eiter_t() };
|
||||
};
|
||||
|
||||
|
||||
Parent& d_parent;
|
||||
Parent &d_parent;
|
||||
};
|
||||
|
||||
class LMDB_SAFE_EXPORT 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()))
|
||||
explicit ROTransaction(TypedDBI *parent)
|
||||
: ReadonlyOperations<ROTransaction>(*this)
|
||||
, d_parent(parent)
|
||||
, d_txn(std::make_shared<MDBROTransaction>(d_parent->d_env->getROTransaction()))
|
||||
{
|
||||
}
|
||||
|
||||
explicit ROTransaction(TypedDBI* parent, std::shared_ptr<MDBROTransaction> txn) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(txn)
|
||||
explicit ROTransaction(TypedDBI *parent, std::shared_ptr<MDBROTransaction> txn)
|
||||
: ReadonlyOperations<ROTransaction>(*this)
|
||||
, d_parent(parent)
|
||||
, d_txn(txn)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ROTransaction(ROTransaction&& rhs) :
|
||||
ReadonlyOperations<ROTransaction>(*this), d_parent(rhs.d_parent),d_txn(std::move(rhs.d_txn))
|
||||
ROTransaction(ROTransaction &&rhs)
|
||||
: ReadonlyOperations<ROTransaction>(*this)
|
||||
, d_parent(rhs.d_parent)
|
||||
, d_txn(std::move(rhs.d_txn))
|
||||
|
||||
{
|
||||
rhs.d_parent = 0;
|
||||
|
@ -559,36 +535,39 @@ public:
|
|||
|
||||
typedef MDBROCursor cursor_t;
|
||||
|
||||
TypedDBI* d_parent;
|
||||
TypedDBI *d_parent;
|
||||
std::shared_ptr<MDBROTransaction> d_txn;
|
||||
};
|
||||
|
||||
|
||||
class LMDB_SAFE_EXPORT RWTransaction : public ReadonlyOperations<RWTransaction>
|
||||
{
|
||||
class LMDB_SAFE_EXPORT RWTransaction : public ReadonlyOperations<RWTransaction> {
|
||||
public:
|
||||
explicit RWTransaction(TypedDBI* parent) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent)
|
||||
explicit RWTransaction(TypedDBI *parent)
|
||||
: ReadonlyOperations<RWTransaction>(*this)
|
||||
, d_parent(parent)
|
||||
{
|
||||
d_txn = std::make_shared<MDBRWTransaction>(d_parent->d_env->getRWTransaction());
|
||||
}
|
||||
|
||||
explicit RWTransaction(TypedDBI* parent, std::shared_ptr<MDBRWTransaction> txn) : ReadonlyOperations<RWTransaction>(*this), d_parent(parent), d_txn(txn)
|
||||
explicit RWTransaction(TypedDBI *parent, std::shared_ptr<MDBRWTransaction> txn)
|
||||
: ReadonlyOperations<RWTransaction>(*this)
|
||||
, d_parent(parent)
|
||||
, d_txn(txn)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RWTransaction(RWTransaction&& rhs) :
|
||||
ReadonlyOperations<RWTransaction>(*this),
|
||||
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
|
||||
RWTransaction(RWTransaction &&rhs)
|
||||
: ReadonlyOperations<RWTransaction>(*this)
|
||||
, d_parent(rhs.d_parent)
|
||||
, d_txn(std::move(rhs.d_txn))
|
||||
{
|
||||
rhs.d_parent = 0;
|
||||
}
|
||||
|
||||
// insert something, with possibly a specific id
|
||||
uint32_t put(const T& t, uint32_t id=0)
|
||||
uint32_t put(const T &t, uint32_t id = 0)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
if(!id) {
|
||||
if (!id) {
|
||||
id = MDBGetMaxID(*d_txn, d_parent->d_main) + 1;
|
||||
flags = MDB_APPEND;
|
||||
}
|
||||
|
@ -605,10 +584,10 @@ public:
|
|||
}
|
||||
|
||||
// modify an item 'in place', plus update indexes
|
||||
void modify(uint32_t id, std::function<void(T&)> func)
|
||||
void modify(uint32_t id, std::function<void(T &)> func)
|
||||
{
|
||||
T t;
|
||||
if(!this->get(id, t))
|
||||
if (!this->get(id, t))
|
||||
throw LMDBError("Could not modify id " + std::to_string(id));
|
||||
func(t);
|
||||
|
||||
|
@ -620,7 +599,7 @@ public:
|
|||
void del(uint32_t id)
|
||||
{
|
||||
T t;
|
||||
if(!this->get(id, t))
|
||||
if (!this->get(id, t))
|
||||
return;
|
||||
|
||||
(*d_txn)->del(d_parent->d_main, id);
|
||||
|
@ -660,10 +639,9 @@ public:
|
|||
return d_txn;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// clear this ID from all indexes
|
||||
void clearIndex(uint32_t id, const T& t)
|
||||
void clearIndex(uint32_t id, const T &t)
|
||||
{
|
||||
#define clearMacro(N) std::get<N>(d_parent->d_tuple).del(*d_txn, t, id);
|
||||
clearMacro(0);
|
||||
|
@ -674,7 +652,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
TypedDBI* d_parent;
|
||||
TypedDBI *d_parent;
|
||||
std::shared_ptr<MDBRWTransaction> d_txn;
|
||||
};
|
||||
|
||||
|
@ -713,4 +691,4 @@ private:
|
|||
std::string d_name;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace LMDBSafe
|
||||
|
|
Loading…
Reference in New Issue