From af0e48a684c1f4d583152f1b229809dd4d1de30e Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 10 Apr 2023 18:01:19 -0300 Subject: [PATCH] Base class documentation, doxugen tweaking, new exception for one case --- CMakeLists.txt | 6 +- README.md | 1 + doc/CMakeLists.txt | 18 +++- doc/custom.css | 3 + doc/header.html | 78 +++++++++++++++++ src/base.cpp | 206 ++++++++++++++++++++++++++++++++++++++++++++- src/base.h | 70 +++++++++++++-- src/exceptions.cpp | 14 +++ src/exceptions.h | 10 +++ src/storage.h | 2 +- src/storage.hpp | 20 ++--- 11 files changed, 408 insertions(+), 20 deletions(-) create mode 100644 doc/custom.css create mode 100644 doc/header.html diff --git a/CMakeLists.txt b/CMakeLists.txt index d56e05d..c60a83e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 3.16) -project(LMDBAL VERSION 0.2.0 LANGUAGES CXX) +project(LMDBAL + VERSION 0.2.0 + DESCRIPTION "LMDB (Lightning Memory-Mapped Database Manager) Abstraction Layer" + LANGUAGES CXX +) string(TOLOWER ${PROJECT_NAME} PROJECT_LOW) cmake_policy(SET CMP0076 NEW) diff --git a/README.md b/README.md index b81524c..fa4de83 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Here is the list of keys you can pass to configuration phase of `cmake ..`: - `BUILD_STATIC` - `True` builds project as a static library, `False` builds as dynamic (default is `False`); - `BUILD_TESTS` - `True` build unit tests, `False` does not (default is `False`); - `BUILD_DOC` - `True` build doxygen documentation, `False` does not (default is `False`); +- `BUILD_DOXYGEN_AWESOME` - `True` build doxygen awesome theme if `BUILD_DOC` is also `True` (default is `False`); - `QT_VERSION_MAJOR` - `5` links against Qt5, `6` links agains Qt6, there is no default, so, if you didn't specify it the project will chose automatically; #### Running tests diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1626a47..24ee33b 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,5 +1,6 @@ set(DOXYGEN_GENERATE_HTML YES) set(DOXYGEN_GENERATE_MAN YES) +set(DOXYGEN_GENERATE_XML YES) if (BUILD_DOXYGEN_AWESOME) include(ExternalProject) @@ -14,9 +15,18 @@ if (BUILD_DOXYGEN_AWESOME) set (DOXYGEN_GENERATE_TREEVIEW YES) set (DOXYGEN_DISABLE_INDEX NO) set (DOXYGEN_FULL_SIDEBAR NO) - set (DOXYGEN_HTML_EXTRA_STYLESHEET ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome.css ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome-sidebar-only.css) + set (DOXYGEN_HTML_EXTRA_STYLESHEET + ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome.css + ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome-sidebar-only.css + ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css + custom.css + ) + set (DOXYGEN_HTML_EXTRA_FILES + ${CMAKE_CURRENT_BINARY_DIR}/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js + ) set (DOXYGEN_FULL_SIDEBAR NO) set (DOXYGEN_HTML_COLORSTYLE "LIGHT") + set (DOXYGEN_HTML_HEADER header.html) endif() doxygen_add_docs( @@ -26,6 +36,12 @@ doxygen_add_docs( ALL COMMENT "Generate man and html pages" ) +install(DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/man + ${CMAKE_CURRENT_BINARY_DIR}/html + ${CMAKE_CURRENT_BINARY_DIR}/xml + TYPE DOC +) if (BUILD_DOXYGEN_AWESOME) add_dependencies(documentation doxygen-awesome-css) diff --git a/doc/custom.css b/doc/custom.css new file mode 100644 index 0000000..160c40a --- /dev/null +++ b/doc/custom.css @@ -0,0 +1,3 @@ +html { + --top-height: 150px; +} diff --git a/doc/header.html b/doc/header.html new file mode 100644 index 0000000..ca26eba --- /dev/null +++ b/doc/header.html @@ -0,0 +1,78 @@ + + + + + + + + +$projectname: $title +$title + + + + + + + + +$treeview +$search +$mathjax +$darkmode + +$extrastylesheet + + + + + + +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
$projectname $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
$searchbox
+
+ + diff --git a/src/base.cpp b/src/base.cpp index 0951bd6..8952652 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -22,6 +22,20 @@ #define UNUSED(x) (void)(x) +/** + * \class LMDBAL::Base + * \brief Database abstraction + * + * This is a basic class that represents the database as a collection of storages. + * Storages is something key-value database has instead of tables in classic SQL databases. + */ + +/** + * \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] mapSize - LMDB map size (MBi), multiplied by 1024^2 and passed to mdb_env_set_mapsize during the call of LMDBAL::Base::open() + */ LMDBAL::Base::Base(const QString& p_name, uint16_t mapSize): name(p_name.toStdString()), opened(false), @@ -31,6 +45,9 @@ LMDBAL::Base::Base(const QString& p_name, uint16_t mapSize): transactions(new Transactions()) {} +/** + * \brief Destroys the database + */ LMDBAL::Base::~Base() { close(); @@ -40,6 +57,14 @@ LMDBAL::Base::~Base() { delete pair.second; } +/** + * \brief Closes the database + * + * Closes all lmdb handles, aborts all public transactions. + * This function will do nothing on closed database + * + * \exception LMDBAL::Unknown - thrown if something went wrong aborting transactions + */ void LMDBAL::Base::close() { if (opened) { for (LMDBAL::TransactionID id : *transactions) @@ -56,7 +81,13 @@ void LMDBAL::Base::close() { } /** - * Almost every LMDBAL::Base require it to be opened, this function opens it. It laso creates the directory for the database if it was an initial launch + * \brief Opens the database + * + * Almost every LMDBAL::Base require it to be opened, this function does it. + * It laso creates the directory for the database if it was an initial launch. + * This function will do nothing on opened database + * + * \exception LMDBAL::Unknown - thrown if something went wrong opening storages and caches */ void LMDBAL::Base::open() { if (!opened) { @@ -79,6 +110,13 @@ void LMDBAL::Base::open() { } } +/** + * \brief Removes database directory + * + * \returns true if removal was successfull of if no directory was created where it's expected to be, false otherwise + * + * \exception LMDBAL::Opened - thrown if this function was called on opened database + */ bool LMDBAL::Base::removeDirectory() { if (opened) throw Opened(name, "remove database directory"); @@ -93,6 +131,20 @@ bool LMDBAL::Base::removeDirectory() { return true; } +/** + * \brief Creates database directory + * + * Creates or opens existing directory with the given name in the location acquired with + * QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + * so, the file system destination of your data would depend on the + * QCoreApplication configuration of your app. + * This function does nothing if the directory was already created + * + * \returns the path of the created directory + * + * \exception LMDBAL::Opened - thrown if called on opened database + * \exception LMDBAL::Directory - if the database couldn't create the folder + */ QString LMDBAL::Base::createDirectory() { if (opened) throw Opened(name, "create database directory"); @@ -110,12 +162,31 @@ QString LMDBAL::Base::createDirectory() { return path; } +/** + * \brief Returns database name + * + * \returns database name + */ QString LMDBAL::Base::getName() const { return QString::fromStdString(name);} + +/** + * \brief Returns database state + * + * \returns true if the database is opened and ready for work, false otherwise + */ bool LMDBAL::Base::ready() const { return opened;} +/** + * \brief Drops the database + * + * Clears all caches and storages of the database + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if something unexpected happend + */ void LMDBAL::Base::drop() { if (!opened) throw Closed("drop", name); @@ -131,18 +202,67 @@ void LMDBAL::Base::drop() { commitTransaction(txn); } +/** + * \brief Begins read-only transaction + * + * \returns read-only transaction ID + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction() const { return beginReadOnlyTransaction(emptyName);} +/** + * \brief Begins writable transaction + * + * \returns writable transaction ID + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginTransaction() const { return beginTransaction(emptyName);} +/** + * \brief Aborts transaction + * + * Terminates transaction cancelling changes. + * This is an optimal way to terminate read-only transactions + * + * \param[in] id - transaction ID you want to abort + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + */ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id) const { return abortTransaction(id, emptyName);} +/** + * \brief Commits transaction + * + * Terminates transaction applying changes. + * + * \param[in] id - transaction ID you want to commit + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + */ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) { return commitTransaction(id, emptyName);} +/** + * \brief Begins read-only transaction + * + * This function is intended to be called from subordinate storage or cache + * + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \returns read-only transaction ID + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& storageName) const { if (!opened) throw Closed("beginReadOnlyTransaction", name, storageName); @@ -155,6 +275,18 @@ LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& return txn; } +/** + * \brief Begins writable transaction + * + * This function is intended to be called from subordinate storage or cache + * + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \returns writable transaction ID + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageName) const { if (!opened) throw Closed("beginTransaction", name, storageName); @@ -167,6 +299,19 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN return txn; } +/** + * \brief Aborts transaction + * + * Terminates transaction cancelling changes. + * This is an optimal way to terminate read-only transactions. + * This function is intended to be called from subordinate storage or cache + * + * \param[in] id - transaction ID you want to abort + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + */ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& storageName) const { if (!opened) throw Closed("abortTransaction", name, storageName); @@ -182,6 +327,18 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string& transactions->erase(itr); } +/** + * \brief Commits transaction + * + * Terminates transaction applying changes. + * This function is intended to be called from subordinate storage or cache + * + * \param[in] id - transaction ID you want to commit + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \exception LMDBAL::Closed - thrown if the database is closed + * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + */ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string& storageName) { if (!opened) throw Closed("abortTransaction", name, storageName); @@ -197,6 +354,18 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string transactions->erase(itr); } +/** + * \brief Begins read-only transaction + * + * This function is intended to be called from subordinate storage or cache, + * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \returns read-only transaction ID + * + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginPrivateReadOnlyTransaction(const std::string& storageName) const { MDB_txn* txn; int rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn); @@ -207,6 +376,18 @@ LMDBAL::TransactionID LMDBAL::Base::beginPrivateReadOnlyTransaction(const std::s return txn; } +/** + * \brief Begins writable transaction + * + * This function is intended to be called from subordinate storage or cache, + * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \returns writable transaction ID + * + * \exception LMDBAL::Unknown - thrown if something unexpected happened + */ LMDBAL::TransactionID LMDBAL::Base::beginPrivateTransaction(const std::string& storageName) const { MDB_txn* txn; int rc = mdb_txn_begin(environment, NULL, 0, &txn); @@ -217,11 +398,34 @@ LMDBAL::TransactionID LMDBAL::Base::beginPrivateTransaction(const std::string& s return txn; } +/** + * \brief Aborts transaction + * + * Terminates transaction cancelling changes. + * This is an optimal way to terminate read-only transactions. + * This function is intended to be called from subordinate storage or cache, + * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * + * \param[in] id - transaction ID you want to abort + * \param[in] storageName - name of the storage/cache that you begin transaction from, unused here + */ void LMDBAL::Base::abortPrivateTransaction(LMDBAL::TransactionID id, const std::string& storageName) const { UNUSED(storageName); mdb_txn_abort(id); } +/** + * \brief Commits transaction + * + * Terminates transaction applying changes. + * This function is intended to be called from subordinate storage or cache + * it's not accounted in transaction collection, other storages and caches are not notified about this kind of transaction + * + * \param[in] id - transaction ID you want to commit + * \param[in] storageName - name of the storage/cache that you begin transaction from, needed just to inform if something went wrong + * + * \exception LMDBAL::Unknown - thrown if transaction with given ID was not found or if something unexpected happened + */ void LMDBAL::Base::commitPrivateTransaction(LMDBAL::TransactionID id, const std::string& storageName) { int rc = mdb_txn_commit(id); if (rc != MDB_SUCCESS) diff --git a/src/base.h b/src/base.h index 349aed4..1168b3b 100644 --- a/src/base.h +++ b/src/base.h @@ -109,7 +109,19 @@ private: #include "operators.hpp" /** - * Adds LMDBAL::Storage with the given name to the LMDBAL::Base, also returns it. The LMDBAL::Base must be closed + * \brief Adds LMDBAL::Storage to the database + * + * Defines that the database is going to have the following storage. + * The LMDBAL::Base must be closed + * + * \param[in] name - storage name + * \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it + * + * \tparam K - key type of the storage + * \tparam V - value type of the storage + * + * \exception LMDBAL::Opened thrown if this method is called on the opened database + * \exception LMDBAL::StorageDuplicate thrown if somebody tries to add storage with repeating name */ template LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& p_name) { @@ -117,12 +129,27 @@ LMDBAL::Storage* LMDBAL::Base::addStorage(const std::string& p_name) { throw Opened(name, "add storage " + p_name); } Storage* storage = new Storage(p_name, this); - storages.insert(std::make_pair(p_name, (iStorage*)storage)); + std::pair pair = storages.insert(std::make_pair(p_name, (iStorage*)storage)); + if (!pair.second) + throw StorageDuplicate(name, p_name); + return storage; } /** - * Adds LMDBAL::Cache with given the name to the LMDBAL::Base, also returns it. The LMDBAL::Base must be closed + * \brief Adds LMDBAL::Cache to the database + * + * Defines that the database is going to have the following cache. + * The LMDBAL::Base must be closed + * + * \param[in] name - cache name + * \returns cache pointer. LMDBAL::Base keeps the ownership of the added cache, you don't need to destoroy it + * + * \tparam K - key type of the cache + * \tparam V - value type of the cahce + * + * \exception LMDBAL::Opened thrown if this method is called on the opened database + * \exception LMDBAL::StorageDuplicate thrown if somebody tries to add cache with repeating name */ template LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& p_name) { @@ -130,12 +157,29 @@ LMDBAL::Cache * LMDBAL::Base::addCache(const std::string& p_name) { throw Opened(name, "add cache " + p_name); } Cache* cache = new Cache(p_name, this); - storages.insert(std::make_pair(p_name, (iStorage*)cache)); + std::pair pair = storages.insert(std::make_pair(p_name, (iStorage*)cache)); + if (!pair.second) + throw StorageDuplicate(name, p_name); + return cache; } /** - * Returns LMDBAL::Storage with the given name + * \brief Returns LMDBAL::Storage handle + * + * Requested storage must have been added before opening database + * Note that template parameters is user responsibility zone! + * If user, for instance, had added storage but calling + * this method with template parameters + * on the same name of the previously added storage, or calling it on cache - the behaviour is undefined + * + * \param[in] name - storage name + * \returns storage pointer. LMDBAL::Base keeps the ownership of the added storage, you don't need to destoroy it + * + * \tparam K - key type of the storage + * \tparam V - value type of the storage + * + * \exception std::out_of_range thrown if storage with the given name was not found */ template LMDBAL::Storage* LMDBAL::Base::getStorage(const std::string& p_name) { @@ -143,7 +187,21 @@ LMDBAL::Storage* LMDBAL::Base::getStorage(const std::string& p_name) { } /** - * Returns LMDBAL::Cache with the given name + * \brief Returns LMDBAL::Cache handle + * + * Requested cache must have been added before opening database + * Note that template parameters is user responsibility zone! + * If user, for instance, had added cache but calling + * this method with template parameters + * on the same name of the previously added cache, or calling it on storage - the behaviour is undefined + * + * \param[in] name - cache name + * \returns cache pointer. LMDBAL::Base keeps the ownership of the added cache, you don't need to destoroy it + * + * \tparam K - key type of the cache + * \tparam V - value type of the cahce + * + * \exception std::out_of_range thrown if cache with the given name was not found */ template LMDBAL::Cache* LMDBAL::Base::getCache(const std::string& p_name) { diff --git a/src/exceptions.cpp b/src/exceptions.cpp index e286ee0..c7491aa 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp @@ -82,6 +82,20 @@ std::string LMDBAL::NotFound::getMessage() const { + " in database " + dbName + " in table " + tableName;} +LMDBAL::StorageDuplicate::StorageDuplicate( + const std::string& p_dbName, + const std::string& p_tableName +): + dbName(p_dbName), + tableName(p_tableName) {} + +std::string LMDBAL::StorageDuplicate::getMessage() const { + return "An attempt to add a storage (or cache) " + tableName + + " to database " + dbName + + " but the database already has a storage with given name"; +} + + LMDBAL::Exist::Exist( const std::string& p_key, const std::string& p_dbName, diff --git a/src/exceptions.h b/src/exceptions.h index 87caecc..88eb510 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -76,6 +76,16 @@ private: std::string tableName; }; +class StorageDuplicate : public Exception { +public: + StorageDuplicate(const std::string& dbName, const std::string& tableName); + + std::string getMessage() const; +private: + std::string dbName; + std::string tableName; +}; + class Exist : public Exception { public: Exist(const std::string& key, const std::string& dbName, const std::string& tableName); diff --git a/src/storage.h b/src/storage.h index eb3a808..eb140c0 100644 --- a/src/storage.h +++ b/src/storage.h @@ -83,7 +83,7 @@ protected: protected: template - int makeTable(MDB_txn* transaction); + int makeStorage(MDB_txn* transaction); template static std::string toString(const T& value); diff --git a/src/storage.hpp b/src/storage.hpp index f46ebd8..3e9df5b 100644 --- a/src/storage.hpp +++ b/src/storage.hpp @@ -681,51 +681,51 @@ void LMDBAL::Storage::removeRecord(const K& key, TransactionID txn) { */ template int LMDBAL::Storage::createStorage(MDB_txn* transaction) { - return makeTable(transaction); + return makeStorage(transaction); } template -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); } template<> -inline int LMDBAL::iStorage::makeTable(MDB_txn* transaction) { +inline int LMDBAL::iStorage::makeStorage(MDB_txn* transaction) { return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi); }