1
0
forked from blue/lmdbal
lmdbal/table.hpp

267 lines
7.6 KiB
C++

// Squawk messenger.
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
//
// 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 <http://www.gnu.org/licenses/>.
#ifndef CORE_TABLE_HPP
#define CORE_TABLE_HPP
#include "table.h"
#include "exceptions.h"
template<class K, class V>
DataBase::Table<K, V>::Table(const std::string& p_name, DataBase* parent):
_Table(p_name, parent),
keySerializer(new Serializer<K>()),
valueSerializer(new Serializer<V>())
{
}
template<class K, class V>
DataBase::Table<K, V>::~Table() {
delete valueSerializer;
delete keySerializer;
}
template<class K, class V>
void DataBase::Table<K, V>::addRecord(const K& key, const V& value) {
if (!db->opened) {
throw Closed("addRecord", db->name, name);
}
MDB_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData = valueSerializer->setData(value);
MDB_txn *txn;
mdb_txn_begin(db->environment, NULL, 0, &txn);
int rc;
rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, MDB_NOOVERWRITE);
if (rc != 0) {
mdb_txn_abort(txn);
if (rc == MDB_KEYEXIST) {
throw Exist(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
} else {
mdb_txn_commit(txn);
}
}
template<class K, class V>
bool DataBase::Table<K, V>::forceRecord(const K& key, const V& value) {
if (!db->opened) {
throw Closed("forceRecord", db->name, name);
}
bool added;
MDB_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData;
MDB_txn *txn;
mdb_txn_begin(db->environment, NULL, 0, &txn);
int rc;
rc = mdb_get(txn, dbi, &lmdbKey, &lmdbData);
if (rc == 0) {
added = false;
} else if (rc == MDB_NOTFOUND) {
added = true;
} else {
mdb_txn_abort(txn);
throw Unknown(db->name, mdb_strerror(rc), name);
}
lmdbData = valueSerializer->setData(value);
rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, 0);
if (rc != 0) {
mdb_txn_abort(txn);
throw Unknown(db->name, mdb_strerror(rc), name);
} else {
mdb_txn_commit(txn);
}
return added;
}
template<class K, class V>
void DataBase::Table<K, V>::changeRecord(const K& key, const V& value) {
if (!db->opened) {
throw Closed("changeRecord", db->name, name);
}
MDB_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData = valueSerializer->setData(value);
MDB_txn *txn;
mdb_txn_begin(db->environment, NULL, 0, &txn);
int rc;
rc = mdb_put(txn, dbi, &lmdbKey, &lmdbData, 0);
if (rc != 0) {
mdb_txn_abort(txn);
if (rc) {
throw Unknown(db->name, mdb_strerror(rc), name);
}
} else {
mdb_txn_commit(txn);
}
}
template<class K, class V>
V DataBase::Table<K, V>::getRecord(const K& key) const {
if (!db->opened) {
throw Closed("getRecord", db->name, name);
}
MDB_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData;
MDB_txn *txn;
int rc;
mdb_txn_begin(db->environment, NULL, MDB_RDONLY, &txn);
rc = mdb_get(txn, dbi, &lmdbKey, &lmdbData);
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw NotFound(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
} else {
V value = valueSerializer->deserialize(lmdbData);
mdb_txn_abort(txn);
return value;
}
}
template<class K, class V>
std::map<K, V> DataBase::Table<K, V>::readAll() const {
if (!db->opened) {
throw Closed("readAll", db->name, name);
}
std::map<K, V> result;
MDB_txn *txn;
MDB_cursor* cursor;
MDB_val lmdbKey, lmdbData;
int rc = mdb_txn_begin(db->environment, NULL, MDB_RDONLY, &txn);
if (rc != MDB_SUCCESS) {
throw Unknown(db->name, mdb_strerror(rc), name);
}
rc = mdb_cursor_open(txn, dbi, &cursor);
if (rc != MDB_SUCCESS) {
throw Unknown(db->name, mdb_strerror(rc), name);
}
rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_FIRST);
while (rc == MDB_SUCCESS) {
K key = keySerializer->deserialize(lmdbKey);
V value = valueSerializer->deserialize(lmdbData);
result.insert(std::make_pair(key, value));
rc = mdb_cursor_get(cursor, &lmdbKey, &lmdbData, MDB_NEXT);
}
if (rc != MDB_NOTFOUND) {
throw Unknown(db->name, mdb_strerror(rc), name);
}
return result;
}
template<class K, class V>
void DataBase::Table<K, V>::removeRecord(const K& key) {
if (!db->opened) {
throw Closed("removeRecord", db->name, name);
}
MDB_val lmdbKey = keySerializer->setData(key);
MDB_txn *txn;
int rc;
mdb_txn_begin(db->environment, NULL, 0, &txn);
rc = mdb_del(txn, dbi, &lmdbKey, NULL);
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw NotFound(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
} else {
mdb_txn_commit(txn);
}
}
template<class K, class V>
int DataBase::Table<K, V>::createTable(MDB_txn* transaction) {
return makeTable<K>(transaction);
}
template<class K>
inline int DataBase::_Table::makeTable(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<uint64_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<uint32_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<uint16_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<uint8_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<int64_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<int32_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<int16_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<>
inline int DataBase::_Table::makeTable<int8_t>(MDB_txn* transaction) {
return mdb_dbi_open(transaction, name.c_str(), MDB_CREATE | MDB_INTEGERKEY, &dbi);
}
template<class T>
inline std::string DataBase::_Table::toString(const T& value) {
return std::to_string(value);
}
template<>
inline std::string DataBase::_Table::toString(const QString& value) {
return value.toStdString();
}
template<>
inline std::string DataBase::_Table::toString(const std::string& value) {
return value;
}
#endif //CORE_TABLE_HPP