Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc

Issue 9107055: Remove single direction conflict set code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Pre-emptive rebase Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h" 5 #include "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 #include <sstream> 9 #include <sstream>
10 #include <vector> 10 #include <vector>
(...skipping 19 matching lines...) Expand all
30 BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSetsCommand() {} 30 BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSetsCommand() {}
31 BuildAndProcessConflictSetsCommand::~BuildAndProcessConflictSetsCommand() {} 31 BuildAndProcessConflictSetsCommand::~BuildAndProcessConflictSetsCommand() {}
32 32
33 std::set<ModelSafeGroup> BuildAndProcessConflictSetsCommand::GetGroupsToChange( 33 std::set<ModelSafeGroup> BuildAndProcessConflictSetsCommand::GetGroupsToChange(
34 const sessions::SyncSession& session) const { 34 const sessions::SyncSession& session) const {
35 return session.GetEnabledGroupsWithConflicts(); 35 return session.GetEnabledGroupsWithConflicts();
36 } 36 }
37 37
38 SyncerError BuildAndProcessConflictSetsCommand::ModelChangingExecuteImpl( 38 SyncerError BuildAndProcessConflictSetsCommand::ModelChangingExecuteImpl(
39 SyncSession* session) { 39 SyncSession* session) {
40 session->mutable_status_controller()->update_conflict_sets_built(
41 BuildAndProcessConflictSets(session));
42 return SYNCER_OK;
43 }
44
45 bool BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSets(
46 SyncSession* session) {
47 syncable::ScopedDirLookup dir(session->context()->directory_manager(), 40 syncable::ScopedDirLookup dir(session->context()->directory_manager(),
48 session->context()->account_name()); 41 session->context()->account_name());
49 if (!dir.good()) 42 if (!dir.good())
50 return false; 43 return DIRECTORY_LOOKUP_FAILED;
51 bool had_single_direction_sets = false;
52 { // Scope for transaction.
53 syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
54 BuildConflictSets(&trans,
55 session->mutable_status_controller()->mutable_conflict_progress());
56 had_single_direction_sets = ProcessSingleDirectionConflictSets(&trans,
57 session->context()->resolver(),
58 session->context()->directory_manager()->GetCryptographer(&trans),
59 session->mutable_status_controller(), session->routing_info());
60 // We applied some updates transactionally, lets try syncing again.
61 if (had_single_direction_sets)
62 return true;
63 }
64 return false;
65 }
66 44
67 bool BuildAndProcessConflictSetsCommand::ProcessSingleDirectionConflictSets( 45 syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
68 syncable::WriteTransaction* trans, ConflictResolver* resolver, 46 BuildConflictSets(&trans,
69 Cryptographer* cryptographer, StatusController* status, 47 session->mutable_status_controller()->mutable_conflict_progress());
70 const ModelSafeRoutingInfo& routes) {
71 if (!status->conflict_progress())
72 return false;
73 bool rv = false;
74 set<ConflictSet*>::const_iterator all_sets_iterator;
75 for (all_sets_iterator = status->conflict_progress()->ConflictSetsBegin();
76 all_sets_iterator != status->conflict_progress()->ConflictSetsEnd();) {
77 const ConflictSet* conflict_set = *all_sets_iterator;
78 CHECK_GE(conflict_set->size(), 2U);
79 // We scan the set to see if it consists of changes of only one type.
80 ConflictSet::const_iterator i;
81 size_t unsynced_count = 0, unapplied_count = 0;
82 for (i = conflict_set->begin(); i != conflict_set->end(); ++i) {
83 syncable::Entry entry(trans, syncable::GET_BY_ID, *i);
84 CHECK(entry.good());
85 if (entry.Get(syncable::IS_UNSYNCED))
86 unsynced_count++;
87 if (entry.Get(syncable::IS_UNAPPLIED_UPDATE))
88 unapplied_count++;
89 }
90 if (conflict_set->size() == unsynced_count && 0 == unapplied_count) {
91 DVLOG(1) << "Skipped transactional commit attempt.";
92 } else if (conflict_set->size() == unapplied_count && 0 == unsynced_count &&
93 ApplyUpdatesTransactionally(trans, conflict_set, resolver,
94 cryptographer, routes, status)) {
95 rv = true;
96 }
97 ++all_sets_iterator;
98 }
99 return rv;
100 }
101 48
102 namespace { 49 return SYNCER_OK;
103
104 void StoreLocalDataForUpdateRollback(syncable::Entry* entry,
105 syncable::EntryKernel* backup) {
106 CHECK(!entry->Get(syncable::IS_UNSYNCED)) << " Storing Rollback data for "
107 "entry that's unsynced." << *entry;
108 CHECK(entry->Get(syncable::IS_UNAPPLIED_UPDATE)) << " Storing Rollback data "
109 "for entry that's not an unapplied update." << *entry;
110 *backup = entry->GetKernelCopy();
111 }
112
113
114 bool RollbackEntry(syncable::WriteTransaction* trans,
115 syncable::EntryKernel* backup) {
116 syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE,
117 backup->ref(syncable::META_HANDLE));
118 CHECK(entry.good());
119
120 if (!entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)))
121 return false;
122
123 entry.Put(syncable::NON_UNIQUE_NAME, backup->ref(syncable::NON_UNIQUE_NAME));
124 entry.Put(syncable::PARENT_ID, backup->ref(syncable::PARENT_ID));
125
126 if (!backup->ref(syncable::IS_DEL)) {
127 if (!entry.PutPredecessor(backup->ref(syncable::PREV_ID))) {
128 // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
129 NOTREACHED();
130 }
131 }
132
133 if (backup->ref(syncable::PREV_ID) != entry.Get(syncable::PREV_ID))
134 return false;
135
136 entry.Put(syncable::CTIME, backup->ref(syncable::CTIME));
137 entry.Put(syncable::MTIME, backup->ref(syncable::MTIME));
138 entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION));
139 entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR));
140 entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL));
141 entry.Put(syncable::ID, backup->ref(syncable::ID));
142 entry.Put(syncable::IS_UNAPPLIED_UPDATE,
143 backup->ref(syncable::IS_UNAPPLIED_UPDATE));
144 return true;
145 }
146
147 void PlaceEntriesAtRoot(syncable::WriteTransaction* trans,
148 const vector<syncable::Id>* ids) {
149 vector<syncable::Id>::const_iterator it;
150 for (it = ids->begin(); it != ids->end(); ++it) {
151 syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it);
152 entry.Put(syncable::PARENT_ID, trans->root_id());
153 }
154 }
155
156 } // namespace
157
158 bool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally(
159 syncable::WriteTransaction* trans,
160 const vector<syncable::Id>* const update_set,
161 ConflictResolver* resolver,
162 Cryptographer* cryptographer,
163 const ModelSafeRoutingInfo& routes,
164 StatusController* status) {
165 // The handles in the |update_set| order.
166 vector<int64> handles;
167
168 // Holds the same Ids as update_set, but sorted so that runs of adjacent
169 // nodes appear in order.
170 vector<syncable::Id> rollback_ids;
171 rollback_ids.reserve(update_set->size());
172
173 // Tracks what's added to |rollback_ids|.
174 syncable::MetahandleSet rollback_ids_inserted_items;
175 vector<syncable::Id>::const_iterator it;
176
177 // 1. Build |rollback_ids| in the order required for successful rollback.
178 // Specifically, for positions to come out right, restoring an item
179 // requires that its predecessor in the sibling order is properly
180 // restored first.
181 // 2. Build |handles|, the list of handles for ApplyUpdates.
182 for (it = update_set->begin(); it != update_set->end(); ++it) {
183 syncable::Entry entry(trans, syncable::GET_BY_ID, *it);
184 SyncerUtil::AddPredecessorsThenItem(trans, &entry,
185 syncable::IS_UNAPPLIED_UPDATE, &rollback_ids_inserted_items,
186 &rollback_ids);
187 handles.push_back(entry.Get(syncable::META_HANDLE));
188 }
189 DCHECK_EQ(rollback_ids.size(), update_set->size());
190 DCHECK_EQ(rollback_ids_inserted_items.size(), update_set->size());
191
192 // 3. Store the information needed to rollback if the transaction fails.
193 // Do this before modifying anything to keep the next/prev values intact.
194 vector<syncable::EntryKernel> rollback_data(rollback_ids.size());
195 for (size_t i = 0; i < rollback_ids.size(); ++i) {
196 syncable::Entry entry(trans, syncable::GET_BY_ID, rollback_ids[i]);
197 StoreLocalDataForUpdateRollback(&entry, &rollback_data[i]);
198 }
199
200 // 4. Use the preparer to move things to an initial starting state where
201 // nothing in the set is a child of anything else. If
202 // we've correctly calculated the set, the server tree is valid and no
203 // changes have occurred locally we should be able to apply updates from this
204 // state.
205 PlaceEntriesAtRoot(trans, update_set);
206
207 // 5. Use the usual apply updates from the special start state we've just
208 // prepared.
209 UpdateApplicator applicator(resolver, cryptographer,
210 handles.begin(), handles.end(),
211 routes, status->group_restriction());
212 while (applicator.AttemptOneApplication(trans)) {
213 // Keep going till all updates are applied.
214 }
215 if (!applicator.AllUpdatesApplied()) {
216 LOG(ERROR) << "Transactional Apply Failed, Rolling back.";
217 // We have to move entries into the temp dir again. e.g. if a swap was in a
218 // set with other failing updates, the swap may have gone through, meaning
219 // the roll back needs to be transactional. But as we're going to a known
220 // good state we should always succeed.
221 PlaceEntriesAtRoot(trans, update_set);
222
223 // Rollback all entries.
224 for (size_t i = 0; i < rollback_data.size(); ++i) {
225 CHECK(RollbackEntry(trans, &rollback_data[i]));
226 }
227 return false; // Don't save progress -- we just undid it.
228 }
229 applicator.SaveProgressIntoSessionState(status->mutable_conflict_progress(),
230 status->mutable_update_progress());
231 return true;
232 } 50 }
233 51
234 void BuildAndProcessConflictSetsCommand::BuildConflictSets( 52 void BuildAndProcessConflictSetsCommand::BuildConflictSets(
235 syncable::BaseTransaction* trans, 53 syncable::BaseTransaction* trans,
236 ConflictProgress* conflict_progress) { 54 ConflictProgress* conflict_progress) {
237 conflict_progress->CleanupSets(); 55 conflict_progress->CleanupSets();
238 set<syncable::Id>::const_iterator i = 56 set<syncable::Id>::const_iterator i =
239 conflict_progress->ConflictingItemsBegin(); 57 conflict_progress->ConflictingItemsBegin();
240 while (i != conflict_progress->ConflictingItemsEnd()) { 58 while (i != conflict_progress->ConflictingItemsEnd()) {
241 syncable::Entry entry(trans, syncable::GET_BY_ID, *i); 59 syncable::Entry entry(trans, syncable::GET_BY_ID, *i);
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 LocallyDeletedPathChecker checker; 229 LocallyDeletedPathChecker checker;
412 if (!checker.CausingConflict(parent, *entry)) 230 if (!checker.CausingConflict(parent, *entry))
413 return; 231 return;
414 conflict_progress->MergeSets(entry->Get(syncable::ID), 232 conflict_progress->MergeSets(entry->Get(syncable::ID),
415 parent.Get(syncable::ID)); 233 parent.Get(syncable::ID));
416 CrawlDeletedTreeMergingSets(trans, parent, conflict_progress, checker); 234 CrawlDeletedTreeMergingSets(trans, parent, conflict_progress, checker);
417 } 235 }
418 } 236 }
419 237
420 } // namespace browser_sync 238 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/build_and_process_conflict_sets_command.h ('k') | chrome/browser/sync/engine/syncer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698