diff options
Diffstat (limited to 'common/storage_lmdb.cpp')
-rw-r--r-- | common/storage_lmdb.cpp | 137 |
1 files changed, 75 insertions, 62 deletions
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 @@ | |||
36 | namespace Akonadi2 | 36 | namespace Akonadi2 |
37 | { | 37 | { |
38 | 38 | ||
39 | int 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 | |||
39 | class Storage::Private | 50 | class Storage::Private |
40 | { | 51 | { |
41 | public: | 52 | public: |
@@ -130,12 +141,14 @@ bool Storage::exists() const | |||
130 | { | 141 | { |
131 | return (d->env != 0); | 142 | return (d->env != 0); |
132 | } | 143 | } |
144 | |||
133 | bool Storage::isInTransaction() const | 145 | bool Storage::isInTransaction() const |
134 | { | 146 | { |
135 | return d->transaction; | 147 | return d->transaction; |
136 | } | 148 | } |
137 | 149 | ||
138 | bool Storage::startTransaction(AccessMode type) | 150 | bool 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 | ||
188 | bool Storage::commitTransaction() | 206 | bool 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 | ||
219 | bool Storage::write(const void *keyPtr, size_t keySize, const void *valuePtr, size_t valueSize) | 238 | bool 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 | ||
265 | bool Storage::write(const std::string &sKey, const std::string &sValue) | 294 | int 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 | |||
270 | void 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 | |||
281 | void 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 | |||
290 | void 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 | ||
357 | void Storage::remove(const void *keyData, uint keySize) | 367 | void 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 | ||
362 | void Storage::remove(const void *keyData, uint keySize, const std::function<void(const Storage::Error &error)> &errorHandler) | 373 | void 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 | |||
413 | void Storage::removeFromDisk() const | 425 | void 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()) { |