MDBX Containers
Loading...
Searching...
No Matches
kv_container_all_types_test.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <thread>
3#include <mutex>
4#include <condition_variable>
5#include <atomic>
6#include <cassert>
8
9
11 int x;
12 float y;
13
14 std::vector<uint8_t> to_bytes() const {
15 std::vector<uint8_t> bytes(sizeof(SimpleStruct));
16 std::memcpy(bytes.data(), this, sizeof(SimpleStruct));
17 return bytes;
18 }
19
20 static SimpleStruct from_bytes(const std::vector<uint8_t>& bytes) {
21 SimpleStruct s{};
22 std::memcpy(&s, bytes.data(), sizeof(SimpleStruct));
23 return s;
24 }
25
26 static SimpleStruct from_bytes(const void* data, size_t size) {
27 if (size != (sizeof(int) + sizeof(float)))
28 throw std::runtime_error("Invalid data size for SimpleStruct");
29 const uint8_t* ptr = static_cast<const uint8_t*>(data);
30 SimpleStruct s{};
31 std::memcpy(&s, ptr, sizeof(SimpleStruct));
32 return s;
33 }
34
35 bool operator==(const SimpleStruct& other) const {
36 return x == other.x && y == other.y;
37 }
38};
39
41 int value;
42
43 std::vector<uint8_t> to_bytes() const {
44 std::vector<uint8_t> bytes(sizeof(ConcurrentStruct));
45 std::memcpy(bytes.data(), this, sizeof(ConcurrentStruct));
46 return bytes;
47 }
48
49 static ConcurrentStruct from_bytes(const void* data, size_t size) {
50 if (size != sizeof(ConcurrentStruct))
51 throw std::runtime_error("Invalid data size");
53 std::memcpy(&s, data, sizeof(ConcurrentStruct));
54 return s;
55 }
56
57 bool operator==(const ConcurrentStruct& other) const {
58 return value == other.value;
59 }
60
61 bool operator!=(const ConcurrentStruct& other) const {
62 return !(*this == other);
63 }
64};
65
66int main() {
67 mdbxc::Config cfg;
68 cfg.pathname = "./data/testdb";
69 cfg.max_dbs = 14;
70 cfg.no_subdir = false;
71 cfg.relative_to_exe = true;
72
73 auto conn = mdbxc::Connection::create(cfg);
74
75 // int8 -> int8
76 std::cout << "int8 -> int8\n";
77 {
79 kv.insert_or_assign(1, 100);
80 assert(kv.find(1).value() == 100);
81 }
82
83 // int8 -> int64
84 std::cout << "int8 -> int64\n";
85 {
87 kv.insert_or_assign(2, 1234567890123456LL);
88 assert(kv.find(2).value() == 1234567890123456LL);
89 }
90
91 // int32 -> string
92 std::cout << "int32 -> string\n";
93 {
95 kv.insert_or_assign(3, "hello");
96 assert(kv.find(3).value() == "hello");
97 }
98
99 // string -> string
100 std::cout << "string -> string\n";
101 {
103 kv.insert_or_assign("key", "value");
104 assert(kv.find("key").value() == "value");
105 }
106
107 // string -> POD
108 std::cout << "string -> POD\n";
109 {
111 SimpleStruct s{42, 3.14f};
112 kv.insert_or_assign("obj", s);
113 assert(kv.find("obj").value() == s);
114 }
115
116 // int64 -> vector<byte>
117 std::cout << "int64 -> vector<byte>\n";
118 {
120 std::vector<uint8_t> data{1, 2, 3, 4};
121 kv.insert_or_assign(9, data);
122 assert(kv.find(9).value() == data);
123 }
124
125 // string -> vector<SimpleStruct>
126 std::cout << "string -> vector<SimpleStruct>\n";
127 {
129 std::vector<SimpleStruct> vec{{1, 1.0f}, {2, 2.0f}};
130 kv.insert_or_assign("many", vec);
131 assert(kv.find("many").value() == vec);
132 }
133
134 // string -> list<string>
135 std::cout << "string -> list<string>\n";
136 {
138 std::list<std::string> lst{"a", "b", "c"};
139 kv.insert_or_assign("letters", lst);
140 assert(kv.find("letters").value() == lst);
141 }
142
143 // string -> vector<string>
144 std::cout << "string -> vector<string>\n";
145 {
147 std::vector<std::string> lst{"a", "b", "c"};
148 kv.insert_or_assign("letters", lst);
149 assert(kv.find("letters").value() == lst);
150 }
151
152 // string -> set<string>
153 std::cout << "string -> set<string>\n";
154 {
156 std::set<std::string> s{"a", "b", "c"};
157 kv.insert_or_assign("letters", s);
158 assert(kv.find("letters").value() == s);
159 }
160
161 // string -> set<int>
162 std::cout << "string -> set<int>\n";
163 {
165 std::set<int> s{1, 2, 3};
166 kv.insert_or_assign("digits", s);
167 assert(kv.find("digits").value() == s);
168 }
169
170 // string -> self-serializable struct
171 std::cout << "string -> self-serializable struct\n";
172 {
173 struct Serializable {
174 int a = 0;
175 std::string b;
176
177 Serializable() {}
178 Serializable(int a_, const std::string& b_) : a(a_), b(b_) {}
179
180 std::vector<uint8_t> to_bytes() const {
181 std::vector<uint8_t> result(sizeof(int) + b.size());
182 std::memcpy(result.data(), &a, sizeof(int));
183 std::memcpy(result.data() + sizeof(int), b.data(), b.size());
184 return result;
185 }
186
187 static Serializable from_bytes(const void* data, size_t size) {
188 if (size < sizeof(int))
189 throw std::runtime_error("Invalid data size for Serializable");
190 const uint8_t* ptr = static_cast<const uint8_t*>(data);
191 Serializable s;
192 std::memcpy(&s.a, ptr, sizeof(int));
193 s.b = std::string(reinterpret_cast<const char*>(ptr + sizeof(int)), size - sizeof(int));
194 return s;
195 }
196
197 bool operator==(const Serializable& other) const {
198 return a == other.a && b == other.b;
199 }
200 };
201
202 mdbxc::KeyValueTable<std::string, Serializable> kv(conn, "str_serializable");
203 Serializable s{7, "seven"};
204 kv.insert_or_assign("ser", s);
205 assert(kv.find("ser").value() == s);
206 }
207
208 {
209 mdbxc::KeyValueTable<int, ConcurrentStruct> kv(conn, "concurrent_test");
210
211 std::mutex mtx;
212 std::condition_variable cv;
213 std::atomic<bool> ready(false);
214 std::atomic<bool> failed(false);
215 ConcurrentStruct written;
216
217 std::thread writer([&kv, &ready, &written, &cv, &mtx] {
218 for (int i = 0; i < 100; ++i) {
219 {
220 std::lock_guard<std::mutex> lock(mtx);
221 written = ConcurrentStruct{i};
222 kv.insert_or_assign(1, written);
223 ready = true;
224 }
225 cv.notify_one();
226 std::this_thread::sleep_for(std::chrono::milliseconds(1));
227 }
228 });
229
230 std::thread reader([&kv, &ready, &failed, &written, &cv, &mtx] {
231 for (int i = 0; i < 100; ++i) {
232 std::unique_lock<std::mutex> lock(mtx);
233 cv.wait(lock, [&] { return ready.load(); });
234
235# if __cplusplus >= 201703L
236 auto val = kv.find(1);
237 if (!val.has_value() || val.value() != written) {
238 std::cerr << "Mismatch at iteration " << i << ": got " << val.value().value << ", expected " << written.value << std::endl;
239 failed = true;
240 break;
241 }
242# else
243 auto val = kv.find_compat(1);
244 if (!val.first || val.second != written) {
245 std::cerr << "Mismatch at iteration " << i << ": got " << val.second.value << ", expected " << written.value << std::endl;
246 failed = true;
247 break;
248 }
249# endif
250
251 ready = false;
252 }
253 });
254
255 writer.join();
256 reader.join();
257
258 if (failed) {
259 std::cerr << "Concurrent test failed." << std::endl;
260 return 1;
261 }
262
263 std::cout << "Concurrent test passed." << std::endl;
264
265 }
266
267 std::cout << "All tests passed.\n";
268 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
269 std::cin.get();
270 return 0;
271}
Declaration of the KeyValueTable class for managing key-value pairs in an MDBX database.
Parameters used by Connection to create the MDBX environment.
Definition Config.hpp:17
bool no_subdir
Whether to store the database in a single file instead of a directory.
Definition Config.hpp:30
std::string pathname
Path to the database file or directory containing the database.
Definition Config.hpp:19
bool relative_to_exe
Whether to resolve a relative path relative to the executable directory.
Definition Config.hpp:33
int64_t max_dbs
Maximum number of named databases (DBI) in the environment.
Definition Config.hpp:27
static std::shared_ptr< Connection > create(const Config &config)
Creates and connects a new shared Connection instance.
Template class for managing key-value pairs in an MDBX database.
void insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn *txn=nullptr)
Inserts or replaces key-value pair.
std::pair< bool, ValueT > find_compat(const KeyT &key, MDBX_txn *txn=nullptr) const
Finds value by key.
bool operator!=(const ConcurrentStruct &other) const
static ConcurrentStruct from_bytes(const void *data, size_t size)
bool operator==(const ConcurrentStruct &other) const
std::vector< uint8_t > to_bytes() const
bool operator==(const SimpleStruct &other) const
static SimpleStruct from_bytes(const void *data, size_t size)
static SimpleStruct from_bytes(const std::vector< uint8_t > &bytes)
std::vector< uint8_t > to_bytes() const