22#include "exceptions.h"
45template<
class K,
class V>
49 cache(new std::map<K, V>()),
58template<
class K,
class V>
59Cache<K, V>::~Cache() {
60 delete transactionCache;
66template<
class K,
class V>
70 if (
cache->count(key) > 0)
74 handleAddRecord(key, value);
77template<
class K,
class V>
79 if (
cache->count(key) > 0)
86 std::pair<K, V>* pair =
new std::pair<K, V>(key, value);
87 tc->second.emplace_back(Operation::add, pair);
91template<
class K,
class V>
92void LMDBAL::Cache<K, V>::handleAddRecord(
const K& key,
const V& value) {
93 cache->insert(std::make_pair(key, value));
95 if (mode != Mode::full)
99template<
class K,
class V>
104 handleForceRecord(key, value, added);
109template<
class K,
class V>
115 std::tuple<bool, K, V>* t =
new std::tuple<bool, K, V>(added, key, value);
116 tc->second.emplace_back(Operation::force, t);
122template<
class K,
class V>
123void LMDBAL::Cache<K, V>::handleForceRecord(
const K& key,
const V& value,
bool added) {
124 if (mode == Mode::full) {
125 (*cache)[key] = value;
130 std::pair<typename std::map<K, V>::iterator,
bool> result =
131 cache->insert(std::make_pair(key, value));
133 result.first->second = value;
139template<
class K,
class V>
143 if (
mode == Mode::full) {
144 typename std::map<K, V>::iterator itr =
cache->find(key);
145 if (itr ==
cache->end())
156 typename std::pair<typename std::map<K, V>::iterator,
bool> res =
157 cache->insert(std::make_pair(key, value));
159 res.first->second = value;
169template<
class K,
class V>
171 if (
mode == Mode::full) {
172 typename std::map<K, V>::iterator itr =
cache->find(key);
173 if (itr ==
cache->end())
191 std::pair<K, V>* pair =
new std::pair<K, V>(key, value);
192 tc->second.emplace_back(Operation::add, pair);
196template<
class K,
class V>
197void LMDBAL::Cache<K, V>::handleChangeRecord(
const K& key,
const V& value) {
198 if (mode == Mode::full) {
199 cache->at(key) = value;
201 typename std::pair<typename std::map<K, V>::iterator,
bool> res =
202 cache->insert(std::make_pair(key, value));
204 res.first->second = value;
210template<
class K,
class V>
219template<
class K,
class V>
223 typename std::map<K, V>::const_iterator itr =
cache->find(key);
224 if (itr !=
cache->end()) {
229 if (
mode == Mode::full ||
abscent->count(key) != 0)
234 appendToCache(key, out);
237 if (
mode != Mode::full)
244template<
class K,
class V>
251template<
class K,
class V>
258 bool currentTransaction =
false;
261 currentTransaction =
true;
262 const Queue& queue = tc->second;
263 for (
typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
264 const Entry& entry = *i;
266 switch (entry.first) {
268 if (
static_cast<std::pair<K, V>*
>(entry.second)->first == key) {
269 out =
static_cast<std::pair<K, V>*
>(entry.second)->second;
273 case Operation::remove:
276 case Operation::change:
277 if (
static_cast<std::pair<K, V>*
>(entry.second)->first == key) {
278 out =
static_cast<std::pair<K, V>*
>(entry.second)->second;
283 case Operation::force:
284 if (std::get<1>(*
static_cast<std::tuple<bool, K, V>*
>(entry.second)) == key) {
285 out = std::get<2>(*
static_cast<std::tuple<bool, K, V>*
>(entry.second));
289 case Operation::drop:
292 case Operation::replace: {
293 std::map<K, V>* newMap =
static_cast<std::map<K, V>*
>(entry.second);
294 typename std::map<K, V>::const_iterator vitr = newMap->find(key);
295 if (vitr != newMap->end()) {
303 case Operation::addMany: {
304 const std::tuple<bool, SizeType, std::map<K, V>>& tuple =
305 *
static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second);
306 const std::map<K, V>& newElements = std::get<2>(tuple);
307 typename std::map<K, V>::const_iterator vitr = newElements.find(key);
308 if (vitr != newElements.end()) {
320 typename std::map<K, V>::const_iterator itr =
cache->find(key);
321 if (itr !=
cache->end()) {
326 if (
mode == Mode::full ||
abscent->count(key) != 0)
331 if (!currentTransaction)
332 appendToCache(key, out);
336 if (!currentTransaction &&
mode != Mode::full)
343template<
class K,
class V>
345 appendToCache(key, value);
348template<
class K,
class V>
355template<
class K,
class V>
359 typename std::map<K, V>::const_iterator itr =
cache->find(key);
360 if (itr !=
cache->end())
363 if (
mode == Mode::full ||
abscent->count(key) != 0)
368 appendToCache(key, value);
372 if (
mode != Mode::full)
379template<
class K,
class V>
386 bool currentTransaction =
false;
389 currentTransaction =
true;
390 const Queue& queue = tc->second;
391 for (
typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
392 const Entry& entry = *i;
394 switch (entry.first) {
396 if (
static_cast<std::pair<K, V>*
>(entry.second)->first == key)
399 case Operation::remove:
400 if (*
static_cast<K*
>(entry.second) == key)
403 case Operation::change:
404 if (
static_cast<std::pair<K, V>*
>(entry.second)->first == key)
407 case Operation::force:
408 if (std::get<1>(*
static_cast<std::tuple<bool, K, V>*
>(entry.second)) == key)
411 case Operation::drop:
414 case Operation::replace:
415 if (
static_cast<std::map<K, V>*
>(entry.second)->count(key) > 0)
420 case Operation::addMany:
422 *
static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second)
432 typename std::map<K, V>::const_iterator itr =
cache->find(key);
433 if (itr !=
cache->end())
436 if (
mode == Mode::full ||
abscent->count(key) != 0)
441 if (!currentTransaction)
442 appendToCache(key, value);
446 if (!currentTransaction &&
mode != Mode::full)
453template<
class K,
class V>
454void LMDBAL::Cache<K, V>::appendToCache(
const K& key,
const V& value)
const {
455 typename std::pair<typename std::map<K, V>::const_iterator,
bool> pair = cache->insert(std::make_pair(key, value));
460template<
class K,
class V>
464 if (
mode != Mode::full) {
474template<
class K,
class V>
478 if (
mode != Mode::full) {
487template<
class K,
class V>
495template<
class K,
class V>
499 Queue& queue = tc->second;
500 if (
mode != Mode::full) {
503 for (
typename Queue::const_iterator i = queue.begin(), end = queue.end(); i != end; ++i) {
504 const Entry& entry = *i;
505 switch (entry.first) {
507 out.insert(*
static_cast<std::pair<K, V>*
>(entry.second));
509 case Operation::remove:
510 out.erase(*
static_cast<K*
>(entry.second));
512 case Operation::change: {
513 std::pair<K, V>* pair =
static_cast<std::pair<K, V>*
>(entry.second);
514 out.at(pair->first) = pair->second;
517 case Operation::force:{
518 const std::tuple<bool, K, V>& tuple =
519 *
static_cast<std::tuple<bool, K, V>*
>(entry.second);
520 out[std::get<1>(tuple)] = std::get<2>(tuple);
523 case Operation::drop:
526 case Operation::replace:
527 out = *
static_cast<std::map<K, V>*
>(entry.second);
529 case Operation::addMany: {
530 const std::tuple<bool, SizeType, std::map<K, V>>& t =
531 *
static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second);
532 const std::map<K, V>& added = std::get<2>(t);
533 bool overwrite = std::get<0>(t);
534 for (
const std::pair<const K, V>& pair : added) {
536 out[pair.first] = pair.second;
548 queue.emplace_back(Operation::replace,
new std::map<K, V>(out));
551 if (
mode != Mode::full) {
561template<
class K,
class V>
566 if (
mode != Mode::full) {
573template<
class K,
class V>
580 std::map<K, V>* map =
new std::map<K, V>(data);
581 tc->second.emplace_back(Operation::replace, map);
585template<
class K,
class V>
586void LMDBAL::Cache<K, V>::handleReplaceAll(std::map<K, V>* data) {
590 if (mode != Mode::full) {
597template<
class K,
class V>
600 handleAddRecords(data, overwrite, newSize);
605template<
class K,
class V>
611 std::tuple<bool, SizeType, std::map<K, V>>* tuple =
612 new std::tuple<bool, SizeType, std::map<K, V>>(overwrite, newSize, data);
613 tc->second.emplace_back(Operation::addMany, tuple);
619template<
class K,
class V>
620void LMDBAL::Cache<K, V>::handleAddRecords(
const std::map<K, V>& data,
bool overwrite,
SizeType newSize) {
621 if (mode == Mode::nothing)
624 std::map<K, V>& c = *cache;
625 std::set<K>& a = *abscent;
626 for (
const std::pair<const K, V>& pair : data) {
627 std::pair<typename std::map<K, V>::iterator,
bool> res = c.insert(pair);
630 res.first->second = pair.second;
631 }
else if (mode != Mode::full) {
636 if (mode != Mode::full) {
637 sizeDifference = newSize -
static_cast<SizeType>(c.size());
638 if (sizeDifference == 0) {
645template<
class K,
class V>
650 if (
mode != Mode::full)
651 noKey =
cache->count(key) == 0;
653 noKey =
abscent->count(key) > 0;
659 handleRemoveRecord(key);
662template<
class K,
class V>
665 if (
mode != Mode::full)
666 noKey =
cache->count(key) == 0;
668 noKey =
abscent->count(key) > 0;
677 tc->second.emplace_back(Operation::remove,
new K(key));
680template<
class K,
class V>
681void LMDBAL::Cache<K, V>::handleRemoveRecord(
const K& key) {
682 if (cache->erase(key) == 0)
685 if (mode != Mode::full)
686 abscent->insert(key);
689template<
class K,
class V>
691 size_t cacheSize =
cache->size();
692 if (cacheSize > std::numeric_limits<LMDBAL::SizeType>::max())
693 throw std::overflow_error(
"Cache size is too big");
711 return static_cast<SizeType>(cacheSize);
717template<
class K,
class V>
720 bool currentTransaction =
false;
723 currentTransaction =
true;
724 const Queue& queue = tc->second;
725 for (
typename Queue::const_reverse_iterator i = queue.rbegin(), end = queue.rend(); i != end; ++i) {
726 const Entry& entry = *i;
728 switch (entry.first) {
732 case Operation::remove:
735 case Operation::change:
737 case Operation::force:
738 if (std::get<0>(*
static_cast<std::tuple<bool, K, V>*
>(entry.second)))
741 case Operation::drop:
744 case Operation::replace: {
745 auto result =
static_cast<int32_t
>(
static_cast<std::map<K, V>*
>(entry.second)->size()) + diff;
747 throw std::overflow_error(
"Invalid cache size");
749 return static_cast<SizeType>(result);
751 case Operation::addMany:{
752 auto result =
static_cast<int32_t
>(std::get<1>(*
static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second))) + diff;
754 throw std::overflow_error(
"Invalid cache size");
756 return static_cast<SizeType>(result);
762 size_t cacheSize =
cache->size();
763 if (cacheSize > std::numeric_limits<SizeType>::max())
764 throw std::overflow_error(
"Cache size is too big");
767 case Mode::nothing: {
769 if (!currentTransaction) {
781 auto result =
static_cast<int32_t
>(cacheSize) +
static_cast<int32_t
>(
sizeDifference) + diff;
784 throw std::overflow_error(
"Invalid cache size");
785 return static_cast<SizeType>(result);
788 auto result =
static_cast<int32_t
>(cacheSize) + diff;
791 throw std::overflow_error(
"Invalid cache size");
793 return static_cast<SizeType>(result);
800template<
class K,
class V>
801void LMDBAL::Cache<K, V>::handleMode()
const {
802 if (mode == Mode::size) {
804 if (sizeDifference == 0) {
811template<
class K,
class V>
817 if (res != MDB_SUCCESS)
822 tc->second.emplace_back(Operation::drop,
nullptr);
827template<
class K,
class V>
835template<
class K,
class V>
841template<
class K,
class V>
845 Queue& queue = itr->second;
846 for (
const Entry& entry : queue)
847 handleTransactionEntry(entry);
853template<
class K,
class V>
857 Queue& queue = itr->second;
858 for (
const Entry& entry : queue)
859 destroyTransactionEntry(entry);
865template<
class K,
class V>
866void LMDBAL::Cache<K, V>::handleTransactionEntry(
const Entry& entry) {
867 switch (entry.first) {
868 case Operation::add: {
869 std::pair<K, V>* pair =
static_cast<std::pair<K, V>*
>(entry.second);
870 handleAddRecord(pair->first, pair->second);
873 case Operation::remove: {
874 K* key =
static_cast<K*
>(entry.second);
875 handleRemoveRecord(*key);
878 case Operation::change: {
879 std::pair<K, V>* pair =
static_cast<std::pair<K, V>*
>(entry.second);
880 handleChangeRecord(pair->first, pair->second);
883 case Operation::force: {
884 std::tuple<bool, K, V>* tuple =
static_cast<std::tuple<bool, K, V>*
>(entry.second);
885 const std::tuple<bool, K, V>& t = *tuple;
886 handleForceRecord(std::get<1>(t), std::get<2>(t), std::get<0>(t));
889 case Operation::drop:
892 case Operation::replace:
893 handleReplaceAll(
static_cast<std::map<K, V>*
>(entry.second));
895 case Operation::addMany: {
896 std::tuple<bool, SizeType, std::map<K, V>>* tuple =
static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second);
897 const std::tuple<bool, SizeType, std::map<K, V>>& t = * tuple;
898 handleAddRecords(std::get<2>(t), std::get<0>(t), std::get<1>(t));
904template<
class K,
class V>
905void LMDBAL::Cache<K, V>::destroyTransactionEntry(
const Entry& entry)
const {
906 switch (entry.first) {
908 delete static_cast<std::pair<K, V>*
>(entry.second);
910 case Operation::remove:
911 delete static_cast<K*
>(entry.second);
913 case Operation::change:
914 delete static_cast<std::pair<K, V>*
>(entry.second);
916 case Operation::force:
917 delete static_cast<std::tuple<bool, K, V>*
>(entry.second);
919 case Operation::drop:
921 case Operation::replace:
922 delete static_cast<std::map<K, V>*
>(entry.second);
924 case Operation::addMany:
925 delete static_cast<std::tuple<bool, SizeType, std::map<K, V>
>*>(entry.second);
SizeType sizeDifference
Difference of size between cached data and amount of records in the lmdb storage.
Definition cache.h:129
Mode mode
Cache mode.
Definition cache.h:126
virtual bool forceRecord(const K &key, const V &value, TransactionID txn) override
Adds a key-value record to the storage, overwrites if it already exists (private transaction variant)...
Definition cache.hpp:110
virtual std::map< K, V > readAll(TransactionID txn) const override
Reads whole storage into a map (private transaction variant).
Definition cache.hpp:488
virtual void transactionAborted(TransactionID txn) const override
called on abortion of public transaction
Definition cache.hpp:854
virtual std::map< K, V > readAll() const override
Reads whole storage into a map.
Definition cache.hpp:461
virtual bool checkRecord(const K &key, TransactionID txn) const override
Chechs if storage has value (private transaction variant).
Definition cache.hpp:380
virtual void discoveredRecord(const K &key, const V &value) const override
A private virtual method that cursor calls when he reads a record, does nothing here but populates th...
Definition cache.hpp:344
std::map< K, V > * cache
Cached data.
Definition cache.h:127
Cache(Base *parent, const std::string &name, bool duplicates=false)
Creates a cache.
Definition cache.hpp:46
TransactionCache * transactionCache
All changes made under under uncommited transactions.
Definition cache.h:130
virtual void replaceAll(const std::map< K, V > &data, TransactionID txn) override
Replaces the content of the whole storage with the given (private transaction variant).
Definition cache.hpp:574
virtual SizeType count() const override
Storage size.
Definition cache.hpp:690
virtual void transactionCommited(TransactionID txn) override
called on commitment of public transaction
Definition cache.hpp:842
virtual void changeRecord(const K &key, const V &value, TransactionID txn) override
Changes key-value record to the storage (private transaction variant).
Definition cache.hpp:170
virtual SizeType addRecords(const std::map< K, V > &data, TransactionID txn, bool overwrite=false) override
Adds records in bulk (private transaction variant).
Definition cache.hpp:606
virtual void getRecord(const K &key, V &out, TransactionID txn) const override
Gets the record from the database (private transaction, reference variant).
Definition cache.hpp:252
virtual void transactionStarted(TransactionID txn, bool readOnly) const override
called on beginning of public transaction
Definition cache.hpp:836
virtual void handleDrop() override
A method where database additionally handles drop.
Definition cache.hpp:828
virtual void removeRecord(const K &key, TransactionID txn) override
Removes one of the records (private transaction variant).
Definition cache.hpp:663
std::set< K > * abscent
Set of keys that are definitely not in the cache.
Definition cache.h:128
virtual void addRecord(const K &key, const V &value, TransactionID txn) override
Adds a key-value record to the storage (private transaction variant).
Definition cache.hpp:78
Thrown if something in the database was not found.
Definition exceptions.h:135
void throwNotFound(std::string_view key) const
Throws LMDBAL::NotFound.
Definition storagecommon.cpp:406
static constexpr std::string_view forceRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:120
static constexpr std::string_view removeRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:122
static std::string toString(const T &value)
A method to cast a value (which can be a value or a key) to string.
Definition storagecommon.hpp:71
static constexpr std::string_view addRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:119
virtual SizeType count() const
Storage size.
Definition storagecommon.cpp:148
static constexpr std::string_view getRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:124
static constexpr std::string_view changeRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:121
const std::string name
this storage name
Definition storagecommon.h:112
TransactionID extractTransactionId(const Transaction &txn, std::string_view action={}) const
Checks if the transaction is still active, returns inner TransactionID.
Definition storagecommon.cpp:72
static constexpr std::string_view readAllMethodName
member function name, just for exceptions
Definition storagecommon.h:125
static constexpr std::string_view checkRecordMethodName
member function name, just for exceptions
Definition storagecommon.h:123
void ensureOpened(std::string_view methodName) const
Helper function; throws an exception if the database is not opened.
Definition storagecommon.cpp:135
const bool duplicates
true if storage supports duplicates
Definition storagecommon.h:113
virtual void drop()
Drops content of a storage interface.
Definition storagecommon.cpp:87
void throwDuplicate(std::string_view key) const
Throws LMDBAL::Exist.
Definition storagecommon.cpp:394
static constexpr std::string_view dropMethodName
member function name, just for exceptions
Definition storagecommon.h:115
virtual void addRecord(const K &key, const V &value, TransactionID txn)
Adds a key-value record to the storage (private transaction variant).
Definition storage.hpp:109
virtual std::map< K, V > readAll() const
Reads whole storage into a map.
Definition storage.hpp:640
virtual void replaceAll(const std::map< K, V > &data, TransactionID txn)
Replaces the content of the whole storage with the given (private transaction variant).
Definition storage.hpp:811
virtual void removeRecord(const K &key, TransactionID txn)
Removes one of the records (private transaction variant).
Definition storage.hpp:976
virtual uint32_t addRecords(const std::map< K, V > &data, TransactionID txn, bool overwrite=false)
Adds records in bulk (private transaction variant).
Definition storage.hpp:889
virtual bool forceRecord(const K &key, const V &value, TransactionID txn)
Adds a key-value record to the storage, overwrites if it already exists (private transaction variant)...
Definition storage.hpp:200
virtual void changeRecord(const K &key, const V &value, TransactionID txn)
Changes key-value record to the storage (private transaction variant).
Definition storage.hpp:316
virtual void getRecord(const K &key, V &value, TransactionID txn) const
Gets the record from the database (private transaction, reference variant).
Definition storage.hpp:517
Storage(Base *parent, const std::string &name, bool duplicates=false)
Creates a storage.
Definition storage.hpp:48
virtual void drop()
Drops content of a storage interface.
Definition storagecommon.cpp:87
Public writable transaction.
Definition transaction.h:54
Destroys a cache.
Definition base.h:36
MDB_txn * TransactionID
I'm going to use transaction pointers as transaction IDs.
Definition base.h:52
uint32_t SizeType
All LMDBAL sizes are uint32.
Definition base.h:53