diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-01-03 15:34:35 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-01-03 16:11:38 +0100 |
commit | 9fa528c5fceefd53303a604625d13cf0cdbb109e (patch) | |
tree | 8f5d6c64300f54af1c6d3afcf5ba8b0cd82a4492 /common/storage_lmdb.cpp | |
parent | 46bf82eaec0a30281d0b8deaf1ffbd06030eb997 (diff) | |
download | sink-9fa528c5fceefd53303a604625d13cf0cdbb109e.tar.gz sink-9fa528c5fceefd53303a604625d13cf0cdbb109e.zip |
Use read-write locks for finer grained control to sDbi and sEnvironments
There are only a few cases where have to access the list of dbis or
environments, so we can normally get away with just read-locking.
This seems to fix a segfault that was possibly caused be an environment
being reused that has already been freed in another thread. The
read-only lock when initially retrieving the environment seems to fix
that.
Diffstat (limited to 'common/storage_lmdb.cpp')
-rw-r--r-- | common/storage_lmdb.cpp | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index 600fbd1..514a4ea 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -23,28 +23,26 @@ | |||
23 | 23 | ||
24 | #include <iostream> | 24 | #include <iostream> |
25 | 25 | ||
26 | #include <QAtomicInt> | ||
27 | #include <QDebug> | 26 | #include <QDebug> |
28 | #include <QDir> | 27 | #include <QDir> |
29 | #include <QReadWriteLock> | 28 | #include <QReadWriteLock> |
30 | #include <QString> | 29 | #include <QString> |
31 | #include <QTime> | 30 | #include <QTime> |
32 | #include <QMutex> | ||
33 | #include <valgrind.h> | 31 | #include <valgrind.h> |
34 | |||
35 | #include <lmdb.h> | 32 | #include <lmdb.h> |
36 | #include "log.h" | 33 | #include "log.h" |
37 | 34 | ||
38 | namespace Sink { | 35 | namespace Sink { |
39 | namespace Storage { | 36 | namespace Storage { |
40 | 37 | ||
41 | //TODO a QReadWriteLock would be a better choice because we mostly do reads. | 38 | extern QReadWriteLock sDbisLock; |
42 | extern QMutex sMutex; | 39 | extern QReadWriteLock sEnvironmentsLock; |
43 | extern QHash<QString, MDB_env *> sEnvironments; | 40 | extern QHash<QString, MDB_env *> sEnvironments; |
44 | extern QHash<QString, MDB_dbi> sDbis; | 41 | extern QHash<QString, MDB_dbi> sDbis; |
45 | 42 | ||
46 | 43 | ||
47 | QMutex sMutex; | 44 | QReadWriteLock sDbisLock; |
45 | QReadWriteLock sEnvironmentsLock; | ||
48 | QHash<QString, MDB_env *> sEnvironments; | 46 | QHash<QString, MDB_env *> sEnvironments; |
49 | QHash<QString, MDB_dbi> sDbis; | 47 | QHash<QString, MDB_dbi> sDbis; |
50 | 48 | ||
@@ -558,6 +556,7 @@ public: | |||
558 | void startTransaction() | 556 | void startTransaction() |
559 | { | 557 | { |
560 | Q_ASSERT(!transaction); | 558 | Q_ASSERT(!transaction); |
559 | Q_ASSERT(sEnvironments.values().contains(env)); | ||
561 | // auto f = [](const char *msg, void *ctx) -> int { | 560 | // auto f = [](const char *msg, void *ctx) -> int { |
562 | // qDebug() << msg; | 561 | // qDebug() << msg; |
563 | // return 0; | 562 | // return 0; |
@@ -636,7 +635,7 @@ bool DataStore::Transaction::commit(const std::function<void(const DataStore::Er | |||
636 | //Add the created dbis to the shared environment | 635 | //Add the created dbis to the shared environment |
637 | if (!d->createdDbs.isEmpty()) { | 636 | if (!d->createdDbs.isEmpty()) { |
638 | if (!d->noLock) { | 637 | if (!d->noLock) { |
639 | sMutex.lock(); | 638 | sDbisLock.lockForWrite(); |
640 | } | 639 | } |
641 | for (auto it = d->createdDbs.constBegin(); it != d->createdDbs.constEnd(); it++) { | 640 | for (auto it = d->createdDbs.constBegin(); it != d->createdDbs.constEnd(); it++) { |
642 | Q_ASSERT(!sDbis.contains(it.key())); | 641 | Q_ASSERT(!sDbis.contains(it.key())); |
@@ -644,7 +643,7 @@ bool DataStore::Transaction::commit(const std::function<void(const DataStore::Er | |||
644 | } | 643 | } |
645 | d->createdDbs.clear(); | 644 | d->createdDbs.clear(); |
646 | if (!d->noLock) { | 645 | if (!d->noLock) { |
647 | sMutex.unlock(); | 646 | sDbisLock.unlock(); |
648 | } | 647 | } |
649 | } | 648 | } |
650 | 649 | ||
@@ -698,18 +697,17 @@ DataStore::NamedDatabase DataStore::Transaction::openDatabase(const QByteArray & | |||
698 | d->implicitCommit = true; | 697 | d->implicitCommit = true; |
699 | auto p = new DataStore::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction); | 698 | auto p = new DataStore::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction); |
700 | if (!d->noLock) { | 699 | if (!d->noLock) { |
701 | //This wouldn't be necessary with a read-write lock, we could read-only lock here | 700 | sDbisLock.lockForRead(); |
702 | sMutex.lock(); | ||
703 | } | 701 | } |
704 | if (!p->openDatabase(d->requestedRead, errorHandler)) { | 702 | if (!p->openDatabase(d->requestedRead, errorHandler)) { |
705 | if (!d->noLock) { | 703 | if (!d->noLock) { |
706 | sMutex.unlock(); | 704 | sDbisLock.unlock(); |
707 | } | 705 | } |
708 | delete p; | 706 | delete p; |
709 | return DataStore::NamedDatabase(); | 707 | return DataStore::NamedDatabase(); |
710 | } | 708 | } |
711 | if (!d->noLock) { | 709 | if (!d->noLock) { |
712 | sMutex.unlock(); | 710 | sDbisLock.unlock(); |
713 | } | 711 | } |
714 | if (p->createdNewDbi) { | 712 | if (p->createdNewDbi) { |
715 | d->createdDbs.insert(p->createdDbName, p->dbi); | 713 | d->createdDbs.insert(p->createdDbName, p->dbi); |
@@ -813,8 +811,11 @@ public: | |||
813 | void initEnvironment(const QString &fullPath, const DbLayout &layout) | 811 | void initEnvironment(const QString &fullPath, const DbLayout &layout) |
814 | { | 812 | { |
815 | // Ensure the environment is only created once, and that we only have one environment per process | 813 | // Ensure the environment is only created once, and that we only have one environment per process |
814 | QReadLocker locker(&sEnvironmentsLock); | ||
816 | if (!(env = sEnvironments.value(fullPath))) { | 815 | if (!(env = sEnvironments.value(fullPath))) { |
817 | QMutexLocker locker(&sMutex); | 816 | locker.unlock(); |
817 | QWriteLocker envLocker(&sEnvironmentsLock); | ||
818 | QWriteLocker dbiLocker(&sDbisLock); | ||
818 | if (!(env = sEnvironments.value(fullPath))) { | 819 | if (!(env = sEnvironments.value(fullPath))) { |
819 | int rc = 0; | 820 | int rc = 0; |
820 | if ((rc = mdb_env_create(&env))) { | 821 | if ((rc = mdb_env_create(&env))) { |
@@ -932,7 +933,10 @@ DataStore::Transaction DataStore::createTransaction(AccessMode type, const std:: | |||
932 | errorHandler(Error(d->name.toLatin1(), ErrorCodes::GenericError, "Failed to create transaction: Requested read/write transaction in read-only mode.")); | 933 | errorHandler(Error(d->name.toLatin1(), ErrorCodes::GenericError, "Failed to create transaction: Requested read/write transaction in read-only mode.")); |
933 | return Transaction(); | 934 | return Transaction(); |
934 | } | 935 | } |
935 | 936 | QReadLocker locker(&sEnvironmentsLock); | |
937 | if (!sEnvironments.values().contains(d->env)) { | ||
938 | return {}; | ||
939 | } | ||
936 | return Transaction(new Transaction::Private(requestedRead, defaultErrorHandler(), d->name, d->env)); | 940 | return Transaction(new Transaction::Private(requestedRead, defaultErrorHandler(), d->name, d->env)); |
937 | } | 941 | } |
938 | 942 | ||
@@ -948,7 +952,8 @@ qint64 DataStore::diskUsage() const | |||
948 | void DataStore::removeFromDisk() const | 952 | void DataStore::removeFromDisk() const |
949 | { | 953 | { |
950 | const QString fullPath(d->storageRoot + '/' + d->name); | 954 | const QString fullPath(d->storageRoot + '/' + d->name); |
951 | QMutexLocker locker(&sMutex); | 955 | QWriteLocker dbiLocker(&sDbisLock); |
956 | QWriteLocker envLocker(&sEnvironmentsLock); | ||
952 | SinkTrace() << "Removing database from disk: " << fullPath; | 957 | SinkTrace() << "Removing database from disk: " << fullPath; |
953 | sEnvironments.take(fullPath); | 958 | sEnvironments.take(fullPath); |
954 | for (const auto &key : sDbis.keys()) { | 959 | for (const auto &key : sDbis.keys()) { |
@@ -967,7 +972,7 @@ void DataStore::removeFromDisk() const | |||
967 | 972 | ||
968 | void DataStore::clearEnv() | 973 | void DataStore::clearEnv() |
969 | { | 974 | { |
970 | QMutexLocker locker(&sMutex); | 975 | QWriteLocker locker(&sEnvironmentsLock); |
971 | for (auto env : sEnvironments) { | 976 | for (auto env : sEnvironments) { |
972 | mdb_env_close(env); | 977 | mdb_env_close(env); |
973 | } | 978 | } |