diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-07 15:40:17 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-07 15:40:17 +0200 |
commit | f0fa3392133e15d68245d88397d5c43023b84b43 (patch) | |
tree | 8d690ed8ce2df4aac5cd8263f778ea97c7a52bca /common/storage_lmdb.cpp | |
parent | 8499c2d29b082f35ac2eb55f7633e0d4103cefe5 (diff) | |
download | sink-f0fa3392133e15d68245d88397d5c43023b84b43.tar.gz sink-f0fa3392133e15d68245d88397d5c43023b84b43.zip |
Detect when we try to operate on transactions that point to a
non-existing env.
...which happens if we remove the env while transactions are open.
Diffstat (limited to 'common/storage_lmdb.cpp')
-rw-r--r-- | common/storage_lmdb.cpp | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index 91d2443..844bbfb 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -40,6 +40,9 @@ SINK_DEBUG_AREA("storage") | |||
40 | 40 | ||
41 | namespace Sink { | 41 | namespace Sink { |
42 | 42 | ||
43 | QMutex sMutex; | ||
44 | QHash<QString, MDB_env *> sEnvironments; | ||
45 | |||
43 | int getErrorCode(int e) | 46 | int getErrorCode(int e) |
44 | { | 47 | { |
45 | switch (e) { | 48 | switch (e) { |
@@ -434,7 +437,7 @@ Storage::Transaction::~Transaction() | |||
434 | commit(); | 437 | commit(); |
435 | } else { | 438 | } else { |
436 | // Trace_area("storage." + d->name.toLatin1()) << "Aborting transaction" << mdb_txn_id(d->transaction) << d->transaction; | 439 | // Trace_area("storage." + d->name.toLatin1()) << "Aborting transaction" << mdb_txn_id(d->transaction) << d->transaction; |
437 | mdb_txn_abort(d->transaction); | 440 | abort(); |
438 | } | 441 | } |
439 | } | 442 | } |
440 | delete d; | 443 | delete d; |
@@ -452,9 +455,10 @@ bool Storage::Transaction::commit(const std::function<void(const Storage::Error | |||
452 | } | 455 | } |
453 | 456 | ||
454 | // Trace_area("storage." + d->name.toLatin1()) << "Committing transaction" << mdb_txn_id(d->transaction) << d->transaction; | 457 | // Trace_area("storage." + d->name.toLatin1()) << "Committing transaction" << mdb_txn_id(d->transaction) << d->transaction; |
458 | Q_ASSERT(sEnvironments.values().contains(d->env)); | ||
455 | const int rc = mdb_txn_commit(d->transaction); | 459 | const int rc = mdb_txn_commit(d->transaction); |
456 | if (rc) { | 460 | if (rc) { |
457 | mdb_txn_abort(d->transaction); | 461 | abort(); |
458 | Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Error during transaction commit: " + QByteArray(mdb_strerror(rc))); | 462 | Error error(d->name.toLatin1(), ErrorCodes::GenericError, "Error during transaction commit: " + QByteArray(mdb_strerror(rc))); |
459 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); | 463 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); |
460 | } | 464 | } |
@@ -470,6 +474,7 @@ void Storage::Transaction::abort() | |||
470 | } | 474 | } |
471 | 475 | ||
472 | // Trace_area("storage." + d->name.toLatin1()) << "Aborting transaction" << mdb_txn_id(d->transaction) << d->transaction; | 476 | // Trace_area("storage." + d->name.toLatin1()) << "Aborting transaction" << mdb_txn_id(d->transaction) << d->transaction; |
477 | Q_ASSERT(sEnvironments.values().contains(d->env)); | ||
473 | mdb_txn_abort(d->transaction); | 478 | mdb_txn_abort(d->transaction); |
474 | d->transaction = nullptr; | 479 | d->transaction = nullptr; |
475 | } | 480 | } |
@@ -580,13 +585,8 @@ public: | |||
580 | 585 | ||
581 | MDB_env *env; | 586 | MDB_env *env; |
582 | AccessMode mode; | 587 | AccessMode mode; |
583 | static QMutex sMutex; | ||
584 | static QHash<QString, MDB_env *> sEnvironments; | ||
585 | }; | 588 | }; |
586 | 589 | ||
587 | QMutex Storage::Private::sMutex; | ||
588 | QHash<QString, MDB_env *> Storage::Private::sEnvironments; | ||
589 | |||
590 | Storage::Private::Private(const QString &s, const QString &n, AccessMode m) : storageRoot(s), name(n), env(0), mode(m) | 590 | Storage::Private::Private(const QString &s, const QString &n, AccessMode m) : storageRoot(s), name(n), env(0), mode(m) |
591 | { | 591 | { |
592 | const QString fullPath(storageRoot + '/' + name); | 592 | const QString fullPath(storageRoot + '/' + name); |
@@ -693,23 +693,24 @@ qint64 Storage::diskUsage() const | |||
693 | void Storage::removeFromDisk() const | 693 | void Storage::removeFromDisk() const |
694 | { | 694 | { |
695 | const QString fullPath(d->storageRoot + '/' + d->name); | 695 | const QString fullPath(d->storageRoot + '/' + d->name); |
696 | QMutexLocker locker(&d->sMutex); | 696 | QMutexLocker locker(&sMutex); |
697 | QDir dir(fullPath); | ||
698 | SinkTrace() << "Removing database from disk: " << fullPath; | 697 | SinkTrace() << "Removing database from disk: " << fullPath; |
698 | sEnvironments.take(fullPath); | ||
699 | auto env = sEnvironments.take(fullPath); | ||
700 | mdb_env_close(env); | ||
701 | QDir dir(fullPath); | ||
699 | if (!dir.removeRecursively()) { | 702 | if (!dir.removeRecursively()) { |
700 | Error error(d->name.toLatin1(), ErrorCodes::GenericError, QString("Failed to remove directory %1 %2").arg(d->storageRoot).arg(d->name).toLatin1()); | 703 | Error error(d->name.toLatin1(), ErrorCodes::GenericError, QString("Failed to remove directory %1 %2").arg(d->storageRoot).arg(d->name).toLatin1()); |
701 | defaultErrorHandler()(error); | 704 | defaultErrorHandler()(error); |
702 | } | 705 | } |
703 | auto env = d->sEnvironments.take(fullPath); | ||
704 | mdb_env_close(env); | ||
705 | } | 706 | } |
706 | 707 | ||
707 | void Storage::clearEnv() | 708 | void Storage::clearEnv() |
708 | { | 709 | { |
709 | for (auto env : Storage::Private::sEnvironments) { | 710 | for (auto env : sEnvironments) { |
710 | mdb_env_close(env); | 711 | mdb_env_close(env); |
711 | } | 712 | } |
712 | Storage::Private::sEnvironments.clear(); | 713 | sEnvironments.clear(); |
713 | } | 714 | } |
714 | 715 | ||
715 | } // namespace Sink | 716 | } // namespace Sink |