summaryrefslogtreecommitdiffstats
path: root/store
diff options
context:
space:
mode:
authorAaron Seigo <aseigo@kde.org>2014-12-05 10:05:19 +0100
committerAaron Seigo <aseigo@kde.org>2014-12-05 10:05:19 +0100
commit93d1c82ffd17df45a5cecd875a01ee3cb15d9983 (patch)
treecda5c31857362ce81f3a50959024f4270d149a07 /store
parent639fc60c100204c87b93112516cf3b3117cfff0d (diff)
parent351a66b5fb1c8659bff8ea20d60f5a6d2d3263ad (diff)
downloadsink-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
Diffstat (limited to 'store')
-rw-r--r--store/CMakeLists.txt1
-rw-r--r--store/database.cpp274
-rw-r--r--store/database.h28
-rw-r--r--store/test/CMakeLists.txt22
-rw-r--r--store/test/calendar.fbs12
-rw-r--r--store/test/storagebenchmark.cpp161
6 files changed, 0 insertions, 498 deletions
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/database.cpp b/store/database.cpp
deleted file mode 100644
index c4dfbd6..0000000
--- a/store/database.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
1#include "database.h"
2
3#include <iostream>
4
5#include <QAtomicInt>
6#include <QDebug>
7#include <QDir>
8#include <QReadWriteLock>
9#include <QString>
10#include <QTime>
11
12#include <lmdb.h>
13
14class Database::Private
15{
16public:
17 Private(const QString &s, const QString &name);
18 ~Private();
19
20 QString storageRoot;
21 QString name;
22 MDB_dbi dbi;
23 MDB_env *env;
24 MDB_txn *transaction;
25 bool readTransaction;
26 bool firstOpen;
27};
28
29Database::Private::Private(const QString &s, const QString &n)
30 : transaction(0),
31 readTransaction(false),
32 firstOpen(true),
33 storageRoot(s),
34 name(n)
35{
36 QDir dir;
37 dir.mkdir(storageRoot);
38
39 //create file
40 if (mdb_env_create(&env)) {
41 // TODO: handle error
42 } else {
43 int rc = mdb_env_open(env, storageRoot.toStdString().data(), 0, 0664);
44
45 if (rc) {
46 std::cerr << "mdb_env_open: " << rc << " " << mdb_strerror(rc) << std::endl;
47 mdb_env_close(env);
48 env = 0;
49 } else {
50 const size_t dbSize = 10485760 * 100; //10MB * 100
51 mdb_env_set_mapsize(env, dbSize);
52 }
53 }
54}
55
56Database::Private::~Private()
57{
58 if (transaction) {
59 mdb_txn_abort(transaction);
60 }
61
62 // it is still there and still unused, so we can shut it down
63 mdb_dbi_close(env, dbi);
64 mdb_env_close(env);
65}
66
67Database::Database(const QString &storageRoot, const QString &name)
68 : d(new Private(storageRoot, name))
69{
70}
71
72Database::~Database()
73{
74 delete d;
75}
76
77bool Database::isInTransaction() const
78{
79 return d->transaction;
80}
81
82bool Database::startTransaction(TransactionType type)
83{
84 if (!d->env) {
85 return false;
86 }
87
88 bool requestedRead = type == ReadOnly;
89 if (d->transaction && (!d->readTransaction || requestedRead)) {
90 return true;
91 }
92
93 if (d->transaction) {
94 // we are about to turn a read transaction into a writable one
95 abortTransaction();
96 }
97
98 if (d->firstOpen && requestedRead) {
99 //A write transaction is at least required the first time
100 mdb_txn_begin(d->env, nullptr, 0, &d->transaction);
101 //Open the database
102 //With this we could open multiple named databases if we wanted to
103 mdb_dbi_open(d->transaction, nullptr, 0, &d->dbi);
104 mdb_txn_abort(d->transaction);
105 }
106
107 int rc;
108 rc = mdb_txn_begin(d->env, NULL, requestedRead ? MDB_RDONLY : 0, &d->transaction);
109 if (!rc) {
110 rc = mdb_dbi_open(d->transaction, NULL, 0, &d->dbi);
111 }
112
113 d->firstOpen = false;
114 return !rc;
115}
116
117bool Database::commitTransaction()
118{
119 if (!d->env) {
120 return false;
121 }
122
123 if (!d->transaction) {
124 return false;
125 }
126
127 int rc;
128 rc = mdb_txn_commit(d->transaction);
129 d->transaction = 0;
130
131 if (rc) {
132 std::cerr << "mdb_txn_commit: " << rc << " " << mdb_strerror(rc) << std::endl;
133 }
134
135 return !rc;
136}
137
138void Database::abortTransaction()
139{
140 if (!d->env || !d->transaction) {
141 return;
142 }
143
144 mdb_txn_abort(d->transaction);
145 d->transaction = 0;
146}
147
148bool Database::write(const char *key, size_t keySize, const char *value, size_t valueSize)
149{
150 write(std::string(key, keySize), std::string(value, valueSize));
151}
152
153bool Database::write(const std::string &sKey, const std::string &sValue)
154{
155 if (!d->env) {
156 return false;
157 }
158
159 const bool implicitTransaction = !d->transaction || d->readTransaction;
160 if (implicitTransaction) {
161 // TODO: if this fails, still try the write below?
162 if (!startTransaction()) {
163 return false;
164 }
165 }
166
167 int rc;
168 MDB_val key, data;
169 key.mv_size = sKey.size();
170 key.mv_data = (void*)sKey.data();
171 data.mv_size = sValue.size();
172 data.mv_data = (void*)sValue.data();
173 rc = mdb_put(d->transaction, d->dbi, &key, &data, 0);
174
175 if (rc) {
176 std::cerr << "mdb_put: " << rc << " " << mdb_strerror(rc) << std::endl;
177 }
178
179 if (implicitTransaction) {
180 if (rc) {
181 abortTransaction();
182 } else {
183 rc = commitTransaction();
184 }
185 }
186
187 return !rc;
188}
189
190bool Database::read(const std::string &sKey, const std::function<void(const std::string &value)> &resultHandler)
191{
192 return read(sKey,
193 [&](void *ptr, int size) {
194 const std::string resultValue(static_cast<char*>(ptr), size);
195 resultHandler(resultValue);
196 });
197// std::cout << "key: " << resultKey << " data: " << resultValue << std::endl;
198}
199
200bool Database::read(const std::string &sKey, const std::function<void(void *ptr, int size)> &resultHandler)
201{
202 if (!d->env) {
203 return false;
204 }
205
206 int rc;
207 MDB_val key;
208 MDB_val data;
209 MDB_cursor *cursor;
210
211 key.mv_size = sKey.size();
212 key.mv_data = (void*)sKey.data();
213
214 const bool implicitTransaction = !d->transaction;
215 if (implicitTransaction) {
216 // TODO: if this fails, still try the write below?
217 if (!startTransaction(ReadOnly)) {
218 return false;
219 }
220 }
221
222 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor);
223 if (rc) {
224 std::cerr << "mdb_cursor_get: " << rc << " " << mdb_strerror(rc) << std::endl;
225 return false;
226 }
227
228 if (sKey.empty()) {
229 std::cout << "Iterating over all values of store!" << std::endl;
230 rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
231 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
232 resultHandler(key.mv_data, data.mv_size);
233 }
234
235 //We never find the last value
236 if (rc == MDB_NOTFOUND) {
237 rc = 0;
238 }
239 } else {
240 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_SET)) == 0) {
241 resultHandler(data.mv_data, data.mv_size);
242 } else {
243 std::cout << "couldn't find value " << sKey << " " << std::endl;
244 }
245 }
246
247 if (rc) {
248 std::cerr << "mdb_cursor_get: " << rc << " " << mdb_strerror(rc) << std::endl;
249 return false;
250 }
251
252 mdb_cursor_close(cursor);
253
254 /**
255 we don't abort the transaction since we need it for reading the values
256 if (implicitTransaction) {
257 abortTransaction();
258 }
259 */
260 return true;
261}
262
263qint64 Database::diskUsage() const
264{
265 QFileInfo info(d->storageRoot + "/data.mdb");
266 return info.size();
267}
268
269void Database::removeFromDisk() const
270{
271 QDir dir(d->storageRoot);
272 dir.remove("data.mdb");
273 dir.remove("lock.mdb");
274}
diff --git a/store/database.h b/store/database.h
deleted file mode 100644
index 1cede39..0000000
--- a/store/database.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#pragma once
2
3#include <string>
4#include <QString>
5
6class Database {
7public:
8 enum TransactionType { ReadOnly, ReadWrite };
9
10 Database(const QString &storageRoot, const QString &name);
11 ~Database();
12 bool isInTransaction() const;
13 bool startTransaction(TransactionType type = ReadWrite);
14 bool commitTransaction();
15 void abortTransaction();
16 bool write(const char *key, size_t keySize, const char *value, size_t valueSize);
17 bool write(const std::string &sKey, const std::string &sValue);
18 //Perhaps prefer iterators (assuming we need to be able to match multiple values
19 bool read(const std::string &sKey, const std::function<void(const std::string &value)> &);
20 bool read(const std::string &sKey, const std::function<void(void *ptr, int size)> &);
21
22 qint64 diskUsage() const;
23 void removeFromDisk() const;
24private:
25 class Private;
26 Private * const d;
27};
28
diff --git a/store/test/CMakeLists.txt b/store/test/CMakeLists.txt
deleted file mode 100644
index c5c4fcb..0000000
--- a/store/test/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
1set(CMAKE_AUTOMOC ON)
2include_directories(${CMAKE_CURRENT_BINARY_DIR})
3
4set(store_path "../")
5set(store_SRCS
6 ${store_path}/database.cpp
7)
8
9generate_flatbuffers(calendar)
10
11macro(manual_tests)
12 foreach(_testname ${ARGN})
13 add_executable(${_testname} ${_testname}.cpp ${store_SRCS})
14 qt5_use_modules(${_testname} Core Test Concurrent)
15 target_link_libraries(${_testname} lmdb)
16 endforeach(_testname)
17endmacro(auto_tests)
18
19manual_tests (
20 storagebenchmark
21 storagetest
22)
diff --git a/store/test/calendar.fbs b/store/test/calendar.fbs
deleted file mode 100644
index 203ee43..0000000
--- a/store/test/calendar.fbs
+++ /dev/null
@@ -1,12 +0,0 @@
1// example IDL file
2
3namespace Calendar;
4
5table Event {
6 summary:string;
7 description:string;
8 attachment:[byte];
9}
10
11root_type Event;
12file_identifier "AKFB";
diff --git a/store/test/storagebenchmark.cpp b/store/test/storagebenchmark.cpp
deleted file mode 100644
index 0bad138..0000000
--- a/store/test/storagebenchmark.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
1#include <QtTest>
2
3#include "calendar_generated.h"
4
5#include <iostream>
6#include <fstream>
7
8#include <QDebug>
9#include <QString>
10#include <QTime>
11
12#include "store/database.h"
13
14using namespace Calendar;
15using namespace flatbuffers;
16
17static std::string createEvent()
18{
19 FlatBufferBuilder fbb;
20 {
21 auto summary = fbb.CreateString("summary");
22
23 const int attachmentSize = 1024*2; // 2KB
24 int8_t rawData[attachmentSize];
25 auto data = fbb.CreateVector(rawData, attachmentSize);
26
27 Calendar::EventBuilder eventBuilder(fbb);
28 eventBuilder.add_summary(summary);
29 eventBuilder.add_attachment(data);
30 auto eventLocation = eventBuilder.Finish();
31 FinishEventBuffer(fbb, eventLocation);
32 }
33 return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
34}
35
36// static void readEvent(const std::string &data)
37// {
38// auto readEvent = GetEvent(data.c_str());
39// std::cout << readEvent->summary()->c_str() << std::endl;
40// }
41
42class StorageBenchmark : public QObject
43{
44 Q_OBJECT
45private:
46 //This should point to a directory on disk and not a ramdisk (since we're measuring performance)
47 QString testDataPath;
48 QString dbName;
49 QString filePath;
50 const int count = 50000;
51
52private Q_SLOTS:
53 void initTestCase()
54 {
55 testDataPath = "./testdb";
56 dbName = "test";
57 filePath = testDataPath + "buffer.fb";
58 }
59
60 void cleanupTestCase()
61 {
62 Database db(testDataPath, dbName);
63 db.removeFromDisk();
64 }
65
66 void testWriteRead_data()
67 {
68 QTest::addColumn<bool>("useDb");
69 QTest::addColumn<int>("count");
70
71 QTest::newRow("db, 50k") << true << count;
72 QTest::newRow("file, 50k") << false << count;
73 }
74
75 void testWriteRead()
76 {
77 QFETCH(bool, useDb);
78 QFETCH(int, count);
79
80 Database *db = 0;
81 if (useDb) {
82 db = new Database(testDataPath, dbName);
83 }
84
85 std::ofstream myfile;
86 myfile.open(filePath.toStdString());
87 const char *keyPrefix = "key";
88
89 QTime time;
90
91 time.start();
92 {
93 auto event = createEvent();
94 for (int i = 0; i < count; i++) {
95 if (db) {
96 if (i % 10000 == 0) {
97 if (i > 0) {
98 db->commitTransaction();
99 }
100 db->startTransaction();
101 }
102
103 db->write(keyPrefix + std::to_string(i), event);
104 } else {
105 myfile << event;
106 }
107 }
108
109 if (db) {
110 db->commitTransaction();
111 } else {
112 myfile.close();
113 }
114 }
115 const int writeDuration = time.restart();
116 qDebug() << "Writing took[ms]: " << writeDuration;
117
118 {
119 for (int i = 0; i < count; i++) {
120 if (db) {
121 db->read(keyPrefix + std::to_string(i), [](std::string value){});
122 }
123 }
124 }
125 const int readDuration = time.restart();
126
127 if (db) {
128 qDebug() << "Reading took[ms]: " << readDuration;
129 } else {
130 qDebug() << "File reading is not implemented.";
131 }
132
133 delete db;
134 }
135
136 void testBufferCreation()
137 {
138 QTime time;
139
140 time.start();
141 {
142 for (int i = 0; i < count; i++) {
143 auto event = createEvent();
144 }
145 }
146 const int bufferDuration = time.elapsed();
147 qDebug() << "Creating buffers took[ms]: " << bufferDuration;
148 }
149
150 void testSizes()
151 {
152 Database db(testDataPath, dbName);
153 qDebug() << "Database size [kb]: " << db.diskUsage()/1024;
154
155 QFileInfo fileInfo(filePath);
156 qDebug() << "File size [kb]: " << fileInfo.size()/1024;
157 }
158};
159
160QTEST_MAIN(StorageBenchmark)
161#include "storagebenchmark.moc"