diff options
author | Rémi Nicole <nicole@kolabsystems.com> | 2018-08-22 14:16:59 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-08-22 14:28:51 +0200 |
commit | 46313049ac01a3007ef60bdc937442945355a38d (patch) | |
tree | 56ce0cd679367a60ba3a706ac4d207bc9cc82230 /tests | |
parent | af91a18748b91f4a4fc0d83247561371d376bec5 (diff) | |
download | sink-46313049ac01a3007ef60bdc937442945355a38d.tar.gz sink-46313049ac01a3007ef60bdc937442945355a38d.zip |
Separate UIDs and Revisions in main databases
Summary:
- Change revision type from `qint64` to `size_t` for LMDB in a couple of places (LMDB supports `unsigned int` or `size_t` which are `long unsigned int` on my machine)
- Better support for database flags (duplicate, integer keys, integer values for now but is extensible)
- Main databases' keys are now revisions
- Some databases switched to integer keys databases:
- Main databases
- the revision to uid mapping database
- the revision to entity type mapping database
- Refactor the entity type's `typeDatabases` method (if in the future we need to change the main databases' flags again)
- New uid to revision mapping database (`uidsToRevisions`):
- Stores all revisions (not uid to latest revision) because we need it for cleaning old revisions
- Flags are: duplicates + integer values (so findLatest finds the latest revision for the given uid)
~~Problems to fix before merging:~~
All Fixed!
- ~~Sometimes Sink can't read what has just been written to the database (maybe because of transactions race conditions)~~
- ~~Most of the times, this results in Sink not able to find the uid for a given revision by reading the `revisions` database~~
- ~~`pipelinetest`'s `testModifyWithConflict` fails because the local changes are overridden~~
~~The first problem prevents me from running benchmarks~~
Reviewers: cmollekopf
Tags: #sink
Differential Revision: https://phabricator.kde.org/D14974
Diffstat (limited to 'tests')
-rw-r--r-- | tests/dbwriter.cpp | 12 | ||||
-rw-r--r-- | tests/entitystoretest.cpp | 95 | ||||
-rw-r--r-- | tests/pipelinetest.cpp | 33 | ||||
-rw-r--r-- | tests/storagetest.cpp | 260 |
4 files changed, 339 insertions, 61 deletions
diff --git a/tests/dbwriter.cpp b/tests/dbwriter.cpp index 3045eac..a25faec 100644 --- a/tests/dbwriter.cpp +++ b/tests/dbwriter.cpp | |||
@@ -29,14 +29,14 @@ int main(int argc, char *argv[]) | |||
29 | qWarning() << "No valid transaction"; | 29 | qWarning() << "No valid transaction"; |
30 | return -1; | 30 | return -1; |
31 | } | 31 | } |
32 | transaction.openDatabase("a", nullptr, false).write(QByteArray::number(i), "a"); | 32 | transaction.openDatabase("a", nullptr, 0).write(QByteArray::number(i), "a"); |
33 | transaction.openDatabase("b", nullptr, false).write(QByteArray::number(i), "b"); | 33 | transaction.openDatabase("b", nullptr, 0).write(QByteArray::number(i), "b"); |
34 | transaction.openDatabase("c", nullptr, false).write(QByteArray::number(i), "c"); | 34 | transaction.openDatabase("c", nullptr, 0).write(QByteArray::number(i), "c"); |
35 | transaction.openDatabase("p", nullptr, false).write(QByteArray::number(i), "c"); | 35 | transaction.openDatabase("p", nullptr, 0).write(QByteArray::number(i), "c"); |
36 | transaction.openDatabase("q", nullptr, false).write(QByteArray::number(i), "c"); | 36 | transaction.openDatabase("q", nullptr, 0).write(QByteArray::number(i), "c"); |
37 | if (i > (count/2)) { | 37 | if (i > (count/2)) { |
38 | for (int d = 0; d < 40; d++) { | 38 | for (int d = 0; d < 40; d++) { |
39 | transaction.openDatabase("db" + QByteArray::number(d), nullptr, false).write(QByteArray::number(i), "a"); | 39 | transaction.openDatabase("db" + QByteArray::number(d), nullptr, 0).write(QByteArray::number(i), "a"); |
40 | } | 40 | } |
41 | } | 41 | } |
42 | if ((i % 1000) == 0) { | 42 | if ((i % 1000) == 0) { |
diff --git a/tests/entitystoretest.cpp b/tests/entitystoretest.cpp index 03b940b..608de4c 100644 --- a/tests/entitystoretest.cpp +++ b/tests/entitystoretest.cpp | |||
@@ -18,6 +18,7 @@ private slots: | |||
18 | void initTestCase() | 18 | void initTestCase() |
19 | { | 19 | { |
20 | Sink::AdaptorFactoryRegistry::instance().registerFactory<Sink::ApplicationDomain::Mail, TestMailAdaptorFactory>("test"); | 20 | Sink::AdaptorFactoryRegistry::instance().registerFactory<Sink::ApplicationDomain::Mail, TestMailAdaptorFactory>("test"); |
21 | Sink::AdaptorFactoryRegistry::instance().registerFactory<Sink::ApplicationDomain::Event, TestEventAdaptorFactory>("test"); | ||
21 | } | 22 | } |
22 | 23 | ||
23 | void cleanup() | 24 | void cleanup() |
@@ -29,6 +30,100 @@ private slots: | |||
29 | { | 30 | { |
30 | } | 31 | } |
31 | 32 | ||
33 | void testFullScan() | ||
34 | { | ||
35 | using namespace Sink; | ||
36 | ResourceContext resourceContext{resourceInstanceIdentifier.toUtf8(), "dummy", AdaptorFactoryRegistry::instance().getFactories("test")}; | ||
37 | Storage::EntityStore store(resourceContext, {}); | ||
38 | |||
39 | auto mail = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
40 | mail.setExtractedMessageId("messageid"); | ||
41 | mail.setExtractedSubject("boo"); | ||
42 | |||
43 | auto mail2 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
44 | mail2.setExtractedMessageId("messageid2"); | ||
45 | mail2.setExtractedSubject("foo"); | ||
46 | |||
47 | auto mail3 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
48 | mail3.setExtractedMessageId("messageid2"); | ||
49 | mail3.setExtractedSubject("foo"); | ||
50 | |||
51 | store.startTransaction(Storage::DataStore::ReadWrite); | ||
52 | store.add("mail", mail, false); | ||
53 | store.add("mail", mail2, false); | ||
54 | store.add("mail", mail3, false); | ||
55 | |||
56 | mail.setExtractedSubject("foo"); | ||
57 | |||
58 | store.modify("mail", mail, QByteArrayList{}, false); | ||
59 | |||
60 | { | ||
61 | const auto ids = store.fullScan("mail"); | ||
62 | |||
63 | QCOMPARE(ids.size(), 3); | ||
64 | QVERIFY(ids.contains(Sink::Storage::Identifier::fromDisplayByteArray(mail.identifier()))); | ||
65 | QVERIFY(ids.contains(Sink::Storage::Identifier::fromDisplayByteArray(mail2.identifier()))); | ||
66 | QVERIFY(ids.contains(Sink::Storage::Identifier::fromDisplayByteArray(mail3.identifier()))); | ||
67 | } | ||
68 | |||
69 | store.remove("mail", mail3, false); | ||
70 | store.commitTransaction(); | ||
71 | |||
72 | { | ||
73 | const auto ids = store.fullScan("mail"); | ||
74 | |||
75 | QCOMPARE(ids.size(), 2); | ||
76 | QVERIFY(ids.contains(Sink::Storage::Identifier::fromDisplayByteArray(mail.identifier()))); | ||
77 | QVERIFY(ids.contains(Sink::Storage::Identifier::fromDisplayByteArray(mail2.identifier()))); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | void testExistsAndContains() | ||
82 | { | ||
83 | |||
84 | using namespace Sink; | ||
85 | ResourceContext resourceContext{resourceInstanceIdentifier.toUtf8(), "dummy", AdaptorFactoryRegistry::instance().getFactories("test")}; | ||
86 | Storage::EntityStore store(resourceContext, {}); | ||
87 | |||
88 | auto mail = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
89 | mail.setExtractedMessageId("messageid"); | ||
90 | mail.setExtractedSubject("boo"); | ||
91 | |||
92 | auto mail2 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
93 | mail2.setExtractedMessageId("messageid2"); | ||
94 | mail2.setExtractedSubject("foo"); | ||
95 | |||
96 | auto mail3 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
97 | mail3.setExtractedMessageId("messageid2"); | ||
98 | mail3.setExtractedSubject("foo"); | ||
99 | |||
100 | auto event = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Event>("res1"); | ||
101 | event.setExtractedUid("messageid2"); | ||
102 | event.setExtractedSummary("foo"); | ||
103 | |||
104 | store.startTransaction(Storage::DataStore::ReadWrite); | ||
105 | store.add("mail", mail, false); | ||
106 | store.add("mail", mail2, false); | ||
107 | store.add("mail", mail3, false); | ||
108 | store.add("event", event, false); | ||
109 | |||
110 | mail.setExtractedSubject("foo"); | ||
111 | |||
112 | store.modify("mail", mail, QByteArrayList{}, false); | ||
113 | store.remove("mail", mail3, false); | ||
114 | store.commitTransaction(); | ||
115 | |||
116 | QVERIFY(store.contains("mail", mail.identifier())); | ||
117 | QVERIFY(store.contains("mail", mail2.identifier())); | ||
118 | QVERIFY(store.contains("mail", mail3.identifier())); | ||
119 | QVERIFY(store.contains("event", event.identifier())); | ||
120 | |||
121 | QVERIFY(store.exists("mail", mail.identifier())); | ||
122 | QVERIFY(store.exists("mail", mail2.identifier())); | ||
123 | QVERIFY(!store.exists("mail", mail3.identifier())); | ||
124 | QVERIFY(store.exists("event", event.identifier())); | ||
125 | } | ||
126 | |||
32 | void readAll() | 127 | void readAll() |
33 | { | 128 | { |
34 | using namespace Sink; | 129 | using namespace Sink; |
diff --git a/tests/pipelinetest.cpp b/tests/pipelinetest.cpp index b41a5c2..801a9e0 100644 --- a/tests/pipelinetest.cpp +++ b/tests/pipelinetest.cpp | |||
@@ -28,26 +28,29 @@ static void removeFromDisk(const QString &name) | |||
28 | store.removeFromDisk(); | 28 | store.removeFromDisk(); |
29 | } | 29 | } |
30 | 30 | ||
31 | static QList<QByteArray> getKeys(const QByteArray &dbEnv, const QByteArray &name) | 31 | static QList<Sink::Storage::Key> getKeys(const QByteArray &dbEnv, const QByteArray &name) |
32 | { | 32 | { |
33 | Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); | 33 | Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); |
34 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 34 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
35 | auto db = transaction.openDatabase(name, nullptr, false); | 35 | auto db = transaction.openDatabase(name, nullptr, Sink::Storage::IntegerKeys); |
36 | QList<QByteArray> result; | 36 | QList<Sink::Storage::Key> result; |
37 | db.scan("", [&](const QByteArray &key, const QByteArray &value) { | 37 | db.scan("", [&](const QByteArray &key, const QByteArray &value) { |
38 | result << key; | 38 | size_t revision = Sink::byteArrayToSizeT(key); |
39 | result << Sink::Storage::Key(Sink::Storage::Identifier::fromDisplayByteArray( | ||
40 | Sink::Storage::DataStore::getUidFromRevision(transaction, revision)), | ||
41 | revision); | ||
39 | return true; | 42 | return true; |
40 | }); | 43 | }); |
41 | return result; | 44 | return result; |
42 | } | 45 | } |
43 | 46 | ||
44 | static QByteArray getEntity(const QByteArray &dbEnv, const QByteArray &name, const QByteArray &uid) | 47 | static QByteArray getEntity(const QByteArray &dbEnv, const QByteArray &name, const Sink::Storage::Key &key) |
45 | { | 48 | { |
46 | Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); | 49 | Sink::Storage::DataStore store(Sink::storageLocation(), dbEnv, Sink::Storage::DataStore::ReadOnly); |
47 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 50 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
48 | auto db = transaction.openDatabase(name, nullptr, false); | 51 | auto db = transaction.openDatabase(name, nullptr, Sink::Storage::IntegerKeys); |
49 | QByteArray result; | 52 | QByteArray result; |
50 | db.scan(uid, [&](const QByteArray &key, const QByteArray &value) { | 53 | db.scan(key.revision().toSizeT(), [&](size_t rev, const QByteArray &value) { |
51 | result = value; | 54 | result = value; |
52 | return true; | 55 | return true; |
53 | }); | 56 | }); |
@@ -251,7 +254,7 @@ private slots: | |||
251 | // Get uid of written entity | 254 | // Get uid of written entity |
252 | auto keys = getKeys(instanceIdentifier(), "event.main"); | 255 | auto keys = getKeys(instanceIdentifier(), "event.main"); |
253 | QCOMPARE(keys.size(), 1); | 256 | QCOMPARE(keys.size(), 1); |
254 | auto key = Sink::Storage::Key::fromInternalByteArray(keys.first()); | 257 | auto key = keys.first(); |
255 | const auto uid = key.identifier().toDisplayByteArray(); | 258 | const auto uid = key.identifier().toDisplayByteArray(); |
256 | 259 | ||
257 | // Execute the modification | 260 | // Execute the modification |
@@ -264,7 +267,7 @@ private slots: | |||
264 | key.setRevision(2); | 267 | key.setRevision(2); |
265 | 268 | ||
266 | // Ensure we've got the new revision with the modification | 269 | // Ensure we've got the new revision with the modification |
267 | auto buffer = getEntity(instanceIdentifier(), "event.main", key.toInternalByteArray()); | 270 | auto buffer = getEntity(instanceIdentifier(), "event.main", key); |
268 | QVERIFY(!buffer.isEmpty()); | 271 | QVERIFY(!buffer.isEmpty()); |
269 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); | 272 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); |
270 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); | 273 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); |
@@ -299,7 +302,7 @@ private slots: | |||
299 | // Get uid of written entity | 302 | // Get uid of written entity |
300 | auto keys = getKeys(instanceIdentifier(), "event.main"); | 303 | auto keys = getKeys(instanceIdentifier(), "event.main"); |
301 | QCOMPARE(keys.size(), 1); | 304 | QCOMPARE(keys.size(), 1); |
302 | auto key = Sink::Storage::Key::fromInternalByteArray(keys.first()); | 305 | auto key = keys.first(); |
303 | const auto uid = key.identifier().toDisplayByteArray(); | 306 | const auto uid = key.identifier().toDisplayByteArray(); |
304 | 307 | ||
305 | 308 | ||
@@ -322,7 +325,7 @@ private slots: | |||
322 | key.setRevision(3); | 325 | key.setRevision(3); |
323 | 326 | ||
324 | // Ensure we've got the new revision with the modification | 327 | // Ensure we've got the new revision with the modification |
325 | auto buffer = getEntity(instanceIdentifier(), "event.main", key.toInternalByteArray()); | 328 | auto buffer = getEntity(instanceIdentifier(), "event.main", key); |
326 | QVERIFY(!buffer.isEmpty()); | 329 | QVERIFY(!buffer.isEmpty()); |
327 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); | 330 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); |
328 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); | 331 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); |
@@ -343,7 +346,7 @@ private slots: | |||
343 | auto result = getKeys(instanceIdentifier(), "event.main"); | 346 | auto result = getKeys(instanceIdentifier(), "event.main"); |
344 | QCOMPARE(result.size(), 1); | 347 | QCOMPARE(result.size(), 1); |
345 | 348 | ||
346 | const auto uid = Sink::Storage::Key::fromInternalByteArray(result.first()).identifier().toDisplayByteArray(); | 349 | const auto uid = result.first().identifier().toDisplayByteArray(); |
347 | 350 | ||
348 | // Delete entity | 351 | // Delete entity |
349 | auto deleteCommand = deleteEntityCommand(uid, 1); | 352 | auto deleteCommand = deleteEntityCommand(uid, 1); |
@@ -386,7 +389,7 @@ private slots: | |||
386 | pipeline.startTransaction(); | 389 | pipeline.startTransaction(); |
387 | auto keys = getKeys(instanceIdentifier(), "event.main"); | 390 | auto keys = getKeys(instanceIdentifier(), "event.main"); |
388 | QCOMPARE(keys.size(), 1); | 391 | QCOMPARE(keys.size(), 1); |
389 | const auto uid = Sink::Storage::Key::fromInternalByteArray(keys.first()).identifier().toDisplayByteArray(); | 392 | const auto uid = keys.first().identifier().toDisplayByteArray(); |
390 | { | 393 | { |
391 | auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 1); | 394 | auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 1); |
392 | pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size()); | 395 | pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size()); |
@@ -427,7 +430,7 @@ private slots: | |||
427 | // Get uid of written entity | 430 | // Get uid of written entity |
428 | auto keys = getKeys(instanceIdentifier(), "event.main"); | 431 | auto keys = getKeys(instanceIdentifier(), "event.main"); |
429 | QCOMPARE(keys.size(), 1); | 432 | QCOMPARE(keys.size(), 1); |
430 | auto key = Sink::Storage::Key::fromInternalByteArray(keys.first()); | 433 | auto key = keys.first(); |
431 | const auto uid = key.identifier().toDisplayByteArray(); | 434 | const auto uid = key.identifier().toDisplayByteArray(); |
432 | 435 | ||
433 | //Simulate local modification | 436 | //Simulate local modification |
@@ -453,7 +456,7 @@ private slots: | |||
453 | key.setRevision(3); | 456 | key.setRevision(3); |
454 | 457 | ||
455 | // Ensure we've got the new revision with the modification | 458 | // Ensure we've got the new revision with the modification |
456 | auto buffer = getEntity(instanceIdentifier(), "event.main", key.toInternalByteArray()); | 459 | auto buffer = getEntity(instanceIdentifier(), "event.main", key); |
457 | QVERIFY(!buffer.isEmpty()); | 460 | QVERIFY(!buffer.isEmpty()); |
458 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); | 461 | Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); |
459 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); | 462 | auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); |
diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp index 81acc13..3d583ab 100644 --- a/tests/storagetest.cpp +++ b/tests/storagetest.cpp | |||
@@ -227,7 +227,7 @@ private slots: | |||
227 | bool gotError = false; | 227 | bool gotError = false; |
228 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"default", 0}}}, Sink::Storage::DataStore::ReadWrite); | 228 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"default", 0}}}, Sink::Storage::DataStore::ReadWrite); |
229 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 229 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
230 | auto db = transaction.openDatabase("default", nullptr, false); | 230 | auto db = transaction.openDatabase("default"); |
231 | db.write("key", "value"); | 231 | db.write("key", "value"); |
232 | db.write("key", "value"); | 232 | db.write("key", "value"); |
233 | 233 | ||
@@ -250,9 +250,10 @@ private slots: | |||
250 | { | 250 | { |
251 | bool gotResult = false; | 251 | bool gotResult = false; |
252 | bool gotError = false; | 252 | bool gotError = false; |
253 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"default", 0x04}}}, Sink::Storage::DataStore::ReadWrite); | 253 | const int flags = Sink::Storage::AllowDuplicates; |
254 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"default", flags}}}, Sink::Storage::DataStore::ReadWrite); | ||
254 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 255 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
255 | auto db = transaction.openDatabase("default", nullptr, true); | 256 | auto db = transaction.openDatabase("default", nullptr, flags); |
256 | db.write("key", "value1"); | 257 | db.write("key", "value1"); |
257 | db.write("key", "value2"); | 258 | db.write("key", "value2"); |
258 | int numValues = db.scan("key", | 259 | int numValues = db.scan("key", |
@@ -357,7 +358,7 @@ private slots: | |||
357 | 358 | ||
358 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 359 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
359 | store.createTransaction(Sink::Storage::DataStore::ReadWrite) | 360 | store.createTransaction(Sink::Storage::DataStore::ReadWrite) |
360 | .openDatabase("test", nullptr, true) | 361 | .openDatabase("test", nullptr, Sink::Storage::AllowDuplicates) |
361 | .write("key1", "value1", [&](const Sink::Storage::DataStore::Error &error) { | 362 | .write("key1", "value1", [&](const Sink::Storage::DataStore::Error &error) { |
362 | qDebug() << error.message; | 363 | qDebug() << error.message; |
363 | gotError = true; | 364 | gotError = true; |
@@ -368,9 +369,10 @@ private slots: | |||
368 | // By default we want only exact matches | 369 | // By default we want only exact matches |
369 | void testSubstringKeys() | 370 | void testSubstringKeys() |
370 | { | 371 | { |
371 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0x04}}}, Sink::Storage::DataStore::ReadWrite); | 372 | const int flags = Sink::Storage::AllowDuplicates; |
373 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", flags}}}, Sink::Storage::DataStore::ReadWrite); | ||
372 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 374 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
373 | auto db = transaction.openDatabase("test", nullptr, true); | 375 | auto db = transaction.openDatabase("test", nullptr, flags); |
374 | db.write("sub", "value1"); | 376 | db.write("sub", "value1"); |
375 | db.write("subsub", "value2"); | 377 | db.write("subsub", "value2"); |
376 | int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }); | 378 | int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }); |
@@ -382,7 +384,7 @@ private slots: | |||
382 | { | 384 | { |
383 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 385 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
384 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 386 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
385 | auto db = transaction.openDatabase("test", nullptr, false); | 387 | auto db = transaction.openDatabase("test"); |
386 | db.write("sub", "value1"); | 388 | db.write("sub", "value1"); |
387 | db.write("subsub", "value2"); | 389 | db.write("subsub", "value2"); |
388 | db.write("wubsub", "value3"); | 390 | db.write("wubsub", "value3"); |
@@ -395,7 +397,7 @@ private slots: | |||
395 | { | 397 | { |
396 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 398 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
397 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 399 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
398 | auto db = transaction.openDatabase("test", nullptr, true); | 400 | auto db = transaction.openDatabase("test", nullptr, Sink::Storage::AllowDuplicates); |
399 | db.write("sub", "value1"); | 401 | db.write("sub", "value1"); |
400 | db.write("subsub", "value2"); | 402 | db.write("subsub", "value2"); |
401 | db.write("wubsub", "value3"); | 403 | db.write("wubsub", "value3"); |
@@ -408,7 +410,7 @@ private slots: | |||
408 | { | 410 | { |
409 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 411 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
410 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 412 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
411 | auto db = transaction.openDatabase("test", nullptr, false); | 413 | auto db = transaction.openDatabase("test"); |
412 | db.write("sub_2", "value2"); | 414 | db.write("sub_2", "value2"); |
413 | db.write("sub_1", "value1"); | 415 | db.write("sub_1", "value1"); |
414 | db.write("sub_3", "value3"); | 416 | db.write("sub_3", "value3"); |
@@ -429,7 +431,7 @@ private slots: | |||
429 | { | 431 | { |
430 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 432 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
431 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 433 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
432 | auto db = transaction.openDatabase("test", nullptr, true); | 434 | auto db = transaction.openDatabase("test", nullptr, Sink::Storage::AllowDuplicates); |
433 | db.write("sub1", "value1"); | 435 | db.write("sub1", "value1"); |
434 | int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }); | 436 | int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }); |
435 | 437 | ||
@@ -440,7 +442,7 @@ private slots: | |||
440 | { | 442 | { |
441 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 443 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
442 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 444 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
443 | auto db = transaction.openDatabase("test", nullptr, false); | 445 | auto db = transaction.openDatabase("test"); |
444 | db.write("sub1", "value1"); | 446 | db.write("sub1", "value1"); |
445 | db.write("sub2", "value2"); | 447 | db.write("sub2", "value2"); |
446 | db.write("wub3", "value3"); | 448 | db.write("wub3", "value3"); |
@@ -455,7 +457,7 @@ private slots: | |||
455 | { | 457 | { |
456 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 458 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
457 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 459 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
458 | auto db = transaction.openDatabase("test", nullptr, false); | 460 | auto db = transaction.openDatabase("test"); |
459 | db.write("sub2", "value2"); | 461 | db.write("sub2", "value2"); |
460 | QByteArray result; | 462 | QByteArray result; |
461 | db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { result = value; }); | 463 | db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { result = value; }); |
@@ -467,7 +469,7 @@ private slots: | |||
467 | { | 469 | { |
468 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 470 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
469 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 471 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
470 | auto db = transaction.openDatabase("test", nullptr, false); | 472 | auto db = transaction.openDatabase("test"); |
471 | db.write("sub2", "value2"); | 473 | db.write("sub2", "value2"); |
472 | db.write("wub3", "value3"); | 474 | db.write("wub3", "value3"); |
473 | QByteArray result; | 475 | QByteArray result; |
@@ -478,8 +480,8 @@ private slots: | |||
478 | 480 | ||
479 | static QMap<QByteArray, int> baseDbs() | 481 | static QMap<QByteArray, int> baseDbs() |
480 | { | 482 | { |
481 | return {{"revisionType", 0}, | 483 | return {{"revisionType", Sink::Storage::IntegerKeys}, |
482 | {"revisions", 0}, | 484 | {"revisions", Sink::Storage::IntegerKeys}, |
483 | {"uids", 0}, | 485 | {"uids", 0}, |
484 | {"default", 0}, | 486 | {"default", 0}, |
485 | {"__flagtable", 0}}; | 487 | {"__flagtable", 0}}; |
@@ -499,7 +501,7 @@ private slots: | |||
499 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); | 501 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"test", 0}}}, Sink::Storage::DataStore::ReadWrite); |
500 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 502 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
501 | QByteArray result; | 503 | QByteArray result; |
502 | auto db = transaction.openDatabase("test", nullptr, false); | 504 | auto db = transaction.openDatabase("test"); |
503 | const auto uid = "{c5d06a9f-1534-4c52-b8ea-415db68bdadf}"; | 505 | const auto uid = "{c5d06a9f-1534-4c52-b8ea-415db68bdadf}"; |
504 | //Ensure we can sort 1 and 10 properly (by default string comparison 10 comes before 6) | 506 | //Ensure we can sort 1 and 10 properly (by default string comparison 10 comes before 6) |
505 | const auto id = Sink::Storage::Identifier::fromDisplayByteArray(uid); | 507 | const auto id = Sink::Storage::Identifier::fromDisplayByteArray(uid); |
@@ -523,7 +525,7 @@ private slots: | |||
523 | { | 525 | { |
524 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); | 526 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); |
525 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 527 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
526 | auto db = transaction.openDatabase("test", nullptr, false); | 528 | auto db = transaction.openDatabase("test"); |
527 | setupTestFindRange(db); | 529 | setupTestFindRange(db); |
528 | QByteArrayList results; | 530 | QByteArrayList results; |
529 | db.findAllInRange("0002", "0004", [&](const QByteArray &key, const QByteArray &value) { results << value; }); | 531 | db.findAllInRange("0002", "0004", [&](const QByteArray &key, const QByteArray &value) { results << value; }); |
@@ -535,7 +537,7 @@ private slots: | |||
535 | { | 537 | { |
536 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); | 538 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); |
537 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 539 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
538 | auto db = transaction.openDatabase("test", nullptr, false); | 540 | auto db = transaction.openDatabase("test"); |
539 | setupTestFindRange(db); | 541 | setupTestFindRange(db); |
540 | 542 | ||
541 | QByteArrayList results1; | 543 | QByteArrayList results1; |
@@ -559,7 +561,7 @@ private slots: | |||
559 | { | 561 | { |
560 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); | 562 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); |
561 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 563 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
562 | auto db = transaction.openDatabase("test", nullptr, false); | 564 | auto db = transaction.openDatabase("test"); |
563 | setupTestFindRange(db); | 565 | setupTestFindRange(db); |
564 | 566 | ||
565 | QByteArrayList results1; | 567 | QByteArrayList results1; |
@@ -571,7 +573,7 @@ private slots: | |||
571 | { | 573 | { |
572 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); | 574 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); |
573 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 575 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
574 | auto db = transaction.openDatabase("test", nullptr, false); | 576 | auto db = transaction.openDatabase("test"); |
575 | setupTestFindRange(db); | 577 | setupTestFindRange(db); |
576 | 578 | ||
577 | QByteArrayList results1; | 579 | QByteArrayList results1; |
@@ -601,21 +603,21 @@ private slots: | |||
601 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"testTransactionVisibility", 0}}}, Sink::Storage::DataStore::ReadWrite); | 603 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"testTransactionVisibility", 0}}}, Sink::Storage::DataStore::ReadWrite); |
602 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 604 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
603 | 605 | ||
604 | auto db = transaction.openDatabase("testTransactionVisibility", nullptr, false); | 606 | auto db = transaction.openDatabase("testTransactionVisibility"); |
605 | db.write("key1", "foo"); | 607 | db.write("key1", "foo"); |
606 | QCOMPARE(readValue(db, "key1"), QByteArray("foo")); | 608 | QCOMPARE(readValue(db, "key1"), QByteArray("foo")); |
607 | 609 | ||
608 | { | 610 | { |
609 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 611 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
610 | auto db2 = transaction2 | 612 | auto db2 = transaction2 |
611 | .openDatabase("testTransactionVisibility", nullptr, false); | 613 | .openDatabase("testTransactionVisibility"); |
612 | QCOMPARE(readValue(db2, "key1"), QByteArray()); | 614 | QCOMPARE(readValue(db2, "key1"), QByteArray()); |
613 | } | 615 | } |
614 | transaction.commit(); | 616 | transaction.commit(); |
615 | { | 617 | { |
616 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 618 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
617 | auto db2 = transaction2 | 619 | auto db2 = transaction2 |
618 | .openDatabase("testTransactionVisibility", nullptr, false); | 620 | .openDatabase("testTransactionVisibility"); |
619 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); | 621 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); |
620 | } | 622 | } |
621 | 623 | ||
@@ -627,16 +629,16 @@ private slots: | |||
627 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"a", 0}, {"b", 0}, {"c", 0}}}, Sink::Storage::DataStore::ReadWrite); | 629 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"a", 0}, {"b", 0}, {"c", 0}}}, Sink::Storage::DataStore::ReadWrite); |
628 | { | 630 | { |
629 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 631 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
630 | transaction.openDatabase("a", nullptr, false); | 632 | transaction.openDatabase("a"); |
631 | transaction.openDatabase("b", nullptr, false); | 633 | transaction.openDatabase("b"); |
632 | transaction.openDatabase("c", nullptr, false); | 634 | transaction.openDatabase("c"); |
633 | transaction.commit(); | 635 | transaction.commit(); |
634 | } | 636 | } |
635 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 637 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
636 | for (int i = 0; i < 1000; i++) { | 638 | for (int i = 0; i < 1000; i++) { |
637 | transaction.openDatabase("a", nullptr, false); | 639 | transaction.openDatabase("a"); |
638 | transaction.openDatabase("b", nullptr, false); | 640 | transaction.openDatabase("b"); |
639 | transaction.openDatabase("c", nullptr, false); | 641 | transaction.openDatabase("c"); |
640 | transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 642 | transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
641 | } | 643 | } |
642 | } | 644 | } |
@@ -662,11 +664,11 @@ private slots: | |||
662 | // Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadOnly); | 664 | // Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadOnly); |
663 | // auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 665 | // auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
664 | // for (int i = 0; i < 100000; i++) { | 666 | // for (int i = 0; i < 100000; i++) { |
665 | // transaction.openDatabase("a", nullptr, false); | 667 | // transaction.openDatabase("a"); |
666 | // transaction.openDatabase("b", nullptr, false); | 668 | // transaction.openDatabase("b"); |
667 | // transaction.openDatabase("c", nullptr, false); | 669 | // transaction.openDatabase("c"); |
668 | // transaction.openDatabase("p", nullptr, false); | 670 | // transaction.openDatabase("p"); |
669 | // transaction.openDatabase("q", nullptr, false); | 671 | // transaction.openDatabase("q"); |
670 | // } | 672 | // } |
671 | // }); | 673 | // }); |
672 | // } | 674 | // } |
@@ -733,7 +735,7 @@ private slots: | |||
733 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"testTransactionVisibility", 0}}}, Sink::Storage::DataStore::ReadWrite); | 735 | Sink::Storage::DataStore store(testDataPath, {dbName, {{"testTransactionVisibility", 0}}}, Sink::Storage::DataStore::ReadWrite); |
734 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 736 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
735 | 737 | ||
736 | auto db = transaction.openDatabase("testTransactionVisibility", nullptr, false); | 738 | auto db = transaction.openDatabase("testTransactionVisibility"); |
737 | db.write("key1", "foo"); | 739 | db.write("key1", "foo"); |
738 | QCOMPARE(readValue(db, "key1"), QByteArray("foo")); | 740 | QCOMPARE(readValue(db, "key1"), QByteArray("foo")); |
739 | transaction.commit(); | 741 | transaction.commit(); |
@@ -748,12 +750,12 @@ private slots: | |||
748 | 750 | ||
749 | //This transaction should open the dbi | 751 | //This transaction should open the dbi |
750 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 752 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
751 | auto db2 = transaction2.openDatabase("testTransactionVisibility", nullptr, false); | 753 | auto db2 = transaction2.openDatabase("testTransactionVisibility"); |
752 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); | 754 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); |
753 | 755 | ||
754 | //This transaction should have the dbi available | 756 | //This transaction should have the dbi available |
755 | auto transaction3 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 757 | auto transaction3 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
756 | auto db3 = transaction3.openDatabase("testTransactionVisibility", nullptr, false); | 758 | auto db3 = transaction3.openDatabase("testTransactionVisibility"); |
757 | QCOMPARE(readValue(db3, "key1"), QByteArray("foo")); | 759 | QCOMPARE(readValue(db3, "key1"), QByteArray("foo")); |
758 | } | 760 | } |
759 | 761 | ||
@@ -766,20 +768,198 @@ private slots: | |||
766 | 768 | ||
767 | //This transaction should open the dbi | 769 | //This transaction should open the dbi |
768 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | 770 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadWrite); |
769 | auto db2 = transaction2.openDatabase("testTransactionVisibility", nullptr, false); | 771 | auto db2 = transaction2.openDatabase("testTransactionVisibility"); |
770 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); | 772 | QCOMPARE(readValue(db2, "key1"), QByteArray("foo")); |
771 | 773 | ||
772 | //This transaction should have the dbi available (creating two write transactions obviously doesn't work) | 774 | //This transaction should have the dbi available (creating two write transactions obviously doesn't work) |
773 | //NOTE: we don't support this scenario. A write transaction must commit or abort before a read transaction opens the same database. | 775 | //NOTE: we don't support this scenario. A write transaction must commit or abort before a read transaction opens the same database. |
774 | // auto transaction3 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); | 776 | // auto transaction3 = store.createTransaction(Sink::Storage::DataStore::ReadOnly); |
775 | // auto db3 = transaction3.openDatabase("testTransactionVisibility", nullptr, false); | 777 | // auto db3 = transaction3.openDatabase("testTransactionVisibility"); |
776 | // QCOMPARE(readValue(db3, "key1"), QByteArray("foo")); | 778 | // QCOMPARE(readValue(db3, "key1"), QByteArray("foo")); |
777 | 779 | ||
778 | //Ensure we can still open further dbis in the write transaction | 780 | //Ensure we can still open further dbis in the write transaction |
779 | auto db4 = transaction2.openDatabase("anotherDb", nullptr, false); | 781 | auto db4 = transaction2.openDatabase("anotherDb"); |
780 | } | 782 | } |
781 | 783 | ||
782 | } | 784 | } |
785 | |||
786 | void testIntegerKeys() | ||
787 | { | ||
788 | const int flags = Sink::Storage::IntegerKeys; | ||
789 | Sink::Storage::DataStore store(testDataPath, | ||
790 | { dbName, { { "test", flags } } }, Sink::Storage::DataStore::ReadWrite); | ||
791 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
792 | auto db = transaction.openDatabase("testIntegerKeys", {}, flags); | ||
793 | db.write(0, "value1"); | ||
794 | db.write(1, "value2"); | ||
795 | |||
796 | size_t resultKey; | ||
797 | QByteArray result; | ||
798 | int numValues = db.scan(0, [&](size_t key, const QByteArray &value) -> bool { | ||
799 | resultKey = key; | ||
800 | result = value; | ||
801 | return true; | ||
802 | }); | ||
803 | |||
804 | QCOMPARE(numValues, 1); | ||
805 | QCOMPARE(resultKey, 0); | ||
806 | QCOMPARE(result, "value1"); | ||
807 | |||
808 | int numValues2 = db.scan(1, [&](size_t key, const QByteArray &value) -> bool { | ||
809 | resultKey = key; | ||
810 | result = value; | ||
811 | return true; | ||
812 | }); | ||
813 | |||
814 | QCOMPARE(numValues2, 1); | ||
815 | QCOMPARE(resultKey, 1); | ||
816 | QCOMPARE(result, "value2"); | ||
817 | } | ||
818 | |||
819 | void testDuplicateIntegerKeys() | ||
820 | { | ||
821 | const int flags = Sink::Storage::IntegerKeys | Sink::Storage::AllowDuplicates; | ||
822 | Sink::Storage::DataStore store(testDataPath, | ||
823 | { dbName, { { "testDuplicateIntegerKeys", flags} } }, | ||
824 | Sink::Storage::DataStore::ReadWrite); | ||
825 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
826 | auto db = transaction.openDatabase("testDuplicateIntegerKeys", {}, flags); | ||
827 | db.write(0, "value1"); | ||
828 | db.write(1, "value2"); | ||
829 | db.write(1, "value3"); | ||
830 | QSet<QByteArray> results; | ||
831 | int numValues = db.scan(1, [&](size_t, const QByteArray &value) -> bool { | ||
832 | results << value; | ||
833 | return true; | ||
834 | }); | ||
835 | |||
836 | QCOMPARE(numValues, 2); | ||
837 | QCOMPARE(results.size(), 2); | ||
838 | QVERIFY(results.contains("value2")); | ||
839 | QVERIFY(results.contains("value3")); | ||
840 | } | ||
841 | |||
842 | void testDuplicateWithIntegerValues() | ||
843 | { | ||
844 | const int flags = Sink::Storage::AllowDuplicates | Sink::Storage::IntegerValues; | ||
845 | Sink::Storage::DataStore store(testDataPath, | ||
846 | { dbName, { { "testDuplicateWithIntegerValues", flags} } }, | ||
847 | Sink::Storage::DataStore::ReadWrite); | ||
848 | |||
849 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
850 | auto db = transaction.openDatabase("testDuplicateWithIntegerValues", {}, flags); | ||
851 | |||
852 | const size_t number1 = 1; | ||
853 | const size_t number2 = 2; | ||
854 | |||
855 | const QByteArray number1BA = Sink::sizeTToByteArray(number1); | ||
856 | const QByteArray number2BA = Sink::sizeTToByteArray(number2); | ||
857 | |||
858 | db.write(0, number1BA); | ||
859 | db.write(1, number2BA); | ||
860 | db.write(1, number1BA); | ||
861 | |||
862 | QList<QByteArray> results; | ||
863 | int numValues = db.scan(1, [&](size_t, const QByteArray &value) -> bool { | ||
864 | results << value; | ||
865 | return true; | ||
866 | }); | ||
867 | |||
868 | QCOMPARE(numValues, 2); | ||
869 | QCOMPARE(results.size(), 2); | ||
870 | QCOMPARE(results[0], number1BA); | ||
871 | QCOMPARE(results[1], number2BA); | ||
872 | } | ||
873 | |||
874 | void testIntegerKeyMultipleOf256() | ||
875 | { | ||
876 | const int flags = Sink::Storage::IntegerKeys; | ||
877 | Sink::Storage::DataStore store(testDataPath, | ||
878 | { dbName, { {"testIntegerKeyMultipleOf256", flags} } }, | ||
879 | Sink::Storage::DataStore::ReadWrite); | ||
880 | |||
881 | { | ||
882 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
883 | auto db = transaction.openDatabase("testIntegerKeyMultipleOf256", {}, flags); | ||
884 | |||
885 | db.write(0x100, "hello"); | ||
886 | db.write(0x200, "hello2"); | ||
887 | db.write(0x42, "hello3"); | ||
888 | |||
889 | transaction.commit(); | ||
890 | } | ||
891 | |||
892 | { | ||
893 | auto transaction2 = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
894 | auto db = transaction2.openDatabase("testIntegerKeyMultipleOf256", {}, flags); | ||
895 | |||
896 | size_t resultKey; | ||
897 | QByteArray resultValue; | ||
898 | db.scan(0x100, [&] (size_t key, const QByteArray &value) { | ||
899 | resultKey = key; | ||
900 | resultValue = value; | ||
901 | return false; | ||
902 | }); | ||
903 | |||
904 | QCOMPARE(resultKey, 0x100); | ||
905 | QCOMPARE(resultValue, "hello"); | ||
906 | } | ||
907 | } | ||
908 | |||
909 | void testIntegerProperlySorted() | ||
910 | { | ||
911 | const int flags = Sink::Storage::IntegerKeys; | ||
912 | Sink::Storage::DataStore store(testDataPath, | ||
913 | { dbName, { {"testIntegerProperlySorted", flags} } }, | ||
914 | Sink::Storage::DataStore::ReadWrite); | ||
915 | |||
916 | { | ||
917 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
918 | auto db = transaction.openDatabase("testIntegerProperlySorted", {}, flags); | ||
919 | |||
920 | for (size_t i = 0; i < 0x100; ++i) { | ||
921 | db.write(i, "hello"); | ||
922 | } | ||
923 | |||
924 | size_t previous = 0; | ||
925 | bool success = true; | ||
926 | db.scan("", [&] (const QByteArray &key, const QByteArray &value) { | ||
927 | size_t current = Sink::byteArrayToSizeT(key); | ||
928 | if (current < previous) { | ||
929 | success = false; | ||
930 | return false; | ||
931 | } | ||
932 | |||
933 | previous = current; | ||
934 | return true; | ||
935 | }); | ||
936 | |||
937 | QVERIFY2(success, "Integer are not properly sorted before commit"); | ||
938 | |||
939 | transaction.commit(); | ||
940 | } | ||
941 | |||
942 | { | ||
943 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
944 | auto db = transaction.openDatabase("testIntegerProperlySorted", {}, flags); | ||
945 | |||
946 | size_t previous = 0; | ||
947 | bool success = true; | ||
948 | db.scan("", [&] (const QByteArray &key, const QByteArray &value) { | ||
949 | size_t current = Sink::byteArrayToSizeT(key); | ||
950 | if (current < previous) { | ||
951 | success = false; | ||
952 | return false; | ||
953 | } | ||
954 | |||
955 | previous = current; | ||
956 | return true; | ||
957 | }); | ||
958 | |||
959 | QVERIFY2(success, "Integer are not properly sorted after commit"); | ||
960 | } | ||
961 | } | ||
962 | |||
783 | }; | 963 | }; |
784 | 964 | ||
785 | QTEST_MAIN(StorageTest) | 965 | QTEST_MAIN(StorageTest) |