diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-06-25 10:57:46 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-06-25 11:08:29 +0200 |
commit | 121c3bc96a273790414ae114082053cb649fc49a (patch) | |
tree | 262f994aaa0f7008aa9acf7589fc99a4447740f7 | |
parent | ed17c92c9f3be95e9b280f2abc67f1c0ba48e8c4 (diff) | |
download | sink-121c3bc96a273790414ae114082053cb649fc49a.tar.gz sink-121c3bc96a273790414ae114082053cb649fc49a.zip |
Fixed the lost update scenario
If we get a fetchMore right between when the revision was updated and
the incrementalQuery actually running, we ended up loosing the update
because the result provider ended up with a too recent revision after
the additional initial query.
-rw-r--r-- | common/queryrunner.cpp | 6 | ||||
-rw-r--r-- | common/queryrunner.h | 15 | ||||
-rw-r--r-- | tests/querytest.cpp | 49 |
3 files changed, 68 insertions, 2 deletions
diff --git a/common/queryrunner.cpp b/common/queryrunner.cpp index 0977940..9ac3517 100644 --- a/common/queryrunner.cpp +++ b/common/queryrunner.cpp | |||
@@ -152,7 +152,11 @@ void QueryRunner<DomainType>::fetch(const Sink::Query &query, const QByteArray & | |||
152 | if (query.liveQuery()) { | 152 | if (query.liveQuery()) { |
153 | mResourceAccess->sendRevisionReplayedCommand(result.newRevision); | 153 | mResourceAccess->sendRevisionReplayedCommand(result.newRevision); |
154 | } | 154 | } |
155 | mResultProvider->setRevision(result.newRevision); | 155 | //Initial queries do not fetch updates, so avoid updating the revision when fetching more content. |
156 | //Otherwise we end up breaking incremental updates. | ||
157 | if (!mResultProvider->revision()) { | ||
158 | mResultProvider->setRevision(result.newRevision); | ||
159 | } | ||
156 | mResultProvider->initialResultSetComplete(result.replayedAll); | 160 | mResultProvider->initialResultSetComplete(result.replayedAll); |
157 | if (mRequestFetchMore) { | 161 | if (mRequestFetchMore) { |
158 | mRequestFetchMore = false; | 162 | mRequestFetchMore = false; |
diff --git a/common/queryrunner.h b/common/queryrunner.h index e449570..52b5e2d 100644 --- a/common/queryrunner.h +++ b/common/queryrunner.h | |||
@@ -35,6 +35,16 @@ class QueryRunnerBase : public QObject | |||
35 | public: | 35 | public: |
36 | typedef std::function<void(Sink::ApplicationDomain::ApplicationDomainType &domainObject)> ResultTransformation; | 36 | typedef std::function<void(Sink::ApplicationDomain::ApplicationDomainType &domainObject)> ResultTransformation; |
37 | 37 | ||
38 | /// Disable query updates on revision change. Used for testing only. | ||
39 | void ignoreRevisionChanges(bool ignore) { | ||
40 | mIgnoreRevisionChanges = ignore; | ||
41 | } | ||
42 | |||
43 | /// Manually triger a revision change. Used for testing only. | ||
44 | void triggerRevisionChange() { | ||
45 | revisionChanged(); | ||
46 | } | ||
47 | |||
38 | protected: | 48 | protected: |
39 | typedef std::function<KAsync::Job<void>()> QueryFunction; | 49 | typedef std::function<KAsync::Job<void>()> QueryFunction; |
40 | 50 | ||
@@ -52,7 +62,9 @@ protected slots: | |||
52 | */ | 62 | */ |
53 | void revisionChanged() | 63 | void revisionChanged() |
54 | { | 64 | { |
55 | run().exec(); | 65 | if (!mIgnoreRevisionChanges) { |
66 | run().exec(); | ||
67 | } | ||
56 | } | 68 | } |
57 | 69 | ||
58 | private: | 70 | private: |
@@ -65,6 +77,7 @@ private: | |||
65 | } | 77 | } |
66 | 78 | ||
67 | QueryFunction queryFunction; | 79 | QueryFunction queryFunction; |
80 | bool mIgnoreRevisionChanges{false}; | ||
68 | }; | 81 | }; |
69 | 82 | ||
70 | /** | 83 | /** |
diff --git a/tests/querytest.cpp b/tests/querytest.cpp index b52ba96..7685086 100644 --- a/tests/querytest.cpp +++ b/tests/querytest.cpp | |||
@@ -1337,6 +1337,55 @@ private slots: | |||
1337 | } | 1337 | } |
1338 | 1338 | ||
1339 | /* | 1339 | /* |
1340 | * This test excercises the scenario where a fetchMore is triggered after | ||
1341 | * the revision is already updated in storage, but the incremental query was not run yet. | ||
1342 | * This resulted in lost modification updates. | ||
1343 | */ | ||
1344 | void testQueryRunnerDontMissUpdatesWithFetchMore() | ||
1345 | { | ||
1346 | // Setup | ||
1347 | auto folder1 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
1348 | folder1.setName("name1"); | ||
1349 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
1350 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
1351 | |||
1352 | Query query; | ||
1353 | query.setFlags(Query::LiveQuery); | ||
1354 | |||
1355 | Sink::ResourceContext resourceContext{"sink.dummy.instance1", "sink.dummy", Sink::AdaptorFactoryRegistry::instance().getFactories("sink.dummy")}; | ||
1356 | Sink::Log::Context logCtx; | ||
1357 | auto runner = new QueryRunner<Folder>(query, resourceContext, ApplicationDomain::getTypeName<Folder>(), logCtx); | ||
1358 | |||
1359 | auto emitter = runner->emitter(); | ||
1360 | QList<Folder::Ptr> added; | ||
1361 | emitter->onAdded([&](Folder::Ptr folder) { | ||
1362 | added << folder; | ||
1363 | }); | ||
1364 | QList<Folder::Ptr> modified; | ||
1365 | emitter->onModified([&](Folder::Ptr folder) { | ||
1366 | modified << folder; | ||
1367 | }); | ||
1368 | |||
1369 | emitter->fetch(); | ||
1370 | QTRY_COMPARE(added.size(), 1); | ||
1371 | QCOMPARE(modified.size(), 0); | ||
1372 | |||
1373 | runner->ignoreRevisionChanges(true); | ||
1374 | |||
1375 | folder1.setName("name2"); | ||
1376 | VERIFYEXEC(Sink::Store::modify<Folder>(folder1)); | ||
1377 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
1378 | |||
1379 | emitter->fetch(); | ||
1380 | |||
1381 | runner->ignoreRevisionChanges(false); | ||
1382 | runner->triggerRevisionChange(); | ||
1383 | |||
1384 | QTRY_COMPARE(added.size(), 1); | ||
1385 | QTRY_COMPARE(modified.size(), 1); | ||
1386 | } | ||
1387 | |||
1388 | /* | ||
1340 | * This test is here to ensure we don't crash if we call removeFromDisk with a running query. | 1389 | * This test is here to ensure we don't crash if we call removeFromDisk with a running query. |
1341 | */ | 1390 | */ |
1342 | void testRemoveFromDiskWithRunningQuery() | 1391 | void testRemoveFromDiskWithRunningQuery() |