diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-05-30 23:15:23 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-05-30 23:15:23 +0200 |
commit | 8588cd99ee9f3ba92a7167be3752fe511200131b (patch) | |
tree | 5ecad52cc4a49ebe31d5d410a1eb396e74ca3f9e | |
parent | fe1940830d7cc2e9c652ec9a13ca7f3790ff4079 (diff) | |
download | sink-8588cd99ee9f3ba92a7167be3752fe511200131b.tar.gz sink-8588cd99ee9f3ba92a7167be3752fe511200131b.zip |
Detect and recover from invalid database environment.
Sometimes wrong databases are returned for the name, probably related
to threading/incorrect usage of lmdb.
For the time being we recover from that by detecting it and retrying.
-rw-r--r-- | common/queryrunner.cpp | 16 | ||||
-rw-r--r-- | common/storage.h | 1 | ||||
-rw-r--r-- | common/storage_lmdb.cpp | 44 |
3 files changed, 57 insertions, 4 deletions
diff --git a/common/queryrunner.cpp b/common/queryrunner.cpp index ea17176..fd966a9 100644 --- a/common/queryrunner.cpp +++ b/common/queryrunner.cpp | |||
@@ -408,9 +408,19 @@ QPair<qint64, qint64> QueryWorker<DomainType>::load(const Sink::Query &query, co | |||
408 | QTime time; | 408 | QTime time; |
409 | time.start(); | 409 | time.start(); |
410 | 410 | ||
411 | Sink::Storage storage(Sink::storageLocation(), mResourceInstanceIdentifier); | 411 | Sink::Storage::Transaction transaction; |
412 | storage.setDefaultErrorHandler([](const Sink::Storage::Error &error) { Warning() << "Error during query: " << error.store << error.message; }); | 412 | { |
413 | auto transaction = storage.createTransaction(Sink::Storage::ReadOnly); | 413 | Sink::Storage storage(Sink::storageLocation(), mResourceInstanceIdentifier); |
414 | storage.setDefaultErrorHandler([](const Sink::Storage::Error &error) { Warning() << "Error during query: " << error.store << error.message; }); | ||
415 | transaction = storage.createTransaction(Sink::Storage::ReadOnly); | ||
416 | } | ||
417 | |||
418 | //FIXME this is a temporary measure to recover from a failure to open the named databases correctly. | ||
419 | //Once the actual problem is fixed it will be enough to simply crash if we open the wrong database (which we check in openDatabase already). | ||
420 | while (!transaction.validateNamedDatabases()) { | ||
421 | Sink::Storage storage(Sink::storageLocation(), mResourceInstanceIdentifier); | ||
422 | transaction = storage.createTransaction(Sink::Storage::ReadOnly); | ||
423 | } | ||
414 | auto db = Storage::mainDatabase(transaction, mBufferType); | 424 | auto db = Storage::mainDatabase(transaction, mBufferType); |
415 | 425 | ||
416 | QSet<QByteArray> remainingFilters; | 426 | QSet<QByteArray> remainingFilters; |
diff --git a/common/storage.h b/common/storage.h index 87573e2..0527c4f 100644 --- a/common/storage.h +++ b/common/storage.h | |||
@@ -141,6 +141,7 @@ public: | |||
141 | void abort(); | 141 | void abort(); |
142 | 142 | ||
143 | QList<QByteArray> getDatabaseNames() const; | 143 | QList<QByteArray> getDatabaseNames() const; |
144 | bool validateNamedDatabases(); | ||
144 | 145 | ||
145 | NamedDatabase openDatabase(const QByteArray &name = QByteArray("default"), | 146 | NamedDatabase openDatabase(const QByteArray &name = QByteArray("default"), |
146 | const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool allowDuplicates = false) const; | 147 | const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool allowDuplicates = false) const; |
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index cc8b28d..ae4bfba 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -437,6 +437,43 @@ void Storage::Transaction::abort() | |||
437 | d->transaction = nullptr; | 437 | d->transaction = nullptr; |
438 | } | 438 | } |
439 | 439 | ||
440 | //Ensure that we opened the correct database by comparing the expected identifier with the one | ||
441 | //we write to the database on first open. | ||
442 | static bool ensureCorrectDb(Storage::NamedDatabase &database, const QByteArray &db, bool readOnly) | ||
443 | { | ||
444 | bool openedTheWrongDatabase = false; | ||
445 | auto count = database.scan("__internal_dbname", [db, &openedTheWrongDatabase](const QByteArray &key, const QByteArray &value) ->bool { | ||
446 | if (value != db) { | ||
447 | Warning() << "Opened the wrong database, got " << value << " instead of " << db; | ||
448 | openedTheWrongDatabase = true; | ||
449 | } | ||
450 | return false; | ||
451 | }, | ||
452 | [](const Storage::Error &error) -> bool{ | ||
453 | return false; | ||
454 | }, false); | ||
455 | //This is the first time we open this database in a write transaction, write the db name | ||
456 | if (!count) { | ||
457 | if (!readOnly) { | ||
458 | database.write("__internal_dbname", db); | ||
459 | } | ||
460 | } | ||
461 | return !openedTheWrongDatabase; | ||
462 | } | ||
463 | |||
464 | bool Storage::Transaction::validateNamedDatabases() | ||
465 | { | ||
466 | auto databases = getDatabaseNames(); | ||
467 | for (const auto &dbName : databases) { | ||
468 | auto db = openDatabase(dbName); | ||
469 | if (!db) { | ||
470 | Warning() << "Failed to open the database: " << dbName; | ||
471 | return false; | ||
472 | } | ||
473 | } | ||
474 | return true; | ||
475 | } | ||
476 | |||
440 | Storage::NamedDatabase Storage::Transaction::openDatabase(const QByteArray &db, const std::function<void(const Storage::Error &error)> &errorHandler, bool allowDuplicates) const | 477 | Storage::NamedDatabase Storage::Transaction::openDatabase(const QByteArray &db, const std::function<void(const Storage::Error &error)> &errorHandler, bool allowDuplicates) const |
441 | { | 478 | { |
442 | if (!d) { | 479 | if (!d) { |
@@ -450,7 +487,12 @@ Storage::NamedDatabase Storage::Transaction::openDatabase(const QByteArray &db, | |||
450 | delete p; | 487 | delete p; |
451 | return Storage::NamedDatabase(); | 488 | return Storage::NamedDatabase(); |
452 | } | 489 | } |
453 | return Storage::NamedDatabase(p); | 490 | auto database = Storage::NamedDatabase(p); |
491 | if (!ensureCorrectDb(database, db, d->requestedRead)) { | ||
492 | Warning() << "Failed to open the database"; | ||
493 | return Storage::NamedDatabase(); | ||
494 | } | ||
495 | return database; | ||
454 | } | 496 | } |
455 | 497 | ||
456 | QList<QByteArray> Storage::Transaction::getDatabaseNames() const | 498 | QList<QByteArray> Storage::Transaction::getDatabaseNames() const |