From 12539f35e385c9250cd67e387c67dbaff4de34f3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 24 Apr 2015 10:41:11 +0200 Subject: Keep thread alive until the end of the query, and cleanup the resultSet. --- common/clientapi.h | 68 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 16 deletions(-) (limited to 'common') diff --git a/common/clientapi.h b/common/clientapi.h index c6c43ee..4786398 100644 --- a/common/clientapi.h +++ b/common/clientapi.h @@ -107,7 +107,7 @@ namespace async { { if (!mResultEmitter) { //We have to go over a separate var and return that, otherwise we'd delete the emitter immediately again - auto sharedPtr = QSharedPointer >::create(); + auto sharedPtr = QSharedPointer >(new ResultEmitter, [this](ResultEmitter *emitter){ done(); delete emitter; }); mResultEmitter = sharedPtr; return sharedPtr; } @@ -124,9 +124,30 @@ namespace async { mQueryRunner = runner; } + void onDone(const std::function &callback) + { + mOnDoneCallback = callback; + } + + bool isDone() const + { + //The existance of the emitter currently defines wether we're done or not. + return mResultEmitter.toStrongRef().isNull(); + } + private: + void done() + { + qWarning() << "done"; + if (mOnDoneCallback) { + mOnDoneCallback(); + } + mOnDoneCallback = std::function(); + } + QWeakPointer > mResultEmitter; QSharedPointer mQueryRunner; + std::function mOnDoneCallback; }; /* @@ -482,31 +503,46 @@ public: static QSharedPointer > load(Query query) { auto resultSet = QSharedPointer >::create(); + // FIXME This is ridiculous but otherwise I can't release the shared pointer before the thread quits + auto resultSetPtr = QSharedPointer > >::create(resultSet); //Execute the search in a thread. //We must guarantee that the emitter is returned before the first result is emitted. //The result provider must be threadsafe. - async::run([resultSet, query](){ + async::run([resultSetPtr, query](){ // Query all resources and aggregate results const QList resources = query.resources; Async::start>([resources](){return resources;}) - .template each([query, resultSet](const QByteArray &resource, Async::Future &future) { + .template each([query, resultSetPtr](const QByteArray &resource, Async::Future &future) { + //TODO pass resource identifier to factory auto facade = FacadeFactory::instance().getFacade(resource); - // TODO The following is a necessary hack to keep the facade alive. - // Otherwise this would reduce to: - // facade->load(query, addCallback).exec(); - // We somehow have to guarantee that the facade remains valid for the duration of the job - // TODO: Use one result set per facade, and merge the results separately - // resultSet->addSubset(facade->query(query)); - facade->load(query, resultSet).template then([&future, facade]() { + if (auto resultSet = *resultSetPtr) { + facade->load(query, resultSet).template then([&future](){future.setFinished();}).exec(); + } else { + qWarning() << "result set is already gone"; future.setFinished(); - }).exec(); - }).template then([resultSet]() { + } + }).template then([resultSetPtr]() { qDebug() << "Query complete"; - resultSet->complete(); - }).exec().waitForFinished(); //We use the eventloop provided by waitForFinished to keep the thread alive until all is done - //FIXME for live query the thread dies after the initial query? - //TODO associate the thread with the query runner + if (auto resultSet = *resultSetPtr) { + resultSet->complete(); + } else { + qWarning() << "result set is already gone"; + } + }).exec(); + + if (auto resultSet = *resultSetPtr) { + resultSetPtr->clear(); + if (!resultSet->isDone()) { + QEventLoop eventLoop; + resultSet->onDone([&eventLoop](){ + eventLoop.quit(); + }); + eventLoop.exec(); + } + } else { + qWarning() << "result set is already gone"; + } }); return resultSet->emitter(); } -- cgit v1.2.3