summaryrefslogtreecommitdiffstats
path: root/common/storage/entitystore.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2018-06-26 10:24:58 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-06-26 10:24:58 +0200
commitda4b74e593f1b1262e83824cc499bd855f1b4e3e (patch)
tree95b56aa073a85022c4218375e1c788894f01c2b6 /common/storage/entitystore.cpp
parent121c3bc96a273790414ae114082053cb649fc49a (diff)
downloadsink-da4b74e593f1b1262e83824cc499bd855f1b4e3e.tar.gz
sink-da4b74e593f1b1262e83824cc499bd855f1b4e3e.zip
Avoid overwriting local changes with remote modifications.
The case we ran into is the following: * Fetching the full payload and marking all messages of a thread as read happens simultaneously. * The local modification to mark as read gets immediately overwritten when the full payload arrives. * Eventually the modification gets replayed to the server though (and the reversal isn't because coming from the source), so on next sync the situation fixes itself. To be able to improve this we try to protect local modifications in that properties that have been modified since baseRevision (which currently isn't, but should be equal to the last to the server replayed revision) are not overwritten. This conflict resolution strategy thus always prefers local modifications. baseRevision is currently set to the current maximum revision of the store at the time when the resource creates the modification.
Diffstat (limited to 'common/storage/entitystore.cpp')
-rw-r--r--common/storage/entitystore.cpp32
1 files changed, 26 insertions, 6 deletions
diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp
index c5b5ffc..dd6bbf0 100644
--- a/common/storage/entitystore.cpp
+++ b/common/storage/entitystore.cpp
@@ -247,22 +247,26 @@ bool EntityStore::add(const QByteArray &type, ApplicationDomainType entity, bool
247 return true; 247 return true;
248} 248}
249 249
250ApplicationDomain::ApplicationDomainType EntityStore::applyDiff(const QByteArray &type, const ApplicationDomainType &current, const ApplicationDomainType &diff, const QByteArrayList &deletions) const 250ApplicationDomain::ApplicationDomainType EntityStore::applyDiff(const QByteArray &type, const ApplicationDomainType &current, const ApplicationDomainType &diff, const QByteArrayList &deletions, const QSet<QByteArray> &excludeProperties) const
251{ 251{
252 SinkTraceCtx(d->logCtx) << "Applying diff: " << current.availableProperties() << "Deletions: " << deletions << "Changeset: " << diff.changedProperties(); 252 SinkTraceCtx(d->logCtx) << "Applying diff: " << current.availableProperties() << "Deletions: " << deletions << "Changeset: " << diff.changedProperties() << "Excluded: " << excludeProperties;
253 auto newEntity = *ApplicationDomainType::getInMemoryRepresentation<ApplicationDomainType>(current, current.availableProperties()); 253 auto newEntity = *ApplicationDomainType::getInMemoryRepresentation<ApplicationDomainType>(current, current.availableProperties());
254 254
255 // Apply diff 255 // Apply diff
256 for (const auto &property : diff.changedProperties()) { 256 for (const auto &property : diff.changedProperties()) {
257 const auto value = diff.getProperty(property); 257 if (!excludeProperties.contains(property)) {
258 if (value.isValid()) { 258 const auto value = diff.getProperty(property);
259 newEntity.setProperty(property, value); 259 if (value.isValid()) {
260 newEntity.setProperty(property, value);
261 }
260 } 262 }
261 } 263 }
262 264
263 // Remove deletions 265 // Remove deletions
264 for (const auto &property : deletions) { 266 for (const auto &property : deletions) {
265 newEntity.setProperty(property, QVariant()); 267 if (!excludeProperties.contains(property)) {
268 newEntity.setProperty(property, QVariant());
269 }
266 } 270 }
267 return newEntity; 271 return newEntity;
268} 272}
@@ -639,6 +643,22 @@ bool EntityStore::exists(const QByteArray &type, const QByteArray &uid)
639 return true; 643 return true;
640} 644}
641 645
646void EntityStore::readRevisions(const QByteArray &type, const QByteArray &uid, qint64 startingRevision, const std::function<void(const QByteArray &uid, qint64 revision, const EntityBuffer &entity)> callback)
647{
648 Q_ASSERT(d);
649 Q_ASSERT(!uid.isEmpty());
650 DataStore::mainDatabase(d->transaction, type)
651 .scan(uid,
652 [&](const QByteArray &key, const QByteArray &value) -> bool {
653 const auto revision = DataStore::revisionFromKey(key);
654 if (revision >= startingRevision) {
655 callback(DataStore::uidFromKey(key), revision, Sink::EntityBuffer(value.data(), value.size()));
656 }
657 return true;
658 },
659 [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error while reading: " << error.message; }, true);
660
661}
642 662
643qint64 EntityStore::maxRevision() 663qint64 EntityStore::maxRevision()
644{ 664{