| OLD | NEW | 
|    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "sync/engine/update_applicator.h" |    5 #include "sync/engine/update_applicator.h" | 
|    6  |    6  | 
|    7 #include <vector> |    7 #include <vector> | 
|    8  |    8  | 
|    9 #include "base/logging.h" |    9 #include "base/logging.h" | 
|   10 #include "sync/engine/syncer_util.h" |   10 #include "sync/engine/syncer_util.h" | 
|   11 #include "sync/sessions/session_state.h" |   11 #include "sync/sessions/session_state.h" | 
|   12 #include "sync/syncable/entry.h" |   12 #include "sync/syncable/entry.h" | 
|   13 #include "sync/syncable/mutable_entry.h" |   13 #include "sync/syncable/mutable_entry.h" | 
|   14 #include "sync/syncable/syncable_id.h" |   14 #include "sync/syncable/syncable_id.h" | 
|   15 #include "sync/syncable/write_transaction.h" |   15 #include "sync/syncable/write_transaction.h" | 
|   16  |   16  | 
|   17 using std::vector; |   17 using std::vector; | 
|   18  |   18  | 
|   19 namespace syncer { |   19 namespace syncer { | 
|   20  |   20  | 
|   21 using syncable::ID; |   21 using syncable::ID; | 
|   22  |   22  | 
|   23 UpdateApplicator::UpdateApplicator(Cryptographer* cryptographer, |   23 UpdateApplicator::UpdateApplicator(Cryptographer* cryptographer, | 
|   24                                    const ModelSafeRoutingInfo& routes, |   24                                    const ModelSafeRoutingInfo& routes, | 
|   25                                    ModelSafeGroup group_filter) |   25                                    ModelSafeGroup group_filter) | 
|   26     : cryptographer_(cryptographer), |   26     : cryptographer_(cryptographer), | 
|   27       group_filter_(group_filter), |   27       group_filter_(group_filter), | 
|   28       routing_info_(routes), |   28       routing_info_(routes) { | 
|   29       application_results_() { |  | 
|   30 } |   29 } | 
|   31  |   30  | 
|   32 UpdateApplicator::~UpdateApplicator() { |   31 UpdateApplicator::~UpdateApplicator() { | 
|   33 } |   32 } | 
|   34  |   33  | 
|   35 // Attempt to apply all updates, using multiple passes if necessary. |   34 // Attempt to apply all updates, using multiple passes if necessary. | 
|   36 // |   35 // | 
|   37 // Some updates must be applied in order.  For example, children must be created |   36 // Some updates must be applied in order.  For example, children must be created | 
|   38 // after their parent folder is created.  This function runs an O(n^2) algorithm |   37 // after their parent folder is created.  This function runs an O(n^2) algorithm | 
|   39 // that will keep trying until there is nothing left to apply, or it stops |   38 // that will keep trying until there is nothing left to apply, or it stops | 
|   40 // making progress, which would indicate that the hierarchy is invalid. |   39 // making progress, which would indicate that the hierarchy is invalid. | 
|   41 // |   40 // | 
|   42 // The update applicator also has to deal with simple conflicts, which occur |   41 // The update applicator also has to deal with simple conflicts, which occur | 
|   43 // when an item is modified on both the server and the local model, and |   42 // when an item is modified on both the server and the local model, and | 
|   44 // encryption conflicts.  There's not much we can do about them here, so we |   43 // encryption conflicts.  There's not much we can do about them here, so we | 
|   45 // don't bother re-processing them on subsequent passes. |   44 // don't bother re-processing them on subsequent passes. | 
|   46 void UpdateApplicator::AttemptApplications( |   45 void UpdateApplicator::AttemptApplications( | 
|   47     syncable::WriteTransaction* trans, |   46     syncable::WriteTransaction* trans, | 
|   48     const std::vector<int64>& handles, |   47     const std::vector<int64>& handles, | 
|   49     sessions::StatusController* status) { |   48     sessions::StatusController* status) { | 
|   50   std::vector<int64> to_apply = handles; |   49   std::vector<int64> to_apply = handles; | 
 |   50   std::set<syncable::Id>* simple_conflict_ids = | 
 |   51       status->mutable_simple_conflict_ids(); | 
 |   52  | 
|   51   DVLOG(1) << "UpdateApplicator running over " << to_apply.size() << " items."; |   53   DVLOG(1) << "UpdateApplicator running over " << to_apply.size() << " items."; | 
|   52   while (!to_apply.empty()) { |   54   while (!to_apply.empty()) { | 
|   53     std::vector<int64> to_reapply; |   55     std::vector<int64> to_reapply; | 
|   54  |   56  | 
|   55     for (UpdateIterator i = to_apply.begin(); i != to_apply.end(); ++i) { |   57     for (UpdateIterator i = to_apply.begin(); i != to_apply.end(); ++i) { | 
|   56       syncable::Entry read_entry(trans, syncable::GET_BY_HANDLE, *i); |   58       syncable::Entry read_entry(trans, syncable::GET_BY_HANDLE, *i); | 
|   57       if (SkipUpdate(read_entry)) { |   59       if (SkipUpdate(read_entry)) { | 
|   58         continue; |   60         continue; | 
|   59       } |   61       } | 
|   60  |   62  | 
|   61       syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *i); |   63       syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *i); | 
|   62       UpdateAttemptResponse result = AttemptToUpdateEntry( |   64       UpdateAttemptResponse result = AttemptToUpdateEntry( | 
|   63           trans, &entry, cryptographer_); |   65           trans, &entry, cryptographer_); | 
|   64  |   66  | 
|   65       switch (result) { |   67       switch (result) { | 
|   66         case SUCCESS: |   68         case SUCCESS: | 
|   67           application_results_.AddSuccess(entry.Get(ID)); |  | 
|   68           status->increment_num_updates_applied(); |   69           status->increment_num_updates_applied(); | 
|   69           break; |   70           break; | 
|   70         case CONFLICT_SIMPLE: |   71         case CONFLICT_SIMPLE: | 
|   71           application_results_.AddSimpleConflict(entry.Get(ID)); |   72           simple_conflict_ids->insert(entry.Get(ID)); | 
|   72           break; |   73           break; | 
|   73         case CONFLICT_ENCRYPTION: |   74         case CONFLICT_ENCRYPTION: | 
|   74           application_results_.AddEncryptionConflict(entry.Get(ID)); |  | 
|   75           status->increment_num_encryption_conflicts(); |   75           status->increment_num_encryption_conflicts(); | 
|   76           break; |   76           break; | 
|   77         case CONFLICT_HIERARCHY: |   77         case CONFLICT_HIERARCHY: | 
|   78           application_results_.AddHierarchyConflict(entry.Get(ID)); |  | 
|   79           // The decision to classify these as hierarchy conflcits is tentative. |   78           // The decision to classify these as hierarchy conflcits is tentative. | 
|   80           // If we make any progress this round, we'll clear the hierarchy |   79           // If we make any progress this round, we'll clear the hierarchy | 
|   81           // conflict count and attempt to reapply these updates. |   80           // conflict count and attempt to reapply these updates. | 
|   82           to_reapply.push_back(*i); |   81           to_reapply.push_back(*i); | 
|   83           break; |   82           break; | 
|   84         default: |   83         default: | 
|   85           NOTREACHED(); |   84           NOTREACHED(); | 
|   86           break; |   85           break; | 
|   87       } |   86       } | 
|   88     } |   87     } | 
|   89  |   88  | 
|   90     if (to_reapply.size() == to_apply.size()) { |   89     if (to_reapply.size() == to_apply.size()) { | 
|   91       // We made no progress.  Must be stubborn hierarchy conflicts. |   90       // We made no progress.  Must be stubborn hierarchy conflicts. | 
|   92       status->set_num_hierarchy_conflicts(to_apply.size()); |   91       status->set_num_hierarchy_conflicts(to_apply.size()); | 
|   93       break; |   92       break; | 
|   94     } |   93     } | 
|   95  |   94  | 
|   96     // We made some progress, so prepare for what might be another iteration. |   95     // We made some progress, so prepare for what might be another iteration. | 
|   97     // If everything went well, to_reapply will be empty and we'll break out on |   96     // If everything went well, to_reapply will be empty and we'll break out on | 
|   98     // the while condition. |   97     // the while condition. | 
|   99     application_results_.ClearHierarchyConflicts(); |  | 
|  100     to_apply.swap(to_reapply); |   98     to_apply.swap(to_reapply); | 
|  101     to_reapply.clear(); |   99     to_reapply.clear(); | 
|  102   } |  100   } | 
|  103 } |  101 } | 
|  104  |  102  | 
|  105 bool UpdateApplicator::SkipUpdate(const syncable::Entry& entry) { |  103 bool UpdateApplicator::SkipUpdate(const syncable::Entry& entry) { | 
|  106   ModelType type = entry.GetServerModelType(); |  104   ModelType type = entry.GetServerModelType(); | 
|  107   ModelSafeGroup g = GetGroupForModelType(type, routing_info_); |  105   ModelSafeGroup g = GetGroupForModelType(type, routing_info_); | 
|  108   // The set of updates passed to the UpdateApplicator should already |  106   // The set of updates passed to the UpdateApplicator should already | 
|  109   // be group-filtered. |  107   // be group-filtered. | 
|  110   if (g != group_filter_) { |  108   if (g != group_filter_) { | 
|  111     NOTREACHED(); |  109     NOTREACHED(); | 
|  112     return true; |  110     return true; | 
|  113   } |  111   } | 
|  114   if (g == GROUP_PASSIVE && |  112   if (g == GROUP_PASSIVE && | 
|  115       !routing_info_.count(type) && |  113       !routing_info_.count(type) && | 
|  116       type != UNSPECIFIED && |  114       type != UNSPECIFIED && | 
|  117       type != TOP_LEVEL_FOLDER) { |  115       type != TOP_LEVEL_FOLDER) { | 
|  118     DVLOG(1) << "Skipping update application, type not permitted."; |  116     DVLOG(1) << "Skipping update application, type not permitted."; | 
|  119     return true; |  117     return true; | 
|  120   } |  118   } | 
|  121   return false; |  119   return false; | 
|  122 } |  120 } | 
|  123  |  121  | 
|  124 void UpdateApplicator::SaveProgressIntoSessionState( |  | 
|  125     std::set<syncable::Id>* simple_conflict_ids, |  | 
|  126     sessions::UpdateProgress* update_progress) { |  | 
|  127   application_results_.SaveProgress(simple_conflict_ids, update_progress); |  | 
|  128 } |  | 
|  129  |  | 
|  130 UpdateApplicator::ResultTracker::ResultTracker() { |  | 
|  131 } |  | 
|  132  |  | 
|  133 UpdateApplicator::ResultTracker::~ResultTracker() { |  | 
|  134 } |  | 
|  135  |  | 
|  136 void UpdateApplicator::ResultTracker::AddSimpleConflict(syncable::Id id) { |  | 
|  137   conflicting_ids_.insert(id); |  | 
|  138 } |  | 
|  139  |  | 
|  140 void UpdateApplicator::ResultTracker::AddEncryptionConflict(syncable::Id id) { |  | 
|  141   encryption_conflict_ids_.insert(id); |  | 
|  142 } |  | 
|  143  |  | 
|  144 void UpdateApplicator::ResultTracker::AddHierarchyConflict(syncable::Id id) { |  | 
|  145   hierarchy_conflict_ids_.insert(id); |  | 
|  146 } |  | 
|  147  |  | 
|  148 void UpdateApplicator::ResultTracker::AddSuccess(syncable::Id id) { |  | 
|  149   successful_ids_.insert(id); |  | 
|  150 } |  | 
|  151  |  | 
|  152 void UpdateApplicator::ResultTracker::SaveProgress( |  | 
|  153     std::set<syncable::Id>* simple_conflict_ids, |  | 
|  154     sessions::UpdateProgress* update_progress) { |  | 
|  155   std::set<syncable::Id>::const_iterator i; |  | 
|  156   *simple_conflict_ids = conflicting_ids_; |  | 
|  157   for (i = conflicting_ids_.begin(); i != conflicting_ids_.end(); ++i) { |  | 
|  158     update_progress->AddAppliedUpdate(CONFLICT_SIMPLE, *i); |  | 
|  159   } |  | 
|  160   for (i = encryption_conflict_ids_.begin(); |  | 
|  161        i != encryption_conflict_ids_.end(); ++i) { |  | 
|  162     update_progress->AddAppliedUpdate(CONFLICT_ENCRYPTION, *i); |  | 
|  163   } |  | 
|  164   for (i = hierarchy_conflict_ids_.begin(); |  | 
|  165        i != hierarchy_conflict_ids_.end(); ++i) { |  | 
|  166     update_progress->AddAppliedUpdate(CONFLICT_HIERARCHY, *i); |  | 
|  167   } |  | 
|  168   for (i = successful_ids_.begin(); i != successful_ids_.end(); ++i) { |  | 
|  169     update_progress->AddAppliedUpdate(SUCCESS, *i); |  | 
|  170   } |  | 
|  171 } |  | 
|  172  |  | 
|  173 void UpdateApplicator::ResultTracker::ClearHierarchyConflicts() { |  | 
|  174   hierarchy_conflict_ids_.clear(); |  | 
|  175 } |  | 
|  176  |  | 
|  177 bool UpdateApplicator::ResultTracker::no_conflicts() const { |  | 
|  178   return conflicting_ids_.empty(); |  | 
|  179 } |  | 
|  180  |  | 
|  181 }  // namespace syncer |  122 }  // namespace syncer | 
| OLD | NEW |