From a613eaed2731a58e1b78f3faff7d539ad002c11d Mon Sep 17 00:00:00 2001 From: blue Date: Tue, 20 Sep 2022 20:16:48 +0300 Subject: [PATCH] first thoughts about cache --- CMakeLists.txt | 2 + cache.h | 53 +++++++++++++++++++++++ cache.hpp | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ database.h | 24 +++++++++++ table.h | 12 +++--- test/basic.cpp | 7 ++- 6 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 cache.h create mode 100644 cache.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cd7f21..26e1b4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,8 @@ set(HEADERS exceptions.h table.h table.hpp + cache.h + cache.hpp serializer.h serializer.hpp serializer_uint8.hpp diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..6432347 --- /dev/null +++ b/cache.h @@ -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 DATABASE_CACHE_H +#define DATABASE_CACHE_H + +#include "database.h" +#include "table.h" +#include +#include + +template +class DataBase::Cache : public DataBase::Table { + friend class DataBase; + enum class Mode { + nothing, + size, + full + }; +protected: + Cache(const std::string& name, DataBase* parent); + ~Cache() override; + +public: + virtual void addRecord(const K& key, const V& value) override; + virtual void changeRecord(const K& key, const V& value) override; + virtual void removeRecord(const K& key) override; + virtual V getRecord(const K& key) const override; + //virtual uint32_t count() const; + //virtual void drop(); + +protected: + Mode mode; + std::map* cache; + std::set* abscent; +}; + +#include "cache.hpp" + +#endif // DATABASE_CACHE_H diff --git a/cache.hpp b/cache.hpp new file mode 100644 index 0000000..47a678a --- /dev/null +++ b/cache.hpp @@ -0,0 +1,114 @@ +// 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 DATABASE_CACHE_HPP +#define DATABASE_CACHE_HPP + +#include "cache.h" +#include "exceptions.h" + +template +DataBase::Cache::Cache(const std::string& p_name, DataBase* parent): + DataBase::Table(p_name, parent), + mode(Mode::nothing), + cache(new std::map()), + abscent(new std::set()) +{ +} + +template +DataBase::Cache::~Cache() { + delete cache; + delete abscent; +} + +template +void DataBase::Cache::addRecord(const K& key, const V& value) { + if (!DataBase::Table::db->opened) { + throw Closed("addRecord", DataBase::Table::db->name, DataBase::Table::name); + } + + if (cache->count(key) > 0) { + throw Exist(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } + + Table::addRecord(key, value); + cache->insert(std::make_pair(key, value)); +} + + + +template +void DataBase::Cache::changeRecord(const K& key, const V& value) { + if (!DataBase::Table::db->opened) { + throw Closed("changeRecord", DataBase::Table::db->name, DataBase::Table::name); + } + + typename std::map::iterator itr = cache->find(key); + if (itr == cache->end() || abscent->count(key) > 0) { + throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } + + try { + Table::changeRecord(key, value); + itr->second = value; + } catch (const NotFound& error) { + abscent->insert(key); + throw error; + } +} + +template +V DataBase::Cache::getRecord(const K& key) const { + if (!DataBase::Table::db->opened) { + throw Closed("getRecord", DataBase::Table::db->name, DataBase::Table::name); + } + + typename std::map::const_iterator itr = cache->find(key); + if (itr != cache->end()) { + return itr->second; + } + + if (abscent->count(key) == 0) { + throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } + + try { + V value = Table::getRecord(key); + cache->insert(std::make_pair(key, value)); + return value; + } catch (const NotFound& error) { + abscent->insert(key); + throw error; + } +} + +template +void DataBase::Cache::removeRecord(const K& key) { + if (!DataBase::Table::db->opened) { + throw Closed("removeRecord", DataBase::Table::db->name, DataBase::Table::name); + } + + typename std::pair::const_iterator, bool> pair = abscent->insert(key); + if (!pair.second) { + throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } + + cache->erase(key); + Table::removeRecord(key); +} + +#endif //DATABASE_CACHE_HPP diff --git a/database.h b/database.h index 167fc95..98ce4cf 100644 --- a/database.h +++ b/database.h @@ -33,6 +33,8 @@ class DataBase public: template class Table; + template + class Cache; DataBase(const QString& name, uint16_t mapSize = 10); ~DataBase(); @@ -47,9 +49,15 @@ public: template Table* addTable(const std::string& name); + template + Cache* addCache(const std::string& name); + template Table* getTable(const std::string& name); + template + Cache* getCache(const std::string& name); + public: //exceptions class Exception; @@ -80,9 +88,25 @@ DataBase::Table* DataBase::addTable(const std::string& p_name) { return table; } +template +DataBase::Cache * DataBase::addCache(const std::string& p_name) { + if (opened) { + throw Opened(name, "add cache " + p_name); + } + DataBase::Cache* cache = new DataBase::Cache(p_name, this); + tables.insert(std::make_pair(p_name, (_Table*)cache)); + return cache; +} + template DataBase::Table* DataBase::getTable(const std::string& p_name) { return static_cast*>(tables.at(p_name)); } +template +DataBase::Cache* DataBase::getCache(const std::string& p_name) { + return static_cast*>(tables.at(p_name)); +} + + #endif // CORE_DATABASE_H diff --git a/table.h b/table.h index 082518c..51d2335 100644 --- a/table.h +++ b/table.h @@ -49,17 +49,17 @@ protected: template class DataBase::Table : public DataBase::_Table { friend class DataBase; -private: +protected: Table(const std::string& name, 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; + virtual void addRecord(const K& key, const V& value); + virtual void changeRecord(const K& key, const V& value); + virtual void removeRecord(const K& key); + virtual V getRecord(const K& key) const; -private: +protected: Serializer* keySerializer; Serializer* valueSerializer; diff --git a/test/basic.cpp b/test/basic.cpp index e68f521..6b39acf 100644 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -2,6 +2,7 @@ #include "database.h" #include "table.h" +#include "cache.h" #include @@ -10,7 +11,8 @@ protected: DataBaseTest(): ::testing::Test(), t1(db->getTable("table1")), - t2(db->getTable("table2")) {} + t2(db->getTable("table2")), + c1(db->getCache("cache1")) {} ~DataBaseTest() {} @@ -19,6 +21,7 @@ protected: db = new DataBase("testBase"); db->addTable("table1"); db->addTable("table2"); + db->addCache("cache1"); } } @@ -33,6 +36,7 @@ protected: DataBase::Table* t1; DataBase::Table* t2; + DataBase::Cache* c1; }; @@ -120,6 +124,7 @@ TEST_F(DataBaseTest, Persistence) { db = new DataBase("testBase"); t1 = db->addTable("table1"); t2 = db->addTable("table2"); + c1 = db->addCache("cache1"); db->open(); EXPECT_EQ(t1->getRecord(3), 15);