summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-03-30 23:38:45 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-03-31 11:11:08 +0200
commit42f32ea5865c95028c577000e15e8a8631d16e74 (patch)
tree2d9e8a77ccccf088a8807f35f87e4264163d6cdd
parent34851314d39307f22df01a4b711e6fd3c5618e23 (diff)
downloadsink-42f32ea5865c95028c577000e15e8a8631d16e74.tar.gz
sink-42f32ea5865c95028c577000e15e8a8631d16e74.zip
Storage: API cleanup/use QByteArray instead of std::string
-rw-r--r--common/index.cpp4
-rw-r--r--common/index.h6
-rw-r--r--common/messagequeue.cpp4
-rw-r--r--common/messagequeue.h6
-rw-r--r--common/pipeline.cpp2
-rw-r--r--common/storage.h90
-rw-r--r--common/storage_common.cpp40
-rw-r--r--common/storage_lmdb.cpp137
-rw-r--r--dummyresource/facade.cpp8
-rw-r--r--tests/hawd/dataset.cpp4
-rw-r--r--tests/storagebenchmark.cpp10
-rw-r--r--tests/storagetest.cpp20
12 files changed, 198 insertions, 133 deletions
diff --git a/common/index.cpp b/common/index.cpp
index 7b0c682..9bb467b 100644
--- a/common/index.cpp
+++ b/common/index.cpp
@@ -17,12 +17,12 @@ void Index::add(const QByteArray &key, const QByteArray &value)
17void Index::lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler, 17void Index::lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler,
18 const std::function<void(const Error &error)> &errorHandler) 18 const std::function<void(const Error &error)> &errorHandler)
19{ 19{
20 mStorage.scan(key.data(), key.size(), [this, resultHandler](void *keyPtr, int keySize, void *valuePtr, int valueSize) -> bool { 20 mStorage.scan(key, [this, resultHandler](void *keyPtr, int keySize, void *valuePtr, int valueSize) -> bool {
21 resultHandler(QByteArray(static_cast<char*>(valuePtr), valueSize)); 21 resultHandler(QByteArray(static_cast<char*>(valuePtr), valueSize));
22 return true; 22 return true;
23 }, 23 },
24 [errorHandler](const Akonadi2::Storage::Error &error) { 24 [errorHandler](const Akonadi2::Storage::Error &error) {
25 qDebug() << "Error while retrieving value" << QString::fromStdString(error.message); 25 qDebug() << "Error while retrieving value" << error.message;
26 errorHandler(Error(error.store, error.code, error.message)); 26 errorHandler(Error(error.store, error.code, error.message));
27 } 27 }
28 ); 28 );
diff --git a/common/index.h b/common/index.h
index aea654a..3cd7cc8 100644
--- a/common/index.h
+++ b/common/index.h
@@ -14,10 +14,10 @@ public:
14 class Error 14 class Error
15 { 15 {
16 public: 16 public:
17 Error(const std::string &s, int c, const std::string &m) 17 Error(const QByteArray &s, int c, const QByteArray &m)
18 : store(s), message(m), code(c) {} 18 : store(s), message(m), code(c) {}
19 std::string store; 19 QByteArray store;
20 std::string message; 20 QByteArray message;
21 int code; 21 int code;
22 }; 22 };
23 23
diff --git a/common/messagequeue.cpp b/common/messagequeue.cpp
index 76f8162..add4759 100644
--- a/common/messagequeue.cpp
+++ b/common/messagequeue.cpp
@@ -23,7 +23,7 @@ void MessageQueue::dequeue(const std::function<void(void *ptr, int size, std::fu
23 const std::function<void(const Error &error)> &errorHandler) 23 const std::function<void(const Error &error)> &errorHandler)
24{ 24{
25 bool readValue = false; 25 bool readValue = false;
26 mStorage.scan("", 0, [this, resultHandler, &readValue](void *keyPtr, int keySize, void *valuePtr, int valueSize) -> bool { 26 mStorage.scan("", [this, resultHandler, &readValue](void *keyPtr, int keySize, void *valuePtr, int valueSize) -> bool {
27 const auto key = QByteArray::fromRawData(static_cast<char*>(keyPtr), keySize); 27 const auto key = QByteArray::fromRawData(static_cast<char*>(keyPtr), keySize);
28 if (Akonadi2::Storage::isInternalKey(key)) { 28 if (Akonadi2::Storage::isInternalKey(key)) {
29 return true; 29 return true;
@@ -42,7 +42,7 @@ void MessageQueue::dequeue(const std::function<void(void *ptr, int size, std::fu
42 return false; 42 return false;
43 }, 43 },
44 [errorHandler](const Akonadi2::Storage::Error &error) { 44 [errorHandler](const Akonadi2::Storage::Error &error) {
45 qDebug() << "Error while retrieving value" << QString::fromStdString(error.message); 45 qDebug() << "Error while retrieving value" << error.message;
46 errorHandler(Error(error.store, error.code, error.message)); 46 errorHandler(Error(error.store, error.code, error.message));
47 } 47 }
48 ); 48 );
diff --git a/common/messagequeue.h b/common/messagequeue.h
index 52eeb1f..b7e3daa 100644
--- a/common/messagequeue.h
+++ b/common/messagequeue.h
@@ -16,10 +16,10 @@ public:
16 class Error 16 class Error
17 { 17 {
18 public: 18 public:
19 Error(const std::string &s, int c, const std::string &m) 19 Error(const QByteArray &s, int c, const QByteArray &m)
20 : store(s), message(m), code(c) {} 20 : store(s), message(m), code(c) {}
21 std::string store; 21 QByteArray store;
22 std::string message; 22 QByteArray message;
23 int code; 23 int code;
24 }; 24 };
25 25
diff --git a/common/pipeline.cpp b/common/pipeline.cpp
index 7cab8ec..f321cf5 100644
--- a/common/pipeline.cpp
+++ b/common/pipeline.cpp
@@ -288,7 +288,7 @@ void PipelineState::step()
288 //TODO skip step if already processed 288 //TODO skip step if already processed
289 //FIXME error handling if no result is found 289 //FIXME error handling if no result is found
290 auto preprocessor = d->filterIt.next(); 290 auto preprocessor = d->filterIt.next();
291 d->pipeline->storage().scan(d->key.toStdString(), [this, preprocessor](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 291 d->pipeline->storage().scan(d->key, [this, preprocessor](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
292 auto entity = Akonadi2::GetEntity(dataValue); 292 auto entity = Akonadi2::GetEntity(dataValue);
293 preprocessor->process(*this, *entity); 293 preprocessor->process(*this, *entity);
294 return false; 294 return false;
diff --git a/common/storage.h b/common/storage.h
index 099b45f..78faac0 100644
--- a/common/storage.h
+++ b/common/storage.h
@@ -33,45 +33,80 @@ class AKONADI2COMMON_EXPORT Storage {
33public: 33public:
34 enum AccessMode { ReadOnly, ReadWrite }; 34 enum AccessMode { ReadOnly, ReadWrite };
35 35
36 enum ErrorCodes {
37 GenericError,
38 NotOpen,
39 ReadOnlyError,
40 TransactionError,
41 NotFound
42 };
43
36 class Error 44 class Error
37 { 45 {
38 public: 46 public:
39 Error(const std::string &s, int c, const std::string &m) 47 Error(const QByteArray &s, int c, const QByteArray &m)
40 : store(s), message(m), code(c) {} 48 : store(s), message(m), code(c) {}
41 std::string store; 49 QByteArray store;
42 std::string message; 50 QByteArray message;
43 int code; 51 int code;
44 }; 52 };
45 53
46 Storage(const QString &storageRoot, const QString &name, AccessMode mode = ReadOnly, bool allowDuplicates = false); 54 Storage(const QString &storageRoot, const QString &name, AccessMode mode = ReadOnly, bool allowDuplicates = false);
47 ~Storage(); 55 ~Storage();
48 bool isInTransaction() const; 56 bool isInTransaction() const;
49 bool startTransaction(AccessMode mode = ReadWrite); 57 bool startTransaction(AccessMode mode = ReadWrite, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
50 bool commitTransaction(); 58 bool commitTransaction(const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
51 void abortTransaction(); 59 void abortTransaction();
52 //TODO: row removal
53 //TODO: cursor based read
54 //TODO: query?
55 bool write(const void *key, size_t keySize, const void *value, size_t valueSize);
56 bool write(const std::string &sKey, const std::string &sValue);
57 void read(const std::string &sKey,
58 const std::function<bool(const std::string &value)> &resultHandler);
59 void read(const std::string &sKey,
60 const std::function<bool(const std::string &value)> &resultHandler,
61 const std::function<void(const Storage::Error &error)> &errorHandler);
62 void read(const std::string &sKey, const std::function<bool(void *ptr, int size)> &resultHandler);
63 void read(const std::string &sKey,
64 const std::function<bool(void *ptr, int size)> & resultHandler,
65 const std::function<void(const Storage::Error &error)> &errorHandler);
66 void scan(const std::string &sKey, const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler);
67 void scan(const char *keyData, uint keySize,
68 const std::function<bool(void *keyPtr, int keySize, void *ptr, int size)> &resultHandler,
69 const std::function<void(const Storage::Error &error)> &errorHandler);
70 void remove(void const *keyData, uint keySize);
71 void remove(void const *keyData, uint keySize,
72 const std::function<void(const Storage::Error &error)> &errorHandler);
73 60
61 /**
62 * Write values.
63 */
64 bool write(const void *key, size_t keySize, const void *value, size_t valueSize, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
65
66 /**
67 * Convenience API
68 */
69 bool write(const QByteArray &key, const QByteArray &value, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
70
71 /**
72 * Read values with a give key.
73 *
74 * * An empty @param key results in a full scan
75 * * If duplicates are existing (revisions), all values are returned.
76 * * The pointers of the returned values are valid during the execution of the @param resultHandler
77 *
78 * @return The number of values retrieved.
79 */
80 int scan(const QByteArray &key, const std::function<bool(void *keyPtr, int keySize, void *ptr, int size)> &resultHandler, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
81
82 /**
83 * Convenience API
84 */
85 int scan(const QByteArray &key, const std::function<bool(const QByteArray &value)> &resultHandler, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
86
87 /**
88 * Remove a value
89 */
90 void remove(void const *key, uint keySize, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
91
92 /**
93 * Convenience API
94 */
95 void remove(const QByteArray &key, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
96
97 /**
98 * Set the default error handler.
99 */
100 void setDefaultErrorHandler(const std::function<void(const Storage::Error &error)> &errorHandler);
101 std::function<void(const Storage::Error &error)> defaultErrorHandler();
102
103 /**
104 * A basic error handler that writes to std::cerr.
105 *
106 * Used if nothing else is configured.
107 */
74 static std::function<void(const Storage::Error &error)> basicErrorHandler(); 108 static std::function<void(const Storage::Error &error)> basicErrorHandler();
109
75 qint64 diskUsage() const; 110 qint64 diskUsage() const;
76 void removeFromDisk() const; 111 void removeFromDisk() const;
77 112
@@ -85,6 +120,9 @@ public:
85 static bool isInternalKey(const QByteArray &key); 120 static bool isInternalKey(const QByteArray &key);
86 121
87private: 122private:
123 std::function<void(const Storage::Error &error)> mErrorHandler;
124
125private:
88 class Private; 126 class Private;
89 Private * const d; 127 Private * const d;
90}; 128};
diff --git a/common/storage_common.cpp b/common/storage_common.cpp
index ff2a2cd..5728096 100644
--- a/common/storage_common.cpp
+++ b/common/storage_common.cpp
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org> 2 * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org>
3 * Copyright (C) 2014 Christian Mollekopf <mollekopf@kolabsys.com>
3 * 4 *
4 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public 6 * modify it under the terms of the GNU Lesser General Public
@@ -32,7 +33,7 @@ void errorHandler(const Storage::Error &error)
32{ 33{
33 //TODO: allow this to be turned on / off globally 34 //TODO: allow this to be turned on / off globally
34 //TODO: log $SOMEWHERE $SOMEHOW rather than just spit to stderr 35 //TODO: log $SOMEWHERE $SOMEHOW rather than just spit to stderr
35 std::cerr << "Read error in " << error.store << ", code " << error.code << ", message: " << error.message << std::endl; 36 std::cout << "Read error in " << error.store.toStdString() << ", code " << error.code << ", message: " << error.message.toStdString() << std::endl;
36} 37}
37 38
38std::function<void(const Storage::Error &error)> Storage::basicErrorHandler() 39std::function<void(const Storage::Error &error)> Storage::basicErrorHandler()
@@ -40,36 +41,47 @@ std::function<void(const Storage::Error &error)> Storage::basicErrorHandler()
40 return errorHandler; 41 return errorHandler;
41} 42}
42 43
43void Storage::read(const std::string &sKey, const std::function<bool(const std::string &value)> &resultHandler) 44void Storage::setDefaultErrorHandler(const std::function<void(const Storage::Error &error)> &errorHandler)
44{ 45{
45 read(sKey, resultHandler, &errorHandler); 46 mErrorHandler = errorHandler;
46} 47}
47 48
48void Storage::read(const std::string &sKey, const std::function<bool(void *ptr, int size)> &resultHandler) 49std::function<void(const Storage::Error &error)> Storage::defaultErrorHandler()
49{ 50{
50 read(sKey, resultHandler, &errorHandler); 51 if (mErrorHandler) {
52 return mErrorHandler;
53 }
54 return basicErrorHandler();
55}
56
57int Storage::scan(const QByteArray &key, const std::function<bool(const QByteArray &value)> &resultHandler, const std::function<void(const Storage::Error &error)> &errorHandler)
58{
59 return scan(key, [&resultHandler](void *keyPtr, int keySize, void *valuePtr, int valueSize) {
60 return resultHandler(QByteArray::fromRawData((char*)(valuePtr), valueSize));
61 },
62 errorHandler);
51} 63}
52 64
53void Storage::scan(const std::string &sKey, const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler) 65bool Storage::write(const QByteArray &sKey, const QByteArray &sValue, const std::function<void(const Storage::Error &error)> &errorHandler)
54{ 66{
55 scan(sKey.data(), sKey.size(), resultHandler, &errorHandler); 67 return write(const_cast<char*>(sKey.data()), sKey.size(), const_cast<char*>(sValue.data()), sValue.size(), errorHandler);
56} 68}
57 69
58void Storage::setMaxRevision(qint64 revision) 70void Storage::setMaxRevision(qint64 revision)
59{ 71{
60 write("__internal_maxRevision", QString::number(revision).toStdString()); 72 write("__internal_maxRevision", QByteArray::number(revision));
61} 73}
62 74
63qint64 Storage::maxRevision() 75qint64 Storage::maxRevision()
64{ 76{
65 qint64 r = 0; 77 qint64 r = 0;
66 read(std::string("__internal_maxRevision"), [&](const std::string &revision) -> bool { 78 scan("__internal_maxRevision", [&](const QByteArray &revision) -> bool {
67 r = QString::fromStdString(revision).toLongLong(); 79 r = revision.toLongLong();
68 return false; 80 return false;
69 }, 81 }, [this](const Error &error){
70 [](const Storage::Error &error) { 82 if (error.code != ErrorCodes::NotFound) {
71 //Ignore the error in case we don't find the value 83 defaultErrorHandler()(error);
72 //TODO only ignore value not found errors 84 }
73 }); 85 });
74 return r; 86 return r;
75} 87}
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp
index c97f9ce..4fcb11f 100644
--- a/common/storage_lmdb.cpp
+++ b/common/storage_lmdb.cpp
@@ -36,6 +36,17 @@
36namespace Akonadi2 36namespace Akonadi2
37{ 37{
38 38
39int getErrorCode(int e)
40{
41 switch (e) {
42 case MDB_NOTFOUND:
43 return Storage::ErrorCodes::NotFound;
44 default:
45 break;
46 }
47 return -1;
48}
49
39class Storage::Private 50class Storage::Private
40{ 51{
41public: 52public:
@@ -130,12 +141,14 @@ bool Storage::exists() const
130{ 141{
131 return (d->env != 0); 142 return (d->env != 0);
132} 143}
144
133bool Storage::isInTransaction() const 145bool Storage::isInTransaction() const
134{ 146{
135 return d->transaction; 147 return d->transaction;
136} 148}
137 149
138bool Storage::startTransaction(AccessMode type) 150bool Storage::startTransaction(AccessMode type,
151 const std::function<void(const Storage::Error &error)> &errorHandler)
139{ 152{
140 if (!d->env) { 153 if (!d->env) {
141 return false; 154 return false;
@@ -144,9 +157,12 @@ bool Storage::startTransaction(AccessMode type)
144 bool requestedRead = type == ReadOnly; 157 bool requestedRead = type == ReadOnly;
145 158
146 if (d->mode == ReadOnly && !requestedRead) { 159 if (d->mode == ReadOnly && !requestedRead) {
160 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Requested read/write transaction in read-only mode.");
161 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
147 return false; 162 return false;
148 } 163 }
149 164
165 //We already have a transaction
150 if (d->transaction && (!d->readTransaction || requestedRead)) { 166 if (d->transaction && (!d->readTransaction || requestedRead)) {
151 return true; 167 return true;
152 } 168 }
@@ -172,11 +188,13 @@ bool Storage::startTransaction(AccessMode type)
172 if (!rc) { 188 if (!rc) {
173 rc = mdb_dbi_open(d->transaction, NULL, d->allowDuplicates ? MDB_DUPSORT : 0, &d->dbi); 189 rc = mdb_dbi_open(d->transaction, NULL, d->allowDuplicates ? MDB_DUPSORT : 0, &d->dbi);
174 if (rc) { 190 if (rc) {
175 qWarning() << "Error while opening transaction: " << mdb_strerror(rc); 191 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Error while opening transaction: " + QByteArray(mdb_strerror(rc)));
192 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
176 } 193 }
177 } else { 194 } else {
178 if (rc) { 195 if (rc) {
179 qWarning() << "Error while beginning transaction: " << mdb_strerror(rc); 196 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Error while beginning transaction: " + QByteArray(mdb_strerror(rc)));
197 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
180 } 198 }
181 } 199 }
182 200
@@ -185,7 +203,7 @@ bool Storage::startTransaction(AccessMode type)
185 return !rc; 203 return !rc;
186} 204}
187 205
188bool Storage::commitTransaction() 206bool Storage::commitTransaction(const std::function<void(const Storage::Error &error)> &errorHandler)
189{ 207{
190 if (!d->env) { 208 if (!d->env) {
191 return false; 209 return false;
@@ -200,7 +218,8 @@ bool Storage::commitTransaction()
200 d->transaction = 0; 218 d->transaction = 0;
201 219
202 if (rc) { 220 if (rc) {
203 std::cerr << "mdb_txn_commit: " << rc << " " << mdb_strerror(rc) << std::endl; 221 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Error during transaction commit: " + QByteArray(mdb_strerror(rc)));
222 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
204 } 223 }
205 224
206 return !rc; 225 return !rc;
@@ -216,25 +235,32 @@ void Storage::abortTransaction()
216 d->transaction = 0; 235 d->transaction = 0;
217} 236}
218 237
219bool Storage::write(const void *keyPtr, size_t keySize, const void *valuePtr, size_t valueSize) 238bool Storage::write(const void *keyPtr, size_t keySize, const void *valuePtr, size_t valueSize,
239 const std::function<void(const Storage::Error &error)> &errorHandler)
220{ 240{
221 if (!d->env) { 241 if (!d->env) {
242 Error error(d->name.toLatin1(), ErrorCodes::NotOpen, "Not open");
243 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
222 return false; 244 return false;
223 } 245 }
224 246
225 if (d->mode == ReadOnly) { 247 if (d->mode == ReadOnly) {
226 std::cerr << "tried to write in read-only mode." << std::endl; 248 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Tried to write in read-only mode.");
249 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
227 return false; 250 return false;
228 } 251 }
229 252
230 if (!keyPtr || keySize == 0) { 253 if (!keyPtr || keySize == 0) {
231 std::cerr << "tried to write empty key." << std::endl; 254 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Tried to write empty key.");
255 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
232 return false; 256 return false;
233 } 257 }
234 258
235 const bool implicitTransaction = !d->transaction || d->readTransaction; 259 const bool implicitTransaction = !d->transaction || d->readTransaction;
236 if (implicitTransaction) { 260 if (implicitTransaction) {
237 if (!startTransaction()) { 261 if (!startTransaction()) {
262 Error error(d->name.toLatin1(), ErrorCodes::TransactionError, "Failed to start transaction.");
263 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
238 return false; 264 return false;
239 } 265 }
240 } 266 }
@@ -248,11 +274,14 @@ bool Storage::write(const void *keyPtr, size_t keySize, const void *valuePtr, si
248 rc = mdb_put(d->transaction, d->dbi, &key, &data, 0); 274 rc = mdb_put(d->transaction, d->dbi, &key, &data, 0);
249 275
250 if (rc) { 276 if (rc) {
251 std::cerr << "mdb_put: " << rc << " " << mdb_strerror(rc) << std::endl; 277 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "mdb_put: " + QByteArray(mdb_strerror(rc)));
278 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
252 } 279 }
253 280
254 if (implicitTransaction) { 281 if (implicitTransaction) {
255 if (rc) { 282 if (rc) {
283 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "aborting transaction");
284 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
256 abortTransaction(); 285 abortTransaction();
257 } else { 286 } else {
258 rc = commitTransaction(); 287 rc = commitTransaction();
@@ -262,39 +291,14 @@ bool Storage::write(const void *keyPtr, size_t keySize, const void *valuePtr, si
262 return !rc; 291 return !rc;
263} 292}
264 293
265bool Storage::write(const std::string &sKey, const std::string &sValue) 294int Storage::scan(const QByteArray &k,
266{ 295 const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler,
267 return write(const_cast<char*>(sKey.data()), sKey.size(), const_cast<char*>(sValue.data()), sValue.size()); 296 const std::function<void(const Storage::Error &error)> &errorHandler)
268}
269
270void Storage::read(const std::string &sKey,
271 const std::function<bool(const std::string &value)> &resultHandler,
272 const std::function<void(const Storage::Error &error)> &errorHandler)
273{
274 read(sKey,
275 [&](void *ptr, int size) -> bool {
276 const std::string resultValue(static_cast<char*>(ptr), size);
277 return resultHandler(resultValue);
278 }, errorHandler);
279}
280
281void Storage::read(const std::string &sKey,
282 const std::function<bool(void *ptr, int size)> &resultHandler,
283 const std::function<void(const Storage::Error &error)> &errorHandler)
284{
285 scan(sKey.data(), sKey.size(), [resultHandler](void *keyPtr, int keySize, void *valuePtr, int valueSize) {
286 return resultHandler(valuePtr, valueSize);
287 }, errorHandler);
288}
289
290void Storage::scan(const char *keyData, uint keySize,
291 const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler,
292 const std::function<void(const Storage::Error &error)> &errorHandler)
293{ 297{
294 if (!d->env) { 298 if (!d->env) {
295 Error error(d->name.toStdString(), -1, "Not open"); 299 Error error(d->name.toLatin1(), ErrorCodes::NotOpen, "Not open");
296 errorHandler(error); 300 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
297 return; 301 return 0;
298 } 302 }
299 303
300 int rc; 304 int rc;
@@ -302,29 +306,33 @@ void Storage::scan(const char *keyData, uint keySize,
302 MDB_val data; 306 MDB_val data;
303 MDB_cursor *cursor; 307 MDB_cursor *cursor;
304 308
305 key.mv_data = (void*)keyData; 309 key.mv_data = (void*)k.constData();
306 key.mv_size = keySize; 310 key.mv_size = k.size();
307 311
308 const bool implicitTransaction = !d->transaction; 312 const bool implicitTransaction = !d->transaction;
309 if (implicitTransaction) { 313 if (implicitTransaction) {
310 if (!startTransaction(ReadOnly)) { 314 if (!startTransaction(ReadOnly)) {
311 Error error(d->name.toStdString(), -2, "Could not start transaction"); 315 Error error(d->name.toLatin1(), ErrorCodes::TransactionError, "Could not start transaction");
312 errorHandler(error); 316 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
313 return; 317 return 0;
314 } 318 }
315 } 319 }
316 320
317 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor); 321 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor);
318 if (rc) { 322 if (rc) {
319 Error error(d->name.toStdString(), rc, std::string("Error during mdb_cursor open: ") + mdb_strerror(rc)); 323 Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Error during mdb_cursor open: ") + QByteArray(mdb_strerror(rc)));
320 errorHandler(error); 324 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
321 return; 325 return 0;
322 } 326 }
323 327
324 if (!keyData || keySize == 0 || d->allowDuplicates) { 328 int numberOfRetrievedValues = 0;
329
330 if (k.isEmpty() || d->allowDuplicates) {
325 if ((rc = mdb_cursor_get(cursor, &key, &data, d->allowDuplicates ? MDB_SET_RANGE : MDB_FIRST)) == 0) { 331 if ((rc = mdb_cursor_get(cursor, &key, &data, d->allowDuplicates ? MDB_SET_RANGE : MDB_FIRST)) == 0) {
332 numberOfRetrievedValues++;
326 if (resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size)) { 333 if (resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size)) {
327 while ((rc = mdb_cursor_get(cursor, &key, &data, d->allowDuplicates ? MDB_NEXT_DUP : MDB_NEXT)) == 0) { 334 while ((rc = mdb_cursor_get(cursor, &key, &data, d->allowDuplicates ? MDB_NEXT_DUP : MDB_NEXT)) == 0) {
335 numberOfRetrievedValues++;
328 if (!resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size)) { 336 if (!resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size)) {
329 break; 337 break;
330 } 338 }
@@ -338,6 +346,7 @@ void Storage::scan(const char *keyData, uint keySize,
338 } 346 }
339 } else { 347 } else {
340 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_SET)) == 0) { 348 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_SET)) == 0) {
349 numberOfRetrievedValues++;
341 resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size); 350 resultHandler(key.mv_data, key.mv_size, data.mv_data, data.mv_size);
342 } 351 }
343 } 352 }
@@ -345,39 +354,42 @@ void Storage::scan(const char *keyData, uint keySize,
345 mdb_cursor_close(cursor); 354 mdb_cursor_close(cursor);
346 355
347 if (rc) { 356 if (rc) {
348 Error error(d->name.toStdString(), rc, std::string("Key: ") + std::string(keyData, keySize) + " : " + mdb_strerror(rc)); 357 Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Key: ") + k + " : " + QByteArray(mdb_strerror(rc)));
349 errorHandler(error); 358 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
350 } 359 }
351 360
352 if (implicitTransaction) { 361 if (implicitTransaction) {
353 abortTransaction(); 362 abortTransaction();
354 } 363 }
364 return numberOfRetrievedValues;
355} 365}
356 366
357void Storage::remove(const void *keyData, uint keySize) 367void Storage::remove(const QByteArray &key,
368 const std::function<void(const Storage::Error &error)> &errorHandler)
358{ 369{
359 remove(keyData, keySize, basicErrorHandler()); 370 remove(key.data(), key.size(), errorHandler);
360} 371}
361 372
362void Storage::remove(const void *keyData, uint keySize, const std::function<void(const Storage::Error &error)> &errorHandler) 373void Storage::remove(const void *keyData, uint keySize,
374 const std::function<void(const Storage::Error &error)> &errorHandler)
363{ 375{
364 if (!d->env) { 376 if (!d->env) {
365 Error error(d->name.toStdString(), -1, "Not open"); 377 Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Not open");
366 errorHandler(error); 378 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
367 return; 379 return;
368 } 380 }
369 381
370 if (d->mode == ReadOnly) { 382 if (d->mode == ReadOnly) {
371 Error error(d->name.toStdString(), -3, "Tried to write in read-only mode"); 383 Error error(d->name.toLatin1(), ErrorCodes::ReadOnlyError, "Tried to write in read-only mode");
372 errorHandler(error); 384 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
373 return; 385 return;
374 } 386 }
375 387
376 const bool implicitTransaction = !d->transaction || d->readTransaction; 388 const bool implicitTransaction = !d->transaction || d->readTransaction;
377 if (implicitTransaction) { 389 if (implicitTransaction) {
378 if (!startTransaction()) { 390 if (!startTransaction()) {
379 Error error(d->name.toStdString(), -2, "Could not start transaction"); 391 Error error(d->name.toLatin1(), ErrorCodes::TransactionError, "Could not start transaction");
380 errorHandler(error); 392 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
381 return; 393 return;
382 } 394 }
383 } 395 }
@@ -389,8 +401,8 @@ void Storage::remove(const void *keyData, uint keySize, const std::function<void
389 rc = mdb_del(d->transaction, d->dbi, &key, 0); 401 rc = mdb_del(d->transaction, d->dbi, &key, 0);
390 402
391 if (rc) { 403 if (rc) {
392 Error error(d->name.toStdString(), -1, QString("Error on mdb_del: %1 %2").arg(rc).arg(mdb_strerror(rc)).toStdString()); 404 Error error(d->name.toLatin1(), ErrorCodes::GenericError, QString("Error on mdb_del: %1 %2").arg(rc).arg(mdb_strerror(rc)).toLatin1());
393 errorHandler(error); 405 errorHandler ? errorHandler(error) : defaultErrorHandler()(error);
394 } 406 }
395 407
396 if (implicitTransaction) { 408 if (implicitTransaction) {
@@ -413,6 +425,7 @@ qint64 Storage::diskUsage() const
413void Storage::removeFromDisk() const 425void Storage::removeFromDisk() const
414{ 426{
415 const QString fullPath(d->storageRoot + '/' + d->name); 427 const QString fullPath(d->storageRoot + '/' + d->name);
428 qDebug() << "removing " << fullPath;
416 QMutexLocker locker(&d->sMutex); 429 QMutexLocker locker(&d->sMutex);
417 QDir dir(fullPath); 430 QDir dir(fullPath);
418 if (!dir.removeRecursively()) { 431 if (!dir.removeRecursively()) {
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp
index e0d27dc..893b585 100644
--- a/dummyresource/facade.cpp
+++ b/dummyresource/facade.cpp
@@ -135,7 +135,7 @@ Async::Job<void> DummyResourceFacade::synchronizeResource(bool sync, bool proces
135 135
136void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery) 136void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery)
137{ 137{
138 storage->scan(key.data(), key.size(), [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 138 storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
139 139
140 //Skip internals 140 //Skip internals
141 if (Akonadi2::Storage::isInternalKey(keyValue, keySize)) { 141 if (Akonadi2::Storage::isInternalKey(keyValue, keySize)) {
@@ -170,7 +170,7 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c
170 } 170 }
171 171
172 if (!resourceBuffer || !metadataBuffer) { 172 if (!resourceBuffer || !metadataBuffer) {
173 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); 173 qWarning() << "invalid buffer " << QByteArray::fromRawData(static_cast<char*>(keyValue), keySize);
174 return true; 174 return true;
175 } 175 }
176 176
@@ -189,7 +189,7 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c
189 return true; 189 return true;
190 }, 190 },
191 [](const Akonadi2::Storage::Error &error) { 191 [](const Akonadi2::Storage::Error &error) {
192 qWarning() << "Error during query: " << QString::fromStdString(error.message); 192 qWarning() << "Error during query: " << error.message;
193 }); 193 });
194} 194}
195 195
@@ -208,7 +208,7 @@ Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const s
208 keys << value; 208 keys << value;
209 }, 209 },
210 [](const Index::Error &error) { 210 [](const Index::Error &error) {
211 qWarning() << "Error in index: " << QString::fromStdString(error.message); 211 qWarning() << "Error in index: " << error.message;
212 }); 212 });
213 } 213 }
214 214
diff --git a/tests/hawd/dataset.cpp b/tests/hawd/dataset.cpp
index e1f9700..9f1d307 100644
--- a/tests/hawd/dataset.cpp
+++ b/tests/hawd/dataset.cpp
@@ -253,7 +253,7 @@ void Dataset::eachRow(const std::function<void(const Row &row)> &resultHandler)
253 } 253 }
254 254
255 Row row(*this); 255 Row row(*this);
256 m_storage.scan(nullptr, 0, 256 m_storage.scan("",
257 [&](void *key, int keySize, void *data, int dataSize) -> bool { 257 [&](void *key, int keySize, void *data, int dataSize) -> bool {
258 if (keySize != sizeof(qint64)) { 258 if (keySize != sizeof(qint64)) {
259 return true; 259 return true;
@@ -277,7 +277,7 @@ Dataset::Row Dataset::row(qint64 key)
277 } 277 }
278 278
279 Row row(*this, key); 279 Row row(*this, key);
280 m_storage.scan((const char *)&key, sizeof(qint64), 280 m_storage.scan(QByteArray::fromRawData((const char *)&key, sizeof(qint64)),
281 [&row](void *keyPtr, int keyLength, void *valuePtr, int valueSize) -> bool { 281 [&row](void *keyPtr, int keyLength, void *valuePtr, int valueSize) -> bool {
282 QByteArray array((const char*)valuePtr, valueSize); 282 QByteArray array((const char*)valuePtr, valueSize);
283 row.fromBinary(array); 283 row.fromBinary(array);
diff --git a/tests/storagebenchmark.cpp b/tests/storagebenchmark.cpp
index 9cf9a71..0233466 100644
--- a/tests/storagebenchmark.cpp
+++ b/tests/storagebenchmark.cpp
@@ -15,7 +15,7 @@
15using namespace Calendar; 15using namespace Calendar;
16using namespace flatbuffers; 16using namespace flatbuffers;
17 17
18static std::string createEvent() 18static QByteArray createEvent()
19{ 19{
20 static const size_t attachmentSize = 1024*2; // 2KB 20 static const size_t attachmentSize = 1024*2; // 2KB
21 static uint8_t rawData[attachmentSize]; 21 static uint8_t rawData[attachmentSize];
@@ -33,7 +33,7 @@ static std::string createEvent()
33 memcpy((void*)Calendar::GetEvent(fbb.GetBufferPointer())->attachment()->Data(), rawData, attachmentSize); 33 memcpy((void*)Calendar::GetEvent(fbb.GetBufferPointer())->attachment()->Data(), rawData, attachmentSize);
34 } 34 }
35 35
36 return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); 36 return QByteArray::fromRawData(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
37} 37}
38 38
39// static void readEvent(const std::string &data) 39// static void readEvent(const std::string &data)
@@ -103,9 +103,9 @@ private Q_SLOTS:
103 store->startTransaction(); 103 store->startTransaction();
104 } 104 }
105 105
106 store->write(keyPrefix + std::to_string(i), event); 106 store->write(keyPrefix + QByteArray::number(i), event);
107 } else { 107 } else {
108 myfile << event; 108 myfile << event.toStdString();
109 } 109 }
110 } 110 }
111 111
@@ -122,7 +122,7 @@ private Q_SLOTS:
122 { 122 {
123 for (int i = 0; i < count; i++) { 123 for (int i = 0; i < count; i++) {
124 if (store) { 124 if (store) {
125 store->read(keyPrefix + std::to_string(i), [](std::string value) -> bool { return true; }); 125 store->scan(keyPrefix + QByteArray::number(i), [](const QByteArray &value) -> bool { return true; });
126 } 126 }
127 } 127 }
128 } 128 }
diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp
index 5b4a0ba..e339c87 100644
--- a/tests/storagetest.cpp
+++ b/tests/storagetest.cpp
@@ -28,7 +28,7 @@ private:
28 } 28 }
29 storage.startTransaction(); 29 storage.startTransaction();
30 } 30 }
31 storage.write(keyPrefix + std::to_string(i), keyPrefix + std::to_string(i)); 31 storage.write(keyPrefix + QByteArray::number(i), keyPrefix + QByteArray::number(i));
32 } 32 }
33 storage.commitTransaction(); 33 storage.commitTransaction();
34 } 34 }
@@ -37,9 +37,9 @@ private:
37 { 37 {
38 bool success = true; 38 bool success = true;
39 bool keyMatch = true; 39 bool keyMatch = true;
40 const auto reference = keyPrefix + std::to_string(i); 40 const auto reference = keyPrefix + QByteArray::number(i);
41 storage.read(keyPrefix + std::to_string(i), 41 storage.scan(keyPrefix + QByteArray::number(i),
42 [&keyMatch, &reference](const std::string &value) -> bool { 42 [&keyMatch, &reference](const QByteArray &value) -> bool {
43 if (value != reference) { 43 if (value != reference) {
44 qDebug() << "Mismatch while reading"; 44 qDebug() << "Mismatch while reading";
45 keyMatch = false; 45 keyMatch = false;
@@ -47,7 +47,7 @@ private:
47 return keyMatch; 47 return keyMatch;
48 }, 48 },
49 [&success](const Akonadi2::Storage::Error &error) { 49 [&success](const Akonadi2::Storage::Error &error) {
50 qDebug() << QString::fromStdString(error.message); 50 qDebug() << error.message;
51 success = false; 51 success = false;
52 } 52 }
53 ); 53 );
@@ -133,7 +133,7 @@ private Q_SLOTS:
133 populate(3); 133 populate(3);
134 Akonadi2::Storage store(testDataPath, dbName, Akonadi2::Storage::ReadWrite); 134 Akonadi2::Storage store(testDataPath, dbName, Akonadi2::Storage::ReadWrite);
135 store.scan("key1", [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 135 store.scan("key1", [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
136 store.remove(keyValue, keySize, [](const Akonadi2::Storage::Error &) { 136 store.remove(QByteArray::fromRawData(static_cast<const char*>(keyValue), keySize), [](const Akonadi2::Storage::Error &) {
137 QVERIFY(false); 137 QVERIFY(false);
138 }); 138 });
139 return false; 139 return false;
@@ -144,14 +144,16 @@ private Q_SLOTS:
144 { 144 {
145 bool gotResult = false; 145 bool gotResult = false;
146 bool gotError = false; 146 bool gotError = false;
147 Akonadi2::Storage store(testDataPath, dbName, Akonadi2::Storage::ReadOnly); 147 Akonadi2::Storage store(testDataPath, dbName, Akonadi2::Storage::ReadWrite);
148 store.scan(0, 0, [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 148 int numValues = store.scan("", [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
149 gotResult = true; 149 gotResult = true;
150 return false; 150 return false;
151 }, 151 },
152 [&](Akonadi2::Storage::Error) { 152 [&](const Akonadi2::Storage::Error &error) {
153 qDebug() << error.message;
153 gotError = true; 154 gotError = true;
154 }); 155 });
156 QCOMPARE(numValues, 0);
155 QVERIFY(!gotResult); 157 QVERIFY(!gotResult);
156 QVERIFY(!gotError); 158 QVERIFY(!gotError);
157 } 159 }