diff options
Diffstat (limited to 'sync/engine/sync_directory_update_handler.cc')
-rw-r--r-- | sync/engine/sync_directory_update_handler.cc | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/sync/engine/sync_directory_update_handler.cc b/sync/engine/sync_directory_update_handler.cc index 0d7953b..1a9bd1e 100644 --- a/sync/engine/sync_directory_update_handler.cc +++ b/sync/engine/sync_directory_update_handler.cc @@ -4,19 +4,25 @@ #include "sync/engine/sync_directory_update_handler.h" +#include "sync/engine/conflict_resolver.h" #include "sync/engine/process_updates_util.h" +#include "sync/engine/update_applicator.h" #include "sync/sessions/status_controller.h" #include "sync/syncable/directory.h" #include "sync/syncable/syncable_model_neutral_write_transaction.h" +#include "sync/syncable/syncable_write_transaction.h" namespace syncer { using syncable::SYNCER; SyncDirectoryUpdateHandler::SyncDirectoryUpdateHandler( - syncable::Directory* dir, ModelType type) + syncable::Directory* dir, + ModelType type, + scoped_refptr<ModelSafeWorker> worker) : dir_(dir), - type_(type) {} + type_(type), + worker_(worker) {} SyncDirectoryUpdateHandler::~SyncDirectoryUpdateHandler() {} @@ -34,6 +40,91 @@ void SyncDirectoryUpdateHandler::ProcessGetUpdatesResponse( UpdateProgressMarker(progress_marker); } +void SyncDirectoryUpdateHandler::ApplyUpdates( + sessions::StatusController* status) { + if (IsControlType(type_)) { + return; // We don't process control types here. + } + + if (!dir_->TypeHasUnappliedUpdates(type_)) { + return; // No work to do. Skip this type. + } + + WorkCallback c = base::Bind( + &SyncDirectoryUpdateHandler::ApplyUpdatesImpl, + // We wait until the callback is executed. We can safely use Unretained. + base::Unretained(this), + base::Unretained(status)); + worker_->DoWorkAndWaitUntilDone(c); +} + +SyncerError SyncDirectoryUpdateHandler::ApplyUpdatesImpl( + sessions::StatusController* status) { + syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir_); + + std::vector<int64> handles; + dir_->GetUnappliedUpdateMetaHandles( + &trans, + FullModelTypeSet(type_), + &handles); + + // First set of update application passes. + UpdateApplicator applicator(dir_->GetCryptographer(&trans)); + applicator.AttemptApplications(&trans, handles); + status->increment_num_updates_applied_by(applicator.updates_applied()); + status->increment_num_hierarchy_conflicts_by( + applicator.hierarchy_conflicts()); + status->increment_num_encryption_conflicts_by( + applicator.encryption_conflicts()); + + if (applicator.simple_conflict_ids().size() != 0) { + // Resolve the simple conflicts we just detected. + ConflictResolver resolver; + resolver.ResolveConflicts(&trans, + dir_->GetCryptographer(&trans), + applicator.simple_conflict_ids(), + status); + + // Conflict resolution sometimes results in more updates to apply. + handles.clear(); + dir_->GetUnappliedUpdateMetaHandles( + &trans, + FullModelTypeSet(type_), + &handles); + + UpdateApplicator conflict_applicator(dir_->GetCryptographer(&trans)); + conflict_applicator.AttemptApplications(&trans, handles); + + // We count the number of updates from both applicator passes. + status->increment_num_updates_applied_by( + conflict_applicator.updates_applied()); + + // Encryption conflicts should remain unchanged by the resolution of simple + // conflicts. Those can only be solved by updating our nigori key bag. + DCHECK_EQ(conflict_applicator.encryption_conflicts(), + applicator.encryption_conflicts()); + + // Hierarchy conflicts should also remain unchanged, for reasons that are + // more subtle. Hierarchy conflicts exist when the application of a pending + // update from the server would make the local folder hierarchy + // inconsistent. The resolution of simple conflicts could never affect the + // hierarchy conflicting item directly, because hierarchy conflicts are not + // processed by the conflict resolver. It could, in theory, modify the + // local hierarchy on which hierarchy conflict detection depends. However, + // the conflict resolution algorithm currently in use does not allow this. + DCHECK_EQ(conflict_applicator.hierarchy_conflicts(), + applicator.hierarchy_conflicts()); + + // There should be no simple conflicts remaining. We know this because the + // resolver should have resolved all the conflicts we detected last time + // and, by the two previous assertions, that no conflicts have been + // downgraded from encryption or hierarchy down to simple. + DCHECK(conflict_applicator.simple_conflict_ids().empty()); + } + + return SYNCER_OK; +} + void SyncDirectoryUpdateHandler::UpdateSyncEntities( syncable::ModelNeutralWriteTransaction* trans, const SyncEntityList& applicable_updates, |