finally, first working prototype

This commit is contained in:
Blue 2022-09-15 01:18:31 +03:00
parent d67a3c32eb
commit 5f90a21fe6
Signed by: blue
GPG Key ID: 9B203B252A63EE38
11 changed files with 193 additions and 112 deletions

View File

@ -18,7 +18,7 @@
#include "exceptions.h"
#include "table.h"
Core::DataBase::DataBase(const QString& p_name, uint16_t mapSize):
DataBase::DataBase(const QString& p_name, uint16_t mapSize):
name(p_name.toStdString()),
opened(false),
size(mapSize),
@ -27,7 +27,7 @@ Core::DataBase::DataBase(const QString& p_name, uint16_t mapSize):
{
}
Core::DataBase::~DataBase()
DataBase::~DataBase()
{
close();
for (const std::pair<const std::string, _Table*>& pair : tables) {
@ -35,7 +35,7 @@ Core::DataBase::~DataBase()
}
}
void Core::DataBase::close()
void DataBase::close()
{
if (opened) {
for (const std::pair<const std::string, _Table*>& pair : tables) {
@ -47,7 +47,7 @@ void Core::DataBase::close()
}
}
void Core::DataBase::open()
void DataBase::open()
{
if (!opened) {
mdb_env_create(&environment);
@ -71,7 +71,7 @@ void Core::DataBase::open()
for (const std::pair<const std::string, _Table*>& pair : tables) {
_Table* table = pair.second;
int rc = mdb_dbi_open(txn, pair.first.c_str(), MDB_CREATE, &table->dbi);
int rc = table->createTable(txn);
if (rc) {
throw Unknown(name, mdb_strerror(rc));
}
@ -82,18 +82,9 @@ void Core::DataBase::open()
}
}
QString Core::DataBase::getName() const
QString DataBase::getName() const
{
return QString::fromStdString(name);
}
template <class K, class V>
Core::DataBase::Table<K, V>* Core::DataBase::addTable(const QString& p_name) {
std::string nm = p_name.toStdString();
if (opened) {
throw Core::DataBase::Opened(name, nm);
}
Core::DataBase::Table<K, V>* table = new Core::DataBase::Table<K, V>(nm, this);
tables.insert(std::make_pair(nm, table));
return table;
}

View File

@ -25,8 +25,6 @@
#include <QDir>
#include <lmdb.h>
namespace Core {
class DataBase
{
class _Table;
@ -63,6 +61,17 @@ private:
std::map<std::string, _Table*> tables;
};
#include "exceptions.h"
template <class K, class V>
DataBase::Table<K, V>* DataBase::addTable(const QString& p_name) {
std::string nm = p_name.toStdString();
if (opened) {
throw Opened(name, nm);
}
DataBase::Table<K, V>* table = new DataBase::Table<K, V>(nm, this);
tables.insert(std::make_pair(nm, (_Table*)table));
return table;
}
#endif // CORE_DATABASE_H

View File

@ -16,14 +16,14 @@
#include "exceptions.h"
Core::DataBase::Directory::Directory(const std::string& p_path):
DataBase::Directory::Directory(const std::string& p_path):
Exception(),
path(p_path) {}
std::string Core::DataBase::Directory::getMessage() const {
std::string DataBase::Directory::getMessage() const {
return "Can't create directory for database at " + path;}
Core::DataBase::Closed::Closed(
DataBase::Closed::Closed(
const std::string& p_operation,
const std::string& p_dbName,
const std::string& p_tableName
@ -33,26 +33,26 @@ Core::DataBase::Closed::Closed(
dbName(p_dbName),
tableName(p_tableName) {}
std::string Core::DataBase::Closed::getMessage() const {
std::string DataBase::Closed::getMessage() const {
return "An attempt to perform operation " + operation
+ " on closed database " + dbName
+ " on table " + tableName;
}
Core::DataBase::Opened::Opened(const std::string& p_dbName, const std::string& p_tableName):
DataBase::Opened::Opened(const std::string& p_dbName, const std::string& p_tableName):
Exception(),
dbName(p_dbName),
tableName(p_tableName) {}
std::string Core::DataBase::Opened::getMessage() const {
std::string DataBase::Opened::getMessage() const {
return "An attempt to add table " + tableName
+ " to the database " + dbName
+ " but it's can't be done because the DataBase is already opened."
+ " Please add all tables before opening DataBase.";
}
Core::DataBase::NotFound::NotFound(
DataBase::NotFound::NotFound(
const std::string& p_key,
const std::string& p_dbName,
const std::string& p_tableName
@ -62,12 +62,12 @@ Core::DataBase::NotFound::NotFound(
dbName(p_dbName),
tableName(p_tableName) {}
std::string Core::DataBase::NotFound::getMessage() const {
std::string DataBase::NotFound::getMessage() const {
return "Element for id " + key + " wasn't found "
+ " in database " + dbName
+ " in table " + tableName;}
Core::DataBase::Exist::Exist(
DataBase::Exist::Exist(
const std::string& p_key,
const std::string& p_dbName,
const std::string& p_tableName
@ -77,14 +77,14 @@ Core::DataBase::Exist::Exist(
dbName(p_dbName),
tableName(p_tableName) {}
std::string Core::DataBase::Exist::getMessage() const {
std::string DataBase::Exist::getMessage() const {
return "An attempt to insert element with key " + key
+ " to database " + dbName
+ " to table " + tableName
+ " but it already has an element with given id";
}
Core::DataBase::Unknown::Unknown(
DataBase::Unknown::Unknown(
const std::string& p_dbName,
const std::string& message,
const std::optional<std::string>& p_tableName
@ -94,7 +94,7 @@ Core::DataBase::Unknown::Unknown(
tableName(p_tableName),
msg(message) {}
std::string Core::DataBase::Unknown::getMessage() const
std::string DataBase::Unknown::getMessage() const
{
std::string result = "Unknown error in database " + dbName;
if (tableName.has_value()) {

View File

@ -20,8 +20,6 @@
#include "exception.h"
#include "database.h"
namespace Core {
class DataBase::Directory: public Utils::Exception {
public:
Directory(const std::string& path);
@ -84,5 +82,5 @@ private:
std::optional<std::string> tableName;
std::string msg;
};
}
#endif //CORE_DATABASE_EXCEPTIONS_H

View File

@ -4,38 +4,31 @@
#include "table.h"
template<class T>
class Serializer {
public:
Serializer(const T& value):val(value) {}
void print() {
std::cout << val << std::endl;
}
T val;
};
template<>
class Serializer<int> {
public:
Serializer(int v): value(v) {}
int value;
};
int main(int argc, char **argv) {
Core::DataBase base("test1");
Core::DataBase::Table<uint32_t, uint32_t>* table1 = base.addTable<uint32_t, uint32_t>("table1");
Core::DataBase::Table<QString, QString>* table2 = base.addTable<QString, QString>("table2");
DataBase base("test1");
DataBase::Table<uint32_t, uint32_t>* table1 = base.addTable<uint32_t, uint32_t>("table1");
DataBase::Table<QString, QString>* table2 = base.addTable<QString, QString>("table2");
base.open();
table1->addRecord(1, 2);
try {
table1->addRecord(1, 2);
} catch (const DataBase::Exist& error) {
std::cout << error.getMessage() << std::endl;
}
uint32_t rec1 = table1->getRecord(1);
std::cout << "table1 record under 1 is " << rec1 << std::endl;
try {
table2->addRecord("hello", "world");
} catch (const DataBase::Exist& error) {
std::cout << error.getMessage() << std::endl;
}
QString rec2 = table2->getRecord("hello");
std::cout << "table2 record under hello is " << rec2.toStdString() << std::endl;
return 0;
}

View File

@ -23,8 +23,6 @@
#include "database.h"
namespace Core {
template<class T>
class DataBase::Serializer
{
@ -33,6 +31,7 @@ public:
Serializer(const T& value);
~Serializer();
T deserialize(const MDB_val& value);
MDB_val setData(const T& value);
MDB_val getData();
void clear();
@ -47,6 +46,7 @@ private:
QDataStream stream;
};
}
#include "serializer.hpp"
#include "serializer_uint32.hpp"
#endif // CORE_DATABASE_SERIALIZER_H

View File

@ -14,57 +14,73 @@
// 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_DATABASE_SERIALIZER_HPP
#define CORE_DATABASE_SERIALIZER_HPP
#include "serializer.h"
template<class T>
Core::DataBase::Serializer<T>::Serializer() :
DataBase::Serializer<T>::Serializer() :
bytes(),
buffer(&bytes),
stream(&buffer)
{
buffer.open(QIODevice::WriteOnly);
buffer.open(QIODevice::ReadWrite);
}
template<class T>
Core::DataBase::Serializer<T>::Serializer(const T& value) :
DataBase::Serializer<T>::Serializer(const T& value) :
bytes(),
buffer(&bytes),
stream(&buffer)
{
buffer.open(QIODevice::WriteOnly);
buffer.open(QIODevice::ReadWrite);
_setValue(value);
}
template<class T>
Core::DataBase::Serializer<T>::~Serializer() {
DataBase::Serializer<T>::~Serializer() {
buffer.close();
}
template<class T>
MDB_val Core::DataBase::Serializer<T>::setData(const T& value) {
MDB_val DataBase::Serializer<T>::setData(const T& value) {
clear();
_setValue(value);
return getValue();
_setData(value);
return getData();
}
template<class T>
void Core::DataBase::Serializer<T>::_setData(const T& value) {
T DataBase::Serializer<T>::deserialize(const MDB_val& value) {
clear();
bytes.setRawData((char*)value.mv_data, value.mv_size);
T result;
stream >> result;
return result;
}
template<class T>
void DataBase::Serializer<T>::_setData(const T& value) {
stream << value;
}
template<class T>
void Core::DataBase::Serializer<T>::clear() {
void DataBase::Serializer<T>::clear() {
if (buffer.pos() > 0) {
buffer.seek(0);
}
}
template<class T>
MDB_val Core::DataBase::Serializer<T>::getData() {
MDB_val DataBase::Serializer<T>::getData() {
MDB_val val;
val.mv_size = buffer.pos();
val.mv_data = (uint8_t*)bytes.data();
val.mv_data = (char*)bytes.data();
return val;
}
#endif //CORE_DATABASE_SERIALIZER_HPP

50
serializer_uint32.hpp Normal file
View File

@ -0,0 +1,50 @@
// 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_DATABASE_SERIALIZER_UINT32_HPP
#define CORE_DATABASE_SERIALIZER_UINT32_HPP
template<>
class DataBase::Serializer<uint32_t>
{
public:
Serializer():value(0) {};
Serializer(const uint32_t& p_value):value(p_value) {};
~Serializer() {};
uint32_t deserialize(const MDB_val& data) {
std::memcpy(&value, data.mv_data, 4);
return value;
};
MDB_val setData(const uint32_t& data) {
value = data;
return getData();
};
MDB_val getData() {
MDB_val result;
result.mv_data = &value,
result.mv_size = 4;
return result;
};
void clear() {}; //not possible;
private:
uint32_t value;
};
#endif //CORE_DATABASE_SERIALIZER_UINT32_HPP

View File

@ -16,11 +16,11 @@
#include "table.h"
Core::DataBase::_Table::_Table(const std::string& p_name, DataBase* parent):
DataBase::_Table::_Table(const std::string& p_name, DataBase* parent):
dbi(),
db(parent),
name(p_name)
{
}
Core::DataBase::_Table::~_Table() {}
DataBase::_Table::~_Table() {}

22
table.h
View File

@ -20,17 +20,23 @@
#include "database.h"
#include "serializer.h"
namespace Core {
class DataBase::_Table {
public:
_Table(const std::string& name, DataBase* parent);
virtual ~_Table();
virtual int createTable(MDB_txn * transaction) = 0;
public:
MDB_dbi dbi;
DataBase* db;
const std::string name;
protected:
template <class T>
int makeTable(MDB_txn* transaction);
template <class T>
static std::string toString(const T& value);
};
template <class K, class V>
@ -47,16 +53,12 @@ public:
V getRecord(const K& key) const;
private:
Serializer<K> keySerializer;
Serializer<V> valueSerializer;
Serializer<K>* keySerializer;
Serializer<V>* valueSerializer;
int createTable(MDB_txn* transaction) override;
};
}
namespace std {
std::string to_string(const QString& str);
}
#include "table.hpp"
#endif // CORE_TABLE_H

View File

@ -20,26 +20,28 @@
#include "table.h"
#include "exceptions.h"
template<typename K, typename V>
Core::DataBase::Table<K, V>::Table(const std::string& p_name, Core::DataBase* parent):
template<class K, class V>
DataBase::Table<K, V>::Table(const std::string& p_name, DataBase* parent):
_Table(p_name, parent),
keySerializer(),
valueSerializer()
keySerializer(new Serializer<K>()),
valueSerializer(new Serializer<V>())
{
}
template<typename K, typename V>
Core::DataBase::Table<K, V>::~Table() {
template<class K, class V>
DataBase::Table<K, V>::~Table() {
delete valueSerializer;
delete keySerializer;
}
template<typename K, typename V>
void Core::DataBase::Table<K, V>::addRecord(const K& key, const V& value) {
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_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData = valueSerializer->setData(value);
MDB_txn *txn;
mdb_txn_begin(db->environment, NULL, 0, &txn);
int rc;
@ -47,7 +49,7 @@ void Core::DataBase::Table<K, V>::addRecord(const K& key, const V& value) {
if (rc != 0) {
mdb_txn_abort(txn);
if (rc == MDB_KEYEXIST) {
throw Exist(std::to_string(key), db->name, name);
throw Exist(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
@ -58,14 +60,14 @@ void Core::DataBase::Table<K, V>::addRecord(const K& key, const V& value) {
template<typename K, typename V>
void Core::DataBase::Table<K, V>::changeRecord(const K& key, const V& value) {
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_val lmdbKey = keySerializer->setData(key);
MDB_val lmdbData = valueSerializer->setData(value);
MDB_txn *txn;
mdb_txn_begin(db->environment, NULL, 0, &txn);
int rc;
@ -80,13 +82,13 @@ void Core::DataBase::Table<K, V>::changeRecord(const K& key, const V& value) {
}
}
template<typename K, typename V>
V Core::DataBase::Table<K, V>::getRecord(const K& key) const {
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 lmdbKey = keySerializer->setData(key);
MDB_val lmdbData;
MDB_txn *txn;
@ -96,26 +98,25 @@ V Core::DataBase::Table<K, V>::getRecord(const K& key) const {
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw NotFound(std::to_string(key), db->name, name);
throw NotFound(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
} else {
V value;
lmdbData >> value;
V value = valueSerializer->deserialize(lmdbData);
mdb_txn_abort(txn);
return value;
}
}
template<typename K, typename V>
void Core::DataBase::Table<K, V>::removeRecord(const K& key) {
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_val lmdbKey = keySerializer->setData(key);
MDB_txn *txn;
int rc;
@ -124,7 +125,7 @@ void Core::DataBase::Table<K, V>::removeRecord(const K& key) {
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw NotFound(std::to_string(key), db->name, name);
throw NotFound(toString(key), db->name, name);
} else {
throw Unknown(db->name, mdb_strerror(rc), name);
}
@ -133,8 +134,29 @@ void Core::DataBase::Table<K, V>::removeRecord(const K& key) {
}
}
std::string std::to_string(const QString& str) {
return str.toStdString();
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<uint32_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();
}
#endif //CORE_TABLE_HPP