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 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'common/queryrunner.cpp') 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); -- cgit v1.2.3