forked from blue/lmdbal
some ideas about transaction
This commit is contained in:
parent
a4bb7e6269
commit
f0779ae2aa
@ -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
|
||||
|
101
src/base.cpp
101
src/base.cpp
@ -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);
|
||||
}
|
||||
|
23
src/base.h
23
src/base.h
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
@ -48,17 +48,20 @@ protected:
|
||||
void throwUnknown(int rc, TransactionID txn) const;
|
||||
void throwUnknown(int rc) const;
|
||||
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;
|
||||
void throwNotFound(const std::string& key) 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user