Home | History | Annotate | Download | only in engine
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "sync/engine/apply_updates_and_resolve_conflicts_command.h"
      6 
      7 #include "base/location.h"
      8 #include "sync/engine/conflict_resolver.h"
      9 #include "sync/engine/update_applicator.h"
     10 #include "sync/sessions/sync_session.h"
     11 #include "sync/syncable/directory.h"
     12 #include "sync/syncable/syncable_read_transaction.h"
     13 #include "sync/syncable/syncable_write_transaction.h"
     14 
     15 namespace syncer {
     16 
     17 using sessions::SyncSession;
     18 
     19 ApplyUpdatesAndResolveConflictsCommand::
     20     ApplyUpdatesAndResolveConflictsCommand() {}
     21 ApplyUpdatesAndResolveConflictsCommand::
     22     ~ApplyUpdatesAndResolveConflictsCommand() {}
     23 
     24 std::set<ModelSafeGroup>
     25 ApplyUpdatesAndResolveConflictsCommand::GetGroupsToChange(
     26     const sessions::SyncSession& session) const {
     27   std::set<ModelSafeGroup> groups_with_unapplied_updates;
     28 
     29   FullModelTypeSet server_types_with_unapplied_updates;
     30   {
     31     syncable::Directory* dir = session.context()->directory();
     32     syncable::ReadTransaction trans(FROM_HERE, dir);
     33     server_types_with_unapplied_updates =
     34         dir->GetServerTypesWithUnappliedUpdates(&trans);
     35   }
     36 
     37   for (FullModelTypeSet::Iterator it =
     38            server_types_with_unapplied_updates.First(); it.Good(); it.Inc()) {
     39     groups_with_unapplied_updates.insert(
     40         GetGroupForModelType(it.Get(), session.context()->routing_info()));
     41   }
     42 
     43   return groups_with_unapplied_updates;
     44 }
     45 
     46 SyncerError ApplyUpdatesAndResolveConflictsCommand::ModelChangingExecuteImpl(
     47     SyncSession* session) {
     48   sessions::StatusController* status = session->mutable_status_controller();
     49   syncable::Directory* dir = session->context()->directory();
     50   syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
     51 
     52   // Compute server types with unapplied updates that fall under our
     53   // group restriction.
     54   const FullModelTypeSet server_types_with_unapplied_updates =
     55       dir->GetServerTypesWithUnappliedUpdates(&trans);
     56   FullModelTypeSet server_type_restriction;
     57   for (FullModelTypeSet::Iterator it =
     58            server_types_with_unapplied_updates.First(); it.Good(); it.Inc()) {
     59     if (GetGroupForModelType(it.Get(), session->context()->routing_info()) ==
     60         status->group_restriction()) {
     61       server_type_restriction.Put(it.Get());
     62     }
     63   }
     64 
     65   // Don't process control type updates here.  They will be handled elsewhere.
     66   FullModelTypeSet control_types = ToFullModelTypeSet(ControlTypes());
     67   server_type_restriction.RemoveAll(control_types);
     68 
     69   std::vector<int64> handles;
     70   dir->GetUnappliedUpdateMetaHandles(
     71       &trans, server_type_restriction, &handles);
     72 
     73   // First set of update application passes.
     74   UpdateApplicator applicator(
     75       dir->GetCryptographer(&trans),
     76       session->context()->routing_info(),
     77       status->group_restriction());
     78   applicator.AttemptApplications(&trans, handles);
     79   status->increment_num_updates_applied_by(applicator.updates_applied());
     80   status->increment_num_hierarchy_conflicts_by(
     81       applicator.hierarchy_conflicts());
     82   status->increment_num_encryption_conflicts_by(
     83       applicator.encryption_conflicts());
     84 
     85   if (applicator.simple_conflict_ids().size() != 0) {
     86     // Resolve the simple conflicts we just detected.
     87     ConflictResolver resolver;
     88     resolver.ResolveConflicts(&trans,
     89                               dir->GetCryptographer(&trans),
     90                               applicator.simple_conflict_ids(),
     91                               status);
     92 
     93     // Conflict resolution sometimes results in more updates to apply.
     94     handles.clear();
     95     dir->GetUnappliedUpdateMetaHandles(
     96         &trans, server_type_restriction, &handles);
     97 
     98     UpdateApplicator conflict_applicator(
     99         dir->GetCryptographer(&trans),
    100         session->context()->routing_info(),
    101         status->group_restriction());
    102     conflict_applicator.AttemptApplications(&trans, handles);
    103 
    104     // We count the number of updates from both applicator passes.
    105     status->increment_num_updates_applied_by(
    106         conflict_applicator.updates_applied());
    107 
    108     // Encryption conflicts should remain unchanged by the resolution of simple
    109     // conflicts.  Those can only be solved by updating our nigori key bag.
    110     DCHECK_EQ(conflict_applicator.encryption_conflicts(),
    111               applicator.encryption_conflicts());
    112 
    113     // Hierarchy conflicts should also remain unchanged, for reasons that are
    114     // more subtle.  Hierarchy conflicts exist when the application of a pending
    115     // update from the server would make the local folder hierarchy
    116     // inconsistent.  The resolution of simple conflicts could never affect the
    117     // hierarchy conflicting item directly, because hierarchy conflicts are not
    118     // processed by the conflict resolver.  It could, in theory, modify the
    119     // local hierarchy on which hierarchy conflict detection depends.  However,
    120     // the conflict resolution algorithm currently in use does not allow this.
    121     DCHECK_EQ(conflict_applicator.hierarchy_conflicts(),
    122               applicator.hierarchy_conflicts());
    123 
    124     // There should be no simple conflicts remaining.  We know this because the
    125     // resolver should have resolved all the conflicts we detected last time
    126     // and, by the two previous assertions, that no conflicts have been
    127     // downgraded from encryption or hierarchy down to simple.
    128     DCHECK(conflict_applicator.simple_conflict_ids().empty());
    129   }
    130 
    131   return SYNCER_OK;
    132 }
    133 
    134 }  // namespace syncer
    135