some ideas about transaction

This commit is contained in:
Blue 2023-04-02 16:00:21 +03:00
parent a4bb7e6269
commit f0779ae2aa
Signed by: blue
GPG Key ID: 9B203B252A63EE38
7 changed files with 125 additions and 65 deletions

View File

@ -36,6 +36,17 @@ else ()
add_library(${PROJECT_NAME} SHARED) add_library(${PROJECT_NAME} SHARED)
endif() endif()
if (CMAKE_BUILD_TYPE STREQUAL "Release")
list(APPEND COMPILE_OPTIONS -O3)
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
list(APPEND COMPILE_OPTIONS -g)
list(APPEND COMPILE_OPTIONS -Wall)
list(APPEND COMPILE_OPTIONS -Wextra)
endif()
message("Compilation options: " ${COMPILE_OPTIONS})
target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS})
set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${version}) set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${version})
set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION 1) set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION 1)
set_property(TARGET ${PROJECT_NAME} PROPERTY set_property(TARGET ${PROJECT_NAME} PROPERTY

View File

@ -20,12 +20,14 @@
#include "exceptions.h" #include "exceptions.h"
#include "storage.h" #include "storage.h"
#define UNUSED(x) (void)(x)
LMDBAL::Base::Base(const QString& p_name, uint16_t mapSize): LMDBAL::Base::Base(const QString& p_name, uint16_t mapSize):
name(p_name.toStdString()), name(p_name.toStdString()),
opened(false), opened(false),
size(mapSize), size(mapSize),
environment(), environment(),
tables(), storages(),
transactions(new Transactions()) transactions(new Transactions())
{} {}
@ -34,18 +36,18 @@ LMDBAL::Base::~Base() {
delete transactions; delete transactions;
for (const std::pair<const std::string, iStorage*>& pair : tables) for (const std::pair<const std::string, iStorage*>& pair : storages)
delete pair.second; delete pair.second;
} }
void LMDBAL::Base::close() { void LMDBAL::Base::close() {
if (opened) { if (opened) {
for (LMDBAL::TransactionID id : *transactions) for (LMDBAL::TransactionID id : *transactions)
mdb_txn_abort(id); abortTransaction(id, emptyName);
for (const std::pair<const std::string, iStorage*>& pair : tables) { for (const std::pair<const std::string, iStorage*>& pair : storages) {
iStorage* table = pair.second; iStorage* storage = pair.second;
mdb_dbi_close(environment, table->dbi); mdb_dbi_close(environment, storage->dbi);
} }
mdb_env_close(environment); mdb_env_close(environment);
transactions->clear(); transactions->clear();
@ -61,20 +63,18 @@ void LMDBAL::Base::open() {
mdb_env_create(&environment); mdb_env_create(&environment);
QString path = createDirectory(); QString path = createDirectory();
mdb_env_set_maxdbs(environment, tables.size()); mdb_env_set_maxdbs(environment, storages.size());
mdb_env_set_mapsize(environment, size * 1024UL * 1024UL); mdb_env_set_mapsize(environment, size * 1024UL * 1024UL);
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664); mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
MDB_txn *txn; TransactionID txn = beginPrivateTransaction(emptyName);
mdb_txn_begin(environment, NULL, 0, &txn); for (const std::pair<const std::string, iStorage*>& pair : storages) {
iStorage* storage = pair.second;
for (const std::pair<const std::string, iStorage*>& pair : tables) { int rc = storage->createStorage(txn);
iStorage* table = pair.second;
int rc = table->createTable(txn);
if (rc) if (rc)
throw Unknown(name, mdb_strerror(rc)); throw Unknown(name, mdb_strerror(rc));
} }
mdb_txn_commit(txn); commitPrivateTransaction(txn, emptyName);
opened = true; opened = true;
} }
} }
@ -120,18 +120,13 @@ void LMDBAL::Base::drop() {
if (!opened) if (!opened)
throw Closed("drop", name); throw Closed("drop", name);
MDB_txn *txn; TransactionID txn = beginPrivateTransaction(emptyName);
int rc = mdb_txn_begin(environment, NULL, 0, &txn); for (const std::pair<const std::string, iStorage*>& pair : storages) {
if (rc) int rc = pair.second->drop(txn);
throw Unknown(name, mdb_strerror(rc));
for (const std::pair<const std::string, iStorage*>& pair : tables) {
rc = pair.second->drop(txn);
if (rc) if (rc)
throw Unknown(name, mdb_strerror(rc), pair.first); throw Unknown(name, mdb_strerror(rc), pair.first);
} }
commitPrivateTransaction(txn, emptyName);
mdb_txn_commit(txn);
} }
LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction() const { LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction() const {
@ -146,18 +141,15 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id) const {
void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) const { void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id) const {
return commitTransaction(id, emptyName);} return commitTransaction(id, emptyName);}
LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& storageName) const { LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& storageName) const {
if (!opened) if (!opened)
throw Closed("beginReadOnlyTransaction", name, storageName); throw Closed("beginReadOnlyTransaction", name, storageName);
MDB_txn* txn; TransactionID txn = beginPrivateReadOnlyTransaction(storageName);
int rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
if (rc) {
mdb_txn_abort(txn);
throw Unknown(name, mdb_strerror(rc), storageName);
}
transactions->emplace(txn); transactions->emplace(txn);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionStarted(txn, true);
return txn; return txn;
} }
@ -165,13 +157,11 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN
if (!opened) if (!opened)
throw Closed("beginTransaction", name, storageName); throw Closed("beginTransaction", name, storageName);
MDB_txn* txn; TransactionID txn = beginPrivateTransaction(storageName);
int rc = mdb_txn_begin(environment, NULL, 0, &txn);
if (rc) {
mdb_txn_abort(txn);
throw Unknown(name, mdb_strerror(rc), storageName);
}
transactions->emplace(txn); transactions->emplace(txn);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionStarted(txn, false);
return txn; return txn;
} }
@ -183,7 +173,10 @@ void LMDBAL::Base::abortTransaction(LMDBAL::TransactionID id, const std::string&
if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this
throw Unknown(name, "unable to abort transaction: transaction was not found", storageName); throw Unknown(name, "unable to abort transaction: transaction was not found", storageName);
mdb_txn_abort(id); abortPrivateTransaction(id, storageName);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionAborted(id);
transactions->erase(itr); transactions->erase(itr);
} }
@ -195,8 +188,40 @@ void LMDBAL::Base::commitTransaction(LMDBAL::TransactionID id, const std::string
if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this if (itr == transactions->end()) //TODO may be it's a good idea to make an exception class for this
throw Unknown(name, "unable to commit transaction: transaction was not found", storageName); throw Unknown(name, "unable to commit transaction: transaction was not found", storageName);
int rc = mdb_txn_commit(id); commitPrivateTransaction(id, storageName);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionCommited(id);
transactions->erase(itr); transactions->erase(itr);
}
LMDBAL::TransactionID LMDBAL::Base::beginPrivateReadOnlyTransaction(const std::string& storageName) const {
MDB_txn* txn;
int rc = mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
if (rc) {
mdb_txn_abort(txn);
throw Unknown(name, mdb_strerror(rc), storageName);
}
return txn;
}
LMDBAL::TransactionID LMDBAL::Base::beginPrivateTransaction(const std::string& storageName) const {
MDB_txn* txn;
int rc = mdb_txn_begin(environment, NULL, 0, &txn);
if (rc) {
mdb_txn_abort(txn);
throw Unknown(name, mdb_strerror(rc), storageName);
}
return txn;
}
void LMDBAL::Base::abortPrivateTransaction(LMDBAL::TransactionID id, const std::string& storageName) const {
UNUSED(storageName);
mdb_txn_abort(id);
}
void LMDBAL::Base::commitPrivateTransaction(LMDBAL::TransactionID id, const std::string& storageName) const {
int rc = mdb_txn_commit(id);
if (rc != MDB_SUCCESS) if (rc != MDB_SUCCESS)
throw Unknown(name, mdb_strerror(rc), storageName); throw Unknown(name, mdb_strerror(rc), storageName);
} }

