MDBX Containers
Loading...
Searching...
No Matches
KeyValueTable.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
3#define _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
4
7
8#include "common.hpp"
9#include <map>
10#include <unordered_set>
11
12namespace mdbxc {
13
26 template<class KeyT, class ValueT>
27 class KeyValueTable final : public BaseTable {
28 public:
29
34 KeyValueTable(std::shared_ptr<Connection> connection,
35 std::string name = "kv_store",
36 MDBX_db_flags_t flags = MDBX_DB_DEFAULTS | MDBX_CREATE)
37 : BaseTable(std::move(connection),
38 std::move(name),
39 flags | get_mdbx_flags<KeyT>()) {}
40
45 explicit KeyValueTable(const Config& config,
46 std::string name = "kv_store",
47 MDBX_db_flags_t flags = MDBX_DB_DEFAULTS | MDBX_CREATE)
48 : BaseTable(Connection::create(config),
49 std::move(name),
50 flags | get_mdbx_flags<KeyT>()) {}
51
53 ~KeyValueTable() override final = default;
54
55 // --- Operators ---
56
62 template<template <class...> class ContainerT>
63 KeyValueTable& operator=(const ContainerT<KeyT, ValueT>& container) {
64 with_transaction([this, &container](MDBX_txn* txn) {
65 db_reconcile(container, txn);
67 return *this;
68 }
69
75 KeyValueTable& operator=(const std::vector<std::pair<KeyT, ValueT>>& container) {
76 with_transaction([this, &container](MDBX_txn* txn) {
77 db_reconcile(container, txn);
79 return *this;
80 }
81
86 template<template<class...> class ContainerT = std::map>
87#if __cplusplus >= 201703L
88 auto operator()() {
89 using ReturnT = std::conditional_t<
90 std::is_same_v<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT>>>,
91 std::vector<std::pair<KeyT, ValueT>>,
92 ContainerT<KeyT, ValueT>
93 >;
94
95 ReturnT container;
96 with_transaction([this, &container](MDBX_txn* txn) {
97 db_load(container, txn);
99 return container;
100 }
101#else
102 typename std::conditional<
103 std::is_same<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT> > >::value,
104 std::vector<std::pair<KeyT, ValueT> >,
105 ContainerT<KeyT, ValueT>
106 >::type operator()() {
107 typedef typename std::conditional<
108 std::is_same<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT> > >::value,
109 std::vector<std::pair<KeyT, ValueT> >,
110 ContainerT<KeyT, ValueT>
111 >::type ReturnT;
112
113 ReturnT container;
114 with_transaction([this, &container](MDBX_txn* txn) {
115 db_load(container, txn);
117 return container;
118 }
119#endif
120
123 public:
128 : m_db(db), m_key(std::move(key)) {}
129
133 AssignmentProxy& operator=(const ValueT& value) {
134 m_db.insert_or_assign(m_key, value);
135 return *this;
136 }
137
140 operator ValueT() const {
141#if __cplusplus >= 201703L
142 auto val = m_db.find(m_key);
143 if (val) return *val;
144#else
145 std::pair<bool, ValueT> val = m_db.find(m_key);
146 if (val.first) return val.second;
147#endif
148 ValueT def{}; // default construct if missing
149 m_db.insert_or_assign(m_key, def); // persist the default value
150 return def;
151 }
152
153 private:
155 KeyT m_key;
156 };
157
161 AssignmentProxy operator[](const KeyT& key) {
162 return AssignmentProxy(*this, key);
163 }
164
165 // --- Existing methods ---
166
172 template<template <class...> class ContainerT>
173 void load(ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
174 with_transaction([this, &container](MDBX_txn* txn) {
175 db_load(container, txn);
177 }
178
184 template<template <class...> class ContainerT>
185 void load(ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
186 load(container, txn.handle());
187 }
188
193 void load(std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
194 with_transaction([this, &container](MDBX_txn* txn) {
195 db_load(container, txn);
197 }
198
203 void load(std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
204 load(container, txn.handle());
205 }
206
212 template<template<class...> class ContainerT = std::map>
213#if __cplusplus >= 201703L
214 auto retrieve_all(MDBX_txn* txn = nullptr) {
215 using ReturnT = std::conditional_t<
216 std::is_same_v<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT>>>,
217 std::vector<std::pair<KeyT, ValueT>>,
218 ContainerT<KeyT, ValueT>
219 >;
220
221 ReturnT container;
222 with_transaction([this, &container](MDBX_txn* txn) {
223 db_load(container, txn);
225 return container;
226 }
227
233 template<template<class...> class ContainerT = std::map>
234 auto retrieve_all(const Transaction& txn) {
235 return retrieve_all<ContainerT>(txn.handle());
236 }
237#else
238 typename std::conditional<
239 std::is_same<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT> > >::value,
240 std::vector<std::pair<KeyT, ValueT> >,
241 ContainerT<KeyT, ValueT>
242 >::type retrieve_all(MDBX_txn* txn = nullptr) {
243 typedef typename std::conditional<
244 std::is_same<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT> > >::value,
245 std::vector<std::pair<KeyT, ValueT> >,
246 ContainerT<KeyT, ValueT>
247 >::type ReturnT;
248
249 ReturnT container;
250 with_transaction([this, &container](MDBX_txn* txn) {
251 db_load(container, txn);
253 return container;
254 }
255
261 template<template<class...> class ContainerT = std::map>
262 typename std::conditional<
263 std::is_same<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT> > >::value,
264 std::vector<std::pair<KeyT, ValueT> >,
265 ContainerT<KeyT, ValueT>
266 >::type retrieve_all(const Transaction& txn) {
267 return retrieve_all<ContainerT>(txn.handle());
268 }
269#endif
270
276 template<template <class...> class ContainerT>
277 void append(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
278 with_transaction([this, &container](MDBX_txn* txn) {
279 db_append(container, txn);
281 }
282
288 template<template <class...> class ContainerT>
289 void append(const ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
290 append(container, txn.handle());
291 }
292
293
298 void append(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
299 with_transaction([this, &container](MDBX_txn* txn) {
300 db_append(container, txn);
302 }
303
308 void append(const std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
309 append(container, txn.handle());
310 }
311
317 template<template <class...> class ContainerT>
318 void reconcile(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
319 with_transaction([this, &container](MDBX_txn* txn) {
320 db_reconcile(container, txn);
322 }
323
329 template<template <class...> class ContainerT>
330 void reconcile(const ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
331 reconcile(container, txn.handle());
332 }
333
338 void reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
339 with_transaction([this, &container](MDBX_txn* txn) {
340 db_reconcile(container, txn);
342 }
343
348 void reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
349 reconcile(container, txn.handle());
350 }
351
358 bool insert(const KeyT &key, const ValueT &value, MDBX_txn* txn = nullptr) {
359 bool res;
360 with_transaction([this, &key, &value, &res](MDBX_txn* txn) {
361 res = db_insert_if_absent(key, value, txn);
363 return res;
364 }
365
372 bool insert(const KeyT &key, const ValueT &value, const Transaction& txn) {
373 return insert(key, value, txn.handle());
374 }
375
381 bool insert(const std::pair<KeyT, ValueT> &pair, MDBX_txn* txn = nullptr) {
382 bool res;
383 with_transaction([this, &pair, &res](MDBX_txn* txn) {
384 res = db_insert_if_absent(pair.first, pair.second, txn);
386 return res;
387 }
388
394 bool insert(const std::pair<KeyT, ValueT> &pair, const Transaction& txn) {
395 return insert(pair, txn.handle());
396 }
397
403 void insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn* txn = nullptr) {
404 with_transaction([this, &key, &value](MDBX_txn* txn) {
405 db_insert_or_assign(key, value, txn);
407 }
408
414 void insert_or_assign(const KeyT &key, const ValueT &value, const Transaction& txn) {
415 insert_or_assign(key, value, txn.handle());
416 }
417
422 void insert_or_assign(const std::pair<KeyT, ValueT> &pair, MDBX_txn* txn = nullptr) {
423 insert_or_assign([&pair](MDBX_txn* txn) {
424 db_insert_or_assign(pair.first, pair.second, txn);
426 }
427
432 void insert_or_assign(const std::pair<KeyT, ValueT> &pair, const Transaction& txn) {
433 insert_or_assign(pair, txn.handle());
434 }
435
442 ValueT at(const KeyT& key, MDBX_txn* txn = nullptr) const {
443 ValueT value;
444 with_transaction([this, &key, &value](MDBX_txn* txn) {
445 if (!db_get(key, value, txn)) {
446 throw std::out_of_range("Key not found in database");
447 }
449 return value;
450 }
451
458 ValueT at(const KeyT& key, const Transaction& txn) const {
459 return at(key, txn.handle());
460 }
461
468 bool try_get(const KeyT& key, ValueT& out, MDBX_txn* txn) const {
469 bool res;
470 with_transaction([this, &key, &out, &res](MDBX_txn* txn) {
471 res = db_get(key, out, txn);
473 return res;
474 }
475
482 bool try_get(const KeyT& key, ValueT& out, const Transaction& txn) const {
483 return try_get(key, out, txn.handle());
484 }
485
486#if __cplusplus >= 201703L
492 std::optional<ValueT> find(const KeyT& key, MDBX_txn* txn = nullptr) const {
493 std::optional<ValueT> result;
494 with_transaction([this, &key, &result](MDBX_txn* txn) {
495 ValueT tmp;
496 if (db_get(key, tmp, txn)) {
497 result = std::move(tmp);
498 }
500 return result;
501 }
502
508 std::optional<ValueT> find(const KeyT& key, const Transaction& txn) const {
509 return find(key, txn.handle());
510 }
511#else
517 std::pair<bool, ValueT> find(const KeyT& key, MDBX_txn* txn = nullptr) const {
518 std::pair<bool, ValueT> result(false, ValueT());
519 with_transaction([this, &key, &result](MDBX_txn* txn) {
520 if (db_get(key, result.second, txn)) {
521 result.first = true;
522 }
524 return result;
525 }
526
532 std::pair<bool, ValueT> find(const KeyT& key, const Transaction& txn) const {
533 return find(key, txn.handle());
534 }
535#endif
536
542 std::pair<bool, ValueT> find_compat(const KeyT& key, MDBX_txn* txn = nullptr) const {
543 std::pair<bool, ValueT> result{false, ValueT{}};
544 with_transaction([this, &key, &result](MDBX_txn* txn) {
545 if (db_get(key, result.second, txn)) {
546 result.first = true;
547 }
549 return result;
550 }
551
557 std::pair<bool, ValueT> find_compat(const KeyT& key, const Transaction& txn) const {
558 return find_compat(key, txn.handle());
559 }
560
566 bool contains(const KeyT& key, MDBX_txn* txn = nullptr) const {
567 bool res;
568 with_transaction([this, &key, &res](MDBX_txn* txn) {
569 res = db_contains(key, txn);
571 return res;
572 }
573
579 bool contains(const KeyT& key, const Transaction& txn) const {
580 return contains(key, txn.handle());
581 }
582
587 std::size_t count(MDBX_txn* txn = nullptr) const {
588 std::size_t res = 0;
589 with_transaction([this, &res](MDBX_txn* txn) {
590 res = db_count(txn);
592 return res;
593 }
594
599 std::size_t count(const Transaction& txn) const {
600 return count(txn.handle());
601 }
602
607 bool empty(MDBX_txn* txn = nullptr) const {
608 std::size_t res = 0;
609 with_transaction([this, &res](MDBX_txn* txn) {
610 res = db_count(txn);
612 return (res == 0);
613 }
614
619 bool empty(const Transaction& txn) const {
620 return empty(txn.handle());
621 }
622
628 bool erase(const KeyT &key, MDBX_txn* txn = nullptr) {
629 bool res;
630 with_transaction([this, &key, &res](MDBX_txn* txn) {
631 res = db_erase(key, txn);
633 return res;
634 }
635
641 bool erase(const KeyT &key, const Transaction& txn) {
642 return erase(key, txn.handle());
643 }
644
648 void clear(MDBX_txn* txn = nullptr) {
649 with_transaction([this](MDBX_txn* txn) {
650 db_clear(txn);
652 }
653
657 void clear(const Transaction& txn) {
658 clear(txn.handle());
659 }
660
661 private:
662
668 template<typename F>
669 void with_transaction(F&& action, TransactionMode mode = TransactionMode::WRITABLE, MDBX_txn* txn = nullptr) const {
670 if (txn) {
671 action(txn);
672 return;
673 }
674 txn = thread_txn(); // reuse transaction bound to this thread if any
675 if (txn) {
676 action(txn);
677 return;
678 }
679
680 auto txn_guard = m_connection->transaction(mode);
681 try {
682 action(txn_guard.handle());
683 txn_guard.commit();
684 } catch(...) {
685 // Ensure rollback on any exception and rethrow to the caller
686 try {
687 txn_guard.rollback();
688 } catch(...) {
689 // Ignore rollback errors here
690 }
691 throw;
692 }
693 }
694
700 template<template <class...> class ContainerT>
701 void db_load(ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
702 MDBX_cursor* cursor = nullptr;
703 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
704
705 MDBX_val db_key, db_val;
706 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
707 auto&& key = deserialize_value<KeyT>(db_key);
708 auto&& value = deserialize_value<ValueT>(db_val);
709 container.emplace(std::move(key), std::move(value));
710 }
711
712 mdbx_cursor_close(cursor);
713 }
714
719 void db_load(std::vector<std::pair<KeyT, ValueT>>& out_vector, MDBX_txn* txn) {
720 MDBX_cursor* cursor = nullptr;
721 check_mdbx(mdbx_cursor_open(txn, m_dbi, &cursor), "Failed to open MDBX cursor");
722
723 MDBX_val db_key, db_val;
724 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
725 auto&& key = deserialize_value<KeyT>(db_key);
726 auto&& value = deserialize_value<ValueT>(db_val);
727 out_vector.emplace_back(std::move(key), std::move(value));
728 }
729
730 mdbx_cursor_close(cursor);
731 }
732
739 bool db_get(const KeyT& key, ValueT& value, MDBX_txn* txn_handle) const {
740 SerializeScratch sc_key;
741 MDBX_val db_key = serialize_key(key, sc_key);
742 MDBX_val db_val;
743 int rc = mdbx_get(txn_handle, m_dbi, &db_key, &db_val);
744 if (rc == MDBX_NOTFOUND) return false;
745 check_mdbx(rc, "Failed to retrieve value");
746 value = deserialize_value<ValueT>(db_val);
747 return true;
748 }
749
755 bool db_contains(const KeyT& key, MDBX_txn* txn_handle) const {
756 SerializeScratch sc_key;
757 MDBX_val db_key = serialize_key(key, sc_key);
758 MDBX_val db_val; // dummy
759 int rc = mdbx_get(txn_handle, m_dbi, &db_key, &db_val);
760 if (rc == MDBX_NOTFOUND) return false;
761 check_mdbx(rc, "Failed to check key presence");
762 return true;
763 }
764
769 std::size_t db_count(MDBX_txn* txn_handle) const {
770 MDBX_stat stat;
771 check_mdbx(mdbx_dbi_stat(txn_handle, m_dbi, &stat, sizeof(stat)), "Failed to query database statistics");
772 return stat.ms_entries;
773 }
774
780 template<template <class...> class ContainerT>
781 void db_append(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
782 SerializeScratch sc_key;
783 SerializeScratch sc_value;
784
785 for (const auto& pair : container) {
786 MDBX_val db_key = serialize_key(pair.first, sc_key);
787 MDBX_val db_val = serialize_value(pair.second, sc_value);
789 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
790 "Failed to write record"
791 );
792 }
793 }
794
799 void db_append(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn_handle) {
800 SerializeScratch sc_key;
801 SerializeScratch sc_value;
802
803#if __cplusplus >= 201703L
804 for (const auto& [key, value] : container) {
805 MDBX_val db_key = serialize_key(key, sc_key);
806 MDBX_val db_val = serialize_value(value, sc_value);
808 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
809 "Failed to write record"
810 );
811 }
812#else
813 for (typename std::vector<std::pair<KeyT, ValueT> >::const_iterator it = container.begin();
814 it != container.end(); ++it) {
815 const KeyT& key = it->first;
816 const ValueT& value = it->second;
817 MDBX_val db_key = serialize_key(key, sc_key);
818 MDBX_val db_val = serialize_value(value, sc_value);
820 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
821 "Failed to write record"
822 );
823 }
824#endif
825 }
826
834 template<template <class...> class ContainerT>
835 void db_reconcile(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
836 SerializeScratch sc_key;
837 SerializeScratch sc_value;
838
839 // 1. Collect all keys from the container
840 std::unordered_set<KeyT> new_keys;
841 for (const auto& pair : container) {
842 new_keys.insert(pair.first);
843 MDBX_val db_key = serialize_key(pair.first, sc_key);
844 MDBX_val db_val = serialize_value(pair.second, sc_value);
846 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
847 "Failed to write record"
848 );
849 }
850
851 // 2. Iterate over existing keys in the DB and remove the extras
852 MDBX_cursor* cursor = nullptr;
853 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
854
855 MDBX_val db_key, db_val;
856 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
857 auto&& key = deserialize_value<KeyT>(db_key);
858 if (new_keys.find(key) == new_keys.end()) {
859 check_mdbx(mdbx_cursor_del(cursor, MDBX_CURRENT), "Failed to delete record using cursor");
860 }
861 }
862
863 mdbx_cursor_close(cursor);
864 }
865
871 void db_reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn_handle) {
872 SerializeScratch sc_key;
873 SerializeScratch sc_value;
874
875 // 1. Collect keys and upsert values
876 std::unordered_set<KeyT> new_keys;
877 for (size_t i = 0; i < container.size(); ++i) {
878 const KeyT& key = container[i].first;
879 const ValueT& value = container[i].second;
880
881 new_keys.insert(key);
882
883 MDBX_val db_key = serialize_key(key, sc_key);
884 MDBX_val db_val = serialize_value(value, sc_value);
886 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
887 "Failed to write record"
888 );
889 }
890
891 // 2. Delete stale keys from DB
892 MDBX_cursor* cursor = nullptr;
893 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
894
895 MDBX_val db_key, db_val;
896 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
897 KeyT key = deserialize_value<KeyT>(db_key);
898 if (new_keys.find(key) == new_keys.end()) {
899 check_mdbx(mdbx_cursor_del(cursor, MDBX_CURRENT), "Failed to delete record using cursor");
900 }
901 }
902
903 mdbx_cursor_close(cursor);
904 }
905
912 bool db_insert_if_absent(const KeyT& key, const ValueT& value, MDBX_txn* txn_handle) {
913 SerializeScratch sc_key;
914 SerializeScratch sc_value;
915 MDBX_val db_key = serialize_key(key, sc_key);
916 MDBX_val db_val = serialize_value(value, sc_value);
917 int rc = mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_NOOVERWRITE);
918
919 if (rc == MDBX_SUCCESS)
920 return true;
921 if (rc == MDBX_KEYEXIST)
922 return false;
923
924 check_mdbx(rc, "Failed to insert key-value pair");
925 return false;
926 }
927
933 void db_insert_or_assign(const KeyT& key, const ValueT& value, MDBX_txn* txn_handle) {
934 SerializeScratch sc_key;
935 SerializeScratch sc_value;
936 MDBX_val db_key = serialize_key(key, sc_key);
937 MDBX_val db_val = serialize_value(value, sc_value);
939 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT), // or 0
940 "Failed to insert or assign key-value pair"
941 );
942 }
943
949 bool db_erase(const KeyT& key, MDBX_txn* txn_handle) {
950 SerializeScratch sc_key;
951 MDBX_val db_key = serialize_key(key, sc_key);
952 int rc = mdbx_del(txn_handle, m_dbi, &db_key, nullptr);
953 if (rc == MDBX_SUCCESS) return true;
954 if (rc == MDBX_NOTFOUND) return false;
955 check_mdbx(rc, "Failed to erase key");
956 return false;
957 }
958
961 void db_clear(MDBX_txn* txn_handle) {
962 check_mdbx(mdbx_drop(txn_handle, m_dbi, 0), "Failed to clear table");
963 }
964
965 }; // KeyValueTable
966
967}; // namespace mdbxc
968
969#endif // _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
MDBX_txn * thread_txn() const
Returns the transaction bound to the current thread, if any.
Definition BaseTable.hpp:97
MDBX_dbi m_dbi
DBI handle for the opened table.
Definition BaseTable.hpp:93
BaseTable(std::shared_ptr< Connection > connection, std::string name, MDBX_db_flags_t flags)
Construct the database table accessor.
Definition BaseTable.hpp:22
std::shared_ptr< Connection > m_connection
Shared connection to MDBX environment.
Definition BaseTable.hpp:92
Parameters used by Connection to create the MDBX environment.
Definition Config.hpp:17
Manages a single MDBX environment and an optional read-only transaction.
Helper proxy for convenient assignment via operator[].
AssignmentProxy(KeyValueTable &db, KeyT key)
Constructs the proxy for a specific key.
KeyValueTable & m_db
Reference to the owning table.
KeyT m_key
Key associated with this proxy.
AssignmentProxy & operator=(const ValueT &value)
Assigns a value to the stored key.
void load(ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Loads data from the database into the container using provided transaction.
void db_reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn_handle)
Reconciles the content of the database with the given vector of key-value pairs.
bool db_insert_if_absent(const KeyT &key, const ValueT &value, MDBX_txn *txn_handle)
Inserts a key-value pair only if the key does not already exist.
std::size_t count(MDBX_txn *txn=nullptr) const
Returns the number of elements in the database.
std::size_t db_count(MDBX_txn *txn_handle) const
Returns the number of elements in the database.
void load(ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Loads data from the database into the container.
bool insert(const KeyT &key, const ValueT &value, MDBX_txn *txn=nullptr)
Inserts key-value only if key is absent.
bool empty(MDBX_txn *txn=nullptr) const
Checks if the database is empty.
void insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn *txn=nullptr)
Inserts or replaces key-value pair.
void load(std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Loads all key-value pairs into a std::vector of pairs.
bool contains(const KeyT &key, const Transaction &txn) const
Checks whether a key exists in the database.
KeyValueTable & operator=(const std::vector< std::pair< KeyT, ValueT > > &container)
Assigns a vector of key-value pairs to the database.
void reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Reconciles the database with the vector of key-value pairs.
bool try_get(const KeyT &key, ValueT &out, const Transaction &txn) const
Tries to find value by key.
void insert_or_assign(const std::pair< KeyT, ValueT > &pair, MDBX_txn *txn=nullptr)
Inserts or replaces key-value pair.
bool insert(const KeyT &key, const ValueT &value, const Transaction &txn)
Inserts key-value only if key is absent.
bool db_erase(const KeyT &key, MDBX_txn *txn_handle)
Removes a key from the database.
bool try_get(const KeyT &key, ValueT &out, MDBX_txn *txn) const
Tries to find value by key.
void db_append(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Appends the content of the container to the database.
void insert_or_assign(const std::pair< KeyT, ValueT > &pair, const Transaction &txn)
Inserts or replaces key-value pair.
AssignmentProxy operator[](const KeyT &key)
Provides convenient access to insert or read a value by key.
std::pair< bool, ValueT > find_compat(const KeyT &key, MDBX_txn *txn=nullptr) const
Finds value by key.
void db_load(std::vector< std::pair< KeyT, ValueT > > &out_vector, MDBX_txn *txn)
Loads all key-value pairs into a std::vector of pairs.
KeyValueTable(const Config &config, std::string name="kv_store", MDBX_db_flags_t flags=MDBX_DB_DEFAULTS|MDBX_CREATE)
Constructor with configuration.
bool contains(const KeyT &key, MDBX_txn *txn=nullptr) const
Checks whether a key exists in the database.
void db_load(ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Loads data from the database into the container.
void reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Reconciles the database with the vector of key-value pairs using provided transaction.
bool empty(const Transaction &txn) const
Checks if the database is empty.
void db_clear(MDBX_txn *txn_handle)
Clears all key-value pairs from the database.
void db_insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn *txn_handle)
Inserts or replaces the key-value pair.
std::pair< bool, ValueT > find(const KeyT &key, MDBX_txn *txn=nullptr) const
Finds value by key.
void db_append(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn_handle)
Appends the content of the vector to the database.
void clear(const Transaction &txn)
Clears all key-value pairs from the database.
void append(const ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Appends data to the database.
ValueT at(const KeyT &key, const Transaction &txn) const
Retrieves value by key or throws.
void reconcile(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Reconciles the database with the container.
bool erase(const KeyT &key, const Transaction &txn)
Removes key from DB.
std::pair< bool, ValueT > find(const KeyT &key, const Transaction &txn) const
Finds value by key.
std::size_t count(const Transaction &txn) const
Returns the number of elements in the database.
void clear(MDBX_txn *txn=nullptr)
Clears all key-value pairs from the database.
void load(std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Loads all key-value pairs into a std::vector of pairs.
void db_reconcile(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Reconciles the content of the database with the container.
ValueT at(const KeyT &key, MDBX_txn *txn=nullptr) const
Retrieves value by key or throws.
void reconcile(const ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Reconciles the database with the container.
bool db_contains(const KeyT &key, MDBX_txn *txn_handle) const
Checks whether a key exists in the database.
std::pair< bool, ValueT > find_compat(const KeyT &key, const Transaction &txn) const
Finds value by key.
bool insert(const std::pair< KeyT, ValueT > &pair, const Transaction &txn)
Inserts key-value only if key is absent.
KeyValueTable(std::shared_ptr< Connection > connection, std::string name="kv_store", MDBX_db_flags_t flags=MDBX_DB_DEFAULTS|MDBX_CREATE)
Default constructor.
void append(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Appends data from a vector to the database.
bool erase(const KeyT &key, MDBX_txn *txn=nullptr)
Removes key from DB.
~KeyValueTable() override final=default
Destructor.
void insert_or_assign(const KeyT &key, const ValueT &value, const Transaction &txn)
Inserts or replaces key-value pair.
std::conditional< std::is_same< ContainerT< KeyT, ValueT >, std::vector< std::pair< KeyT, ValueT > > >::value, std::vector< std::pair< KeyT, ValueT > >, ContainerT< KeyT, ValueT > >::type retrieve_all(const Transaction &txn)
Retrieves all key-value pairs into the specified container type.
std::conditional< std::is_same< ContainerT< KeyT, ValueT >, std::vector< std::pair< KeyT, ValueT > > >::value, std::vector< std::pair< KeyT, ValueT > >, ContainerT< KeyT, ValueT > >::type operator()()
Loads all key-value pairs from the database into a container.
std::conditional< std::is_same< ContainerT< KeyT, ValueT >, std::vector< std::pair< KeyT, ValueT > > >::value, std::vector< std::pair< KeyT, ValueT > >, ContainerT< KeyT, ValueT > >::type retrieve_all(MDBX_txn *txn=nullptr)
Retrieves all key-value pairs into the specified container type.
bool db_get(const KeyT &key, ValueT &value, MDBX_txn *txn_handle) const
Gets a value by key from the database.
void append(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Appends data to the database.
void append(const std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Appends data from a vector to the database using a provided transaction.
void with_transaction(F &&action, TransactionMode mode=TransactionMode::WRITABLE, MDBX_txn *txn=nullptr) const
Executes a functor within a transaction context.
bool insert(const std::pair< KeyT, ValueT > &pair, MDBX_txn *txn=nullptr)
Inserts key-value only if key is absent.
Manages MDBX transactions with automatic cleanup and error handling.
MDBX_txn * handle() const noexcept
Returns the internal MDBX transaction handle.
Publicly usable low-level components of the MDBX Containers library.
std::enable_if<!has_value_type< T >::value &&!std::is_same< T, std::vector< typenameT::value_type > >::value &&!std::is_trivially_copyable< typenameT::value_type >::value &&!has_to_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, MDBX_val >::type serialize_value(const T &value, SerializeScratch &sc)
Serializes a general value into MDBX_val.
Definition utils.hpp:376
std::enable_if<!has_value_type< T >::value &&!has_from_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, T >::type deserialize_value(const MDBX_val &val)
Deserializes a value from MDBX_val into type T.
Definition utils.hpp:486
MDBX_db_flags_t get_mdbx_flags()
Returns MDBX flags for a given key type.
Definition utils.hpp:94
std::enable_if<!has_to_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, MDBX_val >::type serialize_key(const T &key, SerializeScratch &sc)
Serializes a key into MDBX_val for database operations.
Definition utils.hpp:230
void check_mdbx(int rc, const std::string &context)
Throws an MdbxException if MDBX return code indicates an error.
Definition utils.hpp:23
TransactionMode
Specifies the access mode of a transaction.
@ READ_ONLY
Read-only transaction (no write operations allowed).
@ WRITABLE
Writable transaction (allows inserts, updates, deletes).
Per-call scratch buffer to produce MDBX_val without using thread_local.
Definition utils.hpp:168