summaryrefslogtreecommitdiffstats
path: root/common/synchronizer.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-21 23:13:38 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-21 23:51:24 +0100
commit1d713d9e2dbaf27de9da087f9270d260dfc40c31 (patch)
tree666d8edd42e44df3eaa674a35b6e938b99c2f4b4 /common/synchronizer.cpp
parent0adba61a00491b96dadaa6d4719cb46831356222 (diff)
downloadsink-1d713d9e2dbaf27de9da087f9270d260dfc40c31.tar.gz
sink-1d713d9e2dbaf27de9da087f9270d260dfc40c31.zip
Folded the SourceWriteback into the Synchronizer.
By concentrating all communication to the source in one place we get rid of several oddities. * Quite a bit of duplication since both need access to the synchronizationStore and the source. * We currently have an akward locking in place because both classes access the ync store. This is not easier to resolve cleanly. * The live of resource implementers becomes easier. * An implementation could elect to not use changereplay and always do a full sync... (maybe?)
Diffstat (limited to 'common/synchronizer.cpp')
-rw-r--r--common/synchronizer.cpp94
1 files changed, 93 insertions, 1 deletions
diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp
index 713387e..10acefc 100644
--- a/common/synchronizer.cpp
+++ b/common/synchronizer.cpp
@@ -33,7 +33,8 @@ SINK_DEBUG_AREA("synchronizer")
33using namespace Sink; 33using namespace Sink;
34 34
35Synchronizer::Synchronizer(const Sink::ResourceContext &context) 35Synchronizer::Synchronizer(const Sink::ResourceContext &context)
36 : mResourceContext(context), 36 : ChangeReplay(context),
37 mResourceContext(context),
37 mEntityStore(Storage::EntityStore::Ptr::create(mResourceContext)), 38 mEntityStore(Storage::EntityStore::Ptr::create(mResourceContext)),
38 mSyncStorage(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::DataStore::ReadWrite) 39 mSyncStorage(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::DataStore::ReadWrite)
39{ 40{
@@ -310,6 +311,97 @@ Sink::Storage::DataStore::DataStore::Transaction &Synchronizer::syncTransaction(
310 return mSyncTransaction; 311 return mSyncTransaction;
311} 312}
312 313
314bool Synchronizer::canReplay(const QByteArray &type, const QByteArray &key, const QByteArray &value)
315{
316 Sink::EntityBuffer buffer(value);
317 const Sink::Entity &entity = buffer.entity();
318 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
319 Q_ASSERT(metadataBuffer);
320 if (!metadataBuffer->replayToSource()) {
321 SinkTrace() << "Change is coming from the source";
322 }
323 return metadataBuffer->replayToSource();
324}
325
326KAsync::Job<void> Synchronizer::replay(const QByteArray &type, const QByteArray &key, const QByteArray &value)
327{
328 SinkTrace() << "Replaying" << type << key;
329
330 Sink::EntityBuffer buffer(value);
331 const Sink::Entity &entity = buffer.entity();
332 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
333 Q_ASSERT(metadataBuffer);
334 Q_ASSERT(!mSyncStore);
335 Q_ASSERT(!mSyncTransaction);
336 mEntityStore->startTransaction(Storage::DataStore::ReadOnly);
337 mSyncTransaction = mSyncStorage.createTransaction(Sink::Storage::DataStore::ReadWrite);
338
339 const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation;
340 const auto uid = Sink::Storage::DataStore::uidFromKey(key);
341 const auto modifiedProperties = metadataBuffer->modifiedProperties() ? BufferUtils::fromVector(*metadataBuffer->modifiedProperties()) : QByteArrayList();
342 QByteArray oldRemoteId;
343
344 if (operation != Sink::Operation_Creation) {
345 oldRemoteId = syncStore().resolveLocalId(type, uid);
346 if (oldRemoteId.isEmpty()) {
347 SinkWarning() << "Couldn't find the remote id for: " << type << uid;
348 return KAsync::error<void>(1, "Couldn't find the remote id.");
349 }
350 }
351 SinkTrace() << "Replaying " << key << type << uid << oldRemoteId;
352
353 KAsync::Job<QByteArray> job = KAsync::null<QByteArray>();
354 //TODO This requires supporting every domain type here as well. Can we solve this better so we can do the dispatch somewhere centrally?
355 if (type == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) {
356 auto folder = store().readEntity<ApplicationDomain::Folder>(key);
357 job = replay(folder, operation, oldRemoteId, modifiedProperties);
358 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) {
359 auto mail = store().readEntity<ApplicationDomain::Mail>(key);
360 job = replay(mail, operation, oldRemoteId, modifiedProperties);
361 }
362
363 return job.syncThen<void, QByteArray>([this, operation, type, uid, oldRemoteId](const QByteArray &remoteId) {
364 if (operation == Sink::Operation_Creation) {
365 SinkTrace() << "Replayed creation with remote id: " << remoteId;
366 if (remoteId.isEmpty()) {
367 SinkWarning() << "Returned an empty remoteId from the creation";
368 } else {
369 syncStore().recordRemoteId(type, uid, remoteId);
370 }
371 } else if (operation == Sink::Operation_Modification) {
372 SinkTrace() << "Replayed modification with remote id: " << remoteId;
373 if (remoteId.isEmpty()) {
374 SinkWarning() << "Returned an empty remoteId from the creation";
375 } else {
376 syncStore().updateRemoteId(type, uid, remoteId);
377 }
378 } else if (operation == Sink::Operation_Removal) {
379 SinkTrace() << "Replayed removal with remote id: " << oldRemoteId;
380 syncStore().removeRemoteId(type, uid, oldRemoteId);
381 } else {
382 SinkError() << "Unkown operation" << operation;
383 }
384 })
385 .syncThen<void>([this](const KAsync::Error &error) {
386 if (error) {
387 SinkWarning() << "Failed to replay change: " << error.errorMessage;
388 }
389 mSyncStore.clear();
390 mSyncTransaction.commit();
391 mEntityStore->abortTransaction();
392 });
393}
394
395KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Mail &, Sink::Operation, const QByteArray &, const QList<QByteArray> &)
396{
397 return KAsync::null<QByteArray>();
398}
399
400KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Folder &, Sink::Operation, const QByteArray &, const QList<QByteArray> &)
401{
402 return KAsync::null<QByteArray>();
403}
404
313#define REGISTER_TYPE(T) \ 405#define REGISTER_TYPE(T) \
314 template void Synchronizer::createOrModify(const QByteArray &bufferType, const QByteArray &remoteId, const T &entity, const QHash<QByteArray, Sink::Query::Comparator> &mergeCriteria); \ 406 template void Synchronizer::createOrModify(const QByteArray &bufferType, const QByteArray &remoteId, const T &entity, const QHash<QByteArray, Sink::Query::Comparator> &mergeCriteria); \
315 template void Synchronizer::modify(const T &entity); 407 template void Synchronizer::modify(const T &entity);