View File

@ -81,7 +81,7 @@ 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*> Tables; typedef std::map<std::string, LMDBAL::iStorage*> Storages;
typedef std::set<TransactionID> Transactions; typedef std::set<TransactionID> Transactions;
TransactionID beginReadOnlyTransaction(const std::string& storageName) const; TransactionID beginReadOnlyTransaction(const std::string& storageName) const;
@ -89,12 +89,17 @@ private:
void commitTransaction(TransactionID id, const std::string& storageName) const; void commitTransaction(TransactionID id, const std::string& storageName) const;
void abortTransaction(TransactionID id, const std::string& storageName) const; void abortTransaction(TransactionID id, const std::string& storageName) const;
TransactionID beginPrivateReadOnlyTransaction(const std::string& storageName) const;
TransactionID beginPrivateTransaction(const std::string& storageName) const;
void commitPrivateTransaction(TransactionID id, const std::string& storageName) const;
void abortPrivateTransaction(TransactionID id, const std::string& storageName) const;
private: private:
std::string name; std::string name;
bool opened; bool opened;
uint16_t size; uint16_t size;
MDB_env* environment; MDB_env* environment;
Tables tables; Storages storages;
Transactions* transactions; Transactions* transactions;
inline static const std::string emptyName = ""; inline static const std::string emptyName = "";
@ -109,11 +114,11 @@ private:
template <class K, class V> template <class K, class V>
LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& p_name) { LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& p_name) {
if (opened) { if (opened) {
throw Opened(name, "add table " + p_name); throw Opened(name, "add storage " + p_name);
} }
Storage<K, V>* table = new Storage<K, V>(p_name, this); Storage<K, V>* storage = new Storage<K, V>(p_name, this);
tables.insert(std::make_pair(p_name, (iStorage*)table)); storages.insert(std::make_pair(p_name, (iStorage*)storage));
return table; return storage;
} }
/** /**
@ -125,7 +130,7 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& p_name) {
throw Opened(name, "add cache " + p_name); throw Opened(name, "add cache " + p_name);
} }
Cache<K, V>* cache = new Cache<K, V>(p_name, this); Cache<K, V>* cache = new Cache<K, V>(p_name, this);
tables.insert(std::make_pair(p_name, (iStorage*)cache)); storages.insert(std::make_pair(p_name, (iStorage*)cache));
return cache; return cache;
} }
@ -134,7 +139,7 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& p_name) {
*/ */
template <class K, class V> template <class K, class V>
LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& p_name) { LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& p_name) {
return static_cast<Storage<K, V>*>(tables.at(p_name)); return static_cast<Storage<K, V>*>(storages.at(p_name));
} }
/** /**
@ -142,7 +147,7 @@ LMDBAL::Storage<K, V>* LMDBAL::Base::getStorage(const std::string& p_name) {
*/ */
template <class K, class V> template <class K, class V>
LMDBAL::Cache<K, V>* LMDBAL::Base::getCache(const std::string& p_name) { LMDBAL::Cache<K, V>* LMDBAL::Base::getCache(const std::string& p_name) {
return static_cast<Cache<K, V>*>(tables.at(p_name)); return static_cast<Cache<K, V>*>(storages.at(p_name));
} }
#endif //LMDBAL_BASE_H #endif //LMDBAL_BASE_H

