summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorRémi Nicole <nicole@kolabsystems.com>2018-08-22 14:16:59 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-08-22 14:28:51 +0200
commit46313049ac01a3007ef60bdc937442945355a38d (patch)
tree56ce0cd679367a60ba3a706ac4d207bc9cc82230 /tests
parentaf91a18748b91f4a4fc0d83247561371d376bec5 (diff)
downloadsink-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.cpp12
-rw-r--r--tests/entitystoretest.cpp95
-rw-r--r--tests/pipelinetest.cpp33
-rw-r--r--tests/storagetest.cpp260
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
31static QList<QByteArray> getKeys(const QByteArray &dbEnv, const QByteArray &name) 31static 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
44static QByteArray getEntity(const QByteArray &dbEnv, const QByteArray &name, const QByteArray &uid) 47static 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
785QTEST_MAIN(StorageTest) 965QTEST_MAIN(StorageTest)