Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
lmdb_store.test.cpp
Go to the documentation of this file.
1#include <cstddef>
2#include <cstdint>
3#include <gtest/gtest.h>
4
5#include <chrono>
6#include <cstdlib>
7#include <filesystem>
8#include <memory>
9#include <optional>
10#include <sstream>
11#include <stdexcept>
12#include <vector>
13
27
28using namespace bb::lmdblib;
29
30class LMDBStoreTest : public testing::Test {
31 protected:
32 void SetUp() override
33 {
35 _mapSize = 1024 * 1024;
36 _maxReaders = 16;
37 std::filesystem::create_directories(_directory);
38 }
39
40 void TearDown() override { std::filesystem::remove_all(_directory); }
41
42 public:
43 static std::string _directory;
44 static uint32_t _maxReaders;
45 static uint64_t _mapSize;
46};
47
51
57
58void prepare_test_data(int64_t numKeys, int64_t numValues, KeyDupValuesVector& testData, int64_t keyOffset = 0)
59{
60 for (int64_t count = 0; count < numKeys; count++) {
61 int64_t keyValue = keyOffset + count;
62 auto key = get_key(keyValue);
63 ValuesVector dup;
64 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
65 auto data = get_value(keyValue, dupCount);
66 dup.emplace_back(data);
67 }
68 KeyValuesPair pair = { key, dup };
69 testData.emplace_back(pair);
70 }
71}
72
74 std::vector<std::string> dbNames, int64_t numKeys, int64_t numValues, LMDBStore& store, int64_t keyOffset = 0)
75{
76 KeyDupValuesVector toWrite;
78 prepare_test_data(numKeys, numValues, toWrite, keyOffset);
79 for (auto& name : dbNames) {
80 LMDBStore::PutData putData = { toWrite, toDelete, name };
81 std::vector<LMDBStore::PutData> putDatas = { putData };
82 store.put(putDatas);
83 }
84}
85
90
91TEST_F(LMDBStoreTest, can_create_database)
92{
94 const std::string name = "Test Database";
95 EXPECT_NO_THROW(store->open_database(name));
96}
97
98TEST_F(LMDBStoreTest, can_not_create_more_databases_then_specified)
99{
100 LMDBStore::Ptr store = create_store(2);
101 const std::string name1 = "Test Database 1";
102 EXPECT_NO_THROW(store->open_database(name1));
103 const std::string name2 = "Test Database 2";
104 EXPECT_NO_THROW(store->open_database(name2));
105 const std::string name3 = "Test Database 3";
106 EXPECT_THROW(store->open_database(name3), std::runtime_error);
107}
108
109TEST_F(LMDBStoreTest, can_write_to_database)
110{
112 const std::string name = "Test Database";
113 store->open_database(name);
114
115 auto key = get_key(0);
116 auto data = get_value(0, 1);
117 KeyDupValuesVector toWrite = { { { key, { data } } } };
119 LMDBStore::PutData putData = { toWrite, toDelete, name };
120 std::vector<LMDBStore::PutData> putDatas = { putData };
121 EXPECT_NO_THROW(store->put(putDatas));
122}
123
124TEST_F(LMDBStoreTest, can_not_write_to_database_that_does_not_exist)
125{
127 const std::string name = "Test Database";
128 store->open_database(name);
129
130 auto key = get_key(0);
131 auto data = get_value(0, 1);
132 KeyDupValuesVector toWrite = { { { key, { data } } } };
134 LMDBStore::PutData putData = { toWrite, toDelete, "Non Existent Database" };
135 std::vector<LMDBStore::PutData> putDatas = { putData };
136 EXPECT_THROW(store->put(putDatas), std::runtime_error);
137}
138
139TEST_F(LMDBStoreTest, can_close_database)
140{
142 const std::string name = "Test Database";
143 store->open_database(name);
144
145 auto key = get_key(0);
146 auto data = get_value(0, 1);
147 KeyDupValuesVector toWrite = { { { key, { data } } } };
149 LMDBStore::PutData putData = { toWrite, toDelete, name };
150 std::vector<LMDBStore::PutData> putDatas = { putData };
151 EXPECT_NO_THROW(store->put(putDatas));
152
153 EXPECT_NO_THROW(store->close_database(name));
154
155 // try another write
156 key = get_key(1);
157 data = get_value(1, 1);
158 toWrite = { { { key, { data } } } };
159 putData = { toWrite, toDelete, name };
160 putDatas = { putData };
161 EXPECT_THROW(store->put(putDatas), std::runtime_error);
162}
163
164TEST_F(LMDBStoreTest, can_write_duplicate_keys_to_database)
165{
166 LMDBStore::Ptr store = create_store(2);
167 const std::string name = "Test Database";
168 store->open_database(name);
169 const std::string nameDups = "Test Database Dups";
170 store->open_database(nameDups, true);
171
172 // Write a key multiple times with different values
173 auto key = get_key(0);
174 auto data = get_value(0, 1);
175 auto dataDup = get_value(0, 2);
176 KeyDupValuesVector toWrite = { { { key, { data, dataDup } } } };
178 LMDBStore::PutData putData = { toWrite, toDelete, name };
179 std::vector<LMDBStore::PutData> putDatas = { putData };
180 EXPECT_NO_THROW(store->put(putDatas));
181 LMDBStore::PutData putDataDups = { toWrite, toDelete, nameDups };
182 putDatas = { putDataDups };
183 EXPECT_NO_THROW(store->put(putDatas));
184}
185
186TEST_F(LMDBStoreTest, can_write_the_same_data_multiple_times)
187{
188 LMDBStore::Ptr store = create_store(2);
189 const std::string name = "Test Database";
190 store->open_database(name);
191 const std::string nameDups = "Test Database Dups";
192 store->open_database(nameDups, true);
193
194 // Check that writing duplicates in the same tx works
195 auto key = get_key(0);
196 auto data = get_value(0, 1);
197 KeyDupValuesVector toWrite = { { { key, { data, data } } } };
199 LMDBStore::PutData putData = { toWrite, toDelete, name };
200 std::vector<LMDBStore::PutData> putDatas = { putData };
201 EXPECT_NO_THROW(store->put(putDatas));
202
203 LMDBStore::PutData putDataDups = { toWrite, toDelete, nameDups };
204 putDatas = { putDataDups };
205 EXPECT_NO_THROW(store->put(putDatas));
206
207 // writing again, in a new tx should also work
208 EXPECT_NO_THROW(store->put(putDatas));
209 EXPECT_NO_THROW(store->put(putDatas));
210}
211
212TEST_F(LMDBStoreTest, can_read_from_database)
213{
215 const std::string dbName = "Test Database";
216 store->open_database(dbName);
217
218 auto key = get_key(0);
219 auto expected = get_value(0, 1);
220 KeyDupValuesVector toWrite = { { { key, { expected } } } };
222 LMDBStore::PutData putData = { toWrite, toDelete, dbName };
223 std::vector<LMDBStore::PutData> putDatas = { putData };
224 store->put(putDatas);
225
227 KeysVector keys = { { key } };
228 store->get(keys, data, dbName);
229 EXPECT_EQ(data.size(), 1);
230 EXPECT_TRUE(data[0].has_value());
231 EXPECT_EQ(data[0].value(), ValuesVector{ expected });
232}
233
234TEST_F(LMDBStoreTest, can_not_read_from_non_existent_database)
235{
237 const std::string dbName = "Test Database";
238 store->open_database(dbName);
239
240 auto key = get_key(0);
241 auto expected = get_value(0, 1);
242 KeyDupValuesVector toWrite = { { { key, { expected } } } };
244 LMDBStore::PutData putData = { toWrite, toDelete, dbName };
245 std::vector<LMDBStore::PutData> putDatas = { putData };
246 store->put(putDatas);
247
249 KeysVector keys = { { key } };
250 EXPECT_THROW(store->get(keys, data, "Non Existent Database"), std::runtime_error);
251}
252
253TEST_F(LMDBStoreTest, can_write_and_read_multiple)
254{
255 LMDBStore::Ptr store = create_store(2);
256
257 const std::vector<std::string> dbNames = { "Test Database 1", "Test Database 2" };
258 for (const auto& s : dbNames) {
259 EXPECT_NO_THROW(store->open_database(s));
260 }
261
262 // We will write to multiple databases and read back from them both
263 int64_t numKeys = 10;
264 int64_t numValues = 1;
265
266 write_test_data(dbNames, numKeys, numValues, *store);
267
268 {
269 KeysVector keys;
271 for (int64_t count = 0; count < numKeys; count++) {
272 auto key = get_key(count);
273 auto expected = get_value(count, 0);
274 keys.push_back(key);
275 values.emplace_back(ValuesVector{ expected });
276 }
277
278 {
279 OptionalValuesVector retrieved;
280 store->get(keys, retrieved, dbNames[0]);
281 EXPECT_EQ(retrieved.size(), numKeys);
282 EXPECT_EQ(retrieved, values);
283 }
284 {
285 OptionalValuesVector retrieved;
286 store->get(keys, retrieved, dbNames[1]);
287 EXPECT_EQ(retrieved.size(), numKeys);
288 EXPECT_EQ(retrieved, values);
289 }
290 }
291}
292
293TEST_F(LMDBStoreTest, can_write_and_read_multiple_duplicates)
294{
295 LMDBStore::Ptr store = create_store(2);
296
297 const std::vector<std::string> dbNames = { "Test Database No Dups", "Test Database Dups" };
298 store->open_database(dbNames[0], false);
299 store->open_database(dbNames[1], true);
300
301 // We will write multiple values to the same key
302 // Depending on whether the database supports duplicates determines if
303 // we append or overwrite
304 int64_t numKeys = 1;
305 int64_t numValues = 2;
306
307 write_test_data(dbNames, numKeys, numValues, *store);
308
309 {
310 KeysVector keys;
311 OptionalValuesVector valuesWithoutDups;
312 OptionalValuesVector valuesWithDups;
313 for (int64_t count = 0; count < numKeys; count++) {
314 auto key = get_key(count);
315 // For the no dup DB we expect the last written value to be present
316 auto expectedNoDup = get_value(count, numValues - 1);
317 keys.push_back(key);
318 ValuesVector dup;
319 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
320 auto expectedWithDup = get_value(count, dupCount);
321 dup.emplace_back(expectedWithDup);
322 }
323 valuesWithDups.emplace_back(dup);
324 valuesWithoutDups.emplace_back(ValuesVector{ expectedNoDup });
325 }
326
327 {
328 OptionalValuesVector retrieved;
329 store->get(keys, retrieved, dbNames[0]);
330 EXPECT_EQ(retrieved.size(), numKeys);
331 EXPECT_EQ(retrieved, valuesWithoutDups);
332 }
333 {
334 OptionalValuesVector retrieved;
335 store->get(keys, retrieved, dbNames[1]);
336 EXPECT_EQ(retrieved.size(), numKeys);
337 EXPECT_EQ(retrieved, valuesWithDups);
338 }
339 }
340}
341
342TEST_F(LMDBStoreTest, can_read_missing_keys_from_database)
343{
345 const std::string dbName = "Test Database";
346 store->open_database(dbName);
347
348 // We will attempt to read a non-existant key and see that it returns nothing
349
350 auto key = get_key(0);
351 auto expected = get_value(0, 0);
352 KeyDupValuesVector toWrite = { { { key, { expected } } } };
354 LMDBStore::PutData putData = { toWrite, toDelete, dbName };
355 std::vector<LMDBStore::PutData> putDatas = { putData };
356 store->put(putDatas);
357
359 auto missing = serialise(std::string("Missing Key"));
360 KeysVector keys = { { key }, { missing } };
361 store->get(keys, data, dbName);
362 EXPECT_EQ(data.size(), 2);
363 EXPECT_TRUE(data[0].has_value());
364 EXPECT_EQ(data[0].value(), ValuesVector{ expected });
365 EXPECT_FALSE(data[1].has_value());
366}
367
368TEST_F(LMDBStoreTest, can_write_and_delete)
369{
370 LMDBStore::Ptr store = create_store(2);
371
372 const std::string dbName = "Test Database";
373 store->open_database(dbName);
374
375 // Test writing and deleting items from the database
376
377 int64_t numKeys = 10;
378 int64_t numValues = 1;
379
380 write_test_data({ dbName }, numKeys, numValues, *store);
381
382 {
383 // Write 2 more and delete some
384 KeyDupValuesVector toWrite;
386 for (int64_t count = numKeys; count < numKeys + 2; count++) {
387 auto key = get_key(count);
388 auto data = get_value(count, 0);
389 ValuesVector dup = { data };
390 KeyValuesPair pair = { key, dup };
391 toWrite.emplace_back(pair);
392 }
393 for (int64_t count = 3; count < numKeys - 2; count++) {
394 auto key = get_key(count);
395 auto data = get_value(count, 0);
396 KeyValuesPair pair = { key, { data } };
397 toDelete.emplace_back(pair);
398 }
399 LMDBStore::PutData putData = { toWrite, toDelete, dbName };
400 std::vector<LMDBStore::PutData> putDatas = { putData };
401 store->put(putDatas);
402 }
403
404 {
405 KeysVector keys;
407 for (int64_t count = 0; count < numKeys + 2; count++) {
408 auto key = get_key(count);
409 auto expected = get_value(count, 0);
410 keys.push_back(key);
411 values.emplace_back((count < 3 || count >= (numKeys - 2)) ? OptionalValues(ValuesVector{ expected })
412 : std::nullopt);
413 }
414
415 {
416 OptionalValuesVector retrieved;
417 store->get(keys, retrieved, dbName);
418 EXPECT_EQ(retrieved.size(), numKeys + 2);
419 EXPECT_EQ(retrieved, values);
420 }
421 }
422}
423
424TEST_F(LMDBStoreTest, can_write_and_delete_duplicates)
425{
426 LMDBStore::Ptr store = create_store(2);
427
428 const std::string dbName = "Test Database";
429 store->open_database(dbName, true);
430
431 // Test writing and deleting entries from a database supporting duplicates
432
433 int64_t numKeys = 10;
434 int64_t numValues = 5;
435
436 write_test_data({ dbName }, numKeys, numValues, *store);
437
438 {
439 // Write 2 more and delete some
440 KeyDupValuesVector toWrite;
442 for (int64_t count = numKeys; count < numKeys + 2; count++) {
443 auto key = get_key(count);
444 ValuesVector dup;
445 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
446 auto data = get_value(count, dupCount);
447 dup.emplace_back(data);
448 }
449 KeyValuesPair pair = { key, dup };
450 toWrite.emplace_back(pair);
451 }
452
453 // For some keys we remove some of the values
454 for (int64_t count = 3; count < numKeys - 2; count++) {
455 auto key = get_key(count);
456 ValuesVector dup;
457 // Remove some of the values
458 for (int64_t dupCount = 1; dupCount < numValues - 1; dupCount++) {
459 auto data = get_value(count, dupCount);
460 dup.emplace_back(data);
461 }
462 KeyValuesPair pair = { key, dup };
463 toDelete.emplace_back(pair);
464 }
465 LMDBStore::PutData putData = { toWrite, toDelete, dbName };
466 std::vector<LMDBStore::PutData> putDatas = { putData };
467 store->put(putDatas);
468 }
469
470 {
471 KeysVector keys;
472 OptionalValuesVector expectedValues;
473 for (int64_t count = 0; count < numKeys + 2; count++) {
474 auto key = get_key(count);
475 keys.push_back(key);
476 int64_t deletedDupStart = (count < 3 || count >= (numKeys - 2)) ? numValues : 1;
477 int64_t deletedDupEnd = (count < 3 || count >= (numKeys - 2)) ? 0 : numValues - 1;
478 ValuesVector dup;
479 // The number of keys retrieved depends on whether this key had some value deleted
480 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
481 if (dupCount >= deletedDupStart && dupCount < deletedDupEnd) {
482 continue;
483 }
484 auto data = get_value(count, dupCount);
485 dup.emplace_back(data);
486 }
487 expectedValues.emplace_back(OptionalValues(ValuesVector{ dup }));
488 }
489
490 {
491 OptionalValuesVector retrieved;
492 store->get(keys, retrieved, dbName);
493 EXPECT_EQ(retrieved.size(), numKeys + 2);
494 EXPECT_EQ(retrieved, expectedValues);
495 }
496 }
497}
498
499TEST_F(LMDBStoreTest, can_delete_all_values_from_keys)
500{
501 LMDBStore::Ptr store = create_store(2);
502
503 const std::vector<std::string> dbNames = { "Test Database No Dups", "Test Database Dups" };
504 store->open_database(dbNames[0], false);
505 store->open_database(dbNames[1], true);
506
507 // Test writing and deleting entries from a database supporting duplicates
508
509 int64_t numKeys = 10;
510 int64_t numValues = 5;
511
512 write_test_data(dbNames, numKeys, numValues, *store);
513
514 KeyDupValuesVector toWrite;
516 for (int64_t count = 3; count < numKeys - 2; count++) {
517 auto key = get_key(count);
519 toDelete.emplace_back(pair);
520 }
521 LMDBStore::PutData putData1 = { toWrite, toDelete, dbNames[0] };
522 LMDBStore::PutData putData2 = { toWrite, toDelete, dbNames[1] };
523 std::vector<LMDBStore::PutData> putDatas = { putData1, putData2 };
524 store->put(putDatas);
525 // read all the key/value pairs
526 {
527 // We first read the database that supports duplicates
528 KeysVector keys;
529 KeyDupValuesVector expectedValues;
530 for (int64_t count = 0; count < numKeys; count++) {
531 if (count >= 3 && count < numKeys - 2) {
532 continue;
533 }
534 auto key = get_key(count);
535 keys.push_back(key);
536 ValuesVector dup;
537 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
538 auto data = get_value(count, dupCount);
539 dup.emplace_back(data);
540 }
541 KeyValuesPair pair = { key, dup };
542 expectedValues.emplace_back(pair);
543 }
544 LMDBStore::ReadTransaction::SharedPtr readTransaction = store->create_shared_read_transaction();
545 LMDBCursor::Ptr cursor = store->create_cursor(readTransaction, dbNames[1]);
546 cursor->set_at_start();
547
548 KeyDupValuesVector retrieved;
549 cursor->read_next((uint64_t)numKeys, retrieved);
550 EXPECT_EQ(retrieved, expectedValues);
551 }
552
553 {
554 // Now read the database without duplicates
555 KeysVector keys;
556 KeyDupValuesVector expectedValues;
557 for (int64_t count = 0; count < numKeys; count++) {
558 if (count >= 3 && count < numKeys - 2) {
559 continue;
560 }
561 auto key = get_key(count);
562 keys.push_back(key);
563 ValuesVector dup(1, get_value(count, numValues - 1));
564 KeyValuesPair pair = { key, dup };
565 expectedValues.emplace_back(pair);
566 }
567 LMDBStore::ReadTransaction::SharedPtr readTransaction = store->create_shared_read_transaction();
568 LMDBCursor::Ptr cursor = store->create_cursor(readTransaction, dbNames[0]);
569 cursor->set_at_start();
570
571 KeyDupValuesVector retrieved;
572 cursor->read_next((uint64_t)numKeys, retrieved);
573 EXPECT_EQ(retrieved, expectedValues);
574 }
575}
576
577TEST_F(LMDBStoreTest, can_read_forwards_with_cursors)
578{
579 LMDBStore::Ptr store = create_store(2);
580
581 const std::string dbName = "Test Database";
582 store->open_database(dbName);
583
584 int64_t numKeys = 10;
585 int64_t numValues = 1;
586
587 write_test_data({ dbName }, numKeys, numValues, *store);
588
589 {
590 // read from a key mid-way through
591 int64_t startKey = 3;
592 auto key = get_key(startKey);
593 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
594 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
595 bool setResult = cursor->set_at_key(key);
596 EXPECT_TRUE(setResult);
597
598 int64_t numKeysToRead = 4;
599 KeyDupValuesVector keyValues;
600 cursor->read_next((uint64_t)numKeysToRead, keyValues);
601
602 KeyDupValuesVector expected;
603 for (int64_t count = startKey; count < startKey + numKeysToRead; count++) {
604 auto key = get_key(count);
605 auto data = get_value(count, 0);
606 expected.emplace_back(KeyValuesPair{ key, { data } });
607 }
608 EXPECT_EQ(keyValues, expected);
609 }
610}
611
612TEST_F(LMDBStoreTest, can_read_duplicate_values_forwards_with_cursors)
613{
614 LMDBStore::Ptr store = create_store(2);
615
616 const std::string dbName = "Test Database";
617 store->open_database(dbName, true);
618
619 int64_t numKeys = 10;
620 int64_t numValues = 5;
621
622 write_test_data({ dbName }, numKeys, numValues, *store);
623
624 {
625 // read from a key mid-way through
626 int64_t startKey = 3;
627 auto key = get_key(startKey);
628 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
629 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
630 bool setResult = cursor->set_at_key(key);
631 EXPECT_TRUE(setResult);
632
633 int64_t numKeysToRead = 4;
634 KeyDupValuesVector keyValues;
635 cursor->read_next((uint64_t)numKeysToRead, keyValues);
636
637 KeyDupValuesVector expected;
638 for (int64_t count = startKey; count < startKey + numKeysToRead; count++) {
639 auto key = get_key(count);
640 ValuesVector dup;
641 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
642 auto data = get_value(count, dupCount);
643 dup.emplace_back(data);
644 }
645 KeyValuesPair pair = { key, dup };
646 expected.emplace_back(pair);
647 }
648 EXPECT_EQ(keyValues, expected);
649 }
650}
651
652TEST_F(LMDBStoreTest, can_read_backwards_with_cursors)
653{
654 LMDBStore::Ptr store = create_store(2);
655
656 const std::string dbName = "Test Database";
657 store->open_database(dbName, true);
658
659 int64_t numKeys = 10;
660 int64_t numValues = 1;
661
662 write_test_data({ dbName }, numKeys, numValues, *store);
663
664 {
665 // read from a key mid-way through
666 int64_t startKey = 7;
667 auto key = get_key(startKey);
668 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
669 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
670 bool setResult = cursor->set_at_key(key);
671 EXPECT_TRUE(setResult);
672
673 int64_t numKeysToRead = 4;
674 KeyDupValuesVector keyValues;
675 cursor->read_prev((uint64_t)numKeysToRead, keyValues);
676
677 KeyDupValuesVector expected;
678 for (int64_t count = startKey; count > startKey - numKeysToRead; count--) {
679 auto key = get_key(count);
680 auto data = get_value(count, 0);
681 expected.emplace_back(KeyValuesPair{ key, { data } });
682 }
683 EXPECT_EQ(keyValues, expected);
684 }
685}
686
687TEST_F(LMDBStoreTest, can_read_duplicate_values_backwards_with_cursors)
688{
689 LMDBStore::Ptr store = create_store(2);
690
691 const std::string dbName = "Test Database";
692 store->open_database(dbName, true);
693
694 int64_t numKeys = 10;
695 int64_t numValues = 5;
696
697 write_test_data({ dbName }, numKeys, numValues, *store);
698
699 {
700 // read from a key mid-way through
701 int64_t startKey = 7;
702 auto key = get_key(startKey);
703 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
704 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
705 bool setResult = cursor->set_at_key(key);
706 EXPECT_TRUE(setResult);
707
708 int64_t numKeysToRead = 4;
709 KeyDupValuesVector keyValues;
710 cursor->read_prev((uint64_t)numKeysToRead, keyValues);
711
712 KeyDupValuesVector expected;
713 for (int64_t count = startKey; count > startKey - numKeysToRead; count--) {
714 auto key = get_key(count);
715 ValuesVector dup;
716 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
717 auto data = get_value(count, dupCount);
718 dup.emplace_back(data);
719 }
720 KeyValuesPair pair = { key, dup };
721 expected.emplace_back(pair);
722 }
723 EXPECT_EQ(keyValues, expected);
724 }
725}
726
727TEST_F(LMDBStoreTest, can_read_past_the_end_with_cursors)
728{
729 LMDBStore::Ptr store = create_store(2);
730
731 const std::string dbName = "Test Database";
732 store->open_database(dbName, false);
733
734 int64_t numKeys = 10;
735 int64_t numValues = 1;
736
737 write_test_data({ dbName }, numKeys, numValues, *store);
738
739 {
740 // read from a key mid-way through
741 int64_t startKey = 3;
742 auto key = get_key(startKey);
743 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
744 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
745 bool setResult = cursor->set_at_key(key);
746 EXPECT_TRUE(setResult);
747
748 int64_t numKeysToRead = 50;
749 KeyDupValuesVector keyValues;
750 cursor->read_next((uint64_t)numKeysToRead, keyValues);
751
752 KeyDupValuesVector expected;
753 for (int64_t count = startKey; count < numKeys; count++) {
754 auto key = get_key(count);
755 auto data = get_value(count, 0);
756 expected.emplace_back(KeyValuesPair{ key, { data } });
757 }
758 EXPECT_EQ(keyValues, expected);
759 }
760}
761
762TEST_F(LMDBStoreTest, can_read_past_the_start_with_cursors)
763{
764 LMDBStore::Ptr store = create_store(2);
765
766 const std::string dbName = "Test Database";
767 store->open_database(dbName, false);
768
769 int64_t numKeys = 10;
770 int64_t numValues = 1;
771
772 write_test_data({ dbName }, numKeys, numValues, *store);
773
774 {
775 // read from a key mid-way through
776 int64_t startKey = 7;
777 auto key = get_key(startKey);
778 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
779 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
780 bool setResult = cursor->set_at_key(key);
781 EXPECT_TRUE(setResult);
782
783 int64_t numKeysToRead = 50;
784 KeyDupValuesVector keyValues;
785 cursor->read_prev((uint64_t)numKeysToRead, keyValues);
786
787 KeyDupValuesVector expected;
788 for (int64_t count = startKey; count >= 0; count--) {
789 auto key = get_key(count);
790 auto data = get_value(count, 0);
791 expected.emplace_back(KeyValuesPair{ key, { data } });
792 }
793 EXPECT_EQ(keyValues, expected);
794 }
795}
796
797TEST_F(LMDBStoreTest, can_read_duplicates_past_the_end_with_cursors)
798{
799 LMDBStore::Ptr store = create_store(2);
800
801 const std::string dbName = "Test Database";
802 store->open_database(dbName, true);
803
804 int64_t numKeys = 10;
805 int64_t numValues = 5;
806
807 write_test_data({ dbName }, numKeys, numValues, *store);
808
809 {
810 // read from a key mid-way through
811 int64_t startKey = 3;
812 auto key = get_key(startKey);
813 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
814 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
815 bool setResult = cursor->set_at_key(key);
816 EXPECT_TRUE(setResult);
817
818 int64_t numKeysToRead = 50;
819 KeyDupValuesVector keyValues;
820 cursor->read_next((uint64_t)numKeysToRead, keyValues);
821
822 KeyDupValuesVector expected;
823 for (int64_t count = startKey; count < numKeys; count++) {
824 auto key = get_key(count);
825 ValuesVector dup;
826 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
827 auto data = get_value(count, dupCount);
828 dup.emplace_back(data);
829 }
830 KeyValuesPair pair = { key, dup };
831 expected.emplace_back(pair);
832 }
833 EXPECT_EQ(keyValues, expected);
834 }
835}
836
837TEST_F(LMDBStoreTest, can_read_duplicates_past_the_start_with_cursors)
838{
839 LMDBStore::Ptr store = create_store(2);
840
841 const std::string dbName = "Test Database";
842 store->open_database(dbName, true);
843
844 int64_t numKeys = 10;
845 int64_t numValues = 5;
846
847 write_test_data({ dbName }, numKeys, numValues, *store);
848
849 {
850 // read from a key mid-way through
851 int64_t startKey = 7;
852 auto key = get_key(startKey);
853 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
854 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
855 bool setResult = cursor->set_at_key(key);
856 EXPECT_TRUE(setResult);
857
858 int64_t numKeysToRead = 50;
859 KeyDupValuesVector keyValues;
860 cursor->read_prev((uint64_t)numKeysToRead, keyValues);
861
862 KeyDupValuesVector expected;
863 for (int64_t count = startKey; count >= 0; count--) {
864 auto key = get_key(count);
865 ValuesVector dup;
866 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
867 auto data = get_value(count, dupCount);
868 dup.emplace_back(data);
869 }
870 KeyValuesPair pair = { key, dup };
871 expected.emplace_back(pair);
872 }
873 EXPECT_EQ(keyValues, expected);
874 }
875}
876
877TEST_F(LMDBStoreTest, can_read_in_both_directions_with_cursors)
878{
879 LMDBStore::Ptr store = create_store(2);
880
881 const std::string dbName = "Test Database";
882 store->open_database(dbName, true);
883
884 int64_t numKeys = 10;
885 int64_t numValues = 5;
886
887 write_test_data({ dbName }, numKeys, numValues, *store);
888
889 {
890 // read backwards from a key mid-way through
891 int64_t startKey = 7;
892 auto key = get_key(startKey);
893 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
894 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
895 bool setResult = cursor->set_at_key(key);
896 EXPECT_TRUE(setResult);
897
898 int64_t numKeysToRead = 4;
899 KeyDupValuesVector keyValuesReverse;
900 bool result = cursor->read_prev((uint64_t)numKeysToRead, keyValuesReverse);
901 EXPECT_FALSE(result);
902
903 // now read forwards using the same cursor
904 startKey = (startKey - numKeysToRead) + 1;
905 key = get_key(startKey);
906 setResult = cursor->set_at_key(key);
907 EXPECT_TRUE(setResult);
908 KeyDupValuesVector keyValues;
909 result = cursor->read_next((uint64_t)numKeysToRead, keyValues);
910 EXPECT_FALSE(result);
911
912 // Ensure the data returned by the reverse operation matches that returned by the forwards operation
913 KeyDupValuesVector temp(keyValuesReverse.rbegin(), keyValuesReverse.rend());
914 EXPECT_EQ(temp, keyValues);
915 }
916}
917
918TEST_F(LMDBStoreTest, can_count_in_both_directions_with_cursors)
919{
920 LMDBStore::Ptr store = create_store(2);
921
922 const std::string dbName = "Test Database";
923 store->open_database(dbName, false);
924
925 int64_t numKeys = 10;
926 int64_t numValues = 1;
927
928 write_test_data({ dbName }, numKeys, numValues, *store);
929
930 {
931 // count backwards from a key mid-way through
932 int64_t startKey = 7;
933 auto key = get_key(startKey);
934 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
935 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
936 bool setResult = cursor->set_at_key(key);
937 EXPECT_TRUE(setResult);
938
939 int64_t endKey = 2;
940 key = get_key(endKey);
941 uint64_t numKeysRead = 0;
942 bool result = cursor->count_until_prev(key, numKeysRead);
943 EXPECT_FALSE(result);
944 EXPECT_EQ(numKeysRead, startKey - endKey);
945
946 // now count forwards using the same cursor
947 startKey = 3;
948 endKey = 7;
949 numKeysRead = 0;
950 key = get_key(startKey);
951 setResult = cursor->set_at_key(key);
952 EXPECT_TRUE(setResult);
953 key = get_key(endKey);
954 result = cursor->count_until_next(key, numKeysRead);
955 EXPECT_FALSE(result);
956 EXPECT_EQ(numKeysRead, endKey - startKey);
957
958 // now count nothing
959 startKey = 3;
960 endKey = startKey;
961 numKeysRead = 0;
962 key = get_key(startKey);
963 setResult = cursor->set_at_key(key);
964 EXPECT_TRUE(setResult);
965 key = get_key(endKey);
966 result = cursor->count_until_next(key, numKeysRead);
967 EXPECT_FALSE(result);
968 EXPECT_EQ(numKeysRead, 0);
969
970 startKey = 3;
971 endKey = startKey;
972 numKeysRead = 0;
973 key = get_key(startKey);
974 setResult = cursor->set_at_key(key);
975 EXPECT_TRUE(setResult);
976 key = get_key(endKey);
977 result = cursor->count_until_prev(key, numKeysRead);
978 EXPECT_FALSE(result);
979 EXPECT_EQ(numKeysRead, 0);
980 }
981}
982
983TEST_F(LMDBStoreTest, can_count_in_both_directions_with_cursors_with_holes)
984{
985 LMDBStore::Ptr store = create_store(2);
986
987 const std::string dbName = "Test Database";
988 store->open_database(dbName, false);
989
990 int64_t numKeys = 3;
991 int64_t numValues = 1;
992
993 write_test_data({ dbName }, numKeys, numValues, *store, 1);
994 write_test_data({ dbName }, numKeys, numValues, *store, 5);
995
996 {
997 // count backwards detecting hole
998 int64_t startKey = 7;
999 auto key = get_key(startKey);
1000 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1001 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1002 bool setResult = cursor->set_at_key(key);
1003 EXPECT_TRUE(setResult);
1004
1005 int64_t endKey = 4; // There is no key 4
1006 key = get_key(endKey);
1007 uint64_t numKeysRead = 0;
1008 bool result = cursor->count_until_prev(key, numKeysRead);
1009 EXPECT_FALSE(result);
1010 EXPECT_EQ(numKeysRead, 3);
1011
1012 // now count forwards using the same cursor
1013 startKey = 1;
1014 endKey = 4; // There is no key 4
1015 numKeysRead = 0;
1016 key = get_key(startKey);
1017 setResult = cursor->set_at_key(key);
1018 EXPECT_TRUE(setResult);
1019 key = get_key(endKey);
1020 result = cursor->count_until_next(key, numKeysRead);
1021 EXPECT_FALSE(result);
1022 EXPECT_EQ(numKeysRead, 3);
1023 }
1024}
1025
1026TEST_F(LMDBStoreTest, can_count_past_end_in_both_directions_with_cursors)
1027{
1028 LMDBStore::Ptr store = create_store(2);
1029
1030 const std::string dbName = "Test Database";
1031 store->open_database(dbName, false);
1032
1033 int64_t numKeys = 7;
1034 int64_t numValues = 1;
1035
1036 write_test_data({ dbName }, numKeys, numValues, *store, 2);
1037
1038 {
1039 // count backwards from a key mid-way through
1040 int64_t startKey = 5;
1041 auto key = get_key(startKey);
1042 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1043 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1044 bool setResult = cursor->set_at_key(key);
1045 EXPECT_TRUE(setResult);
1046
1047 int64_t endKey = 0;
1048 key = get_key(endKey);
1049 uint64_t numKeysRead = 0;
1050 bool result = cursor->count_until_prev(key, numKeysRead);
1051 EXPECT_TRUE(result);
1052 EXPECT_EQ(numKeysRead, 4);
1053
1054 // now count forwards using the same cursor
1055 startKey = 3;
1056 endKey = 9;
1057 numKeysRead = 0;
1058 key = get_key(startKey);
1059 setResult = cursor->set_at_key(key);
1060 EXPECT_TRUE(setResult);
1061 key = get_key(endKey);
1062 result = cursor->count_until_next(key, numKeysRead);
1063 EXPECT_TRUE(result);
1064 EXPECT_EQ(numKeysRead, 6);
1065
1066 // now count nothing
1067 startKey = 3;
1068 endKey = startKey;
1069 numKeysRead = 0;
1070 key = get_key(startKey);
1071 setResult = cursor->set_at_key(key);
1072 EXPECT_TRUE(setResult);
1073 key = get_key(endKey);
1074 result = cursor->count_until_next(key, numKeysRead);
1075 EXPECT_FALSE(result);
1076 EXPECT_EQ(numKeysRead, 0);
1077
1078 startKey = 3;
1079 endKey = startKey;
1080 numKeysRead = 0;
1081 key = get_key(startKey);
1082 setResult = cursor->set_at_key(key);
1083 EXPECT_TRUE(setResult);
1084 key = get_key(endKey);
1085 result = cursor->count_until_prev(key, numKeysRead);
1086 EXPECT_FALSE(result);
1087 EXPECT_EQ(numKeysRead, 0);
1088 }
1089}
1090
1091TEST_F(LMDBStoreTest, can_count_duplicates_in_both_directions_with_cursors)
1092{
1093 LMDBStore::Ptr store = create_store(2);
1094
1095 const std::string dbName = "Test Database";
1096 store->open_database(dbName, true);
1097
1098 int64_t numKeys = 7;
1099 int64_t numValues = 5;
1100
1101 write_test_data({ dbName }, numKeys, numValues, *store, 2);
1102
1103 {
1104 // count backwards from a key mid-way through
1105 int64_t startKey = 5;
1106 auto key = get_key(startKey);
1107 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1108 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1109 bool setResult = cursor->set_at_key(key);
1110 EXPECT_TRUE(setResult);
1111
1112 int64_t endKey = 3;
1113 key = get_key(endKey);
1114 uint64_t numKeysRead = 0;
1115 bool result = cursor->count_until_prev(key, numKeysRead);
1116 EXPECT_FALSE(result);
1117 EXPECT_EQ(numKeysRead, numValues * 2);
1118
1119 // now count forwards using the same cursor
1120 startKey = 3;
1121 endKey = 7;
1122 numKeysRead = 0;
1123 key = get_key(startKey);
1124 setResult = cursor->set_at_key(key);
1125 EXPECT_TRUE(setResult);
1126 key = get_key(endKey);
1127 result = cursor->count_until_next(key, numKeysRead);
1128 EXPECT_FALSE(result);
1129 EXPECT_EQ(numKeysRead, numValues * (endKey - startKey));
1130
1131 // now count nothing
1132 startKey = 5;
1133 endKey = startKey;
1134 numKeysRead = 0;
1135 key = get_key(startKey);
1136 setResult = cursor->set_at_key(key);
1137 EXPECT_TRUE(setResult);
1138 key = get_key(endKey);
1139 result = cursor->count_until_next(key, numKeysRead);
1140 EXPECT_FALSE(result);
1141 EXPECT_EQ(numKeysRead, 0);
1142
1143 startKey = 5;
1144 endKey = startKey;
1145 numKeysRead = 0;
1146 key = get_key(startKey);
1147 setResult = cursor->set_at_key(key);
1148 EXPECT_TRUE(setResult);
1149 key = get_key(endKey);
1150 result = cursor->count_until_prev(key, numKeysRead);
1151 EXPECT_FALSE(result);
1152 EXPECT_EQ(numKeysRead, 0);
1153 }
1154}
1155
1156TEST_F(LMDBStoreTest, can_count_duplicates_past_end_in_both_directions_with_cursors)
1157{
1158 LMDBStore::Ptr store = create_store(2);
1159
1160 const std::string dbName = "Test Database";
1161 store->open_database(dbName, true);
1162
1163 int64_t numKeys = 7;
1164 int64_t numValues = 5;
1165
1166 write_test_data({ dbName }, numKeys, numValues, *store, 2);
1167
1168 {
1169 // count backwards from a key mid-way through
1170 int64_t startKey = 5;
1171 auto key = get_key(startKey);
1172 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1173 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1174 bool setResult = cursor->set_at_key(key);
1175 EXPECT_TRUE(setResult);
1176
1177 int64_t endKey = 0;
1178 key = get_key(endKey);
1179 uint64_t numKeysRead = 0;
1180 bool result = cursor->count_until_prev(key, numKeysRead);
1181 EXPECT_TRUE(result);
1182 EXPECT_EQ(numKeysRead, numValues * 4);
1183
1184 // now count forwards using the same cursor
1185 startKey = 3;
1186 endKey = 9;
1187 numKeysRead = 0;
1188 key = get_key(startKey);
1189 setResult = cursor->set_at_key(key);
1190 EXPECT_TRUE(setResult);
1191 key = get_key(endKey);
1192 result = cursor->count_until_next(key, numKeysRead);
1193 EXPECT_TRUE(result);
1194 EXPECT_EQ(numKeysRead, numValues * 6);
1195
1196 startKey = 5;
1197 endKey = startKey;
1198 numKeysRead = 0;
1199 key = get_key(startKey);
1200 setResult = cursor->set_at_key(key);
1201 EXPECT_TRUE(setResult);
1202 key = get_key(endKey);
1203 result = cursor->count_until_next(key, numKeysRead);
1204 EXPECT_FALSE(result);
1205 EXPECT_EQ(numKeysRead, 0);
1206
1207 startKey = 3;
1208 endKey = startKey;
1209 numKeysRead = 0;
1210 key = get_key(startKey);
1211 setResult = cursor->set_at_key(key);
1212 EXPECT_TRUE(setResult);
1213 key = get_key(endKey);
1214 result = cursor->count_until_prev(key, numKeysRead);
1215 EXPECT_FALSE(result);
1216 EXPECT_EQ(numKeysRead, 0);
1217 }
1218}
1219
1220TEST_F(LMDBStoreTest, can_use_multiple_cursors_with_same_tx)
1221{
1222 LMDBStore::Ptr store = create_store(2);
1223
1224 const std::string dbName = "Test Database";
1225 store->open_database(dbName, true);
1226
1227 int64_t numKeys = 10;
1228 int64_t numValues = 5;
1229
1230 write_test_data({ dbName }, numKeys, numValues, *store);
1231
1232 {
1233 // read backwards from a key mid-way through
1234 int64_t startKey = 7;
1235 auto key = get_key(startKey);
1236 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1237 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1238 bool setResult = cursor->set_at_key(key);
1239 EXPECT_TRUE(setResult);
1240
1241 int64_t numKeysToRead = 4;
1242 KeyDupValuesVector keyValuesReverse;
1243 cursor->read_prev((uint64_t)numKeysToRead, keyValuesReverse);
1244
1245 // now read forwards using a second cursor against the same transaction
1246 LMDBStore::Cursor::Ptr cursor2 = store->create_cursor(tx, dbName);
1247 startKey = (startKey - numKeysToRead) + 1;
1248
1249 key = get_key(startKey);
1250 setResult = cursor2->set_at_key(key);
1251 EXPECT_TRUE(setResult);
1252
1253 KeyDupValuesVector keyValues;
1254 cursor2->read_next((uint64_t)numKeysToRead, keyValues);
1255
1256 KeyDupValuesVector temp(keyValuesReverse.rbegin(), keyValuesReverse.rend());
1257 EXPECT_EQ(temp, keyValues);
1258 }
1259}
1260
1261TEST_F(LMDBStoreTest, can_write_and_delete_many_times)
1262{
1263 LMDBStore::Ptr store = create_store(2);
1264
1265 const std::vector<std::string> dbNames = { "Test Database No Dups", "Test Database Dups" };
1266 store->open_database(dbNames[0], false);
1267 store->open_database(dbNames[1], true);
1268
1269 int64_t numKeys = 5000;
1270 int64_t numValues = 10;
1271 int64_t numIterations = 20;
1272
1273 KeyOptionalValuesVector toDelete;
1274 for (int64_t i = 0; i < numIterations; i++) {
1275 KeyDupValuesVector testDataNoDuplicates;
1276 KeyDupValuesVector testDataDuplicates;
1277 prepare_test_data(numKeys, numValues, testDataDuplicates, i * numKeys);
1278 prepare_test_data(numKeys, 1, testDataNoDuplicates, i * numKeys);
1279 if (i > 0) {
1280 // delete all of the previous iteration's keys
1281 for (int64_t k = 0; k < numKeys; k++) {
1282 int64_t keyToDelete = ((i - 1) * numKeys) + k;
1283 toDelete.emplace_back(get_key(keyToDelete), std::nullopt);
1284 }
1285 }
1286 LMDBStore::PutData putData1 = { testDataNoDuplicates, toDelete, dbNames[0] };
1287 LMDBStore::PutData putData2 = { testDataDuplicates, toDelete, dbNames[1] };
1288 std::vector<LMDBStore::PutData> putDatas{ putData1, putData2 };
1289 EXPECT_NO_THROW(store->put(putDatas));
1290 }
1291}
1292
1293TEST_F(LMDBStoreTest, reports_stats)
1294{
1295 LMDBStore::Ptr store = create_store(2);
1296
1297 const std::vector<std::string> dbNames = { "Test Database No Dups", "Test Database Dups" };
1298 store->open_database(dbNames[0], false);
1299 store->open_database(dbNames[1], true);
1300
1301 int64_t numKeys = 10;
1302 int64_t numValues = 5;
1303
1304 write_test_data(dbNames, numKeys, numValues, *store);
1305
1307 auto [mapSize, physicalFileSize] = store->get_stats(stats);
1308 std::string dataDbPath = (std::filesystem::path(_directory) / "data.mdb").string();
1309 EXPECT_TRUE(std::filesystem::exists(dataDbPath));
1310
1311 EXPECT_EQ(mapSize, LMDBStoreTest::_mapSize * 1024);
1312 EXPECT_EQ(physicalFileSize, std::filesystem::file_size(dataDbPath));
1313 EXPECT_EQ(stats.size(), 2);
1314 for (size_t i = 0; i < 2; i++) {
1315 if (stats[i].name == dbNames[0]) {
1316 // The DB without duplicates should contain as many items as there are keys
1317 EXPECT_EQ(stats[i].numDataItems, numKeys);
1318 } else if (stats[i].name == dbNames[1]) {
1319 // The DB with duplicates should contain as keys * values number of items
1320 EXPECT_EQ(stats[i].numDataItems, numKeys * numValues);
1321 } else {
1322 FAIL();
1323 }
1324 }
1325}
1326
1327TEST_F(LMDBStoreTest, can_read_data_from_multiple_threads)
1328{
1329 LMDBStore::Ptr store = create_store(2);
1330
1331 const std::string dbName = "Test Database";
1332 store->open_database(dbName, true);
1333
1334 int64_t numKeys = 10;
1335 int64_t numValues = 5;
1336 int64_t numIterationsPerThread = 1000;
1337 uint64_t numThreads = 10;
1338
1339 write_test_data({ dbName }, numKeys, numValues, *store);
1340
1341 std::vector<std::thread> threads;
1342 {
1343 auto func = [&]() -> void {
1344 for (int64_t iteration = 0; iteration < numIterationsPerThread; iteration++) {
1345 for (int64_t count = 0; count < numKeys; count++) {
1346 auto key = get_key(count);
1347 LMDBStore::ReadTransaction::SharedPtr tx = store->create_shared_read_transaction();
1348 LMDBStore::Cursor::Ptr cursor = store->create_cursor(tx, dbName);
1349 cursor->set_at_key(key);
1350 KeyDupValuesVector keyValuePairs;
1351 cursor->read_next(1, keyValuePairs);
1352
1353 ValuesVector dup;
1354 KeyDupValuesVector expected;
1355 for (int64_t dupCount = 0; dupCount < numValues; dupCount++) {
1356 auto data = get_value(count, dupCount);
1357 dup.emplace_back(data);
1358 }
1359 KeyValuesPair pair = { key, dup };
1360 expected.emplace_back(pair);
1361 EXPECT_EQ(keyValuePairs, expected);
1362 }
1363 }
1364 };
1366 for (uint64_t count = 0; count < numThreads; count++) {
1367 threads.emplace_back(std::make_unique<std::thread>(func));
1368 }
1369 for (uint64_t count = 0; count < numThreads; count++) {
1370 threads[count]->join();
1371 }
1372 }
1373}
void SetUp() override
void TearDown() override
static std::string _directory
static uint64_t _mapSize
static uint32_t _maxReaders
std::unique_ptr< LMDBCursor > Ptr
std::shared_ptr< LMDBReadTransaction > SharedPtr
std::unique_ptr< LMDBStore > Ptr
void put(std::vector< PutData > &data)
const std::vector< FF > data
void prepare_test_data(int64_t numKeys, int64_t numValues, KeyDupValuesVector &testData, int64_t keyOffset=0)
void write_test_data(std::vector< std::string > dbNames, int64_t numKeys, int64_t numValues, LMDBStore &store, int64_t keyOffset=0)
LMDBStore::Ptr create_store(uint32_t maxNumDbs=1)
TEST_F(LMDBStoreTest, can_create_store)
std::vector< Key > KeysVector
Definition types.hpp:13
std::pair< Key, OptionalValues > KeyOptionalValuesPair
Definition types.hpp:19
Key get_key(int64_t keyCount)
Definition fixtures.hpp:30
std::vector< KeyValuesPair > KeyDupValuesVector
Definition types.hpp:18
std::vector< OptionalValues > OptionalValuesVector
Definition types.hpp:17
Value get_value(int64_t keyCount, int64_t valueCount)
Definition fixtures.hpp:35
std::vector< Value > ValuesVector
Definition types.hpp:14
std::pair< Key, ValuesVector > KeyValuesPair
Definition types.hpp:15
std::vector< KeyOptionalValuesPair > KeyOptionalValuesVector
Definition types.hpp:20
std::vector< uint8_t > serialise(std::string key)
Definition fixtures.hpp:24
std::optional< ValuesVector > OptionalValues
Definition types.hpp:16
std::string random_temp_directory()
Definition fixtures.hpp:17
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13