View File

@ -18,6 +18,8 @@
#include "storage.h" #include "storage.h"
#define UNUSED(x) (void)(x)
LMDBAL::iStorage::iStorage(const std::string& p_name, Base* parent): LMDBAL::iStorage::iStorage(const std::string& p_name, Base* parent):
dbi(), dbi(),
db(parent), db(parent),
@ -125,13 +127,27 @@ void LMDBAL::iStorage::throwNotFound(const std::string& key) const {
throw NotFound(key, db->name, name);} throw NotFound(key, db->name, name);}
LMDBAL::TransactionID LMDBAL::iStorage::beginReadOnlyTransaction() const { LMDBAL::TransactionID LMDBAL::iStorage::beginReadOnlyTransaction() const {
return db->beginReadOnlyTransaction(name);} return db->beginPrivateReadOnlyTransaction(name);}
LMDBAL::TransactionID LMDBAL::iStorage::beginTransaction() const { LMDBAL::TransactionID LMDBAL::iStorage::beginTransaction() const {
return db->beginTransaction(name);} return db->beginPrivateTransaction(name);}
void LMDBAL::iStorage::abortTransaction(LMDBAL::TransactionID id) const { void LMDBAL::iStorage::abortTransaction(LMDBAL::TransactionID id) const {
db->abortTransaction(id);} db->abortPrivateTransaction(id, name);}
void LMDBAL::iStorage::commitTransaction(LMDBAL::TransactionID id) const { void LMDBAL::iStorage::commitTransaction(LMDBAL::TransactionID id) const {
db->commitTransaction(id);} db->commitPrivateTransaction(id, name);}
void LMDBAL::iStorage::transactionStarted(LMDBAL::TransactionID txn, bool readOnly) const {
UNUSED(txn);
UNUSED(readOnly);
}
void LMDBAL::iStorage::transactionCommited(LMDBAL::TransactionID txn) const {
UNUSED(txn);
}
void LMDBAL::iStorage::transactionAborted(LMDBAL::TransactionID txn) const {
UNUSED(txn);
}

