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