From c3139974f1b40a9caf8d5e6aabcf9b19e259e13b Mon Sep 17 00:00:00 2001 From: blue Date: Mon, 5 Sep 2022 23:25:39 +0300 Subject: [PATCH] Temp ideas --- CMakeLists.txt | 2 + database.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++ database.h | 68 +++++++++++++++++++++++++++++++ exceptions.h | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ table.cpp | 25 ++++++++++++ table.h | 52 ++++++++++++++++++++++++ table.hpp | 53 +++++++++++++++++++++++++ 7 files changed, 404 insertions(+) create mode 100644 database.cpp create mode 100644 database.h create mode 100644 exceptions.h create mode 100644 table.cpp create mode 100644 table.h create mode 100644 table.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f462b3b..2c18426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ endif () add_executable(storage main.cpp exception.cpp + table.cpp + database.cpp ) diff --git a/database.cpp b/database.cpp new file mode 100644 index 0000000..0e9344c --- /dev/null +++ b/database.cpp @@ -0,0 +1,98 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#include "database.h" +#include "exceptions.h" +#include "table.h" + +Core::DataBase::DataBase(const QString& p_name, uint16_t mapSize): + name(p_name.toStdString()), + opened(false), + size(mapSize), + environment(), + tables() +{ +} + +Core::DataBase::~DataBase() +{ + close(); + for (const std::pair& pair : tables) { + delete pair.second; + } +} + +void Core::DataBase::close() +{ + if (opened) { + for (const std::pair& pair : tables) { + _Table* table = pair.second; + mdb_dbi_close(environment, table->dbi); + } + mdb_env_close(environment); + opened = false; + } +} + +void Core::DataBase::open() +{ + if (!opened) { + mdb_env_create(&environment); + QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); + path += "/" + getName(); + QDir cache(path); + + if (!cache.exists()) { + bool res = cache.mkpath(path); + if (!res) { + throw Directory(path.toStdString()); + } + } + + mdb_env_set_maxdbs(environment, tables.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& pair : tables) { + _Table* table = pair.second; + int rc = mdb_dbi_open(txn, pair.first.c_str(), MDB_CREATE, &table->dbi); + if (rc) { + throw Unknown(name, mdb_strerror(rc)); + } + + } + mdb_txn_commit(txn); + opened = true; + } +} + +QString Core::DataBase::getName() const +{ + return QString::fromStdString(name); +} + +template +Core::DataBase::Table* Core::DataBase::addTable(const QString& p_name) { + if (opened) { + throw Core::DataBase::Opened(name); + } + Core::DataBase::Table* table = new Core::DataBase::Table(); + tables.insert(std::make_pair(p_name.toStdString(), table)); + return table; +} diff --git a/database.h b/database.h new file mode 100644 index 0000000..a407531 --- /dev/null +++ b/database.h @@ -0,0 +1,68 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#ifndef CORE_DATABASE_H +#define CORE_DATABASE_H + +#include +#include + +#include +#include +#include +#include + +namespace Core { + +class DataBase +{ + class _Table; +public: + template + class Table; + + DataBase(const QString& name, uint16_t mapSize = 10); + ~DataBase(); + + void open(); + void close(); + QString getName() const; + + template + Table* addTable(const QString& name); + +public: + //exceptions + class Directory; + class Closed; + class Opened; + class NotFound; + class Empty; + class Exist; + class NoAvatar; + class Unknown; + +private: + std::string name; + bool opened; + uint16_t size; + MDB_env* environment; + std::map tables; +}; + +} + +#endif // CORE_DATABASE_H diff --git a/exceptions.h b/exceptions.h new file mode 100644 index 0000000..82a0fce --- /dev/null +++ b/exceptions.h @@ -0,0 +1,106 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#ifndef CORE_DATABASE_EXCEPTIONS_H +#define CORE_DATABASE_EXCEPTIONS_H + +#include "exception.h" +#include "database.h" + +namespace Core { + +class DataBase::Directory: public Utils::Exception { +public: + Directory(const std::string& p_path):Exception(), path(p_path){} + + std::string getMessage() const{return "Can't create directory for database at " + path;} +private: + std::string path; +}; + +class DataBase::Closed : public Utils::Exception { +public: + Closed(const std::string& op, const std::string& acc):Exception(), operation(op), account(acc){} + + std::string getMessage() const{return "An attempt to perform operation " + operation + " on closed archive for " + account;} +private: + std::string operation; + std::string account; +}; + +class DataBase::Opened : public Utils::Exception { +public: + Opened(const std::string& tn):Exception(), tableName(tn){} + + std::string getMessage() const{return "An attempt to add table " + tableName + " but it's impossible to do if the DataBase is already opened";} +private: + std::string tableName; +}; + +class DataBase::NotFound : public Utils::Exception { +public: + NotFound(const std::string& k, const std::string& acc):Exception(), key(k), account(acc){} + + std::string getMessage() const{return "Element for id " + key + " wasn't found in database " + account;} +private: + std::string key; + std::string account; +}; + +class DataBase::Empty : public Utils::Exception { +public: + Empty(const std::string& acc):Exception(), account(acc){} + + std::string getMessage() const{return "An attempt to read ordered elements from database " + account + " but it's empty";} +private: + std::string account; +}; + +class DataBase::Exist : public Utils::Exception { +public: + Exist(const std::string& acc, const std::string& p_key):Exception(), account(acc), key(p_key){} + + std::string getMessage() const{return "An attempt to insert element " + key + " to database " + account + " but it already has an element with given id";} +private: + std::string account; + std::string key; +}; + +class DataBase::NoAvatar : public Utils::Exception { +public: + NoAvatar(const std::string& el, const std::string& res):Exception(), element(el), resource(res){ + if (resource.size() == 0) { + resource = "for himself"; + } + } + + std::string getMessage() const{return "Element " + element + " has no avatar for " + resource ;} +private: + std::string element; + std::string resource; +}; + +class DataBase::Unknown : public Utils::Exception { +public: + Unknown(const std::string& acc, const std::string& message):Exception(), account(acc), msg(message){} + + std::string getMessage() const{return "Unknown error on database " + account + ": " + msg;} +private: + std::string account; + std::string msg; +}; +} +#endif //CORE_DATABASE_EXCEPTIONS_H diff --git a/table.cpp b/table.cpp new file mode 100644 index 0000000..adc2265 --- /dev/null +++ b/table.cpp @@ -0,0 +1,25 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#include "table.h" + +Core::DataBase::_Table::_Table(DataBase* parent): + dbi(), + db(parent) +{ +} + +Core::DataBase::_Table::~_Table() {} diff --git a/table.h b/table.h new file mode 100644 index 0000000..8a39d05 --- /dev/null +++ b/table.h @@ -0,0 +1,52 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#ifndef CORE_TABLE_H +#define CORE_TABLE_H + +#include "database.h" + +namespace Core { + +class DataBase::_Table { +public: + _Table(DataBase* parent); + virtual ~_Table(); + +public: + MDB_dbi dbi; + DataBase* db; +}; + +template +class DataBase::Table : private DataBase::_Table { + friend class DataBase; +private: + Table(DataBase* parent); + ~Table() override; + +public: + void addRecord(const K& key, const V& value); + void changeRecord(const K& key, const V& value); + void removeRecord(const K& key); + V getRecord(const K& key) const; +}; + +} + +#include "table.hpp" + +#endif // CORE_TABLE_H diff --git a/table.hpp b/table.hpp new file mode 100644 index 0000000..d900940 --- /dev/null +++ b/table.hpp @@ -0,0 +1,53 @@ +// Squawk messenger. +// Copyright (C) 2019 Yury Gubich +// +// 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 . + +#ifndef CORE_TABLE_HPP +#define CORE_TABLE_HPP + +#include "table.h" + + +template +void Core::DataBase::Table::addRecord(const K& key, const V& value) { + if (!db->opened) { + throw Closed("addRecord", db->name); + } + QByteArray ba; + QDataStream ds(&ba, QIODevice::WriteOnly); + ds << value; + + MDB_val lmdbKey, lmdbData; + lmdbKey << key; + + lmdbData.mv_size = ba.size(); + lmdbData.mv_data = (uint8_t*)ba.data(); + 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(db->name, std::to_string(key)); + } else { + throw Unknown(db->name, mdb_strerror(rc)); + } + } else { + mdb_txn_commit(txn); + } +} + +#endif //CORE_TABLE_HPP