diff options
author | Aaron Seigo <aseigo@kde.org> | 2014-12-05 10:05:19 +0100 |
---|---|---|
committer | Aaron Seigo <aseigo@kde.org> | 2014-12-05 10:05:19 +0100 |
commit | 93d1c82ffd17df45a5cecd875a01ee3cb15d9983 (patch) | |
tree | cda5c31857362ce81f3a50959024f4270d149a07 | |
parent | 639fc60c100204c87b93112516cf3b3117cfff0d (diff) | |
parent | 351a66b5fb1c8659bff8ea20d60f5a6d2d3263ad (diff) | |
download | sink-93d1c82ffd17df45a5cecd875a01ee3cb15d9983.tar.gz sink-93d1c82ffd17df45a5cecd875a01ee3cb15d9983.zip |
Merge branch 'kyoto'
Conflicts:
common/storage.h
common/storage_lmdb.cpp
dummyresource/facade.cpp
store/test/CMakeLists.txt
tests/storagebenchmark.cpp
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | common/CMakeLists.txt | 12 | ||||
-rw-r--r-- | common/storage.h (renamed from store/database.h) | 6 | ||||
-rw-r--r-- | common/storage_kyoto.cpp | 170 | ||||
-rw-r--r-- | common/storage_lmdb.cpp (renamed from store/database.cpp) | 44 | ||||
-rw-r--r-- | dummyresource/facade.cpp | 10 | ||||
-rw-r--r-- | dummyresource/facade.h | 4 | ||||
-rw-r--r-- | store/CMakeLists.txt | 1 | ||||
-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.cpp | 112 |
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 |
48 | add_subdirectory(resource) | 48 | add_subdirectory(resource) |
49 | 49 | ||
50 | # the store | ||
51 | add_subdirectory(store) | ||
52 | |||
53 | # a simple dummy resource implementation | 50 | # a simple dummy resource implementation |
54 | add_subdirectory(dummyresource) | 51 | add_subdirectory(dummyresource) |
55 | 52 | ||
53 | # some tests | ||
54 | add_subdirectory(tests) | ||
55 | |||
56 | feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) | 56 | feature_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) | |||
2 | generate_flatbuffers(commands/handshake | 2 | generate_flatbuffers(commands/handshake |
3 | commands/revisionupdate) | 3 | commands/revisionupdate) |
4 | 4 | ||
5 | if (STORAGE_KYOTO) | ||
6 | set(storage_SRCS storage_kyoto.cpp) | ||
7 | set(storage_LIBS kyotocabinet) | ||
8 | else (STORAGE_KYOTO) | ||
9 | set(storage_SRCS storage_lmdb.cpp) | ||
10 | set(storage_LIBS lmdb) | ||
11 | endif (STORAGE_KYOTO) | ||
12 | |||
5 | set(command_SRCS | 13 | set(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 | ||
10 | add_library(${PROJECT_NAME} ${command_SRCS}) | 18 | add_library(${PROJECT_NAME} ${command_SRCS}) |
19 | SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) | ||
11 | qt5_use_modules(${PROJECT_NAME} Widgets) | 20 | qt5_use_modules(${PROJECT_NAME} Widgets) |
21 | target_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 | ||
6 | class Database { | 6 | class Storage { |
7 | public: | 7 | public: |
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 | |||
15 | class Storage::Private | ||
16 | { | ||
17 | public: | ||
18 | Private(const QString &storageRoot, const QString &name); | ||
19 | ~Private(); | ||
20 | |||
21 | kyotocabinet::TreeDB db; | ||
22 | bool dbOpen; | ||
23 | bool inTransaction; | ||
24 | }; | ||
25 | |||
26 | Storage::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 | |||
39 | Storage::Private::~Private() | ||
40 | { | ||
41 | if (dbOpen && inTransaction) { | ||
42 | db.end_transaction(false); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | Storage::Storage(const QString &storageRoot, const QString &name) | ||
47 | : d(new Private(storageRoot, name)) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | Storage::~Storage() | ||
52 | { | ||
53 | delete d; | ||
54 | } | ||
55 | |||
56 | bool Storage::isInTransaction() const | ||
57 | { | ||
58 | return d->inTransaction; | ||
59 | } | ||
60 | |||
61 | bool 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 | |||
76 | bool 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 | |||
91 | void 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 | |||
101 | bool 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 | |||
111 | bool 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 | |||
121 | bool 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 | |||
136 | bool 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 | |||
151 | qint64 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 | |||
161 | void 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 | ||
14 | class Database::Private | 14 | class Storage::Private |
15 | { | 15 | { |
16 | public: | 16 | public: |
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 | ||
29 | Database::Private::Private(const QString &s, const QString &n) | 30 | Storage::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 | ||
56 | Database::Private::~Private() | 57 | Storage::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 | ||
67 | Database::Database(const QString &storageRoot, const QString &name) | 68 | Storage::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 | ||
72 | Database::~Database() | 73 | Storage::~Storage() |
73 | { | 74 | { |
74 | delete d; | 75 | delete d; |
75 | } | 76 | } |
76 | 77 | ||
77 | bool Database::isInTransaction() const | 78 | bool Storage::isInTransaction() const |
78 | { | 79 | { |
79 | return d->transaction; | 80 | return d->transaction; |
80 | } | 81 | } |
81 | 82 | ||
82 | bool Database::startTransaction(TransactionType type) | 83 | bool 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 | ||
117 | bool Database::commitTransaction() | 118 | bool 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 | ||
138 | void Database::abortTransaction() | 139 | void 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 | ||
148 | bool Database::write(const char *key, size_t keySize, const char *value, size_t valueSize) | 149 | bool 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 | ||
153 | bool Database::write(const std::string &sKey, const std::string &sValue) | 154 | bool 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 | ||
190 | bool Database::read(const std::string &sKey, const std::function<void(const std::string &value)> &resultHandler) | 191 | bool 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 | ||
200 | bool Database::read(const std::string &sKey, const std::function<void(void *ptr, int size)> &resultHandler) | 201 | bool 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 | ||
263 | qint64 Database::diskUsage() const | 264 | qint64 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 | ||
269 | void Database::removeFromDisk() const | 270 | void Storage::removeFromDisk() const |
271 | { | ||
272 | QDir dir(d->path); | ||
273 | dir.remove("data.mdb"); | ||
274 | dir.remove("lock.mdb"); | ||
275 | } | ||
276 | |||
277 | void 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; | |||
11 | DummyResourceFacade::DummyResourceFacade() | 11 | DummyResourceFacade::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 | ||
75 | void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) | 75 | void 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 | ||
6 | class ResourceAccess; | 6 | class ResourceAccess; |
7 | 7 | ||
@@ -18,5 +18,5 @@ public: | |||
18 | 18 | ||
19 | private: | 19 | private: |
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 @@ | |||
1 | add_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 @@ | |||
1 | set(CMAKE_AUTOMOC ON) | 1 | set(CMAKE_AUTOMOC ON) |
2 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) | 2 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
3 | 3 | ||
4 | set(store_path "../") | ||
5 | set(store_SRCS | ||
6 | ${store_path}/database.cpp | ||
7 | ) | ||
8 | |||
9 | generate_flatbuffers(calendar) | 4 | generate_flatbuffers(calendar) |
10 | 5 | ||
11 | macro(manual_tests) | 6 | macro(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) |
17 | endmacro(auto_tests) | 12 | endmacro(manual_tests) |
18 | 13 | ||
19 | manual_tests ( | 14 | manual_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 | ||
14 | using namespace Calendar; | 14 | using namespace Calendar; |
15 | using namespace flatbuffers; | 15 | using 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 | |||
11 | class StorageTest : public QObject | ||
12 | { | ||
13 | Q_OBJECT | ||
14 | private: | ||
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 | |||
50 | private 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 | |||
111 | QTEST_MAIN(StorageTest) | ||
112 | #include "storagetest.moc" | ||