summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-01-31 19:01:10 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-01-31 19:38:57 +0100
commita910706986aa8e83e070d23525c02649d80c05c3 (patch)
treed31cf91bdfbaf47ed750a744000327f0f8d45f2a
parent546d86aae7cd0b9766f3a0ea73f3777334d55814 (diff)
downloadsink-a910706986aa8e83e070d23525c02649d80c05c3.tar.gz
sink-a910706986aa8e83e070d23525c02649d80c05c3.zip
Don't call into the model after the model has been destroyed.
-rw-r--r--common/modelresult.cpp49
-rw-r--r--common/modelresult.h1
-rw-r--r--common/resultprovider.h60
3 files changed, 85 insertions, 25 deletions
diff --git a/common/modelresult.cpp b/common/modelresult.cpp
index 695072c..0825518 100644
--- a/common/modelresult.cpp
+++ b/common/modelresult.cpp
@@ -21,6 +21,7 @@
21 21
22#include <QDebug> 22#include <QDebug>
23#include <QThread> 23#include <QThread>
24#include <QPointer>
24 25
25#include "log.h" 26#include "log.h"
26 27
@@ -31,18 +32,26 @@ static uint qHash(const Sink::ApplicationDomain::ApplicationDomainType &type)
31 return qHash(type.resourceInstanceIdentifier() + type.identifier()); 32 return qHash(type.resourceInstanceIdentifier() + type.identifier());
32} 33}
33 34
35static qint64 getIdentifier(const QModelIndex &idx)
36{
37 if (!idx.isValid()) {
38 return 0;
39 }
40 return idx.internalId();
41}
42
34template <class T, class Ptr> 43template <class T, class Ptr>
35ModelResult<T, Ptr>::ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns, const Sink::Log::Context &ctx) 44ModelResult<T, Ptr>::ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns, const Sink::Log::Context &ctx)
36 : QAbstractItemModel(), mLogCtx(ctx.subContext("modelresult")), mPropertyColumns(propertyColumns), mQuery(query) 45 : QAbstractItemModel(), mLogCtx(ctx.subContext("modelresult")), mPropertyColumns(propertyColumns), mQuery(query)
37{ 46{
38} 47}
39 48
40static qint64 getIdentifier(const QModelIndex &idx) 49template <class T, class Ptr>
50ModelResult<T, Ptr>::~ModelResult()
41{ 51{
42 if (!idx.isValid()) { 52 if (mEmitter) {
43 return 0; 53 mEmitter->waitForMethodExecutionEnd();
44 } 54 }
45 return idx.internalId();
46} 55}
47 56
48template <class T, class Ptr> 57template <class T, class Ptr>
@@ -259,33 +268,41 @@ void ModelResult<T, Ptr>::setEmitter(const typename Sink::ResultEmitter<Ptr>::Pt
259{ 268{
260 setFetcher([this](const Ptr &parent) { mEmitter->fetch(parent); }); 269 setFetcher([this](const Ptr &parent) { mEmitter->fetch(parent); });
261 270
262 emitter->onAdded([this](const Ptr &value) { 271 QPointer<QObject> guard(this);
272 emitter->onAdded([this, guard](const Ptr &value) {
263 SinkTraceCtx(mLogCtx) << "Received addition: " << value->identifier(); 273 SinkTraceCtx(mLogCtx) << "Received addition: " << value->identifier();
264 threadBoundary.callInMainThread([this, value]() { 274 Q_ASSERT(guard);
275 threadBoundary.callInMainThread([this, value, guard]() {
276 Q_ASSERT(guard);
265 add(value); 277 add(value);
266 }); 278 });
267 }); 279 });
268 emitter->onModified([this](const Ptr &value) { 280 emitter->onModified([this, guard](const Ptr &value) {
269 SinkTraceCtx(mLogCtx) << "Received modification: " << value->identifier(); 281 SinkTraceCtx(mLogCtx) << "Received modification: " << value->identifier();
282 Q_ASSERT(guard);
270 threadBoundary.callInMainThread([this, value]() { 283 threadBoundary.callInMainThread([this, value]() {
271 modify(value); 284 modify(value);
272 }); 285 });
273 }); 286 });
274 emitter->onRemoved([this](const Ptr &value) { 287 emitter->onRemoved([this, guard](const Ptr &value) {
275 SinkTraceCtx(mLogCtx) << "Received removal: " << value->identifier(); 288 SinkTraceCtx(mLogCtx) << "Received removal: " << value->identifier();
289 Q_ASSERT(guard);
276 threadBoundary.callInMainThread([this, value]() { 290 threadBoundary.callInMainThread([this, value]() {
277 remove(value); 291 remove(value);
278 }); 292 });
279 }); 293 });
280 emitter->onInitialResultSetComplete([this](const Ptr &parent, bool fetchedAll) { 294 emitter->onInitialResultSetComplete([this, guard](const Ptr &parent, bool fetchedAll) {
281 SinkTraceCtx(mLogCtx) << "Initial result set complete. Fetched all: " << fetchedAll; 295 SinkTraceCtx(mLogCtx) << "Initial result set complete. Fetched all: " << fetchedAll;
282 const qint64 parentId = parent ? qHash(*parent) : 0; 296 Q_ASSERT(guard);
283 const auto parentIndex = createIndexFromId(parentId); 297 threadBoundary.callInMainThread([=]() {
284 mEntityChildrenFetchComplete.insert(parentId); 298 const qint64 parentId = parent ? qHash(*parent) : 0;
285 if (fetchedAll) { 299 const auto parentIndex = createIndexFromId(parentId);
286 mEntityAllChildrenFetched.insert(parentId); 300 mEntityChildrenFetchComplete.insert(parentId);
287 } 301 if (fetchedAll) {
288 emit dataChanged(parentIndex, parentIndex, QVector<int>() << ChildrenFetchedRole); 302 mEntityAllChildrenFetched.insert(parentId);
303 }
304 emit dataChanged(parentIndex, parentIndex, QVector<int>() << ChildrenFetchedRole);
305 });
289 }); 306 });
290 mEmitter = emitter; 307 mEmitter = emitter;
291} 308}
diff --git a/common/modelresult.h b/common/modelresult.h
index daa48bd..f30a8e1 100644
--- a/common/modelresult.h
+++ b/common/modelresult.h
@@ -42,6 +42,7 @@ public:
42 }; 42 };
43 43
44 ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns, const Sink::Log::Context &); 44 ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns, const Sink::Log::Context &);
45 ~ModelResult();
45 46
46 void setEmitter(const typename Sink::ResultEmitter<Ptr>::Ptr &); 47 void setEmitter(const typename Sink::ResultEmitter<Ptr>::Ptr &);
47 48
diff --git a/common/resultprovider.h b/common/resultprovider.h
index cda4dac..86138db 100644
--- a/common/resultprovider.h
+++ b/common/resultprovider.h
@@ -22,6 +22,8 @@
22 22
23#include <functional> 23#include <functional>
24#include <memory> 24#include <memory>
25#include <QMutexLocker>
26#include <QPointer>
25 27
26namespace Sink { 28namespace Sink {
27 29
@@ -82,21 +84,21 @@ public:
82 void add(const T &value) 84 void add(const T &value)
83 { 85 {
84 if (auto strongRef = mResultEmitter.toStrongRef()) { 86 if (auto strongRef = mResultEmitter.toStrongRef()) {
85 strongRef->addHandler(value); 87 strongRef->add(value);
86 } 88 }
87 } 89 }
88 90
89 void modify(const T &value) 91 void modify(const T &value)
90 { 92 {
91 if (auto strongRef = mResultEmitter.toStrongRef()) { 93 if (auto strongRef = mResultEmitter.toStrongRef()) {
92 strongRef->modifyHandler(value); 94 strongRef->modify(value);
93 } 95 }
94 } 96 }
95 97
96 void remove(const T &value) 98 void remove(const T &value)
97 { 99 {
98 if (auto strongRef = mResultEmitter.toStrongRef()) { 100 if (auto strongRef = mResultEmitter.toStrongRef()) {
99 strongRef->removeHandler(value); 101 strongRef->remove(value);
100 } 102 }
101 } 103 }
102 104
@@ -194,6 +196,15 @@ public:
194 196
195 virtual ~ResultEmitter() 197 virtual ~ResultEmitter()
196 { 198 {
199 //Try locking in case we're in the middle of an execution in another thread
200 QMutexLocker locker{&mMutex};
201 }
202
203 virtual void waitForMethodExecutionEnd()
204 {
205 //If we're in the middle of a method execution, this will block until the method is done.
206 QMutexLocker locker{&mMutex};
207 mDone = true;
197 } 208 }
198 209
199 void onAdded(const std::function<void(const DomainType &)> &handler) 210 void onAdded(const std::function<void(const DomainType &)> &handler)
@@ -226,38 +237,55 @@ public:
226 clearHandler = handler; 237 clearHandler = handler;
227 } 238 }
228 239
240 bool guardOk()
241 {
242 return !mDone;
243 }
244
229 void add(const DomainType &value) 245 void add(const DomainType &value)
230 { 246 {
231 addHandler(value); 247 QMutexLocker locker{&mMutex};
248 if (guardOk()) {
249 addHandler(value);
250 }
232 } 251 }
233 252
234 void modify(const DomainType &value) 253 void modify(const DomainType &value)
235 { 254 {
236 modifyHandler(value); 255 QMutexLocker locker{&mMutex};
256 if (guardOk()) {
257 modifyHandler(value);
258 }
237 } 259 }
238 260
239 void remove(const DomainType &value) 261 void remove(const DomainType &value)
240 { 262 {
241 removeHandler(value); 263 QMutexLocker locker{&mMutex};
264 if (guardOk()) {
265 removeHandler(value);
266 }
242 } 267 }
243 268
244 void initialResultSetComplete(const DomainType &parent, bool replayedAll) 269 void initialResultSetComplete(const DomainType &parent, bool replayedAll)
245 { 270 {
246 if (initialResultSetCompleteHandler) { 271 QMutexLocker locker{&mMutex};
272 if (initialResultSetCompleteHandler && guardOk()) {
247 initialResultSetCompleteHandler(parent, replayedAll); 273 initialResultSetCompleteHandler(parent, replayedAll);
248 } 274 }
249 } 275 }
250 276
251 void complete() 277 void complete()
252 { 278 {
253 if (completeHandler) { 279 QMutexLocker locker{&mMutex};
280 if (completeHandler && guardOk()) {
254 completeHandler(); 281 completeHandler();
255 } 282 }
256 } 283 }
257 284
258 void clear() 285 void clear()
259 { 286 {
260 if (clearHandler) { 287 QMutexLocker locker{&mMutex};
288 if (clearHandler && guardOk()) {
261 clearHandler(); 289 clearHandler();
262 } 290 }
263 } 291 }
@@ -285,6 +313,8 @@ private:
285 std::function<void(void)> clearHandler; 313 std::function<void(void)> clearHandler;
286 314
287 std::function<void(const DomainType &parent)> mFetcher; 315 std::function<void(const DomainType &parent)> mFetcher;
316 QMutex mMutex;
317 bool mDone = false;
288}; 318};
289 319
290template <class DomainType> 320template <class DomainType>
@@ -293,6 +323,18 @@ class AggregatingResultEmitter : public ResultEmitter<DomainType>
293public: 323public:
294 typedef QSharedPointer<AggregatingResultEmitter<DomainType>> Ptr; 324 typedef QSharedPointer<AggregatingResultEmitter<DomainType>> Ptr;
295 325
326 ~AggregatingResultEmitter()
327 {
328 }
329
330 virtual void waitForMethodExecutionEnd() Q_DECL_OVERRIDE
331 {
332 for (const auto &emitter : mEmitter) {
333 emitter->waitForMethodExecutionEnd();
334 }
335 ResultEmitter<DomainType>::waitForMethodExecutionEnd();
336 }
337
296 void addEmitter(const typename ResultEmitter<DomainType>::Ptr &emitter) 338 void addEmitter(const typename ResultEmitter<DomainType>::Ptr &emitter)
297 { 339 {
298 Q_ASSERT(emitter); 340 Q_ASSERT(emitter);