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

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