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

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

Issue 8922015: [Sync] Don't commit items with predecessors/parents in conflict. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments + rebase Created 8 years, 10 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/get_commit_ids_command.h" 5 #include "chrome/browser/sync/engine/get_commit_ids_command.h"
6 6
7 #include <set> 7 #include <set>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "chrome/browser/sync/engine/nigori_util.h" 11 #include "chrome/browser/sync/engine/nigori_util.h"
12 #include "chrome/browser/sync/engine/syncer_util.h" 12 #include "chrome/browser/sync/engine/syncer_util.h"
13 #include "chrome/browser/sync/syncable/directory_manager.h" 13 #include "chrome/browser/sync/syncable/directory_manager.h"
14 #include "chrome/browser/sync/syncable/syncable.h" 14 #include "chrome/browser/sync/syncable/syncable.h"
15 #include "chrome/browser/sync/util/cryptographer.h" 15 #include "chrome/browser/sync/util/cryptographer.h"
16 16
17 using std::set; 17 using std::set;
18 using std::vector; 18 using std::vector;
19 19
20 namespace browser_sync { 20 namespace browser_sync {
21 21
22 using sessions::OrderedCommitSet; 22 using sessions::OrderedCommitSet;
23 using sessions::SyncSession; 23 using sessions::SyncSession;
24 using sessions::StatusController; 24 using sessions::StatusController;
25 25
26 GetCommitIdsCommand::GetCommitIdsCommand(int commit_batch_size) 26 GetCommitIdsCommand::GetCommitIdsCommand(int commit_batch_size)
27 : requested_commit_batch_size_(commit_batch_size), 27 : requested_commit_batch_size_(commit_batch_size) {}
28 passphrase_missing_(false) {}
29 28
30 GetCommitIdsCommand::~GetCommitIdsCommand() {} 29 GetCommitIdsCommand::~GetCommitIdsCommand() {}
31 30
32 SyncerError GetCommitIdsCommand::ExecuteImpl(SyncSession* session) { 31 SyncerError GetCommitIdsCommand::ExecuteImpl(SyncSession* session) {
33 // Gather the full set of unsynced items and store it in the session. They 32 // Gather the full set of unsynced items and store it in the session. They
34 // are not in the correct order for commit. 33 // are not in the correct order for commit.
34 std::set<int64> ready_unsynced_set;
35 syncable::Directory::UnsyncedMetaHandles all_unsynced_handles; 35 syncable::Directory::UnsyncedMetaHandles all_unsynced_handles;
36 SyncerUtil::GetUnsyncedEntries(session->write_transaction(), 36 SyncerUtil::GetUnsyncedEntries(session->write_transaction(),
37 &all_unsynced_handles); 37 &all_unsynced_handles);
38 38
39 syncable::ModelTypeSet encrypted_types;
40 bool passphrase_missing = false;
39 Cryptographer* cryptographer = 41 Cryptographer* cryptographer =
40 session->context()->directory_manager()->GetCryptographer( 42 session->context()->directory_manager()->GetCryptographer(
41 session->write_transaction()); 43 session->write_transaction());
42 if (cryptographer) { 44 if (cryptographer) {
43 encrypted_types_ = cryptographer->GetEncryptedTypes(); 45 encrypted_types = cryptographer->GetEncryptedTypes();
44 passphrase_missing_ = cryptographer->has_pending_keys(); 46 passphrase_missing = cryptographer->has_pending_keys();
45 }; 47 };
46 48
47 const syncable::ModelTypeSet throttled_types = 49 const syncable::ModelTypeSet throttled_types =
48 session->context()->GetThrottledTypes(); 50 session->context()->GetThrottledTypes();
49 // We filter out all unready entries from the set of unsynced handles to 51 // We filter out all unready entries from the set of unsynced handles. This
50 // ensure we don't trigger useless sync cycles attempting to retry due to 52 // new set of ready and unsynced items (which excludes throttled items as
51 // there being work to do. (see ScheduleNextSync in sync_scheduler) 53 // well) is then what we use to determine what is a candidate for commit.
52 FilterUnreadyEntries(session->write_transaction(), 54 FilterUnreadyEntries(session->write_transaction(),
53 throttled_types, 55 throttled_types,
54 &all_unsynced_handles); 56 encrypted_types,
57 passphrase_missing,
58 all_unsynced_handles,
59 &ready_unsynced_set);
60
61 BuildCommitIds(session->write_transaction(),
62 session->routing_info(),
63 ready_unsynced_set);
55 64
56 StatusController* status = session->mutable_status_controller(); 65 StatusController* status = session->mutable_status_controller();
57 status->set_unsynced_handles(all_unsynced_handles); 66 syncable::Directory::UnsyncedMetaHandles ready_unsynced_vector(
58 BuildCommitIds(status->unsynced_handles(), session->write_transaction(), 67 ready_unsynced_set.begin(), ready_unsynced_set.end());
59 session->routing_info(), throttled_types); 68 status->set_unsynced_handles(ready_unsynced_vector);
60
61 const vector<syncable::Id>& verified_commit_ids = 69 const vector<syncable::Id>& verified_commit_ids =
62 ordered_commit_set_->GetAllCommitIds(); 70 ordered_commit_set_->GetAllCommitIds();
63 71
64 for (size_t i = 0; i < verified_commit_ids.size(); i++) 72 for (size_t i = 0; i < verified_commit_ids.size(); i++)
65 DVLOG(1) << "Debug commit batch result:" << verified_commit_ids[i]; 73 DVLOG(1) << "Debug commit batch result:" << verified_commit_ids[i];
66 74
67 status->set_commit_set(*ordered_commit_set_.get()); 75 status->set_commit_set(*ordered_commit_set_.get());
68 return SYNCER_OK; 76 return SYNCER_OK;
69 } 77 }
70 78
71 namespace { 79 namespace {
72 80
73 // An entry ready for commit is defined as: 81 bool IsEntryInConflict(const syncable::Entry& entry) {
74 // 1. Not in conflict (SERVER_VERSION == BASE_VERSION || SERVER_VERSION == 0) 82 if (entry.Get(syncable::IS_UNSYNCED) &&
75 // and not requiring encryption (any entry containing an encrypted datatype 83 entry.Get(syncable::SERVER_VERSION) > 0 &&
76 // while the cryptographer requires a passphrase is not ready for commit.)
77 // 2. Its type is not currently throttled.
78 bool IsEntryReadyForCommit(syncable::ModelTypeSet encrypted_types,
79 bool passphrase_missing,
80 const syncable::Entry& entry,
81 syncable::ModelTypeSet throttled_types) {
82 if (!entry.Get(syncable::IS_UNSYNCED))
83 return false;
84
85 if (entry.Get(syncable::SERVER_VERSION) > 0 &&
86 (entry.Get(syncable::SERVER_VERSION) > 84 (entry.Get(syncable::SERVER_VERSION) >
87 entry.Get(syncable::BASE_VERSION))) { 85 entry.Get(syncable::BASE_VERSION))) {
88 // The local and server versions don't match. The item must be in 86 // The local and server versions don't match. The item must be in
89 // conflict, so there's no point in attempting to commit. 87 // conflict, so there's no point in attempting to commit.
90 DCHECK(entry.Get(syncable::IS_UNAPPLIED_UPDATE)); // In conflict. 88 DCHECK(entry.Get(syncable::IS_UNAPPLIED_UPDATE));
91 DVLOG(1) << "Excluding entry from commit due to version mismatch " 89 DVLOG(1) << "Excluding entry from commit due to version mismatch "
92 << entry; 90 << entry;
91 return true;
92 }
93 return false;
94 }
95
96 // An entry is not considered ready for commit if any are true:
97 // 1. It's in conflict.
98 // 2. It requires encryption (either the type is encrypted but a passphrase
99 // is missing from the cryptographer, or the entry itself wasn't properly
100 // encrypted).
101 // 3. It's type is currently throttled.
102 // 4. It's a delete but has not been committed.
103 bool IsEntryReadyForCommit(syncable::ModelTypeSet throttled_types,
104 syncable::ModelTypeSet encrypted_types,
105 bool passphrase_missing,
106 const syncable::Entry& entry) {
107 DCHECK(entry.Get(syncable::IS_UNSYNCED));
108 if (IsEntryInConflict(entry))
93 return false; 109 return false;
94 }
95 110
96 const syncable::ModelType type = entry.GetModelType(); 111 const syncable::ModelType type = entry.GetModelType();
97 // We special case the nigori node because even though it is considered an 112 // We special case the nigori node because even though it is considered an
98 // "encrypted type", not all nigori node changes require valid encryption 113 // "encrypted type", not all nigori node changes require valid encryption
99 // (ex: sync_tabs). 114 // (ex: sync_tabs).
100 if ((type != syncable::NIGORI) && 115 if ((type != syncable::NIGORI) &&
101 encrypted_types.Has(type) && 116 encrypted_types.Has(type) &&
102 (passphrase_missing || 117 (passphrase_missing ||
103 syncable::EntryNeedsEncryption(encrypted_types, entry))) { 118 syncable::EntryNeedsEncryption(encrypted_types, entry))) {
104 // This entry requires encryption but is not properly encrypted (possibly 119 // This entry requires encryption but is not properly encrypted (possibly
105 // due to the cryptographer not being initialized or the user hasn't 120 // due to the cryptographer not being initialized or the user hasn't
106 // provided the most recent passphrase). 121 // provided the most recent passphrase).
107 DVLOG(1) << "Excluding entry from commit due to lack of encryption " 122 DVLOG(1) << "Excluding entry from commit due to lack of encryption "
108 << entry; 123 << entry;
109 return false; 124 return false;
110 } 125 }
111 126
112 // Look at the throttled types. 127 // Look at the throttled types.
113 if (throttled_types.Has(type)) 128 if (throttled_types.Has(type))
114 return false; 129 return false;
115 130
131 // Drop deleted uncommitted entries.
132 if (entry.Get(syncable::IS_DEL) && !entry.Get(syncable::ID).ServerKnows()) {
133 // TODO(zea): These will remain unsynced indefinitely. This is harmless,
134 // but we should clean them up somewhere.
135 DVLOG(1) << "Ignoring deleted and uncommitted item." << entry;
136 return false;
137 }
138
139 // Extra validity checks.
140 syncable::Id id = entry.Get(syncable::ID);
141 if (id == entry.Get(syncable::PARENT_ID)) {
142 CHECK(id.IsRoot()) << "Non-root item is self parenting." << entry;
143 // If the root becomes unsynced it can cause us problems.
144 NOTREACHED() << "Root item became unsynced " << entry;
145 return false;
146 }
147
148 if (entry.IsRoot()) {
149 NOTREACHED() << "Permanent item became unsynced " << entry;
150 return false;
151 }
152
153 DVLOG(2) << "Entry is ready for commit: " << entry;
116 return true; 154 return true;
117 } 155 }
118 156
119 } // namespace 157 } // namespace
120 158
121 void GetCommitIdsCommand::FilterUnreadyEntries( 159 void GetCommitIdsCommand::FilterUnreadyEntries(
122 syncable::BaseTransaction* trans, 160 syncable::BaseTransaction* trans,
123 syncable::ModelTypeSet throttled_types, 161 syncable::ModelTypeSet throttled_types,
124 syncable::Directory::UnsyncedMetaHandles* unsynced_handles) { 162 syncable::ModelTypeSet encrypted_types,
125 syncable::Directory::UnsyncedMetaHandles::iterator iter; 163 bool passphrase_missing,
126 syncable::Directory::UnsyncedMetaHandles new_unsynced_handles; 164 const syncable::Directory::UnsyncedMetaHandles& unsynced_handles,
127 new_unsynced_handles.reserve(unsynced_handles->size()); 165 std::set<int64>* ready_unsynced_set) {
128 for (iter = unsynced_handles->begin(); 166 for (syncable::Directory::UnsyncedMetaHandles::const_iterator iter =
129 iter != unsynced_handles->end(); 167 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) {
130 ++iter) {
131 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); 168 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter);
132 if (IsEntryReadyForCommit(encrypted_types_, 169 if (IsEntryReadyForCommit(throttled_types,
133 passphrase_missing_, 170 encrypted_types,
134 entry, 171 passphrase_missing,
135 throttled_types)) 172 entry)) {
136 new_unsynced_handles.push_back(*iter); 173 ready_unsynced_set->insert(*iter);
174 }
137 } 175 }
138 if (new_unsynced_handles.size() != unsynced_handles->size())
139 unsynced_handles->swap(new_unsynced_handles);
140 } 176 }
141 177
142 void GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors( 178 bool GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors(
143 syncable::BaseTransaction* trans, 179 syncable::BaseTransaction* trans,
144 syncable::Id parent_id,
145 const ModelSafeRoutingInfo& routes, 180 const ModelSafeRoutingInfo& routes,
146 syncable::ModelTypeSet throttled_types) { 181 const std::set<int64>& ready_unsynced_set,
182 const syncable::Entry& item,
183 sessions::OrderedCommitSet* result) const {
147 OrderedCommitSet item_dependencies(routes); 184 OrderedCommitSet item_dependencies(routes);
185 syncable::Id parent_id = item.Get(syncable::PARENT_ID);
148 186
149 // Climb the tree adding entries leaf -> root. 187 // Climb the tree adding entries leaf -> root.
150 while (!parent_id.ServerKnows()) { 188 while (!parent_id.ServerKnows()) {
151 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); 189 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id);
152 CHECK(parent.good()) << "Bad user-only parent in item path."; 190 CHECK(parent.good()) << "Bad user-only parent in item path.";
153 int64 handle = parent.Get(syncable::META_HANDLE); 191 int64 handle = parent.Get(syncable::META_HANDLE);
154 if (ordered_commit_set_->HaveCommitItem(handle) || 192 if (ordered_commit_set_->HaveCommitItem(handle)) {
155 item_dependencies.HaveCommitItem(handle)) { 193 // We've already added this parent (and therefore all of its parents).
194 // We can return early.
156 break; 195 break;
157 } 196 }
158 if (!AddItemThenPredecessors(trans, throttled_types, &parent, 197 if (!AddItemThenPredecessors(trans, ready_unsynced_set, parent,
159 syncable::IS_UNSYNCED,
160 &item_dependencies)) { 198 &item_dependencies)) {
161 break; // Parent was already present in the set. 199 // There was a parent/predecessor in conflict. We return without adding
200 // anything to |ordered_commit_set_|.
201 DVLOG(1) << "Parent or parent's predecessor was in conflict, omitting "
202 << item;
203 return false;
162 } 204 }
163 parent_id = parent.Get(syncable::PARENT_ID); 205 parent_id = parent.Get(syncable::PARENT_ID);
164 } 206 }
165 207
166 // Reverse what we added to get the correct order. 208 // Reverse what we added to get the correct order.
167 ordered_commit_set_->AppendReverse(item_dependencies); 209 result->AppendReverse(item_dependencies);
210 return true;
168 } 211 }
169 212
170 bool GetCommitIdsCommand::AddItem(syncable::Entry* item, 213 bool GetCommitIdsCommand::AddItem(const std::set<int64>& ready_unsynced_set,
171 syncable::ModelTypeSet throttled_types, 214 const syncable::Entry& item,
172 OrderedCommitSet* result) { 215 OrderedCommitSet* result) const {
173 if (!IsEntryReadyForCommit(encrypted_types_, passphrase_missing_, *item, 216 DCHECK(item.Get(syncable::IS_UNSYNCED));
174 throttled_types)) 217 // An item in conflict means that dependent items (successors and children)
218 // cannot be added either.
219 if (IsEntryInConflict(item))
175 return false; 220 return false;
176 int64 item_handle = item->Get(syncable::META_HANDLE); 221 int64 item_handle = item.Get(syncable::META_HANDLE);
177 if (result->HaveCommitItem(item_handle) || 222 if (ready_unsynced_set.count(item_handle) == 0) {
178 ordered_commit_set_->HaveCommitItem(item_handle)) { 223 // It's not in conflict, but not ready for commit. Just return true without
179 return false; 224 // adding it to the commit set.
225 return true;
180 } 226 }
181 result->AddCommitItem(item_handle, item->Get(syncable::ID), 227 result->AddCommitItem(item_handle, item.Get(syncable::ID),
182 item->GetModelType()); 228 item.GetModelType());
183 return true; 229 return true;
184 } 230 }
185 231
186 bool GetCommitIdsCommand::AddItemThenPredecessors( 232 bool GetCommitIdsCommand::AddItemThenPredecessors(
187 syncable::BaseTransaction* trans, 233 syncable::BaseTransaction* trans,
188 syncable::ModelTypeSet throttled_types, 234 const std::set<int64>& ready_unsynced_set,
189 syncable::Entry* item, 235 const syncable::Entry& item,
190 syncable::IndexedBitField inclusion_filter, 236 OrderedCommitSet* result) const {
191 OrderedCommitSet* result) { 237 int64 item_handle = item.Get(syncable::META_HANDLE);
192 if (!AddItem(item, throttled_types, result)) 238 if (ordered_commit_set_->HaveCommitItem(item_handle)) {
193 return false; 239 // We've already added this item to the commit set, and so must have
194 if (item->Get(syncable::IS_DEL)) 240 // already added the predecessors as well.
241 return true;
242 }
243 if (!AddItem(ready_unsynced_set, item, result))
244 return false; // Item is in conflict.
245 if (item.Get(syncable::IS_DEL))
195 return true; // Deleted items have no predecessors. 246 return true; // Deleted items have no predecessors.
196 247
197 syncable::Id prev_id = item->Get(syncable::PREV_ID); 248 syncable::Id prev_id = item.Get(syncable::PREV_ID);
198 while (!prev_id.IsRoot()) { 249 while (!prev_id.IsRoot()) {
199 syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id); 250 syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id);
200 CHECK(prev.good()) << "Bad id when walking predecessors."; 251 CHECK(prev.good()) << "Bad id when walking predecessors.";
201 if (!prev.Get(inclusion_filter)) 252 if (!prev.Get(syncable::IS_UNSYNCED))
202 break; 253 break;
203 if (!AddItem(&prev, throttled_types, result)) 254 int64 handle = prev.Get(syncable::META_HANDLE);
204 break; 255 if (ordered_commit_set_->HaveCommitItem(handle)) {
256 // We've already added this item to the commit set, and so must have
257 // already added the predecessors as well.
258 return true;
259 }
260 if (!AddItem(ready_unsynced_set, prev, result))
261 return false; // Item is in conflict.
205 prev_id = prev.Get(syncable::PREV_ID); 262 prev_id = prev.Get(syncable::PREV_ID);
206 } 263 }
207 return true; 264 return true;
208 } 265 }
209 266
210 void GetCommitIdsCommand::AddPredecessorsThenItem( 267 bool GetCommitIdsCommand::AddPredecessorsThenItem(
211 syncable::BaseTransaction* trans, 268 syncable::BaseTransaction* trans,
212 syncable::ModelTypeSet throttled_types, 269 const ModelSafeRoutingInfo& routes,
213 syncable::Entry* item, 270 const std::set<int64>& ready_unsynced_set,
214 syncable::IndexedBitField inclusion_filter, 271 const syncable::Entry& item,
215 const ModelSafeRoutingInfo& routes) { 272 OrderedCommitSet* result) const {
216 OrderedCommitSet item_dependencies(routes); 273 OrderedCommitSet item_dependencies(routes);
217 AddItemThenPredecessors(trans, throttled_types, item, inclusion_filter, 274 if (!AddItemThenPredecessors(trans, ready_unsynced_set, item,
218 &item_dependencies); 275 &item_dependencies)) {
276 // Either the item or its predecessors are in conflict, so don't add any
277 // items to the commit set.
278 DVLOG(1) << "Predecessor was in conflict, omitting " << item;
279 return false;
280 }
219 281
220 // Reverse what we added to get the correct order. 282 // Reverse what we added to get the correct order.
221 ordered_commit_set_->AppendReverse(item_dependencies); 283 result->AppendReverse(item_dependencies);
284 return true;
222 } 285 }
223 286
224 bool GetCommitIdsCommand::IsCommitBatchFull() { 287 bool GetCommitIdsCommand::IsCommitBatchFull() const {
225 return ordered_commit_set_->Size() >= requested_commit_batch_size_; 288 return ordered_commit_set_->Size() >= requested_commit_batch_size_;
226 } 289 }
227 290
228 void GetCommitIdsCommand::AddCreatesAndMoves( 291 void GetCommitIdsCommand::AddCreatesAndMoves(
229 const vector<int64>& unsynced_handles,
230 syncable::WriteTransaction* write_transaction, 292 syncable::WriteTransaction* write_transaction,
231 const ModelSafeRoutingInfo& routes, 293 const ModelSafeRoutingInfo& routes,
232 syncable::ModelTypeSet throttled_types) { 294 const std::set<int64>& ready_unsynced_set) {
233 // Add moves and creates, and prepend their uncommitted parents. 295 // Add moves and creates, and prepend their uncommitted parents.
234 for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction, 296 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
235 ordered_commit_set_.get()); 297 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
236 !IsCommitBatchFull() && iterator.Valid(); 298 int64 metahandle = *iter;
237 iterator.Increment()) { 299 if (ordered_commit_set_->HaveCommitItem(metahandle))
238 int64 metahandle = iterator.Current(); 300 continue;
239 301
240 syncable::Entry entry(write_transaction, 302 syncable::Entry entry(write_transaction,
241 syncable::GET_BY_HANDLE, 303 syncable::GET_BY_HANDLE,
242 metahandle); 304 metahandle);
243 if (!entry.Get(syncable::IS_DEL)) { 305 if (!entry.Get(syncable::IS_DEL)) {
244 AddUncommittedParentsAndTheirPredecessors(write_transaction, 306 // We only commit an item + its dependencies if it and all its
245 entry.Get(syncable::PARENT_ID), routes, throttled_types); 307 // dependencies are not in conflict.
246 AddPredecessorsThenItem(write_transaction, throttled_types, &entry, 308 OrderedCommitSet item_dependencies(routes);
247 syncable::IS_UNSYNCED, routes); 309 if (AddUncommittedParentsAndTheirPredecessors(
310 write_transaction,
311 routes,
312 ready_unsynced_set,
313 entry,
314 &item_dependencies) &&
315 AddPredecessorsThenItem(write_transaction,
316 routes,
317 ready_unsynced_set,
318 entry,
319 &item_dependencies)) {
320 ordered_commit_set_->Append(item_dependencies);
321 }
248 } 322 }
249 } 323 }
250 324
251 // It's possible that we overcommitted while trying to expand dependent 325 // It's possible that we overcommitted while trying to expand dependent
252 // items. If so, truncate the set down to the allowed size. 326 // items. If so, truncate the set down to the allowed size.
253 ordered_commit_set_->Truncate(requested_commit_batch_size_); 327 ordered_commit_set_->Truncate(requested_commit_batch_size_);
254 } 328 }
255 329
256 void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles, 330 void GetCommitIdsCommand::AddDeletes(
257 syncable::WriteTransaction* write_transaction) { 331 syncable::WriteTransaction* write_transaction,
332 const std::set<int64>& ready_unsynced_set) {
258 set<syncable::Id> legal_delete_parents; 333 set<syncable::Id> legal_delete_parents;
259 334
260 for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction, 335 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
261 ordered_commit_set_.get()); 336 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
262 !IsCommitBatchFull() && iterator.Valid(); 337 int64 metahandle = *iter;
263 iterator.Increment()) { 338 if (ordered_commit_set_->HaveCommitItem(metahandle))
264 int64 metahandle = iterator.Current(); 339 continue;
265 340
266 syncable::Entry entry(write_transaction, syncable::GET_BY_HANDLE, 341 syncable::Entry entry(write_transaction, syncable::GET_BY_HANDLE,
267 metahandle); 342 metahandle);
268 343
269 if (entry.Get(syncable::IS_DEL)) { 344 if (entry.Get(syncable::IS_DEL)) {
270 syncable::Entry parent(write_transaction, syncable::GET_BY_ID, 345 syncable::Entry parent(write_transaction, syncable::GET_BY_ID,
271 entry.Get(syncable::PARENT_ID)); 346 entry.Get(syncable::PARENT_ID));
272 // If the parent is deleted and unsynced, then any children of that 347 // If the parent is deleted and unsynced, then any children of that
273 // parent don't need to be added to the delete queue. 348 // parent don't need to be added to the delete queue.
274 // 349 //
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 // examined entries. 387 // examined entries.
313 // 388 //
314 // Scan through the UnsyncedMetaHandles again. If we have a deleted 389 // Scan through the UnsyncedMetaHandles again. If we have a deleted
315 // entry, then check if the parent is in legal_delete_parents. 390 // entry, then check if the parent is in legal_delete_parents.
316 // 391 //
317 // Parent being in legal_delete_parents means for the child: 392 // Parent being in legal_delete_parents means for the child:
318 // a recursive delete is not currently happening (no recent deletes in same 393 // a recursive delete is not currently happening (no recent deletes in same
319 // folder) 394 // folder)
320 // parent did expect at least one old deleted child 395 // parent did expect at least one old deleted child
321 // parent was not deleted 396 // parent was not deleted
322 397 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
323 for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction, 398 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
324 ordered_commit_set_.get()); 399 int64 metahandle = *iter;
325 !IsCommitBatchFull() && iterator.Valid(); 400 if (ordered_commit_set_->HaveCommitItem(metahandle))
326 iterator.Increment()) { 401 continue;
327 int64 metahandle = iterator.Current();
328 syncable::MutableEntry entry(write_transaction, syncable::GET_BY_HANDLE, 402 syncable::MutableEntry entry(write_transaction, syncable::GET_BY_HANDLE,
329 metahandle); 403 metahandle);
330 if (entry.Get(syncable::IS_DEL)) { 404 if (entry.Get(syncable::IS_DEL)) {
331 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); 405 syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
332 if (legal_delete_parents.count(parent_id)) { 406 if (legal_delete_parents.count(parent_id)) {
333 ordered_commit_set_->AddCommitItem(metahandle, entry.Get(syncable::ID), 407 ordered_commit_set_->AddCommitItem(metahandle, entry.Get(syncable::ID),
334 entry.GetModelType()); 408 entry.GetModelType());
335 } 409 }
336 } 410 }
337 } 411 }
338 } 412 }
339 413
340 void GetCommitIdsCommand::BuildCommitIds(const vector<int64>& unsynced_handles, 414 void GetCommitIdsCommand::BuildCommitIds(
341 syncable::WriteTransaction* write_transaction, 415 syncable::WriteTransaction* write_transaction,
342 const ModelSafeRoutingInfo& routes, 416 const ModelSafeRoutingInfo& routes,
343 syncable::ModelTypeSet throttled_types) { 417 const std::set<int64>& ready_unsynced_set) {
344 ordered_commit_set_.reset(new OrderedCommitSet(routes)); 418 ordered_commit_set_.reset(new OrderedCommitSet(routes));
345 // Commits follow these rules: 419 // Commits follow these rules:
346 // 1. Moves or creates are preceded by needed folder creates, from 420 // 1. Moves or creates are preceded by needed folder creates, from
347 // root to leaf. For folders whose contents are ordered, moves 421 // root to leaf. For folders whose contents are ordered, moves
348 // and creates appear in order. 422 // and creates appear in order.
349 // 2. Moves/Creates before deletes. 423 // 2. Moves/Creates before deletes.
350 // 3. Deletes, collapsed. 424 // 3. Deletes, collapsed.
351 // We commit deleted moves under deleted items as moves when collapsing 425 // We commit deleted moves under deleted items as moves when collapsing
352 // delete trees. 426 // delete trees.
353 427
354 // Add moves and creates, and prepend their uncommitted parents. 428 // Add moves and creates, and prepend their uncommitted parents.
355 AddCreatesAndMoves(unsynced_handles, write_transaction, routes, 429 AddCreatesAndMoves(write_transaction, routes, ready_unsynced_set);
356 throttled_types);
357 430
358 // Add all deletes. 431 // Add all deletes.
359 AddDeletes(unsynced_handles, write_transaction); 432 AddDeletes(write_transaction, ready_unsynced_set);
360 } 433 }
361 434
362 } // namespace browser_sync 435 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/get_commit_ids_command.h ('k') | chrome/browser/sync/engine/syncer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698