From 1deac558af4b1c9f04352ede7f8e172f11a70a6b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 15 Sep 2016 21:24:37 +0200 Subject: Avoid crashing if the executing object is already gone when we go into the continuation. This happens if Kube is used to look at a folder that is currently being freshly synchronized, so we continuously get new results. --- common/queryrunner.cpp | 24 +++++++++++++++++++----- common/queryrunner.h | 5 +++-- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/queryrunner.cpp b/common/queryrunner.cpp index 052db39..11459f1 100644 --- a/common/queryrunner.cpp +++ b/common/queryrunner.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "commands.h" #include "log.h" @@ -71,6 +72,7 @@ QueryRunner::QueryRunner(const Sink::Query &query, const Sink::Resou if (query.limit && query.sortProperty.isEmpty()) { SinkWarning() << "A limited query without sorting is typically a bad idea."; } + auto guardPtr = QPointer(&guard); // We delegate loading of initial data to the result provider, so it can decide for itself what it needs to load. mResultProvider->setFetcher([=](const typename DomainType::Ptr &parent) { const QByteArray parentId = parent ? parent->identifier() : QByteArray(); @@ -81,12 +83,20 @@ QueryRunner::QueryRunner(const Sink::Query &query, const Sink::Resou worker.executeInitialQuery(query, parent, *resultProvider, mOffset[parentId], mBatchSize); resultProvider->initialResultSetComplete(parent); } else { - async::run >([=]() { - QueryWorker worker(query, instanceIdentifier, factory, bufferType, mResultTransformation); - const auto newRevisionAndReplayedEntities = worker.executeInitialQuery(query, parent, *resultProvider, mOffset[parentId], mBatchSize); + auto resultTransformation = mResultTransformation; + auto offset = mOffset[parentId]; + auto batchSize = mBatchSize; + //The lambda will be executed in a separate thread, so we're extra careful + async::run >([resultTransformation, offset, batchSize, query, bufferType, instanceIdentifier, factory, resultProvider, parent]() { + QueryWorker worker(query, instanceIdentifier, factory, bufferType, resultTransformation); + const auto newRevisionAndReplayedEntities = worker.executeInitialQuery(query, parent, *resultProvider, offset, batchSize); return newRevisionAndReplayedEntities; }) - .template syncThen>([=](const QPair &newRevisionAndReplayedEntities) { + .template syncThen>([this, parentId, query, parent, resultProvider, guardPtr](const QPair &newRevisionAndReplayedEntities) { + if (!guardPtr) { + qWarning() << "The parent object is already gone"; + return; + } mOffset[parentId] += newRevisionAndReplayedEntities.second; // Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise. if (query.liveQuery) { @@ -110,7 +120,11 @@ QueryRunner::QueryRunner(const Sink::Query &query, const Sink::Resou const auto newRevisionAndReplayedEntities = worker.executeIncrementalQuery(query, *resultProvider); return newRevisionAndReplayedEntities; }) - .template syncThen >([query, this, resultProvider](const QPair &newRevisionAndReplayedEntities) { + .template syncThen >([query, this, resultProvider, guardPtr](const QPair &newRevisionAndReplayedEntities) { + if (!guardPtr) { + qWarning() << "The parent object is already gone"; + return; + } // Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise. mResourceAccess->sendRevisionReplayedCommand(newRevisionAndReplayedEntities.first); resultProvider->setRevision(newRevisionAndReplayedEntities.first); diff --git a/common/queryrunner.h b/common/queryrunner.h index 155528e..439a990 100644 --- a/common/queryrunner.h +++ b/common/queryrunner.h @@ -74,8 +74,8 @@ private: * A QueryRunner runs a query and updates the corresponding result set. * * The lifetime of the QueryRunner is defined by the resut set (otherwise it's doing useless work), - * and by how long a result set must be updated. If the query is one off the runner dies after the execution, - * otherwise it lives on the react to changes and updates the corresponding result set. + * and by how long a result set must be updated. If the query is a one off, the runner dies after the execution, + * otherwise it lives on to react to changes, and updates the corresponding result set. * * QueryRunner has to keep ResourceAccess alive in order to keep getting updates. */ @@ -101,4 +101,5 @@ private: ResultTransformation mResultTransformation; QHash mOffset; int mBatchSize; + QObject guard; }; -- cgit v1.2.3