summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--common/CMakeLists.txt12
-rw-r--r--common/storage.h (renamed from store/database.h)6
-rw-r--r--common/storage_kyoto.cpp170
-rw-r--r--common/storage_lmdb.cpp (renamed from store/database.cpp)44
-rw-r--r--dummyresource/facade.cpp10
-rw-r--r--dummyresource/facade.h4
-rw-r--r--store/CMakeLists.txt1
-rw-r--r--tests/CMakeLists.txt (renamed from store/test/CMakeLists.txt)11
-rw-r--r--tests/calendar.fbs (renamed from store/test/calendar.fbs)0
-rw-r--r--tests/storagebenchmark.cpp (renamed from store/test/storagebenchmark.cpp)34
-rw-r--r--tests/storagetest.cpp112
12 files changed, 352 insertions, 58 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 392ca39..e8b6f23 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,10 +47,10 @@ add_subdirectory(client)
47# the resource 47# the resource
48add_subdirectory(resource) 48add_subdirectory(resource)
49 49
50# the store
51add_subdirectory(store)
52
53# a simple dummy resource implementation 50# a simple dummy resource implementation
54add_subdirectory(dummyresource) 51add_subdirectory(dummyresource)
55 52
53# some tests
54add_subdirectory(tests)
55
56feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 56feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index d409828..9b3f777 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -2,10 +2,20 @@ project(akonadinextcommon)
2generate_flatbuffers(commands/handshake 2generate_flatbuffers(commands/handshake
3 commands/revisionupdate) 3 commands/revisionupdate)
4 4
5if (STORAGE_KYOTO)
6 set(storage_SRCS storage_kyoto.cpp)
7 set(storage_LIBS kyotocabinet)
8else (STORAGE_KYOTO)
9 set(storage_SRCS storage_lmdb.cpp)
10 set(storage_LIBS lmdb)
11endif (STORAGE_KYOTO)
12
5set(command_SRCS 13set(command_SRCS
6 commands.cpp 14 commands.cpp
7 console.cpp 15 console.cpp
8 ${CMAKE_CURRENT_BINARY_DIR}/commands/handshake_generated.h) 16 ${storage_SRCS})
9 17
10add_library(${PROJECT_NAME} ${command_SRCS}) 18add_library(${PROJECT_NAME} ${command_SRCS})
19SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
11qt5_use_modules(${PROJECT_NAME} Widgets) 20qt5_use_modules(${PROJECT_NAME} Widgets)
21target_link_libraries(${PROJECT_NAME} ${storage_LIBS})
diff --git a/store/database.h b/common/storage.h
index 1cede39..0b548fb 100644
--- a/store/database.h
+++ b/common/storage.h
@@ -3,12 +3,12 @@
3#include <string> 3#include <string>
4#include <QString> 4#include <QString>
5 5
6class Database { 6class Storage {
7public: 7public:
8 enum TransactionType { ReadOnly, ReadWrite }; 8 enum TransactionType { ReadOnly, ReadWrite };
9 9
10 Database(const QString &storageRoot, const QString &name); 10 Storage(const QString &storageRoot, const QString &name);
11 ~Database(); 11 ~Storage();
12 bool isInTransaction() const; 12 bool isInTransaction() const;
13 bool startTransaction(TransactionType type = ReadWrite); 13 bool startTransaction(TransactionType type = ReadWrite);
14 bool commitTransaction(); 14 bool commitTransaction();
diff --git a/common/storage_kyoto.cpp b/common/storage_kyoto.cpp
new file mode 100644
index 0000000..40bd3e6
--- /dev/null
+++ b/common/storage_kyoto.cpp
@@ -0,0 +1,170 @@
1#include "storage.h"
2
3#include <iostream>
4
5#include <QAtomicInt>
6#include <QDebug>
7#include <QDir>
8#include <QFileInfo>
9#include <QReadWriteLock>
10#include <QString>
11#include <QTime>
12
13#include <kchashdb.h>
14
15class Storage::Private
16{
17public:
18 Private(const QString &storageRoot, const QString &name);
19 ~Private();
20
21 kyotocabinet::TreeDB db;
22 bool dbOpen;
23 bool inTransaction;
24};
25
26Storage::Private::Private(const QString &storageRoot, const QString &name)
27 : inTransaction(false)
28{
29 QDir dir;
30 dir.mkdir(storageRoot);
31
32 //create file
33 dbOpen = db.open((storageRoot + "/" + name + ".kch").toStdString(), kyotocabinet::BasicDB::OWRITER | kyotocabinet::BasicDB::OCREATE);
34 if (!dbOpen) {
35 // TODO: handle error
36 }
37}
38
39Storage::Private::~Private()
40{
41 if (dbOpen && inTransaction) {
42 db.end_transaction(false);
43 }
44}
45
46Storage::Storage(const QString &storageRoot, const QString &name)
47 : d(new Private(storageRoot, name))
48{
49}
50
51Storage::~Storage()
52{
53 delete d;
54}
55
56bool Storage::isInTransaction() const
57{
58 return d->inTransaction;
59}
60
61bool Storage::startTransaction(TransactionType type)
62{
63 if (!d->dbOpen) {
64 return false;
65 }
66
67 if (d->inTransaction) {
68 return true;
69 }
70
71 //TODO handle errors
72 d->inTransaction = d->db.begin_transaction();
73 return d->inTransaction;
74}
75
76bool Storage::commitTransaction()
77{
78 if (!d->dbOpen) {
79 return false;
80 }
81
82 if (!d->inTransaction) {
83 return false;
84 }
85
86 bool success = d->db.end_transaction(true);
87 d->inTransaction = false;
88 return success;
89}
90
91void Storage::abortTransaction()
92{
93 if (!d->dbOpen || !d->inTransaction) {
94 return;
95 }
96
97 d->db.end_transaction(false);
98 d->inTransaction = false;
99}
100
101bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize)
102{
103 if (!d->dbOpen) {
104 return false;
105 }
106
107 bool success = d->db.set(key, keySize, value, valueSize);
108 return success;
109}
110
111bool Storage::write(const std::string &sKey, const std::string &sValue)
112{
113 if (!d->dbOpen) {
114 return false;
115 }
116
117 bool success = d->db.set(sKey, sValue);
118 return success;
119}
120
121bool Storage::read(const std::string &sKey, const std::function<void(const std::string &value)> &resultHandler)
122{
123 if (!d->dbOpen) {
124 return false;
125 }
126
127 std::string value;
128 if (d->db.get(sKey, &value)) {
129 resultHandler(value);
130 return true;
131 }
132
133 return false;
134}
135
136bool Storage::read(const std::string &sKey, const std::function<void(void *ptr, int size)> &resultHandler)
137{
138 if (!d->dbOpen) {
139 return false;
140 }
141
142 size_t valueSize;
143 char *valueBuffer = d->db.get(sKey.data(), sKey.size(), &valueSize);
144 if (valueBuffer) {
145 resultHandler(valueBuffer, valueSize);
146 }
147 delete[] valueBuffer;
148 return valueBuffer != nullptr;
149}
150
151qint64 Storage::diskUsage() const
152{
153 if (!d->dbOpen) {
154 return 0;
155 }
156
157 QFileInfo info(QString::fromStdString(d->db.path()));
158 return info.size();
159}
160
161void Storage::removeFromDisk() const
162{
163 if (!d->dbOpen) {
164 return;
165 }
166
167 QFileInfo info(QString::fromStdString(d->db.path()));
168 QDir dir = info.dir();
169 dir.remove(info.fileName());
170}
diff --git a/store/database.cpp b/common/storage_lmdb.cpp
index c4dfbd6..283205f 100644
--- a/store/database.cpp
+++ b/common/storage_lmdb.cpp
@@ -1,4 +1,4 @@
1#include "database.h" 1#include "storage.h"
2 2
3#include <iostream> 3#include <iostream>
4 4
@@ -11,7 +11,7 @@
11 11
12#include <lmdb.h> 12#include <lmdb.h>
13 13
14class Database::Private 14class Storage::Private
15{ 15{
16public: 16public:
17 Private(const QString &s, const QString &name); 17 Private(const QString &s, const QString &name);
@@ -19,6 +19,7 @@ public:
19 19
20 QString storageRoot; 20 QString storageRoot;
21 QString name; 21 QString name;
22
22 MDB_dbi dbi; 23 MDB_dbi dbi;
23 MDB_env *env; 24 MDB_env *env;
24 MDB_txn *transaction; 25 MDB_txn *transaction;
@@ -26,7 +27,7 @@ public:
26 bool firstOpen; 27 bool firstOpen;
27}; 28};
28 29
29Database::Private::Private(const QString &s, const QString &n) 30Storage::Private::Private(const QString &s, const QString &n)
30 : transaction(0), 31 : transaction(0),
31 readTransaction(false), 32 readTransaction(false),
32 firstOpen(true), 33 firstOpen(true),
@@ -53,7 +54,7 @@ Database::Private::Private(const QString &s, const QString &n)
53 } 54 }
54} 55}
55 56
56Database::Private::~Private() 57Storage::Private::~Private()
57{ 58{
58 if (transaction) { 59 if (transaction) {
59 mdb_txn_abort(transaction); 60 mdb_txn_abort(transaction);
@@ -64,22 +65,22 @@ Database::Private::~Private()
64 mdb_env_close(env); 65 mdb_env_close(env);
65} 66}
66 67
67Database::Database(const QString &storageRoot, const QString &name) 68Storage::Storage(const QString &storageRoot, const QString &name)
68 : d(new Private(storageRoot, name)) 69 : d(new Private(storageRoot, name))
69{ 70{
70} 71}
71 72
72Database::~Database() 73Storage::~Storage()
73{ 74{
74 delete d; 75 delete d;
75} 76}
76 77
77bool Database::isInTransaction() const 78bool Storage::isInTransaction() const
78{ 79{
79 return d->transaction; 80 return d->transaction;
80} 81}
81 82
82bool Database::startTransaction(TransactionType type) 83bool Storage::startTransaction(TransactionType type)
83{ 84{
84 if (!d->env) { 85 if (!d->env) {
85 return false; 86 return false;
@@ -114,7 +115,7 @@ bool Database::startTransaction(TransactionType type)
114 return !rc; 115 return !rc;
115} 116}
116 117
117bool Database::commitTransaction() 118bool Storage::commitTransaction()
118{ 119{
119 if (!d->env) { 120 if (!d->env) {
120 return false; 121 return false;
@@ -135,7 +136,7 @@ bool Database::commitTransaction()
135 return !rc; 136 return !rc;
136} 137}
137 138
138void Database::abortTransaction() 139void Storage::abortTransaction()
139{ 140{
140 if (!d->env || !d->transaction) { 141 if (!d->env || !d->transaction) {
141 return; 142 return;
@@ -145,12 +146,12 @@ void Database::abortTransaction()
145 d->transaction = 0; 146 d->transaction = 0;
146} 147}
147 148
148bool Database::write(const char *key, size_t keySize, const char *value, size_t valueSize) 149bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize)
149{ 150{
150 write(std::string(key, keySize), std::string(value, valueSize)); 151 write(std::string(key, keySize), std::string(value, valueSize));
151} 152}
152 153
153bool Database::write(const std::string &sKey, const std::string &sValue) 154bool Storage::write(const std::string &sKey, const std::string &sValue)
154{ 155{
155 if (!d->env) { 156 if (!d->env) {
156 return false; 157 return false;
@@ -187,7 +188,7 @@ bool Database::write(const std::string &sKey, const std::string &sValue)
187 return !rc; 188 return !rc;
188} 189}
189 190
190bool Database::read(const std::string &sKey, const std::function<void(const std::string &value)> &resultHandler) 191bool Storage::read(const std::string &sKey, const std::function<void(const std::string &value)> &resultHandler)
191{ 192{
192 return read(sKey, 193 return read(sKey,
193 [&](void *ptr, int size) { 194 [&](void *ptr, int size) {
@@ -197,7 +198,7 @@ bool Database::read(const std::string &sKey, const std::function<void(const std:
197// std::cout << "key: " << resultKey << " data: " << resultValue << std::endl; 198// std::cout << "key: " << resultKey << " data: " << resultValue << std::endl;
198} 199}
199 200
200bool Database::read(const std::string &sKey, const std::function<void(void *ptr, int size)> &resultHandler) 201bool Storage::read(const std::string &sKey, const std::function<void(void *ptr, int size)> &resultHandler)
201{ 202{
202 if (!d->env) { 203 if (!d->env) {
203 return false; 204 return false;
@@ -244,13 +245,13 @@ bool Database::read(const std::string &sKey, const std::function<void(void *ptr,
244 } 245 }
245 } 246 }
246 247
248 mdb_cursor_close(cursor);
249
247 if (rc) { 250 if (rc) {
248 std::cerr << "mdb_cursor_get: " << rc << " " << mdb_strerror(rc) << std::endl; 251 std::cerr << "mdb_cursor_get: " << rc << " " << mdb_strerror(rc) << std::endl;
249 return false; 252 return false;
250 } 253 }
251 254
252 mdb_cursor_close(cursor);
253
254 /** 255 /**
255 we don't abort the transaction since we need it for reading the values 256 we don't abort the transaction since we need it for reading the values
256 if (implicitTransaction) { 257 if (implicitTransaction) {
@@ -260,13 +261,20 @@ bool Database::read(const std::string &sKey, const std::function<void(void *ptr,
260 return true; 261 return true;
261} 262}
262 263
263qint64 Database::diskUsage() const 264qint64 Storage::diskUsage() const
264{ 265{
265 QFileInfo info(d->storageRoot + "/data.mdb"); 266 QFileInfo info(d->storageRoot + "/data.mdb");
266 return info.size(); 267 return info.size();
267} 268}
268 269
269void Database::removeFromDisk() const 270void Storage::removeFromDisk() const
271{
272 QDir dir(d->path);
273 dir.remove("data.mdb");
274 dir.remove("lock.mdb");
275}
276
277void Storage::removeFromDisk() const
270{ 278{
271 QDir dir(d->storageRoot); 279 QDir dir(d->storageRoot);
272 dir.remove("data.mdb"); 280 dir.remove("data.mdb");
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp
index 7e9881b..9758c1b 100644
--- a/dummyresource/facade.cpp
+++ b/dummyresource/facade.cpp
@@ -11,7 +11,7 @@ using namespace flatbuffers;
11DummyResourceFacade::DummyResourceFacade() 11DummyResourceFacade::DummyResourceFacade()
12 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), 12 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(),
13 mResourceAccess(new ResourceAccess("dummyresource")), 13 mResourceAccess(new ResourceAccess("dummyresource")),
14 mDatabase(new Database(Akonadi2::Store::storageLocation(), "dummyresource")) 14 mStorage(new Storage(Akonadi2::Store::storageLocation(), "dummyresource"))
15{ 15{
16 // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged); 16 // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged);
17} 17}
@@ -69,20 +69,20 @@ public:
69 DummyEvent const *buffer; 69 DummyEvent const *buffer;
70 70
71 //Keep query alive so values remain valid 71 //Keep query alive so values remain valid
72 QSharedPointer<Database> db; 72 QSharedPointer<Storage> storage;
73}; 73};
74 74
75void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) 75void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback)
76{ 76{
77 qDebug() << "load called"; 77 qDebug() << "load called";
78 //TODO only read values matching the query 78 //TODO only read values matching the query
79 auto db = QSharedPointer<Database>::create(Akonadi2::Store::storageLocation(), "dummyresource"); 79 auto storage = QSharedPointer<Storage>::create(Akonadi2::Store::storageLocation(), "dummyresource");
80 db->read("", [resultCallback, db](void *data, int size) { 80 storage->read("", [resultCallback, storage](void *data, int size) {
81 //TODO read second buffer as well 81 //TODO read second buffer as well
82 auto eventBuffer = GetDummyEvent(data); 82 auto eventBuffer = GetDummyEvent(data);
83 auto event = QSharedPointer<DummyEventAdaptor>::create("dummyresource", "key", 0); 83 auto event = QSharedPointer<DummyEventAdaptor>::create("dummyresource", "key", 0);
84 event->buffer = eventBuffer; 84 event->buffer = eventBuffer;
85 event->db = db; 85 event->storage = storage;
86 resultCallback(event); 86 resultCallback(event);
87 }); 87 });
88} 88}
diff --git a/dummyresource/facade.h b/dummyresource/facade.h
index 7a516de..310ef77 100644
--- a/dummyresource/facade.h
+++ b/dummyresource/facade.h
@@ -1,7 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "client/clientapi.h" 3#include "client/clientapi.h"
4#include "store/database.h" 4#include "common/storage.h"
5 5
6class ResourceAccess; 6class ResourceAccess;
7 7
@@ -18,5 +18,5 @@ public:
18 18
19private: 19private:
20 QSharedPointer<ResourceAccess> mResourceAccess; 20 QSharedPointer<ResourceAccess> mResourceAccess;
21 QSharedPointer<Database> mDatabase; 21 QSharedPointer<Storage> mStorage;
22}; 22};
diff --git a/store/CMakeLists.txt b/store/CMakeLists.txt
deleted file mode 100644
index 552439e..0000000
--- a/store/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
1add_subdirectory(test)
diff --git a/store/test/CMakeLists.txt b/tests/CMakeLists.txt
index c5c4fcb..1629acb 100644
--- a/store/test/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,20 +1,15 @@
1set(CMAKE_AUTOMOC ON) 1set(CMAKE_AUTOMOC ON)
2include_directories(${CMAKE_CURRENT_BINARY_DIR}) 2include_directories(${CMAKE_CURRENT_BINARY_DIR})
3 3
4set(store_path "../")
5set(store_SRCS
6 ${store_path}/database.cpp
7)
8
9generate_flatbuffers(calendar) 4generate_flatbuffers(calendar)
10 5
11macro(manual_tests) 6macro(manual_tests)
12 foreach(_testname ${ARGN}) 7 foreach(_testname ${ARGN})
13 add_executable(${_testname} ${_testname}.cpp ${store_SRCS}) 8 add_executable(${_testname} ${_testname}.cpp)
14 qt5_use_modules(${_testname} Core Test Concurrent) 9 qt5_use_modules(${_testname} Core Test Concurrent)
15 target_link_libraries(${_testname} lmdb) 10 target_link_libraries(${_testname} akonadinextcommon)
16 endforeach(_testname) 11 endforeach(_testname)
17endmacro(auto_tests) 12endmacro(manual_tests)
18 13
19manual_tests ( 14manual_tests (
20 storagebenchmark 15 storagebenchmark
diff --git a/store/test/calendar.fbs b/tests/calendar.fbs
index 203ee43..203ee43 100644
--- a/store/test/calendar.fbs
+++ b/tests/calendar.fbs
diff --git a/store/test/storagebenchmark.cpp b/tests/storagebenchmark.cpp
index 0bad138..f9fea7c 100644
--- a/store/test/storagebenchmark.cpp
+++ b/tests/storagebenchmark.cpp
@@ -9,7 +9,7 @@
9#include <QString> 9#include <QString>
10#include <QTime> 10#include <QTime>
11 11
12#include "store/database.h" 12#include "common/storage.h"
13 13
14using namespace Calendar; 14using namespace Calendar;
15using namespace flatbuffers; 15using namespace flatbuffers;
@@ -59,8 +59,8 @@ private Q_SLOTS:
59 59
60 void cleanupTestCase() 60 void cleanupTestCase()
61 { 61 {
62 Database db(testDataPath, dbName); 62 Storage store(testDataPath, dbName);
63 db.removeFromDisk(); 63 store.removeFromDisk();
64 } 64 }
65 65
66 void testWriteRead_data() 66 void testWriteRead_data()
@@ -77,9 +77,9 @@ private Q_SLOTS:
77 QFETCH(bool, useDb); 77 QFETCH(bool, useDb);
78 QFETCH(int, count); 78 QFETCH(int, count);
79 79
80 Database *db = 0; 80 Storage *store = 0;
81 if (useDb) { 81 if (useDb) {
82 db = new Database(testDataPath, dbName); 82 store = new Storage(testDataPath, dbName);
83 } 83 }
84 84
85 std::ofstream myfile; 85 std::ofstream myfile;
@@ -92,22 +92,22 @@ private Q_SLOTS:
92 { 92 {
93 auto event = createEvent(); 93 auto event = createEvent();
94 for (int i = 0; i < count; i++) { 94 for (int i = 0; i < count; i++) {
95 if (db) { 95 if (store) {
96 if (i % 10000 == 0) { 96 if (i % 10000 == 0) {
97 if (i > 0) { 97 if (i > 0) {
98 db->commitTransaction(); 98 store->commitTransaction();
99 } 99 }
100 db->startTransaction(); 100 store->startTransaction();
101 } 101 }
102 102
103 db->write(keyPrefix + std::to_string(i), event); 103 store->write(keyPrefix + std::to_string(i), event);
104 } else { 104 } else {
105 myfile << event; 105 myfile << event;
106 } 106 }
107 } 107 }
108 108
109 if (db) { 109 if (store) {
110 db->commitTransaction(); 110 store->commitTransaction();
111 } else { 111 } else {
112 myfile.close(); 112 myfile.close();
113 } 113 }
@@ -117,20 +117,20 @@ private Q_SLOTS:
117 117
118 { 118 {
119 for (int i = 0; i < count; i++) { 119 for (int i = 0; i < count; i++) {
120 if (db) { 120 if (store) {
121 db->read(keyPrefix + std::to_string(i), [](std::string value){}); 121 store->read(keyPrefix + std::to_string(i), [](std::string value){});
122 } 122 }
123 } 123 }
124 } 124 }
125 const int readDuration = time.restart(); 125 const int readDuration = time.restart();
126 126
127 if (db) { 127 if (store) {
128 qDebug() << "Reading took[ms]: " << readDuration; 128 qDebug() << "Reading took[ms]: " << readDuration;
129 } else { 129 } else {
130 qDebug() << "File reading is not implemented."; 130 qDebug() << "File reading is not implemented.";
131 } 131 }
132 132
133 delete db; 133 delete store;
134 } 134 }
135 135
136 void testBufferCreation() 136 void testBufferCreation()
@@ -149,8 +149,8 @@ private Q_SLOTS:
149 149
150 void testSizes() 150 void testSizes()
151 { 151 {
152 Database db(testDataPath, dbName); 152 Storage store(testDataPath, dbName);
153 qDebug() << "Database size [kb]: " << db.diskUsage()/1024; 153 qDebug() << "Database size [kb]: " << store.diskUsage()/1024;
154 154
155 QFileInfo fileInfo(filePath); 155 QFileInfo fileInfo(filePath);
156 qDebug() << "File size [kb]: " << fileInfo.size()/1024; 156 qDebug() << "File size [kb]: " << fileInfo.size()/1024;
diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp
new file mode 100644
index 0000000..2b2805d
--- /dev/null
+++ b/tests/storagetest.cpp
@@ -0,0 +1,112 @@
1#include <QtTest>
2
3#include <iostream>
4
5#include <QDebug>
6#include <QString>
7#include <QtConcurrent/QtConcurrentRun>
8
9#include "common/storage.h"
10
11class StorageTest : public QObject
12{
13 Q_OBJECT
14private:
15 //This should point to a directory on disk and not a ramdisk (since we're measuring performance)
16 QString testDataPath;
17 QString dbName;
18 const char *keyPrefix = "key";
19
20 void populate(int count)
21 {
22 Storage storage(testDataPath, dbName);
23 for (int i = 0; i < count; i++) {
24 //This should perhaps become an implementation detail of the db?
25 if (i % 10000 == 0) {
26 if (i > 0) {
27 storage.commitTransaction();
28 }
29 storage.startTransaction();
30 }
31 storage.write(keyPrefix + std::to_string(i), keyPrefix + std::to_string(i));
32 }
33 storage.commitTransaction();
34 }
35
36 bool verify(Storage &storage, int i)
37 {
38 bool success = true;
39 bool keyMatch = true;
40 const auto reference = keyPrefix + std::to_string(i);
41 success = storage.read(keyPrefix + std::to_string(i), [&error, &reference](const std::string &value) {
42 if (value != reference) {
43 qDebug() << "Mismatch while reading";
44 keyMatch = false;
45 }
46 });
47 return succes && keyMatch;
48 }
49
50private Q_SLOTS:
51 void initTestCase()
52 {
53 testDataPath = "./testdb";
54 dbName = "test";
55 }
56
57 void cleanupTestCase()
58 {
59 Database db(testDataPath, dbName);
60 db.removeFromDisk();
61 }
62
63
64 void testRead()
65 {
66 const int count = 100;
67
68 populate(count);
69
70 //ensure we can read everything back correctly
71 {
72 Database db(testDataPath, dbName);
73 for (int i = 0; i < count; i++) {
74 QVERIFY(verify(db, i));
75 }
76 }
77
78 Database db(testDataPath, dbName);
79 db.removeFromDisk();
80 }
81
82 void testConcurrentRead()
83 {
84 const int count = 10000;
85
86 populate(count);
87
88 //Try to concurrently read
89 QList<QFuture<void> > futures;
90 const int concurrencyLevel = 4;
91 for (int num = 0; num < concurrencyLevel; num++) {
92 futures << QtConcurrent::run([this, count](){
93 Database db(testDataPath, dbName);
94 for (int i = 0; i < count; i++) {
95 if (!verify(db, i)) {
96 qWarning() << "invalid value";
97 break;
98 }
99 }
100 });
101 }
102 for(auto future : futures) {
103 future.waitForFinished();
104 }
105
106 Database db(testDataPath, dbName);
107 db.removeFromDisk();
108 }
109};
110
111QTEST_MAIN(StorageTest)
112#include "storagetest.moc"