1
0
forked from blue/lmdbal

some ideas about transaction

This commit is contained in:
Blue 2023-04-02 16:00:21 +03:00
parent a4bb7e6269
commit f0779ae2aa
Signed by untrusted user: 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)
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 SOVERSION 1)
set_property(TARGET ${PROJECT_NAME} PROPERTY

View File

@ -20,12 +20,14 @@
#include "exceptions.h"
#include "storage.h"
#define UNUSED(x) (void)(x)
LMDBAL::Base::Base(const QString& p_name, uint16_t mapSize):
name(p_name.toStdString()),
opened(false),
size(mapSize),
environment(),
tables(),
storages(),
transactions(new Transactions())
{}
@ -34,18 +36,18 @@ LMDBAL::Base::~Base() {
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;
}
void LMDBAL::Base::close() {
if (opened) {
for (LMDBAL::TransactionID id : *transactions)
mdb_txn_abort(id);
abortTransaction(id, emptyName);
for (const std::pair<const std::string, iStorage*>& pair : tables) {
iStorage* table = pair.second;
mdb_dbi_close(environment, table->dbi);
for (const std::pair<const std::string, iStorage*>& pair : storages) {
iStorage* storage = pair.second;
mdb_dbi_close(environment, storage->dbi);
}
mdb_env_close(environment);
transactions->clear();
@ -61,20 +63,18 @@ void LMDBAL::Base::open() {
mdb_env_create(&environment);
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_open(environment, path.toStdString().c_str(), 0, 0664);
MDB_txn *txn;
mdb_txn_begin(environment, NULL, 0, &txn);
for (const std::pair<const std::string, iStorage*>& pair : tables) {
iStorage* table = pair.second;
int rc = table->createTable(txn);
TransactionID txn = beginPrivateTransaction(emptyName);
for (const std::pair<const std::string, iStorage*>& pair : storages) {
iStorage* storage = pair.second;
int rc = storage->createStorage(txn);
if (rc)
throw Unknown(name, mdb_strerror(rc));
}
mdb_txn_commit(txn);
commitPrivateTransaction(txn, emptyName);
opened = true;
}
}
@ -120,18 +120,13 @@ void LMDBAL::Base::drop() {
if (!opened)
throw Closed("drop", name);
MDB_txn *txn;
int rc = mdb_txn_begin(environment, NULL, 0, &txn);
if (rc)
throw Unknown(name, mdb_strerror(rc));
for (const std::pair<const std::string, iStorage*>& pair : tables) {
rc = pair.second->drop(txn);
TransactionID txn = beginPrivateTransaction(emptyName);
for (const std::pair<const std::string, iStorage*>& pair : storages) {
int rc = pair.second->drop(txn);
if (rc)
throw Unknown(name, mdb_strerror(rc), pair.first);
}
mdb_txn_commit(txn);
commitPrivateTransaction(txn, emptyName);
}
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 {
return commitTransaction(id, emptyName);}
LMDBAL::TransactionID LMDBAL::Base::beginReadOnlyTransaction(const std::string& storageName) const {
if (!opened)
throw Closed("beginReadOnlyTransaction", name, storageName);
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);
}
TransactionID txn = beginPrivateReadOnlyTransaction(storageName);
transactions->emplace(txn);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionStarted(txn, true);
return txn;
}
@ -165,13 +157,11 @@ LMDBAL::TransactionID LMDBAL::Base::beginTransaction(const std::string& storageN
if (!opened)
throw Closed("beginTransaction", name, storageName);
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);
}
TransactionID txn = beginPrivateTransaction(storageName);
transactions->emplace(txn);
for (const std::pair<const std::string, LMDBAL::iStorage*>& pair : storages)
pair.second->transactionStarted(txn, false);
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
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);
}
@ -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
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);
}
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)
throw Unknown(name, mdb_strerror(rc), storageName);
}

View File

@ -81,7 +81,7 @@ public:
LMDBAL::Cache<K, V>* getCache(const std::string& name);
private:
typedef std::map<std::string, LMDBAL::iStorage*> Tables;
typedef std::map<std::string, LMDBAL::iStorage*> Storages;
typedef std::set<TransactionID> Transactions;
TransactionID beginReadOnlyTransaction(const std::string& storageName) const;
@ -89,12 +89,17 @@ private:
void commitTransaction(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:
std::string name;
bool opened;
uint16_t size;
MDB_env* environment;
Tables tables;
Storages storages;
Transactions* transactions;
inline static const std::string emptyName = "";
@ -109,11 +114,11 @@ private:
template <class K, class V>
LMDBAL::Storage<K, V>* LMDBAL::Base::addStorage(const std::string& p_name) {
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);
tables.insert(std::make_pair(p_name, (iStorage*)table));
return table;
Storage<K, V>* storage = new Storage<K, V>(p_name, this);
storages.insert(std::make_pair(p_name, (iStorage*)storage));
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);
}
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;
}
@ -134,7 +139,7 @@ LMDBAL::Cache<K, V> * LMDBAL::Base::addCache(const std::string& p_name) {
*/
template <class K, class V>
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>
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

View File

@ -18,6 +18,8 @@
#include "storage.h"
#define UNUSED(x) (void)(x)
LMDBAL::iStorage::iStorage(const std::string& p_name, Base* parent):
dbi(),
db(parent),
@ -125,13 +127,27 @@ void LMDBAL::iStorage::throwNotFound(const std::string& key) const {
throw NotFound(key, db->name, name);}
LMDBAL::TransactionID LMDBAL::iStorage::beginReadOnlyTransaction() const {
return db->beginReadOnlyTransaction(name);}
return db->beginPrivateReadOnlyTransaction(name);}
LMDBAL::TransactionID LMDBAL::iStorage::beginTransaction() const {
return db->beginTransaction(name);}
return db->beginPrivateTransaction(name);}
void LMDBAL::iStorage::abortTransaction(LMDBAL::TransactionID id) const {
db->abortTransaction(id);}
db->abortPrivateTransaction(id, name);}
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);
virtual ~iStorage();
virtual int createTable(MDB_txn * transaction) = 0;
virtual int createStorage(MDB_txn * transaction) = 0;
virtual int drop(MDB_txn * transaction);
bool isDBOpened() const;
@ -50,15 +50,18 @@ protected:
void throwDuplicate(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 beginTransaction() const;
void commitTransaction(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:
MDB_dbi dbi;
@ -122,7 +125,7 @@ protected:
Serializer<K>* keySerializer;
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>
int LMDBAL::Storage<K, V>::createTable(MDB_txn* transaction) {
int LMDBAL::Storage<K, V>::createStorage(MDB_txn* transaction) {
return makeTable<K>(transaction);
}

View File

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