This commit is contained in:
Blue 2023-04-12 12:36:33 -03:00
parent 66df0da5f6
commit 2b4763b575
Signed by: blue
GPG Key ID: 9B203B252A63EE38
9 changed files with 141 additions and 49 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(LMDBAL project(LMDBAL
VERSION 0.2.0 VERSION 0.3.0
DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer"
LANGUAGES CXX LANGUAGES CXX
) )

View File

@ -3,7 +3,7 @@
[![AUR license](https://img.shields.io/aur/license/lmdbal?style=flat-square)](https://git.macaw.me/blue/lmdbal/raw/branch/master/LICENSE.md) [![AUR license](https://img.shields.io/aur/license/lmdbal?style=flat-square)](https://git.macaw.me/blue/lmdbal/raw/branch/master/LICENSE.md)
[![AUR version](https://img.shields.io/aur/version/lmdbal?style=flat-square)](https://aur.archlinux.org/packages/lmdbal/) [![AUR version](https://img.shields.io/aur/version/lmdbal?style=flat-square)](https://aur.archlinux.org/packages/lmdbal/)
[![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me)
[![Documentation](https://img.shields.io/badge/Documentation-HTLM-green)](https://macaw.me/lmdbal/doc/html) [![Documentation](https://img.shields.io/badge/Documentation-HTML-green)](https://macaw.me/lmdbal/doc/html)
### Prerequisites ### Prerequisites

View File

@ -1,6 +1,6 @@
# Maintainer: Yury Gubich <blue@macaw.me> # Maintainer: Yury Gubich <blue@macaw.me>
pkgname=lmdbal pkgname=lmdbal
pkgver=0.2.0 pkgver=0.3.0
pkgrel=1 pkgrel=1
pkgdesc="LMDB Abstraction Layer, qt5 version" pkgdesc="LMDB Abstraction Layer, qt5 version"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
@ -19,5 +19,5 @@ build() {
} }
package() { package() {
cd "$srcdir/$pkgname" cd "$srcdir/$pkgname"
DESTDIR="$pkgdir/" cmake --install . cmake --install . --prefix $pkgdir/
} }

View File

@ -34,7 +34,7 @@
* \brief Creates the database * \brief Creates the database
* *
* \param[in] _name - name of the database, it is going to affect folder name that is created to store data * \param[in] _name - name of the database, it is going to affect folder name that is created to store data
* \param[in] _mapSize - LMDB map size (MBi), multiplied by 1024^2 and passed to <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5">mdb_env_set_mapsize</a> during the call of LMDBAL::Base::open() * \param[in] _mapSize - LMDB map size (MiB), multiplied by 1024^2 and passed to <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5">mdb_env_set_mapsize</a> during the call of LMDBAL::Base::open()
*/ */
LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize): LMDBAL::Base::Base(const QString& _name, uint16_t _mapSize):
name(_name.toStdString()), name(_name.toStdString()),

View File

@ -46,7 +46,7 @@ class Storage;
template <class K, class V> template <class K, class V>
class Cache; class Cache;
typedef MDB_txn* TransactionID; typedef MDB_txn* TransactionID; /**<I'm going to use transaction pointers as transaction IDs*/
class Base { class Base {
friend class iStorage; friend class iStorage;
@ -81,8 +81,8 @@ public:
LMDBAL::Cache<K, V>* getCache(const std::string& name); LMDBAL::Cache<K, V>* getCache(const std::string& name);
private: private:
typedef std::map<std::string, LMDBAL::iStorage*> Storages; typedef std::map<std::string, LMDBAL::iStorage*> Storages; /**<Storage and Cache pointers are saved in the std::map*/
typedef std::set<TransactionID> Transactions; typedef std::set<TransactionID> Transactions; /**<Piblic transaction IDs are saved in the std::set*/
TransactionID beginReadOnlyTransaction(const std::string& storageName) const; TransactionID beginReadOnlyTransaction(const std::string& storageName) const;
TransactionID beginTransaction(const std::string& storageName) const; TransactionID beginTransaction(const std::string& storageName) const;
@ -95,14 +95,14 @@ private:
void abortPrivateTransaction(TransactionID id, const std::string& storageName) const; void abortPrivateTransaction(TransactionID id, const std::string& storageName) const;
private: private:
std::string name; std::string name; /**<\brief Name of this database*/
bool opened; bool opened; /**<\brief State of this database*/
uint16_t size; uint16_t size; /**<\brief lmdb map size in MiB*/
MDB_env* environment; MDB_env* environment; /**<\brief lmdb environment handle*/
Storages storages; Storages storages; /**<\brief Registered storages and caches*/
Transactions* transactions; Transactions* transactions; /**<\brief Active public transactions*/
inline static const std::string emptyName = ""; inline static const std::string emptyName = ""; /**<\brief Empty string for general fallback purposes*/
}; };
} }

View File

@ -30,13 +30,13 @@ namespace LMDBAL {
template <class K, class V> template <class K, class V>
class Cache : public Storage<K, V> { class Cache : public Storage<K, V> {
friend class Base; friend class Base;
enum class Mode { //it's a cache state when we: enum class Mode { /**<it's a cache state when we:*/
nothing, // - know nothing about records in database on disk nothing, /**< - know nothing about records in database on disk*/
size, // - know just an amount of records size, /**< - know just an amount of records*/
full // - shure that our cache is equal to the database on disk full /**< - shure that our cache is equal to the database on disk*/
}; };
enum class Operation { enum class Operation { /**<Operation type, used in pcrocessing cache modification after writable transaction is commited*/
add, add,
remove, remove,
change, change,
@ -101,11 +101,20 @@ public:
virtual SizeType addRecords(const std::map<K, V>& data, TransactionID txn, bool overwrite = false) override; virtual SizeType addRecords(const std::map<K, V>& data, TransactionID txn, bool overwrite = false) override;
protected: protected:
/**
* \brief Cache mode
*
* Sometimes we have a complete information about the content of the database,
* and we don't even need to refer to lmdb to fetch or check for data.
* This member actually shows what is the current state, more about them you can read in Enum descriptions
*
* It's done with pointer to comply some of the const method limitations which would modify this state eventually
*/
Mode* mode; Mode* mode;
std::map<K, V>* cache; std::map<K, V>* cache; /**<\brief Cached data*/
std::set<K>* abscent; std::set<K>* abscent; /**<\brief Set of keys that are definitely not in the cache*/
SizeType* sizeDifference; SizeType* sizeDifference; /**<\brief Difference of size between cached data and amount of records in the lmdb storage*/
TransactionCache* transactionCache; TransactionCache* transactionCache; /**<\brief All changes made under under uncommited transactions*/
}; };
} }

View File

@ -22,9 +22,29 @@
#include "cache.h" #include "cache.h"
#include "exceptions.h" #include "exceptions.h"
/**
* \class LMDBAL::Cache
* \brief Storage with additional caching in std::map
*
* \tparam K type of the keys of the cache
* \tparam V type of the values of the cache
*
* You can receive an instance of this class calling LMDBAL::Base::addCache(const std::string&)
* if the database is yet closed and you're defining the storages you're going to need.
* Or you can call LMDBAL::Base::getCache(const std::string&) if you didn't save a pointer to the cache at first
*
* You are not supposed to instantiate or destory instances of this class yourself!
*/
/**
* \brief Creates a cache
*
* \param[in] _name - name of the new cache
* \param[in] parent - parent database pointed (borrowed)
*/
template<class K, class V> template<class K, class V>
LMDBAL::Cache<K, V>::Cache(const std::string& p_name, Base* parent): LMDBAL::Cache<K, V>::Cache(const std::string& _name, Base* parent):
Storage<K, V>(p_name, parent), Storage<K, V>(_name, parent),
mode(new Mode), mode(new Mode),
cache(new std::map<K, V>()), cache(new std::map<K, V>()),
abscent(new std::set<K>()), abscent(new std::set<K>()),
@ -35,6 +55,9 @@ LMDBAL::Cache<K, V>::Cache(const std::string& p_name, Base* parent):
*sizeDifference = 0; *sizeDifference = 0;
} }
/**
* \brief Destroys a cache
*/
template<class K, class V> template<class K, class V>
LMDBAL::Cache<K, V>::~Cache() { LMDBAL::Cache<K, V>::~Cache() {
delete transactionCache; delete transactionCache;

View File

@ -64,22 +64,22 @@ public:
virtual SizeType count(TransactionID txn) const; virtual SizeType count(TransactionID txn) const;
protected: protected:
MDB_dbi dbi; MDB_dbi dbi; /**<\brief lmdb storage handle*/
Base* db; Base* db; /**<\brief parent database pointer (borrowed)*/
const std::string name; const std::string name; /**<\brief this storage name*/
inline static const std::string dropMethodName = "drop"; inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/
inline static const std::string countMethodName = "count"; inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/
inline static const std::string addRecordMethodName = "addRecord"; inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string forceRecordMethodName = "forceRecord"; inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string changeRecordMethodName = "changeRecord"; inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string removeRecordMethodName = "removeRecord"; inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string checkRecordMethodName = "checkRecord"; inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string getRecordMethodName = "getRecord"; inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string readAllMethodName = "readAllRecord"; inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/
inline static const std::string replaceAllMethodName = "replaceAll"; inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/
inline static const std::string addRecordsMethodName = "addRecords"; inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/
protected: protected:
template <class T> template <class T>
@ -122,8 +122,8 @@ public:
virtual uint32_t addRecords(const std::map<K, V>& data, TransactionID txn, bool overwrite = false); virtual uint32_t addRecords(const std::map<K, V>& data, TransactionID txn, bool overwrite = false);
protected: protected:
Serializer<K>* keySerializer; Serializer<K>* keySerializer; /**<\brief internal object that would serialize and deserialize keys*/
Serializer<V>* valueSerializer; Serializer<V>* valueSerializer; /**<\brief internal object that would serialize and deserialize values*/
int createStorage(MDB_txn* transaction) override; int createStorage(MDB_txn* transaction) override;
}; };

View File

@ -31,18 +31,27 @@
* *
* You can receive an instance of this class calling LMDBAL::Base::addStorage(const std::string&) * You can receive an instance of this class calling LMDBAL::Base::addStorage(const std::string&)
* if the database is yet closed and you're defining the storages you're going to need. * if the database is yet closed and you're defining the storages you're going to need.
* Or you can call LMDBAL::Base::getStorage(const std::string&) if the database is opened and you didn't save a pointer to the storage * Or you can call LMDBAL::Base::getStorage(const std::string&) if you didn't save a pointer to the storage at first
* *
* You are not supposed to instantiate or destory instances of this class yourself! * You are not supposed to instantiate or destory instances of this class yourself!
*/ */
/**
* \brief Creates a storage
*
* \param[in] _name - name of the new storage
* \param[in] parent - parent database pointed (borrowed)
*/
template<class K, class V> template<class K, class V>
LMDBAL::Storage<K, V>::Storage(const std::string& p_name, Base* parent): LMDBAL::Storage<K, V>::Storage(const std::string& _name, Base* parent):
iStorage(p_name, parent), iStorage(_name, parent),
keySerializer(new Serializer<K>()), keySerializer(new Serializer<K>()),
valueSerializer(new Serializer<V>()) valueSerializer(new Serializer<V>())
{} {}
/**
* \brief Destroys a storage
*/
template<class K, class V> template<class K, class V>
LMDBAL::Storage<K, V>::~Storage() { LMDBAL::Storage<K, V>::~Storage() {
delete valueSerializer; delete valueSerializer;
@ -673,57 +682,92 @@ void LMDBAL::Storage<K, V>::removeRecord(const K& key, TransactionID txn) {
} }
/** /**
* \brief A private virtual function I need to open database * \brief A private virtual function I need to open each storage in the database
* *
* This and the following collection of specializations are a way to optimise database using * \param[in] transaction - lmdb transaction to call <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a">mdb_dbi_open</a>
* MDB_INTEGERKEY flag, when the key is actually kind of an integer * \returns MDB_SUCCESS if everything went smooth or MDB_<error> -like error code
* This infrastructure also allowes us to customize mdb_dbi_open call in the future
*/ */
template<class K, class V> template<class K, class V>
int LMDBAL::Storage<K, V>::createStorage(MDB_txn* transaction) { int LMDBAL::Storage<K, V>::createStorage(MDB_txn* transaction) {
return makeStorage<K>(transaction); return makeStorage<K>(transaction);
} }
/**
* \brief A functiion to actually open <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gadbe68a06c448dfb62da16443d251a78b">MDB_dbi</a> storage
*
* \tparam K type of keys in opening storage
*
* \param[in] transaction - lmdb transaction to call <a class="el" href="http://www.lmdb.tech/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a">mdb_dbi_open</a>, must be a writable transaction!
* \returns MDB_SUCCESS if everything went smooth or MDB_<error> -like error code
*
* This and the following collection of specializations are a way to optimise database using
* MDB_INTEGERKEY flag, when the key is actually kind of an integer
* This infrastructure also allowes us to customize mdb_dbi_open call in the future
*/
template<class K> template<class K>
inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi);
} }
/**
* \brief Opening database function specialization for uint64_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<uint64_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<uint64_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for uint32_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<uint32_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<uint32_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for uint16_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<uint16_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<uint16_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for uint8_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<uint8_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<uint8_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for int64_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<int64_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<int64_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for int32_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<int32_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<int32_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for int16_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<int16_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<int16_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
} }
/**
* \brief Opening database function specialization for int8_t
*/
template<> template<>
inline int LMDBAL::iStorage::makeStorage<int8_t>(MDB_txn* transaction) { inline int LMDBAL::iStorage::makeStorage<int8_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
@ -743,11 +787,27 @@ inline std::string LMDBAL::iStorage::toString(const T& value) {
return std::to_string(value); return std::to_string(value);
} }
/**
* \brief A method to cast a value (which can be a value or a key) to string.
*
* QString spectialization
*
* \param[in] value a value that should be converted to string
* \returns a string presentation of value
*/
template<> template<>
inline std::string LMDBAL::iStorage::toString(const QString& value) { inline std::string LMDBAL::iStorage::toString(const QString& value) {
return value.toStdString(); return value.toStdString();
} }
/**
* \brief A method to cast a value (which can be a value or a key) to string.
*
* std::string spectialization
*
* \param[in] value a value that should be converted to string
* \returns a string presentation of value
*/
template<> template<>
inline std::string LMDBAL::iStorage::toString(const std::string& value) { inline std::string LMDBAL::iStorage::toString(const std::string& value) {
return value; return value;