diff --git a/cache.h b/cache.h index 6432347..9ba0a3d 100644 --- a/cache.h +++ b/cache.h @@ -25,27 +25,31 @@ template class DataBase::Cache : public DataBase::Table { friend class DataBase; - enum class Mode { - nothing, - size, - full + enum class Mode { //it's a cache state when we: + nothing, // - know nothing about records in database on disk + size, // - know just an amount of records + full // - shure that our cache is equal to the database on disk }; protected: Cache(const std::string& name, DataBase* parent); ~Cache() override; +private: + void handleMode() const; + 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(); + virtual uint32_t count() const override; + virtual void drop() override; protected: - Mode mode; + Mode* mode; std::map* cache; std::set* abscent; + uint32_t* sizeDifference; }; #include "cache.hpp" diff --git a/cache.hpp b/cache.hpp index 47a678a..fc05ab6 100644 --- a/cache.hpp +++ b/cache.hpp @@ -23,14 +23,19 @@ template DataBase::Cache::Cache(const std::string& p_name, DataBase* parent): DataBase::Table(p_name, parent), - mode(Mode::nothing), + mode(new Mode), cache(new std::map()), - abscent(new std::set()) + abscent(new std::set()), + sizeDifference(new uint32_t) { + *mode = Mode::nothing; + *sizeDifference = 0; } template DataBase::Cache::~Cache() { + delete sizeDifference; + delete mode; delete cache; delete abscent; } @@ -50,24 +55,37 @@ void DataBase::Cache::addRecord(const K& key, const V& 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 { + if (*mode == Mode::full) { + typename std::map::iterator itr = cache->find(key); + if (itr != cache->end()) { + throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } Table::changeRecord(key, value); itr->second = value; - } catch (const NotFound& error) { - abscent->insert(key); - throw error; + } else { + if (abscent->count(key) > 0) { + throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); + } + + try { + Table::changeRecord(key, value); + typename std::map::iterator itr = cache->find(key); + if (itr != cache->end()) { + itr->second = value; + } else { + cache->insert(std::make_pair(key, value)); + handleMode(); + } + } catch (const NotFound& error) { + abscent->insert(key); + throw error; + } } } @@ -82,13 +100,14 @@ V DataBase::Cache::getRecord(const K& key) const { return itr->second; } - if (abscent->count(key) == 0) { + if (*mode == Mode::full || 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)); + handleMode(); return value; } catch (const NotFound& error) { abscent->insert(key); @@ -107,8 +126,55 @@ void DataBase::Cache::removeRecord(const K& key) { throw NotFound(DataBase::_Table::toString(key), DataBase::Table::db->name, DataBase::Table::name); } - cache->erase(key); Table::removeRecord(key); + if (cache->erase(key) == 0) { //if it was not cached and we are now in size mode then the sizeDifference would decrease + handleMode(); + } + if (*mode != Mode::full) { + abscent->insert(key); + } +} + +template +uint32_t DataBase::Cache::count() const { + switch (*mode) { + case Mode::nothing: + { + uint32_t sz = DataBase::Table::count(); + *sizeDifference = sz - cache->size(); + if (sz == 0) { + *mode = Mode::full; + abscent->clear(); + } else { + *mode = Mode::size; + } + return sz; + } + case Mode::size: + return cache->size() + *sizeDifference; + case Mode::full: + return cache->size(); + } +} + +template +void DataBase::Cache::handleMode() const { + if (*mode == Mode::size) { + --(*sizeDifference); + if (*sizeDifference == 0) { + *mode = Mode::full; + abscent->clear(); + } + } +} + +template +void DataBase::Cache::drop() { + DataBase::Table::drop(); + cache->clear(); + abscent->clear(); + *mode = Mode::full; + *sizeDifference = 0; } #endif //DATABASE_CACHE_HPP