View File

@ -34,7 +34,7 @@ protected:
iStorage(const std::string& name, Base* parent); iStorage(const std::string& name, Base* parent);
virtual ~iStorage(); virtual ~iStorage();
virtual int createTable(MDB_txn * transaction) = 0; virtual int createStorage(MDB_txn * transaction) = 0;
virtual int drop(MDB_txn * transaction); virtual int drop(MDB_txn * transaction);
bool isDBOpened() const; bool isDBOpened() const;
@ -50,15 +50,18 @@ protected:
void throwDuplicate(const std::string& key) const; void throwDuplicate(const std::string& key) const;
void throwNotFound(const std::string& key) const; void throwNotFound(const std::string& key) const;
public:
virtual void drop();
virtual SizeType count() const;
virtual SizeType count(TransactionID txn) const;
TransactionID beginReadOnlyTransaction() const; TransactionID beginReadOnlyTransaction() const;
TransactionID beginTransaction() const; TransactionID beginTransaction() const;
void commitTransaction(TransactionID id) const; void commitTransaction(TransactionID id) const;
void abortTransaction(TransactionID id) const; void abortTransaction(TransactionID id) const;
void transactionStarted(TransactionID txn, bool readOnly) const;
void transactionCommited(TransactionID txn) const;
void transactionAborted(TransactionID txn) const;
public:
virtual void drop();
virtual SizeType count() const;
virtual SizeType count(TransactionID txn) const;
protected: protected:
MDB_dbi dbi; MDB_dbi dbi;
@ -122,7 +125,7 @@ protected:
Serializer<K>* keySerializer; Serializer<K>* keySerializer;
Serializer<V>* valueSerializer; Serializer<V>* valueSerializer;
int createTable(MDB_txn* transaction) override; int createStorage(MDB_txn* transaction) override;
}; };
} }

View File

