/* * LMDB Abstraction Layer. * Copyright (C) 2023 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LMDBAL_STORAGE_H #define LMDBAL_STORAGE_H #include #include #include "base.h" #include "serializer.h" #include "cursor.h" #include "transaction.h" class BaseTest; class DuplicatesTest; class CacheCursorTest; class StorageCursorTest; namespace LMDBAL { class iStorage { friend class Base; public: protected: iStorage(Base* parent, const std::string& name, bool duplicates = false); virtual ~iStorage(); /** * \brief A private virtual function I need to open each storage in the database * * \param[in] transaction - lmdb transaction to call mdb_dbi_open * \returns MDB_SUCCESS if everything went smooth or MDB_ -like error code */ virtual int open(MDB_txn * transaction) = 0; virtual void close(); virtual void handleDrop(); bool isDBOpened() const; const std::string& dbName() const; void ensureOpened(const std::string& methodName) const; void throwDuplicateOrUnknown(int rc, const std::string& key) const; void throwDuplicateOrUnknown(int rc, TransactionID txn, const std::string& key) const; void throwNotFoundOrUnknown(int rc, const std::string& key) const; void throwNotFoundOrUnknown(int rc, TransactionID txn, const std::string& key) const; void throwUnknown(int rc, TransactionID txn) const; void throwUnknown(int rc) const; void throwUnknown(const std::string& message) const; void throwDuplicate(const std::string& key) const; void throwNotFound(const std::string& key) const; void throwCursorNotReady(const std::string& method) const; TransactionID extractTransactionId(const Transaction& txn, const std::string& action = "") const; TransactionID beginReadOnlyTransaction() const; TransactionID beginTransaction() const; void commitTransaction(TransactionID id); void abortTransaction(TransactionID id) const; virtual void transactionStarted(TransactionID txn, bool readOnly) const; virtual void transactionCommited(TransactionID txn); virtual void transactionAborted(TransactionID txn) const; virtual int drop(TransactionID transaction); virtual SizeType count(TransactionID txn) const; public: virtual void drop(); virtual int drop(const WriteTransaction& txn); virtual SizeType count() const; virtual SizeType count(const Transaction& txn) const; protected: MDB_dbi dbi; /**<\brief lmdb storage handle*/ Base* db; /**<\brief parent database pointer (borrowed)*/ const std::string name; /**<\brief this storage name*/ const bool duplicates; /**<\brief true if storage supports duplicates*/ inline static const std::string dropMethodName = "drop"; /**<\brief member function name, just for exceptions*/ inline static const std::string countMethodName = "count"; /**<\brief member function name, just for exceptions*/ inline static const std::string flagsMethodName = "flags"; /**<\brief member function name, just for exceptions*/ inline static const std::string addRecordMethodName = "addRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string forceRecordMethodName = "forceRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string changeRecordMethodName = "changeRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string removeRecordMethodName = "removeRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string checkRecordMethodName = "checkRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string getRecordMethodName = "getRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string readAllMethodName = "readAllRecord"; /**<\brief member function name, just for exceptions*/ inline static const std::string replaceAllMethodName = "replaceAll"; /**<\brief member function name, just for exceptions*/ inline static const std::string addRecordsMethodName = "addRecords"; /**<\brief member function name, just for exceptions*/ protected: template int makeStorage(MDB_txn* transaction, bool duplicates = false); template static std::string toString(const T& value); }; template class Storage : public iStorage { friend class ::BaseTest; friend class ::DuplicatesTest; friend class ::CacheCursorTest; friend class ::StorageCursorTest; friend class Base; friend class Cursor; protected: Storage(Base* parent, const std::string& name, bool duplicates = false); ~Storage() override; virtual void discoveredRecord(const K& key, const V& value) const; virtual void discoveredRecord(const K& key, const V& value, TransactionID txn) const; uint32_t flags() const; virtual void addRecord(const K& key, const V& value, TransactionID txn); virtual bool forceRecord(const K& key, const V& value, TransactionID txn); virtual void changeRecord(const K& key, const V& value, TransactionID txn); virtual void removeRecord(const K& key, TransactionID txn); virtual bool checkRecord(const K& key, TransactionID txn) const; virtual void getRecord(const K& key, V& value, TransactionID txn) const; virtual V getRecord(const K& key, TransactionID txn) const; virtual std::map readAll(TransactionID txn) const; virtual void readAll(std::map& result, TransactionID txn) const; virtual void replaceAll(const std::map& data, TransactionID txn); virtual uint32_t addRecords(const std::map& data, TransactionID txn, bool overwrite = false); public: using iStorage::drop; virtual void addRecord(const K& key, const V& value); virtual void addRecord(const K& key, const V& value, const WriteTransaction& txn); virtual bool forceRecord(const K& key, const V& value); //returns true if there was addition, false if change virtual bool forceRecord(const K& key, const V& value, const WriteTransaction& txn); virtual void changeRecord(const K& key, const V& value); virtual void changeRecord(const K& key, const V& value, const WriteTransaction& txn); virtual void removeRecord(const K& key); virtual void removeRecord(const K& key, const WriteTransaction& txn); virtual bool checkRecord(const K& key) const; //checks if there is a record with given key virtual bool checkRecord(const K& key, const Transaction& txn) const; virtual void getRecord(const K& key, V& value) const; virtual void getRecord(const K& key, V& value, const Transaction& txn) const; virtual V getRecord(const K& key) const; virtual V getRecord(const K& key, const Transaction& txn) const; virtual std::map readAll() const; virtual std::map readAll(const Transaction& txn) const; virtual void readAll(std::map& result) const; virtual void readAll(std::map& result, const Transaction& txn) const; virtual void replaceAll(const std::map& data); virtual void replaceAll(const std::map& data, const WriteTransaction& txn); virtual uint32_t addRecords(const std::map& data, bool overwrite = false); virtual uint32_t addRecords(const std::map& data, const WriteTransaction& txn, bool overwrite = false); Cursor createCursor(); void destroyCursor(Cursor& cursor); protected: mutable Serializer keySerializer; /**<\brief internal object that would serialize and deserialize keys*/ mutable Serializer valueSerializer; /**<\brief internal object that would serialize and deserialize values*/ std::map*> cursors; /**<\brief a set of cursors that has been created under this storage*/ int open(MDB_txn* transaction) override; void close() override; }; } #include "storage.hpp" #endif //LMDBAL_STORAGE_H