2023-03-23 17:27:46 +00:00
|
|
|
/*
|
|
|
|
* LMDB Abstraction Layer.
|
|
|
|
* Copyright (C) 2023 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/>.
|
|
|
|
*/
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-03-21 11:05:54 +00:00
|
|
|
#ifndef LMDBAL_CACHE_HPP
|
|
|
|
#define LMDBAL_CACHE_HPP
|
2022-09-20 17:16:48 +00:00
|
|
|
|
|
|
|
#include "cache.h"
|
|
|
|
#include "exceptions.h"
|
|
|
|
|
2023-04-12 15:36:33 +00:00
|
|
|
/**
|
|
|
|
* \class LMDBAL::Cache
|
|
|
|
* \brief Storage with additional caching in std::map
|
|
|
|
*
|
|
|
|
* \tparam K type of the keys of the cache
|
|
|
|
* \tparam V type of the values of the cache
|
|
|
|
*
|
|
|
|
* You can receive an instance of this class calling LMDBAL::Base::addCache(const std::string&)
|
|
|
|
* if the database is yet closed and you're defining the storages you're going to need.
|
|
|
|
* Or you can call LMDBAL::Base::getCache(const std::string&) if you didn't save a pointer to the cache at first
|
|
|
|
*
|
|
|
|
* You are not supposed to instantiate or destory instances of this class yourself!
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Creates a cache
|
|
|
|
*
|
|
|
|
* \param[in] _name - name of the new cache
|
|
|
|
* \param[in] parent - parent database pointed (borrowed)
|
|
|
|
*/
|
2022-09-20 17:16:48 +00:00
|
|
|
template<class K, class V>
|
2023-04-12 15:36:33 +00:00
|
|
|
LMDBAL::Cache<K, V>::Cache(const std::string& _name, Base* parent):
|
|
|
|
Storage<K, V>(_name, parent),
|
2023-08-05 20:13:43 +00:00
|
|
|
mode(Mode::nothing),
|
2022-09-20 17:16:48 +00:00
|
|
|
cache(new std::map<K, V>()),
|
2022-10-08 16:45:07 +00:00
|
|
|
abscent(new std::set<K>()),
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference(0),
|
|
|
|
transactionCache(new TransactionCache) {}
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-04-12 15:36:33 +00:00
|
|
|
/**
|
|
|
|
* \brief Destroys a cache
|
|
|
|
*/
|
2022-09-20 17:16:48 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
LMDBAL::Cache<K, V>::~Cache() {
|
2023-04-03 18:48:13 +00:00
|
|
|
delete transactionCache;
|
2022-09-20 17:16:48 +00:00
|
|
|
delete cache;
|
|
|
|
delete abscent;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
void LMDBAL::Cache<K, V>::addRecord(const K& key, const V& value) {
|
|
|
|
iStorage::ensureOpened(iStorage::addRecordMethodName);
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-03-20 15:37:13 +00:00
|
|
|
if (cache->count(key) > 0)
|
2023-03-21 11:05:54 +00:00
|
|
|
iStorage::throwDuplicate(iStorage::toString(key));
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-03-20 15:37:13 +00:00
|
|
|
Storage<K, V>::addRecord(key, value);
|
2023-04-03 18:48:13 +00:00
|
|
|
handleAddRecord(key, value);
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::addRecord(const K& key, const V& value, TransactionID txn) {
|
|
|
|
iStorage::ensureOpened(iStorage::addRecordMethodName);
|
|
|
|
|
|
|
|
if (cache->count(key) > 0)
|
|
|
|
iStorage::throwDuplicate(iStorage::toString(key));
|
|
|
|
|
|
|
|
Storage<K, V>::addRecord(key, value, txn);
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
std::pair<K, V>* pair = new std::pair<K, V>(key, value);
|
|
|
|
tc->second.emplace_back(Operation::add, pair);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleAddRecord(const K& key, const V& value) {
|
2022-09-20 17:16:48 +00:00
|
|
|
cache->insert(std::make_pair(key, value));
|
2022-12-13 22:57:49 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2022-12-13 22:57:49 +00:00
|
|
|
abscent->erase(key);
|
2022-09-20 17:16:48 +00:00
|
|
|
}
|
|
|
|
|
2022-12-13 22:57:49 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
bool LMDBAL::Cache<K, V>::forceRecord(const K& key, const V& value) {
|
|
|
|
iStorage::ensureOpened(iStorage::forceRecordMethodName);
|
2022-12-13 22:57:49 +00:00
|
|
|
|
2023-03-20 15:37:13 +00:00
|
|
|
bool added = Storage<K, V>::forceRecord(key, value);
|
2023-04-03 18:48:13 +00:00
|
|
|
handleForceRecord(key, value, added);
|
|
|
|
|
|
|
|
return added;
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
bool LMDBAL::Cache<K, V>::forceRecord(const K& key, const V& value, TransactionID txn) {
|
|
|
|
iStorage::ensureOpened(iStorage::forceRecordMethodName);
|
|
|
|
|
|
|
|
bool added = Storage<K, V>::forceRecord(key, value, txn);
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
std::tuple<bool, K, V>* t = new std::tuple<bool, K, V>(added, key, value);
|
|
|
|
tc->second.emplace_back(Operation::force, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return added;
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleForceRecord(const K& key, const V& value, bool added) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full) {
|
2022-12-13 22:57:49 +00:00
|
|
|
(*cache)[key] = value;
|
|
|
|
} else {
|
2023-03-20 15:37:13 +00:00
|
|
|
if (added)
|
2022-12-13 22:57:49 +00:00
|
|
|
abscent->erase(key);
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
std::pair<typename std::map<K, V>::iterator, bool> result =
|
|
|
|
cache->insert(std::make_pair(key, value));
|
2023-03-20 15:37:13 +00:00
|
|
|
if (!result.second)
|
2022-12-13 22:57:49 +00:00
|
|
|
result.first->second = value;
|
2023-03-20 15:37:13 +00:00
|
|
|
else if (!added) //this way database had value but cache didn't, so, need to decrease sizeDifference
|
2022-12-13 22:57:49 +00:00
|
|
|
handleMode();
|
|
|
|
}
|
|
|
|
}
|
2022-09-20 17:16:48 +00:00
|
|
|
|
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
void LMDBAL::Cache<K, V>::changeRecord(const K& key, const V& value) {
|
|
|
|
iStorage::ensureOpened(iStorage::changeRecordMethodName);
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full) {
|
2022-10-08 16:45:07 +00:00
|
|
|
typename std::map<K, V>::iterator itr = cache->find(key);
|
2023-03-20 15:37:13 +00:00
|
|
|
if (itr == cache->end())
|
2023-03-21 11:05:54 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2023-03-20 15:37:13 +00:00
|
|
|
|
|
|
|
Storage<K, V>::changeRecord(key, value);
|
2022-09-20 17:16:48 +00:00
|
|
|
itr->second = value;
|
2022-10-08 16:45:07 +00:00
|
|
|
} else {
|
2023-03-20 15:37:13 +00:00
|
|
|
if (abscent->count(key) > 0)
|
2023-03-21 11:05:54 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2022-10-08 16:45:07 +00:00
|
|
|
|
|
|
|
try {
|
2023-03-20 15:37:13 +00:00
|
|
|
Storage<K, V>::changeRecord(key, value);
|
2023-04-05 23:01:24 +00:00
|
|
|
typename std::pair<typename std::map<K, V>::iterator, bool> res =
|
|
|
|
cache->insert(std::make_pair(key, value));
|
2023-03-20 15:37:13 +00:00
|
|
|
if (!res.second)
|
2022-12-18 14:45:12 +00:00
|
|
|
res.first->second = value;
|
2023-03-20 15:37:13 +00:00
|
|
|
else
|
2022-10-08 16:45:07 +00:00
|
|
|
handleMode();
|
|
|
|
} catch (const NotFound& error) {
|
|
|
|
abscent->insert(key);
|
|
|
|
throw error;
|
|
|
|
}
|
2022-09-20 17:16:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::changeRecord(const K& key, const V& value, TransactionID txn) {
|
|
|
|
iStorage::ensureOpened(iStorage::changeRecordMethodName);
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full) {
|
2023-04-04 23:27:31 +00:00
|
|
|
typename std::map<K, V>::iterator itr = cache->find(key);
|
|
|
|
if (itr == cache->end())
|
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
|
|
|
|
|
|
|
Storage<K, V>::changeRecord(key, value, txn);
|
|
|
|
} else {
|
|
|
|
if (abscent->count(key) > 0)
|
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Storage<K, V>::changeRecord(key, value, txn);
|
|
|
|
} catch (const NotFound& error) {
|
|
|
|
abscent->insert(key);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
std::pair<K, V>* pair = new std::pair<K, V>(key, value);
|
|
|
|
tc->second.emplace_back(Operation::add, pair);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleChangeRecord(const K& key, const V& value) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full) {
|
2023-04-03 18:48:13 +00:00
|
|
|
cache->at(key) = value;
|
|
|
|
} else {
|
2023-04-05 23:01:24 +00:00
|
|
|
typename std::pair<typename std::map<K, V>::iterator, bool> res =
|
|
|
|
cache->insert(std::make_pair(key, value));
|
2023-04-03 18:48:13 +00:00
|
|
|
if (!res.second)
|
|
|
|
res.first->second = value;
|
|
|
|
else
|
|
|
|
handleMode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-20 17:16:48 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
V LMDBAL::Cache<K, V>::getRecord(const K& key) const {
|
|
|
|
iStorage::ensureOpened(iStorage::getRecordMethodName);
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
V value;
|
|
|
|
Cache<K, V>::getRecord(key, value);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::getRecord(const K& key, V& out) const {
|
|
|
|
iStorage::ensureOpened(iStorage::getRecordMethodName);
|
|
|
|
|
2022-09-20 17:16:48 +00:00
|
|
|
typename std::map<K, V>::const_iterator itr = cache->find(key);
|
2023-04-05 23:01:24 +00:00
|
|
|
if (itr != cache->end()) {
|
|
|
|
out = itr->second;
|
|
|
|
return;
|
|
|
|
}
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full || abscent->count(key) != 0)
|
2023-03-21 11:05:54 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2022-09-20 17:16:48 +00:00
|
|
|
|
|
|
|
try {
|
2023-04-05 23:01:24 +00:00
|
|
|
Storage<K, V>::getRecord(key, out);
|
|
|
|
cache->insert(std::make_pair(key, out));
|
2022-10-08 16:45:07 +00:00
|
|
|
handleMode();
|
2023-04-05 23:01:24 +00:00
|
|
|
return;
|
2022-09-20 17:16:48 +00:00
|
|
|
} catch (const NotFound& error) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2022-12-15 17:29:49 +00:00
|
|
|
abscent->insert(key);
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2022-09-20 17:16:48 +00:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
V LMDBAL::Cache<K, V>::getRecord(const K& key, TransactionID txn) const {
|
|
|
|
iStorage::ensureOpened(iStorage::getRecordMethodName);
|
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
V value;
|
|
|
|
Cache<K, V>::getRecord(key, value, txn);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::getRecord(const K& key, V& out, TransactionID txn) const {
|
|
|
|
iStorage::ensureOpened(iStorage::getRecordMethodName);
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
//if there are any changes made within this transaction
|
|
|
|
//I will be able to see them among pending changes
|
|
|
|
//so, I'm going to go through them in reverse order
|
|
|
|
//and check every key. If it has anything to do this requested key
|
|
|
|
//there is a way to tell...
|
2023-04-05 23:01:24 +00:00
|
|
|
bool currentTransaction = false;
|
2023-04-04 23:27:31 +00:00
|
|
|
typename TransactionCache::const_iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
2023-04-05 23:01:24 +00:00
|
|
|
currentTransaction = true;
|
2023-04-04 23:27:31 +00:00
|
|
|
const Queue& queue = tc->second;
|
|
|
|
for (typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
|
|
|
|
const Entry& entry = *i;
|
|
|
|
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add:
|
2023-04-05 23:01:24 +00:00
|
|
|
if (static_cast<std::pair<K, V>*>(entry.second)->first == key) {
|
|
|
|
out = static_cast<std::pair<K, V>*>(entry.second)->second;
|
|
|
|
return;
|
|
|
|
}
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::remove:
|
2023-04-05 23:01:24 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::change:
|
2023-04-05 23:01:24 +00:00
|
|
|
if (static_cast<std::pair<K, V>*>(entry.second)->first == key) {
|
|
|
|
out = static_cast<std::pair<K, V>*>(entry.second)->second;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::force:
|
2023-04-05 23:01:24 +00:00
|
|
|
if (std::get<1>(*static_cast<std::tuple<bool, K, V>*>(entry.second)) == key) {
|
|
|
|
out = std::get<2>(*static_cast<std::tuple<bool, K, V>*>(entry.second));
|
|
|
|
return;
|
|
|
|
}
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::drop:
|
2023-04-05 23:01:24 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::replace: {
|
|
|
|
std::map<K, V>* newMap = static_cast<std::map<K, V>*>(entry.second);
|
|
|
|
typename std::map<K, V>::const_iterator vitr = newMap->find(key);
|
2023-04-05 23:01:24 +00:00
|
|
|
if (vitr != newMap->end()) {
|
|
|
|
out = vitr->second;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
|
|
|
}
|
2023-04-04 23:27:31 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Operation::addMany: {
|
2023-04-05 23:01:24 +00:00
|
|
|
const std::tuple<bool, SizeType, std::map<K, V>>& tuple =
|
|
|
|
*static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second);
|
2023-04-04 23:27:31 +00:00
|
|
|
const std::map<K, V>& newElements = std::get<2>(tuple);
|
|
|
|
typename std::map<K, V>::const_iterator vitr = newElements.find(key);
|
|
|
|
if (vitr != newElements.end()) {
|
2023-04-05 23:01:24 +00:00
|
|
|
out = vitr->second;
|
|
|
|
return;
|
2023-04-04 23:27:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//... but if nothing was found or if the transaction is not the one
|
|
|
|
//which caused the changes i just need to check it among local cache
|
|
|
|
|
|
|
|
typename std::map<K, V>::const_iterator itr = cache->find(key);
|
2023-04-05 23:01:24 +00:00
|
|
|
if (itr != cache->end()) {
|
|
|
|
out = itr->second;
|
|
|
|
return;
|
2023-04-04 23:27:31 +00:00
|
|
|
}
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full || abscent->count(key) != 0)
|
2023-04-05 23:01:24 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
try {
|
2023-04-05 23:01:24 +00:00
|
|
|
Storage<K, V>::getRecord(key, out, txn);
|
|
|
|
if (!currentTransaction) {
|
|
|
|
cache->insert(std::make_pair(key, out));
|
|
|
|
handleMode();
|
|
|
|
}
|
|
|
|
return;
|
2023-04-04 23:27:31 +00:00
|
|
|
} catch (const NotFound& error) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (!currentTransaction && mode != Mode::full)
|
2023-04-04 23:27:31 +00:00
|
|
|
abscent->insert(key);
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-15 17:29:49 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
bool LMDBAL::Cache<K, V>::checkRecord(const K& key) const {
|
|
|
|
iStorage::ensureOpened(iStorage::checkRecordMethodName);
|
2022-12-15 17:29:49 +00:00
|
|
|
|
|
|
|
typename std::map<K, V>::const_iterator itr = cache->find(key);
|
2023-03-20 15:37:13 +00:00
|
|
|
if (itr != cache->end())
|
2022-12-15 17:29:49 +00:00
|
|
|
return true;
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full || abscent->count(key) != 0)
|
2022-12-15 17:29:49 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
try {
|
2023-03-20 15:37:13 +00:00
|
|
|
V value = Storage<K, V>::getRecord(key);
|
2022-12-15 17:29:49 +00:00
|
|
|
cache->insert(std::make_pair(key, value));
|
|
|
|
handleMode();
|
|
|
|
return true;
|
|
|
|
} catch (const NotFound& error) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2022-12-15 17:29:49 +00:00
|
|
|
abscent->insert(key);
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2022-12-15 17:29:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
bool LMDBAL::Cache<K, V>::checkRecord(const K& key, TransactionID txn) const {
|
|
|
|
iStorage::ensureOpened(iStorage::checkRecordMethodName);
|
|
|
|
|
|
|
|
//if there are any changes made within this transaction
|
|
|
|
//I will be able to see them among pending changes
|
|
|
|
//so, I'm going to go through them in reverse order
|
|
|
|
//and check every key. If it has anything to do this requested key
|
|
|
|
//there is a way to tell...
|
2023-04-05 23:01:24 +00:00
|
|
|
bool currentTransaction = false;
|
2023-04-04 23:27:31 +00:00
|
|
|
typename TransactionCache::const_iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
2023-04-05 23:01:24 +00:00
|
|
|
currentTransaction = true;
|
2023-04-04 23:27:31 +00:00
|
|
|
const Queue& queue = tc->second;
|
|
|
|
for (typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
|
|
|
|
const Entry& entry = *i;
|
|
|
|
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add:
|
|
|
|
if (static_cast<std::pair<K, V>*>(entry.second)->first == key)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case Operation::remove:
|
|
|
|
if (*static_cast<K*>(entry.second) == key)
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case Operation::change:
|
|
|
|
if (static_cast<std::pair<K, V>*>(entry.second)->first == key)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case Operation::force:
|
|
|
|
if (std::get<1>(*static_cast<std::tuple<bool, K, V>*>(entry.second)) == key)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case Operation::drop:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case Operation::replace:
|
|
|
|
if (static_cast<std::map<K, V>*>(entry.second)->count(key) > 0)
|
|
|
|
return true;
|
2023-04-05 23:01:24 +00:00
|
|
|
else
|
|
|
|
return false;
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::addMany:
|
2023-04-05 23:01:24 +00:00
|
|
|
if (std::get<2>(
|
|
|
|
*static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second)
|
|
|
|
).count(key) > 0)
|
2023-04-04 23:27:31 +00:00
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//... but if nothing was found or if the transaction is not the one
|
|
|
|
//which caused the changes i just need to check it among local cache
|
|
|
|
|
|
|
|
typename std::map<K, V>::const_iterator itr = cache->find(key);
|
|
|
|
if (itr != cache->end())
|
|
|
|
return true;
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::full || abscent->count(key) != 0)
|
2023-04-04 23:27:31 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
V value = Storage<K, V>::getRecord(key, txn);
|
2023-04-05 23:01:24 +00:00
|
|
|
if (!currentTransaction) {
|
|
|
|
cache->insert(std::make_pair(key, value));
|
|
|
|
handleMode();
|
|
|
|
}
|
2023-04-04 23:27:31 +00:00
|
|
|
return true;
|
|
|
|
} catch (const NotFound& error) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (!currentTransaction && mode != Mode::full)
|
2023-04-04 23:27:31 +00:00
|
|
|
abscent->insert(key);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-15 10:54:34 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
std::map<K, V> LMDBAL::Cache<K, V>::readAll() const {
|
|
|
|
iStorage::ensureOpened(iStorage::readAllMethodName);
|
2022-10-15 10:54:34 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) { //there is a room for optimization
|
|
|
|
mode = Mode::full; //I can read and deserialize only those values
|
2023-03-20 15:37:13 +00:00
|
|
|
*cache = Storage<K, V>::readAll(); //that are missing in the cache
|
2022-10-15 10:54:34 +00:00
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = 0;
|
2022-10-15 10:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return *cache;
|
|
|
|
}
|
|
|
|
|
2023-04-06 23:51:45 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::readAll(std::map<K, V>& out) const {
|
|
|
|
iStorage::ensureOpened(iStorage::readAllMethodName);
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) { //there is a room for optimization
|
|
|
|
mode = Mode::full; //I can read and deserialize only those values
|
2023-04-06 23:51:45 +00:00
|
|
|
Storage<K, V>::readAll(out); //that are missing in the cache
|
|
|
|
*cache = out;
|
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = 0;
|
2023-04-06 23:51:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
template<class K, class V>
|
|
|
|
std::map<K, V> LMDBAL::Cache<K, V>::readAll(TransactionID txn) const {
|
|
|
|
iStorage::ensureOpened(iStorage::readAllMethodName);
|
|
|
|
|
2023-04-06 23:51:45 +00:00
|
|
|
std::map<K, V> out;
|
|
|
|
readAll(out, txn);
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::readAll(std::map<K, V>& out, TransactionID txn) const {
|
|
|
|
iStorage::ensureOpened(iStorage::readAllMethodName);
|
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
Queue& queue = tc->second;
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) {
|
2023-04-06 23:51:45 +00:00
|
|
|
out = *cache;
|
2023-04-05 23:01:24 +00:00
|
|
|
|
|
|
|
for (typename Queue::const_iterator i = queue.begin(), end = queue.end(); i != end; ++i) {
|
|
|
|
const Entry& entry = *i;
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add:
|
2023-04-06 23:51:45 +00:00
|
|
|
out.insert(*static_cast<std::pair<K, V>*>(entry.second));
|
2023-04-05 23:01:24 +00:00
|
|
|
break;
|
|
|
|
case Operation::remove:
|
2023-04-06 23:51:45 +00:00
|
|
|
out.erase(*static_cast<K*>(entry.second));
|
2023-04-05 23:01:24 +00:00
|
|
|
break;
|
|
|
|
case Operation::change: {
|
|
|
|
std::pair<K, V>* pair = static_cast<std::pair<K, V>*>(entry.second);
|
2023-04-06 23:51:45 +00:00
|
|
|
out.at(pair->first) = pair->second;
|
2023-04-05 23:01:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Operation::force:{
|
|
|
|
const std::tuple<bool, K, V>& tuple =
|
|
|
|
*static_cast<std::tuple<bool, K, V>*>(entry.second);
|
2023-04-06 23:51:45 +00:00
|
|
|
out[std::get<1>(tuple)] = std::get<2>(tuple);
|
2023-04-05 23:01:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Operation::drop:
|
2023-04-06 23:51:45 +00:00
|
|
|
out.clear();
|
2023-04-05 23:01:24 +00:00
|
|
|
break;
|
|
|
|
case Operation::replace:
|
2023-04-06 23:51:45 +00:00
|
|
|
out = *static_cast<std::map<K, V>*>(entry.second);
|
2023-04-05 23:01:24 +00:00
|
|
|
break;
|
|
|
|
case Operation::addMany: {
|
|
|
|
const std::tuple<bool, SizeType, std::map<K, V>>& t =
|
|
|
|
*static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second);
|
|
|
|
const std::map<K, V>& added = std::get<2>(t);
|
|
|
|
bool overwrite = std::get<0>(t);
|
|
|
|
for (const std::pair<const K, V>& pair : added) {
|
|
|
|
if (overwrite)
|
2023-04-06 23:51:45 +00:00
|
|
|
out[pair.first] = pair.second;
|
2023-04-05 23:01:24 +00:00
|
|
|
else
|
2023-04-06 23:51:45 +00:00
|
|
|
out.insert(pair);
|
2023-04-05 23:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-04-06 23:51:45 +00:00
|
|
|
Storage<K, V>::readAll(out, txn);
|
2023-04-05 23:01:24 +00:00
|
|
|
|
2023-04-06 23:51:45 +00:00
|
|
|
//queue.clear(); //since I'm getting a complete state of the database
|
|
|
|
queue.emplace_back(Operation::replace, new std::map<K, V>(out)); //I can as well erase all previous cache entries
|
2023-04-05 23:01:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) { //there is a room for optimization
|
|
|
|
mode = Mode::full; //I can read and deserialize only those values
|
2023-04-06 23:51:45 +00:00
|
|
|
Storage<K, V>::readAll(out); //that are missing in the cache
|
|
|
|
*cache = out;
|
2023-04-05 23:01:24 +00:00
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = 0;
|
2023-04-05 23:01:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-18 14:45:12 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
void LMDBAL::Cache<K, V>::replaceAll(const std::map<K, V>& data) {
|
2023-03-20 15:37:13 +00:00
|
|
|
Storage<K, V>::replaceAll(data);
|
2022-12-18 14:45:12 +00:00
|
|
|
*cache = data;
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) {
|
|
|
|
mode = Mode::full;
|
2023-03-20 15:37:13 +00:00
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = 0;
|
2023-03-20 15:37:13 +00:00
|
|
|
}
|
2022-12-18 14:45:12 +00:00
|
|
|
}
|
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::replaceAll(const std::map<K, V>& data, TransactionID txn) {
|
|
|
|
Storage<K, V>::replaceAll(data, txn);
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
//queue.clear();
|
|
|
|
std::map<K, V>* map = new std::map<K, V>(data); //since I'm getting a complete state of the database
|
|
|
|
tc->second.emplace_back(Operation::replace, map); //I can as well erase all previous cache entries
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-18 14:45:12 +00:00
|
|
|
template<class K, class V>
|
2023-04-03 18:48:13 +00:00
|
|
|
void LMDBAL::Cache<K, V>::handleReplaceAll(std::map<K, V>* data) {
|
|
|
|
delete cache;
|
|
|
|
cache = data;
|
2022-12-18 14:45:12 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) {
|
|
|
|
mode = Mode::full;
|
2023-04-03 18:48:13 +00:00
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = 0;
|
2023-04-03 18:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
LMDBAL::SizeType LMDBAL::Cache<K, V>::addRecords(const std::map<K, V>& data, bool overwrite) {
|
|
|
|
SizeType newSize = Storage<K, V>::addRecords(data, overwrite);
|
|
|
|
handleAddRecords(data, overwrite, newSize);
|
|
|
|
|
|
|
|
return newSize;
|
|
|
|
}
|
|
|
|
|
2023-04-05 23:01:24 +00:00
|
|
|
template<class K, class V>
|
|
|
|
LMDBAL::SizeType LMDBAL::Cache<K, V>::addRecords(const std::map<K, V>& data, TransactionID txn, bool overwrite) {
|
|
|
|
SizeType newSize = Storage<K, V>::addRecords(data, txn, overwrite);
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
std::tuple<bool, SizeType, std::map<K, V>>* tuple =
|
|
|
|
new std::tuple<bool, SizeType, std::map<K, V>>(overwrite, newSize, data);
|
|
|
|
tc->second.emplace_back(Operation::addMany, tuple);
|
|
|
|
}
|
|
|
|
|
|
|
|
return newSize;
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleAddRecords(const std::map<K, V>& data, bool overwrite, SizeType newSize) {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::nothing)
|
|
|
|
mode = Mode::size;
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2022-12-18 14:45:12 +00:00
|
|
|
std::map<K, V>& c = *cache;
|
|
|
|
std::set<K>& a = *abscent;
|
|
|
|
for (const std::pair<const K, V>& pair : data) {
|
|
|
|
std::pair<typename std::map<K, V>::iterator, bool> res = c.insert(pair);
|
|
|
|
if (!res.second) {
|
2023-03-20 15:37:13 +00:00
|
|
|
if (overwrite)
|
2022-12-18 14:45:12 +00:00
|
|
|
res.first->second = pair.second;
|
2023-08-05 20:13:43 +00:00
|
|
|
} else if (mode != Mode::full) {
|
2022-12-18 14:45:12 +00:00
|
|
|
a.erase(pair.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full) {
|
|
|
|
sizeDifference = newSize - c.size();
|
|
|
|
if (sizeDifference == 0) {
|
|
|
|
mode = Mode::full;
|
2022-12-18 14:45:12 +00:00
|
|
|
abscent->clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-20 17:16:48 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
void LMDBAL::Cache<K, V>::removeRecord(const K& key) {
|
|
|
|
iStorage::ensureOpened(iStorage::removeRecordMethodName);
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
bool noKey = false;
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2023-04-03 18:48:13 +00:00
|
|
|
noKey = cache->count(key) == 0;
|
|
|
|
else
|
|
|
|
noKey = abscent->count(key) > 0;
|
|
|
|
|
|
|
|
if (noKey)
|
2023-03-21 11:05:54 +00:00
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
2022-09-20 17:16:48 +00:00
|
|
|
|
2023-03-20 15:37:13 +00:00
|
|
|
Storage<K, V>::removeRecord(key);
|
2023-04-03 18:48:13 +00:00
|
|
|
handleRemoveRecord(key);
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::removeRecord(const K& key, TransactionID txn) {
|
|
|
|
iStorage::ensureOpened(iStorage::removeRecordMethodName);
|
|
|
|
|
|
|
|
bool noKey = false;
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2023-04-04 23:27:31 +00:00
|
|
|
noKey = cache->count(key) == 0;
|
|
|
|
else
|
|
|
|
noKey = abscent->count(key) > 0;
|
|
|
|
|
|
|
|
if (noKey)
|
|
|
|
iStorage::throwNotFound(iStorage::toString(key));
|
|
|
|
|
|
|
|
Storage<K, V>::removeRecord(key, txn);
|
|
|
|
|
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end())
|
|
|
|
tc->second.emplace_back(Operation::remove, new K(key));
|
|
|
|
}
|
|
|
|
|
2023-04-03 18:48:13 +00:00
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleRemoveRecord(const K& key) {
|
2023-03-20 15:37:13 +00:00
|
|
|
if (cache->erase(key) == 0) //if it was not cached and we are now in size mode then the sizeDifference would decrease
|
2022-10-08 16:45:07 +00:00
|
|
|
handleMode();
|
2023-03-20 15:37:13 +00:00
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode != Mode::full)
|
2022-10-08 16:45:07 +00:00
|
|
|
abscent->insert(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
uint32_t LMDBAL::Cache<K, V>::count() const {
|
2023-08-05 20:13:43 +00:00
|
|
|
switch (mode) {
|
2022-10-08 16:45:07 +00:00
|
|
|
case Mode::nothing:
|
|
|
|
{
|
2023-03-20 15:37:13 +00:00
|
|
|
uint32_t sz = Storage<K, V>::count();
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = sz - cache->size();
|
2022-10-08 16:45:07 +00:00
|
|
|
if (sz == 0) {
|
2023-08-05 20:13:43 +00:00
|
|
|
mode = Mode::full;
|
2022-10-08 16:45:07 +00:00
|
|
|
abscent->clear();
|
|
|
|
} else {
|
2023-08-05 20:13:43 +00:00
|
|
|
mode = Mode::size;
|
2022-10-08 16:45:07 +00:00
|
|
|
}
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
case Mode::size:
|
2023-08-05 20:13:43 +00:00
|
|
|
return cache->size() + sizeDifference;
|
2022-10-08 16:45:07 +00:00
|
|
|
case Mode::full:
|
|
|
|
return cache->size();
|
2023-03-20 15:37:13 +00:00
|
|
|
default:
|
|
|
|
return 0; //unreachable, no such state, just to suppress the waring
|
2022-10-08 16:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
template<class K, class V>
|
|
|
|
uint32_t LMDBAL::Cache<K, V>::count(TransactionID txn) const {
|
|
|
|
|
|
|
|
int32_t diff = 0;
|
|
|
|
bool currentTransaction = false;
|
|
|
|
typename TransactionCache::const_iterator tc = transactionCache->find(txn);
|
|
|
|
if (tc != transactionCache->end()) {
|
|
|
|
currentTransaction = true;
|
|
|
|
const Queue& queue = tc->second;
|
|
|
|
for (typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
|
|
|
|
const Entry& entry = *i;
|
|
|
|
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add:
|
|
|
|
++diff;
|
|
|
|
break;
|
|
|
|
case Operation::remove:
|
|
|
|
--diff;
|
|
|
|
break;
|
|
|
|
case Operation::change:
|
|
|
|
break;
|
|
|
|
case Operation::force:
|
|
|
|
if (std::get<0>(*static_cast<std::tuple<bool, K, V>*>(entry.second)))
|
2023-04-05 23:01:24 +00:00
|
|
|
++diff;
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
case Operation::drop:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case Operation::replace:
|
|
|
|
return static_cast<std::map<K, V>*>(entry.second)->size() + diff;
|
|
|
|
break;
|
|
|
|
case Operation::addMany:
|
2023-04-05 23:01:24 +00:00
|
|
|
return std::get<1>(*static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second)) + diff;
|
2023-04-04 23:27:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-05 20:13:43 +00:00
|
|
|
switch (mode) {
|
2023-04-04 23:27:31 +00:00
|
|
|
case Mode::nothing: {
|
|
|
|
uint32_t sz = Storage<K, V>::count(txn);
|
|
|
|
if (!currentTransaction) {
|
2023-08-05 20:13:43 +00:00
|
|
|
sizeDifference = sz - cache->size();
|
2023-04-04 23:27:31 +00:00
|
|
|
if (sz == 0) {
|
2023-08-05 20:13:43 +00:00
|
|
|
mode = Mode::full;
|
2023-04-04 23:27:31 +00:00
|
|
|
abscent->clear();
|
|
|
|
} else {
|
2023-08-05 20:13:43 +00:00
|
|
|
mode = Mode::size;
|
2023-04-04 23:27:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
case Mode::size:
|
2023-08-05 20:13:43 +00:00
|
|
|
return cache->size() + sizeDifference + diff;
|
2023-04-04 23:27:31 +00:00
|
|
|
case Mode::full:
|
|
|
|
return cache->size() + diff;
|
|
|
|
default:
|
|
|
|
return 0; //unreachable, no such state, just to suppress the waring
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-08 16:45:07 +00:00
|
|
|
template<class K, class V>
|
2023-03-21 11:05:54 +00:00
|
|
|
void LMDBAL::Cache<K, V>::handleMode() const {
|
2023-08-05 20:13:43 +00:00
|
|
|
if (mode == Mode::size) {
|
|
|
|
--sizeDifference;
|
|
|
|
if (sizeDifference == 0) {
|
|
|
|
mode = Mode::full;
|
2022-10-08 16:45:07 +00:00
|
|
|
abscent->clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
2023-04-03 18:48:13 +00:00
|
|
|
int LMDBAL::Cache<K, V>::drop(TransactionID transaction) {
|
2023-03-20 15:37:13 +00:00
|
|
|
int res = Storage<K, V>::drop(transaction);
|
2023-04-03 18:48:13 +00:00
|
|
|
|
2023-04-04 23:27:31 +00:00
|
|
|
typename TransactionCache::iterator tc = transactionCache->find(transaction);
|
|
|
|
if (tc != transactionCache->end())
|
|
|
|
tc->second.emplace_back(Operation::drop, nullptr);
|
2023-04-03 18:48:13 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleDrop() {
|
2022-10-08 16:45:07 +00:00
|
|
|
cache->clear();
|
|
|
|
abscent->clear();
|
2023-08-05 20:13:43 +00:00
|
|
|
mode = Mode::full;
|
|
|
|
sizeDifference = 0;
|
2023-04-03 18:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::transactionStarted(TransactionID txn, bool readOnly) const {
|
|
|
|
if (!readOnly)
|
|
|
|
transactionCache->emplace(txn, Queue());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::transactionCommited(TransactionID txn) {
|
|
|
|
typename TransactionCache::iterator itr = transactionCache->find(txn);
|
|
|
|
if (itr != transactionCache->end()) {
|
|
|
|
Queue& queue = itr->second;
|
|
|
|
for (const Entry& entry : queue)
|
|
|
|
handleTransactionEntry(entry);
|
|
|
|
|
|
|
|
transactionCache->erase(itr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::transactionAborted(TransactionID txn) const {
|
|
|
|
typename TransactionCache::iterator itr = transactionCache->find(txn);
|
|
|
|
if (itr != transactionCache->end()) {
|
|
|
|
Queue& queue = itr->second;
|
|
|
|
for (const Entry& entry : queue)
|
|
|
|
destroyTransactionEntry(entry);
|
|
|
|
|
|
|
|
transactionCache->erase(itr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::handleTransactionEntry(const Entry& entry) {
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add: {
|
|
|
|
std::pair<K, V>* pair = static_cast<std::pair<K, V>*>(entry.second);
|
|
|
|
handleAddRecord(pair->first, pair->second);
|
|
|
|
delete pair;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Operation::remove: {
|
|
|
|
K* key = static_cast<K*>(entry.second);
|
|
|
|
handleRemoveRecord(*key);
|
|
|
|
delete key;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case Operation::change: {
|
|
|
|
std::pair<K, V>* pair = static_cast<std::pair<K, V>*>(entry.second);
|
|
|
|
handleChangeRecord(pair->first, pair->second);
|
|
|
|
delete pair;
|
|
|
|
}
|
|
|
|
case Operation::force: {
|
|
|
|
std::tuple<bool, K, V>* tuple = static_cast<std::tuple<bool, K, V>*>(entry.second);
|
|
|
|
const std::tuple<bool, K, V>& t = *tuple;
|
|
|
|
handleForceRecord(std::get<1>(t), std::get<2>(t), std::get<0>(t));
|
|
|
|
delete tuple;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Operation::drop:
|
|
|
|
handleDrop();
|
|
|
|
break;
|
|
|
|
case Operation::replace:
|
|
|
|
handleReplaceAll(static_cast<std::map<K, V>*>(entry.second)); //I take ownership, no need to delete
|
|
|
|
break;
|
|
|
|
case Operation::addMany: {
|
|
|
|
std::tuple<bool, SizeType, std::map<K, V>>* tuple = static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second);
|
|
|
|
const std::tuple<bool, SizeType, std::map<K, V>>& t = * tuple;
|
|
|
|
handleAddRecords(std::get<2>(t), std::get<0>(t), std::get<1>(t));
|
|
|
|
delete tuple;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class V>
|
|
|
|
void LMDBAL::Cache<K, V>::destroyTransactionEntry(const Entry& entry) const {
|
|
|
|
switch (entry.first) {
|
|
|
|
case Operation::add:
|
|
|
|
delete static_cast<std::pair<K, V>*>(entry.second);
|
|
|
|
break;
|
|
|
|
case Operation::remove:
|
|
|
|
delete static_cast<K*>(entry.second);
|
|
|
|
break;
|
|
|
|
case Operation::change:
|
|
|
|
delete static_cast<std::pair<K, V>*>(entry.second);
|
|
|
|
break;
|
|
|
|
case Operation::force:
|
|
|
|
delete static_cast<std::tuple<bool, K, V>*>(entry.second);
|
|
|
|
break;
|
|
|
|
case Operation::drop:
|
|
|
|
break;
|
|
|
|
case Operation::replace:
|
|
|
|
delete static_cast<std::map<K, V>*>(entry.second);
|
|
|
|
break;
|
|
|
|
case Operation::addMany:
|
|
|
|
delete static_cast<std::tuple<bool, SizeType, std::map<K, V>>*>(entry.second);
|
|
|
|
break;
|
|
|
|
}
|
2022-09-20 17:16:48 +00:00
|
|
|
}
|
|
|
|
|
2023-03-21 11:05:54 +00:00
|
|
|
#endif //LMDBAL_CACHE_HPP
|