@ -372,7 +372,7 @@ void LMDBAL::Storage<K, V>::removeRecord(const K& key, TransactionID txn) {
} }
template<class K, class V> template<class K, class V>
int LMDBAL::Storage<K, V>::createTable(MDB_txn* transaction) { int LMDBAL::Storage<K, V>::createStorage(MDB_txn* transaction) {
return makeTable<K>(transaction); return makeTable<K>(transaction);
} }

View File

@ -46,7 +46,7 @@ TEST_F(StorageTransactionsTest, Adding) {
LMDBAL::TransactionID txn = db->beginTransaction(); LMDBAL::TransactionID txn = db->beginTransaction();
t1->addRecord(5, 13, txn); t1->addRecord(5, 13, txn);
t1->addRecord(-53, 782, txn); t1->addRecord(-53, 782, txn);
t1->addRecord(58392, -37829, txn); t1->addRecord(5892, -37829, txn);
t2->addRecord("lorem", 481, txn); t2->addRecord("lorem", 481, txn);
t2->addRecord("decallence", 8532.48, txn); t2->addRecord("decallence", 8532.48, txn);
@ -60,7 +60,7 @@ TEST_F(StorageTransactionsTest, Adding) {
EXPECT_EQ(t1->count(), 3); EXPECT_EQ(t1->count(), 3);
EXPECT_EQ(t1->getRecord(5), 13); EXPECT_EQ(t1->getRecord(5), 13);
EXPECT_EQ(t1->getRecord(-53), 782); EXPECT_EQ(t1->getRecord(-53), 782);
EXPECT_EQ(t1->getRecord(58392), -37829); EXPECT_EQ(t1->getRecord(5892), -37829);
EXPECT_EQ(t2->count(), 3); EXPECT_EQ(t2->count(), 3);
EXPECT_FLOAT_EQ(t2->getRecord("lorem"), 481); EXPECT_FLOAT_EQ(t2->getRecord("lorem"), 481);
@ -74,7 +74,7 @@ TEST_F(StorageTransactionsTest, Aborting) {
LMDBAL::SizeType s1 = t1->count(); LMDBAL::SizeType s1 = t1->count();
LMDBAL::SizeType s2 = t2->count(); LMDBAL::SizeType s2 = t2->count();
LMDBAL::TransactionID txn = t1->beginTransaction(); LMDBAL::TransactionID txn = db->beginTransaction();
t1->addRecord(18, 40, txn); t1->addRecord(18, 40, txn);
t1->addRecord(85, -4, txn); t1->addRecord(85, -4, txn);
t1->addRecord(-5, -3, txn); t1->addRecord(-5, -3, txn);
@ -86,7 +86,7 @@ TEST_F(StorageTransactionsTest, Aborting) {
EXPECT_EQ(t1->count(), s1); EXPECT_EQ(t1->count(), s1);
EXPECT_EQ(t2->count(), s2); EXPECT_EQ(t2->count(), s2);
t1->abortTransaction(txn); db->abortTransaction(txn);
EXPECT_EQ(t1->count(), s1); EXPECT_EQ(t1->count(), s1);
EXPECT_EQ(t2->count(), s2); EXPECT_EQ(t2->count(), s2);
@ -100,7 +100,7 @@ TEST_F(StorageTransactionsTest, Reading) {
EXPECT_EQ(t1->count(txn), 3); EXPECT_EQ(t1->count(txn), 3);
EXPECT_EQ(t1->getRecord(5, txn), 13); EXPECT_EQ(t1->getRecord(5, txn), 13);
EXPECT_EQ(t1->getRecord(-53, txn), 782); EXPECT_EQ(t1->getRecord(-53, txn), 782);
EXPECT_EQ(t1->getRecord(58392, txn), -37829); EXPECT_EQ(t1->getRecord(5892, txn), -37829);
EXPECT_EQ(t2->count(txn), 3); EXPECT_EQ(t2->count(txn), 3);
EXPECT_FLOAT_EQ(t2->getRecord("lorem", txn), 481); EXPECT_FLOAT_EQ(t2->getRecord("lorem", txn), 481);