Improve comments

This commit is contained in:
Martchus 2022-02-21 23:46:32 +01:00
parent 6c21fe7cb1
commit bf6dbf0e42
2 changed files with 115 additions and 47 deletions

View File

@ -40,6 +40,9 @@ using string_view = boost::string_ref;
#endif
#endif
/*!
* \brief The LMDBError class is thrown when an error happens.
*/
class LMDB_SAFE_EXPORT LMDBError : public std::runtime_error {
public:
explicit LMDBError(const std::string &error) noexcept
@ -79,19 +82,24 @@ public:
class MDBRWTransactionImpl;
class MDBROTransactionImpl;
using MDBROTransaction = std::unique_ptr<MDBROTransactionImpl>;
using MDBRWTransaction = std::unique_ptr<MDBRWTransactionImpl>;
/*!
* \brief The MDBEnv class is a handle to an MDB environment.
*/
class LMDB_SAFE_EXPORT MDBEnv {
public:
MDBEnv(const char *fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 10);
/*!
* \brief Closes the MDB environment.
* \remarks Only a single thread may call this function. All transactions, databases, and cursors must already be closed
* before calling this function.
*/
~MDBEnv()
{
// Only a single thread may call this function. All transactions, databases, and cursors must already be closed before calling this function
mdb_env_close(d_env);
// but, elsewhere, docs say database handles do not need to be closed?
}
MDBDbi openDB(const string_view dbname, unsigned int flags);
@ -119,8 +127,14 @@ private:
std::map<std::thread::id, int> d_ROtransactionsOut;
};
/*!
* \brief Opens an MDB environment for the specified database file.
*/
LMDB_SAFE_EXPORT std::shared_ptr<MDBEnv> getMDBEnv(const char *fname, unsigned int flags, mdb_mode_t mode, MDB_dbi maxDBs = 128);
/*!
* \brief The MDBOutVal struct is the handle to an MDB value used as output.
*/
struct LMDB_SAFE_EXPORT MDBOutVal {
operator MDB_val &()
{
@ -170,6 +184,9 @@ template <> inline string_view MDBOutVal::get<string_view>() const
return string_view(static_cast<char *>(d_mdbval.mv_data), d_mdbval.mv_size);
}
/*!
* \brief The MDBInVal struct is the handle to an MDB value used as input.
*/
class LMDB_SAFE_EXPORT MDBInVal {
public:
MDBInVal(const MDBOutVal &rhs)
@ -226,6 +243,9 @@ private:
class MDBROCursor;
/*!
* \brief The MDBROTransactionImpl class wraps read operations.
*/
class LMDB_SAFE_EXPORT MDBROTransactionImpl {
protected:
MDBROTransactionImpl(MDBEnv *parent, MDB_txn *txn);
@ -465,6 +485,9 @@ public:
}
};
/*!
* \brief The MDBROCursor class represents a read-only cursor.
*/
class LMDB_SAFE_EXPORT MDBROCursor : public MDBGenCursor<MDBROTransactionImpl, MDBROCursor> {
public:
MDBROCursor() = default;
@ -478,6 +501,9 @@ public:
class MDBRWCursor;
/*!
* \brief The MDBRWTransactionImpl class wraps write operations.
*/
class LMDB_SAFE_EXPORT MDBRWTransactionImpl : public MDBROTransactionImpl {
protected:
MDBRWTransactionImpl(MDBEnv *parent, MDB_txn *txn);

View File

@ -8,32 +8,37 @@
namespace LMDBSafe {
/*
Open issues:
Perhaps use the separate index concept from multi_index
perhaps get eiter to be of same type so for(auto& a : x) works
make it more value "like" with unique_ptr
*/
/*!
* \brief The type used to store IDs. "0" indicates "no such ID".
*/
using IDType = std::uint32_t;
/** Return the highest ID used in a database. Returns 0 for an empty DB.
This makes us start everything at ID=1, which might make it possible to
treat id 0 as special
*/
/*!
* \brief Returns the highest ID used in a database. Returns 0 for an empty DB.
* \remarks
* This makes us start everything at ID "1", which might make it possible to
* treat id 0 as special.
*/
LMDB_SAFE_EXPORT IDType 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.
*/
/*!
* \brief Converts \a t to an std::string.
*
* This is the serialization interface. You need to define this function for the
* types you'd like to store.
*/
template <typename T> std::string serToString(const T &t);
/*!
* \brief Initializes \a ret from \a str.
*
* This is the deserialization interface. You need to define this function for the
* types you'd like to store.
*/
template <typename T> void serFromString(string_view str, T &ret);
// define some "shortcuts" (to avoid full-blown serialization stuff for trivial cases)
/// \cond
/// Define some "shortcuts" (to avoid full-blown serialization stuff for trivial cases):
template <> inline std::string serToString(const std::string_view &t)
{
return std::string(t);
@ -107,9 +112,14 @@ template <> inline void serFromString<>(string_view str, std::uint64_t &ret)
ret = CppUtilities::LE::toUInt64(str.data());
}
/** This is the serialization interface for keys.
You need to define your these functions for the types you'd like to use as keys.
*/
/// \endcond
/*!
* \brief Converts \a t to an std::string.
*
* This is the serialization interface for keys. You need to define your this function
* 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, typename std::enable_if<std::is_arithmetic<T>::value, T>::type * = nullptr> inline string_view keyConv(const T &t)
@ -117,6 +127,8 @@ template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::typ
return string_view(reinterpret_cast<const char *>(&t), sizeof(t));
}
/// \cond
/// Define keyConv for trivial cases:
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;
@ -126,6 +138,7 @@ template <class T, typename std::enable_if<std::is_same<T, string_view>::value,
{
return t;
}
/// \endcond
/*!
* \brief The LMDBIndexOps struct implements index operations, but only the operations that
@ -135,7 +148,7 @@ template <class T, typename std::enable_if<std::is_same<T, string_view>::value,
* only includes calls that should be ignored for empty indexes.
*
* This class only needs methods that must happen for all indexes at once. So specifically, *not*
* size<t> or get<t>. People ask for those themselves, and should no do that on indexes that
* size<t> or get<t>. People ask for those themselves, and should not do that on indexes that
* don't exist.
*/
template <class Class, typename Type, typename Parent> struct LMDB_SAFE_EXPORT LMDBIndexOps {
@ -170,8 +183,9 @@ template <class Class, typename Type, typename Parent> struct LMDB_SAFE_EXPORT L
Parent *d_parent;
};
/** This is an index on a field in a struct, it derives from the LMDBIndexOps */
/*!
* \brief The index_on struct is used to declare an index on a member variable of a particular type.
*/
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)
@ -185,7 +199,10 @@ template <class Class, typename Type, Type Class::*PtrToMember> struct index_on
typedef Type type;
};
/** This is a calculated index */
/*!
* \brief The index_on_function struct is used to declare an index which is dynamically computed via
* a function.
*/
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)
@ -204,6 +221,11 @@ template <class Class, typename Type, class Func> struct index_on_function : LMD
* \brief The TypedDBI class is the main class.
* \tparam T Specifies the type to store within the database.
* \tparam I Specifies an index, should be an instantiation of index_on.
*
* Open issues:
* - Perhaps use the separate index concept from multi_index.
* - Perhaps get eiter to be of same type so for(auto& a : x) works
* make it more value "like" with unique_ptr.
*/
template <typename T, typename... I> class LMDB_SAFE_EXPORT TypedDBI {
public:
@ -214,6 +236,7 @@ public:
private:
tuple_t d_tuple;
/// \cond
template <class Tuple, std::size_t N> struct IndexIterator {
static inline void apply(Tuple &tuple, auto &&func)
{
@ -238,6 +261,7 @@ private:
{
IndexIterator<tuple_t, std::tuple_size_v<tuple_t>>::apply(d_tuple, std::forward<decltype(func)>(func));
}
/// \endcond
public:
TypedDBI(std::shared_ptr<MDBEnv> env, string_view name)
@ -249,8 +273,9 @@ public:
forEachIndex([&](auto &&i) { i.openDB(d_env, CppUtilities::argsToString(name, '_', index++), MDB_CREATE | MDB_DUPFIXED | MDB_DUPSORT); });
}
// We support readonly and rw transactions. Here we put the Readonly operations
// which get sourced by both kinds of transactions
/*!
* \brief The ReadonlyOperations struct defines read-only operations.
*/
template <class Parent> struct ReadonlyOperations {
ReadonlyOperations(Parent &parent)
: d_parent(parent)
@ -309,7 +334,9 @@ public:
return count;
}
//! End iderator type
/*!
* \brief The eiter_t struct is the end iterator.
*/
struct eiter_t {
};
@ -317,11 +344,18 @@ public:
template <typename> struct DirectStorage {
};
// 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!
/*!
* \brief The iter_t struct is the iterator type for walking through the database rows.
* \remarks
* - The iterator can be on the main database or on an index. It returns the data directly on
* the main database and indirectly when on an index.
* - An iterator can be limited to one key or iterate over the entire database.
* - The iter_t struct requires you to put the cursor in the right place first.
* - The object can be stored as direct member of iter_t or as std::unique_ptr or std::shared_ptr
* by specifying the corresponding template as \tp ElementType. The pointer can then be accessed
* via getPointer(). Note that the returned pointer object is re-used when the iterator is incremented
* or decremented unless the owned object is moved into another pointer object.
*/
template <template <typename> class StorageType, typename ElementType = T> struct iter_t {
using UsingDirectStorage = CppUtilities::Traits::IsSpecializationOf<StorageType<ElementType>, DirectStorage>;
@ -345,7 +379,7 @@ public:
: d_parent(parent)
, d_cursor(std::move(cursor))
, d_prefix(prefix)
, d_on_index(true) // is this an iterator on main database or on index?
, d_on_index(true)
, d_one_key(false)
, d_end(false)
, d_deserialized(false)
@ -356,7 +390,6 @@ public:
throw LMDBError("Missing id in constructor");
}
std::function<bool(const MDBOutVal &)> filter;
void del()
{
d_cursor.del();
@ -433,7 +466,7 @@ public:
return &value();
}
// implements generic ++ or --
//! Implements generic ++ or --.
iter_t &genoperator(MDB_cursor_op dupop, MDB_cursor_op op)
{
d_deserialized = false;
@ -463,7 +496,7 @@ public:
return genoperator(MDB_PREV_DUP, MDB_PREV);
}
// get ID this iterator points to
//! Returns the ID this iterator points to.
IDType getID()
{
return d_on_index ? d_id.get<IDType>() : d_key.get<IDType>();
@ -474,14 +507,17 @@ public:
return d_key;
}
//! A filter to allow skipping rows by their raw value.
std::function<bool(const MDBOutVal &)> filter;
private:
// transaction we are part of
//! The transaction the iterator is part of.
Parent *d_parent;
typename Parent::cursor_t d_cursor;
// gcc complains if I don't zero-init these, which is worrying XXX
std::string d_prefix;
MDBOutVal d_key{ { 0, 0 } }, d_data{ { 0, 0 } }, d_id{ { 0, 0 } };
//! Whether it is an iterator on the main database or an index.
bool d_on_index;
bool d_one_key;
bool d_end;
@ -575,7 +611,7 @@ public:
return genfind<N, StorageType>(key, MDB_SET_RANGE);
}
//! equal range - could possibly be expressed through genfind
//! Returns the range matching the specified \a key.
template <std::size_t N, template <typename> class StorageType = DirectStorage>
std::pair<iter_t<StorageType>, eiter_t> equal_range(const index_t<N> &key)
{
@ -594,7 +630,7 @@ public:
return { iter_t<StorageType>{ &d_parent, std::move(cursor), true, true }, eiter_t() };
};
//! equal range - could possibly be expressed through genfind
//! Returns the range where the key starts with the specified \a key.
template <std::size_t N, template <typename> class StorageType = DirectStorage>
std::pair<iter_t<StorageType>, eiter_t> prefix_range(const index_t<N> &key)
{
@ -616,6 +652,9 @@ public:
Parent &d_parent;
};
/*!
* \brief The ROTransaction class represents a read-only transaction.
*/
class LMDB_SAFE_EXPORT ROTransaction : public ReadonlyOperations<ROTransaction> {
public:
explicit ROTransaction()
@ -677,6 +716,9 @@ public:
std::shared_ptr<MDBROTransaction> d_txn;
};
/*!
* \brief The RWTransaction class represents a read-write transaction.
*/
class LMDB_SAFE_EXPORT RWTransaction : public ReadonlyOperations<RWTransaction> {
public:
explicit RWTransaction()
@ -721,7 +763,7 @@ public:
return d_txn != nullptr;
}
// insert something, with possibly a specific id
//! Inserts something, with possibly a specific id.
IDType put(const T &t, IDType id = 0)
{
unsigned int flags = 0;
@ -734,7 +776,7 @@ public:
return id;
}
// modify an item 'in place', plus update indexes
//! Modifies an item "in place" updating indexes.
void modify(IDType id, std::function<void(T &)> func)
{
T t;
@ -746,7 +788,7 @@ public:
put(t, id);
}
//! delete an item, and from indexes
//! Deletes an item from the main database and from indexes.
void del(IDType id)
{
T t;
@ -757,7 +799,7 @@ public:
clearIndex(id, t);
}
//! clear database & indexes
//! Clears the database and indexes.
void clear()
{
if (const auto rc = mdb_drop(**d_txn, d_parent->d_main, 0)) {
@ -766,13 +808,13 @@ public:
d_parent->forEachIndex([&](auto &&i) { i.clear(*d_txn); });
}
//! commit this transaction
//! Commits this transaction.
void commit()
{
(*d_txn)->commit();
}
//! abort this transaction
//! Aborts this transaction.
void abort()
{
(*d_txn)->abort();