Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 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/get_commit_ids_command.h" | 5 #include "sync/engine/get_commit_ids.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <utility> | |
| 9 #include <vector> | 8 #include <vector> |
| 10 | 9 |
| 10 #include "base/basictypes.h" | |
| 11 #include "sync/engine/syncer_util.h" | 11 #include "sync/engine/syncer_util.h" |
| 12 #include "sync/sessions/nudge_tracker.h" | 12 #include "sync/syncable/directory.h" |
| 13 #include "sync/syncable/entry.h" | 13 #include "sync/syncable/entry.h" |
| 14 #include "sync/syncable/nigori_handler.h" | 14 #include "sync/syncable/nigori_handler.h" |
| 15 #include "sync/syncable/nigori_util.h" | 15 #include "sync/syncable/nigori_util.h" |
| 16 #include "sync/syncable/syncable_base_transaction.h" | 16 #include "sync/syncable/syncable_base_transaction.h" |
| 17 #include "sync/syncable/syncable_util.h" | 17 #include "sync/syncable/syncable_util.h" |
| 18 #include "sync/util/cryptographer.h" | 18 #include "sync/util/cryptographer.h" |
| 19 | 19 |
| 20 using std::set; | 20 using std::set; |
| 21 using std::vector; | 21 using std::vector; |
| 22 | 22 |
| 23 namespace syncer { | 23 namespace syncer { |
| 24 | 24 |
| 25 using sessions::OrderedCommitSet; | 25 namespace { |
| 26 using sessions::SyncSession; | |
| 27 using sessions::StatusController; | |
| 28 | 26 |
| 29 GetCommitIdsCommand::GetCommitIdsCommand( | 27 // Forward-declare some helper functions. This gives us more options for |
| 28 // ordering the function defintions within this file. | |
| 29 | |
| 30 void FilterUnreadyEntries( | |
| 30 syncable::BaseTransaction* trans, | 31 syncable::BaseTransaction* trans, |
| 31 ModelTypeSet requested_types, | 32 ModelTypeSet requested_types, |
| 32 const size_t commit_batch_size, | 33 ModelTypeSet encrypted_types, |
| 33 sessions::OrderedCommitSet* commit_set) | 34 bool passphrase_missing, |
| 34 : trans_(trans), | 35 const syncable::Directory::Metahandles& unsynced_handles, |
| 35 requested_types_(requested_types), | 36 std::set<int64>* ready_unsynced_set); |
| 36 requested_commit_batch_size_(commit_batch_size), | |
| 37 commit_set_(commit_set) { | |
| 38 } | |
| 39 | 37 |
| 40 GetCommitIdsCommand::~GetCommitIdsCommand() {} | 38 SYNC_EXPORT_PRIVATE void OrderCommitIds( |
| 39 syncable::BaseTransaction* trans, | |
| 40 size_t max_entries, | |
| 41 const std::set<int64>& ready_unsynced_set, | |
| 42 std::vector<int64>* out); | |
| 41 | 43 |
| 42 SyncerError GetCommitIdsCommand::ExecuteImpl(SyncSession* session) { | 44 } // namespace |
| 45 | |
| 46 void GetCommitIdsForType( | |
| 47 syncable::BaseTransaction* trans, | |
| 48 ModelType type, | |
| 49 size_t max_entries, | |
| 50 syncable::Directory::Metahandles* out) { | |
| 51 syncable::Directory* dir = trans->directory(); | |
| 52 | |
| 43 // Gather the full set of unsynced items and store it in the session. They | 53 // Gather the full set of unsynced items and store it in the session. They |
| 44 // are not in the correct order for commit. | 54 // are not in the correct order for commit. |
| 45 std::set<int64> ready_unsynced_set; | 55 std::set<int64> ready_unsynced_set; |
| 46 syncable::Directory::Metahandles all_unsynced_handles; | 56 syncable::Directory::Metahandles all_unsynced_handles; |
| 47 GetUnsyncedEntries(trans_, | 57 GetUnsyncedEntries(trans, &all_unsynced_handles); |
| 48 &all_unsynced_handles); | |
| 49 | 58 |
| 50 ModelTypeSet encrypted_types; | 59 ModelTypeSet encrypted_types; |
| 51 bool passphrase_missing = false; | 60 bool passphrase_missing = false; |
| 52 Cryptographer* cryptographer = | 61 Cryptographer* cryptographer = dir->GetCryptographer(trans); |
| 53 session->context()-> | |
| 54 directory()->GetCryptographer(trans_); | |
| 55 if (cryptographer) { | 62 if (cryptographer) { |
| 56 encrypted_types = session->context()->directory()->GetNigoriHandler()-> | 63 encrypted_types = dir->GetNigoriHandler()->GetEncryptedTypes(trans); |
| 57 GetEncryptedTypes(trans_); | |
| 58 passphrase_missing = cryptographer->has_pending_keys(); | 64 passphrase_missing = cryptographer->has_pending_keys(); |
| 59 }; | 65 }; |
| 60 | 66 |
| 61 // We filter out all unready entries from the set of unsynced handles. This | 67 // We filter out all unready entries from the set of unsynced handles. This |
| 62 // new set of ready and unsynced items is then what we use to determine what | 68 // new set of ready and unsynced items is then what we use to determine what |
| 63 // is a candidate for commit. The caller of this SyncerCommand is responsible | 69 // is a candidate for commit. The caller of this SyncerCommand is responsible |
| 64 // for ensuring that no throttled types are included among the | 70 // for ensuring that no throttled types are included among the |
| 65 // requested_types. | 71 // requested_types. |
| 66 FilterUnreadyEntries(trans_, | 72 FilterUnreadyEntries(trans, |
| 67 requested_types_, | 73 ModelTypeSet(type), |
| 68 encrypted_types, | 74 encrypted_types, |
| 69 passphrase_missing, | 75 passphrase_missing, |
| 70 all_unsynced_handles, | 76 all_unsynced_handles, |
| 71 &ready_unsynced_set); | 77 &ready_unsynced_set); |
| 72 | 78 |
| 73 BuildCommitIds(trans_, | 79 OrderCommitIds(trans, max_entries, ready_unsynced_set, out); |
| 74 session->context()->routing_info(), | |
| 75 ready_unsynced_set); | |
| 76 | 80 |
| 77 return SYNCER_OK; | 81 for (size_t i = 0; i < out->size(); i++) |
| 82 DVLOG(1) << "Debug commit batch result:" << (*out)[i]; | |
|
tim (not reviewing)
2013/09/08 19:48:20
nit - It's a generally followed convention / good
rlarocque
2013/09/09 17:41:29
Done.
| |
| 78 } | 83 } |
| 79 | 84 |
| 80 namespace { | 85 namespace { |
| 81 | 86 |
| 82 bool IsEntryInConflict(const syncable::Entry& entry) { | 87 bool IsEntryInConflict(const syncable::Entry& entry) { |
| 83 if (entry.Get(syncable::IS_UNSYNCED) && | 88 if (entry.Get(syncable::IS_UNSYNCED) && |
| 84 entry.Get(syncable::SERVER_VERSION) > 0 && | 89 entry.Get(syncable::SERVER_VERSION) > 0 && |
| 85 (entry.Get(syncable::SERVER_VERSION) > | 90 (entry.Get(syncable::SERVER_VERSION) > |
| 86 entry.Get(syncable::BASE_VERSION))) { | 91 entry.Get(syncable::BASE_VERSION))) { |
| 87 // The local and server versions don't match. The item must be in | 92 // The local and server versions don't match. The item must be in |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 | 152 |
| 148 if (entry.IsRoot()) { | 153 if (entry.IsRoot()) { |
| 149 NOTREACHED() << "Permanent item became unsynced " << entry; | 154 NOTREACHED() << "Permanent item became unsynced " << entry; |
| 150 return false; | 155 return false; |
| 151 } | 156 } |
| 152 | 157 |
| 153 DVLOG(2) << "Entry is ready for commit: " << entry; | 158 DVLOG(2) << "Entry is ready for commit: " << entry; |
| 154 return true; | 159 return true; |
| 155 } | 160 } |
| 156 | 161 |
| 157 } // namespace | 162 // Filters |unsynced_handles| to remove all entries that do not belong to the |
| 158 | 163 // specified |requested_types|, or are not eligible for a commit at this time. |
| 159 void GetCommitIdsCommand::FilterUnreadyEntries( | 164 void FilterUnreadyEntries( |
| 160 syncable::BaseTransaction* trans, | 165 syncable::BaseTransaction* trans, |
| 161 ModelTypeSet requested_types, | 166 ModelTypeSet requested_types, |
| 162 ModelTypeSet encrypted_types, | 167 ModelTypeSet encrypted_types, |
| 163 bool passphrase_missing, | 168 bool passphrase_missing, |
| 164 const syncable::Directory::Metahandles& unsynced_handles, | 169 const syncable::Directory::Metahandles& unsynced_handles, |
| 165 std::set<int64>* ready_unsynced_set) { | 170 std::set<int64>* ready_unsynced_set) { |
| 166 for (syncable::Directory::Metahandles::const_iterator iter = | 171 for (syncable::Directory::Metahandles::const_iterator iter = |
| 167 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { | 172 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { |
| 168 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); | 173 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); |
| 169 if (IsEntryReadyForCommit(requested_types, | 174 if (IsEntryReadyForCommit(requested_types, |
| 170 encrypted_types, | 175 encrypted_types, |
| 171 passphrase_missing, | 176 passphrase_missing, |
| 172 entry)) { | 177 entry)) { |
| 173 ready_unsynced_set->insert(*iter); | 178 ready_unsynced_set->insert(*iter); |
| 174 } | 179 } |
| 175 } | 180 } |
| 176 } | 181 } |
| 177 | 182 |
| 178 bool GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors( | 183 // This class helps to implement OrderCommitIds(). Its members track the |
| 184 // progress of a traversal while its methods extend it. It can return early if | |
| 185 // the traversal reaches the desired size before the full traversal is complete. | |
| 186 class Traversal { | |
| 187 public: | |
| 188 Traversal( | |
| 179 syncable::BaseTransaction* trans, | 189 syncable::BaseTransaction* trans, |
| 180 const ModelSafeRoutingInfo& routes, | 190 int64 max_entries, |
| 191 syncable::Directory::Metahandles* out); | |
| 192 ~Traversal(); | |
| 193 | |
| 194 // First step of traversal building. Adds non-deleted items in order. | |
| 195 void AddCreatesAndMoves(const std::set<int64>& ready_unsynced_set); | |
| 196 | |
| 197 // Second step of traverals building. Appends deleted items. | |
| 198 void AddDeletes(const std::set<int64>& ready_unsynced_set); | |
| 199 | |
| 200 private: | |
| 201 // The following functions do not modify the traversal directly. They return | |
| 202 // their results in the |result| vector instead. | |
| 203 bool AddUncommittedParentsAndTheirPredecessors( | |
| 204 const std::set<int64>& ready_unsynced_set, | |
| 205 const syncable::Entry& item, | |
| 206 syncable::Directory::Metahandles* result) const; | |
| 207 | |
| 208 void TryAddItem(const std::set<int64>& ready_unsynced_set, | |
| 209 const syncable::Entry& item, | |
| 210 syncable::Directory::Metahandles* result) const; | |
| 211 | |
| 212 void AddItemThenPredecessors( | |
| 213 const std::set<int64>& ready_unsynced_set, | |
| 214 const syncable::Entry& item, | |
| 215 syncable::Directory::Metahandles* result) const; | |
| 216 | |
| 217 void AddPredecessorsThenItem( | |
| 218 const std::set<int64>& ready_unsynced_set, | |
| 219 const syncable::Entry& item, | |
| 220 syncable::Directory::Metahandles* result) const; | |
| 221 | |
| 222 // Returns true if we've collected enough items. | |
| 223 bool IsFull() const; | |
| 224 | |
| 225 // Returns true if the specified handle is already in the traversal. | |
| 226 bool HaveItem(int64 handle) const; | |
| 227 | |
| 228 // Adds the specified handles to the traversal. | |
| 229 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles); | |
| 230 | |
| 231 // Adds the specifed handle to the traversal. | |
| 232 void AppendToTraversal(int64 handle); | |
| 233 | |
| 234 syncable::Directory::Metahandles* out_; | |
| 235 std::set<int64> added_handles_; | |
| 236 const size_t max_entries_; | |
| 237 syncable::BaseTransaction* trans_; | |
| 238 | |
| 239 DISALLOW_COPY_AND_ASSIGN(Traversal); | |
| 240 }; | |
| 241 | |
| 242 Traversal::Traversal( | |
| 243 syncable::BaseTransaction* trans, | |
| 244 int64 max_entries, | |
| 245 syncable::Directory::Metahandles* out) | |
| 246 : out_(out), | |
| 247 max_entries_(max_entries), | |
| 248 trans_(trans) { } | |
| 249 | |
| 250 Traversal::~Traversal() {} | |
| 251 | |
| 252 bool Traversal::AddUncommittedParentsAndTheirPredecessors( | |
| 181 const std::set<int64>& ready_unsynced_set, | 253 const std::set<int64>& ready_unsynced_set, |
| 182 const syncable::Entry& item, | 254 const syncable::Entry& item, |
| 183 sessions::OrderedCommitSet* result) const { | 255 syncable::Directory::Metahandles* result) const { |
| 184 OrderedCommitSet item_dependencies(routes); | 256 syncable::Directory::Metahandles dependencies; |
| 185 syncable::Id parent_id = item.Get(syncable::PARENT_ID); | 257 syncable::Id parent_id = item.Get(syncable::PARENT_ID); |
| 186 | 258 |
| 187 // Climb the tree adding entries leaf -> root. | 259 // Climb the tree adding entries leaf -> root. |
| 188 while (!parent_id.ServerKnows()) { | 260 while (!parent_id.ServerKnows()) { |
| 189 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); | 261 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); |
| 190 CHECK(parent.good()) << "Bad user-only parent in item path."; | 262 CHECK(parent.good()) << "Bad user-only parent in item path."; |
| 191 int64 handle = parent.Get(syncable::META_HANDLE); | 263 int64 handle = parent.Get(syncable::META_HANDLE); |
| 192 if (commit_set_->HaveCommitItem(handle)) { | 264 if (HaveItem(handle)) { |
| 193 // We've already added this parent (and therefore all of its parents). | 265 // We've already added this parent (and therefore all of its parents). |
| 194 // We can return early. | 266 // We can return early. |
| 195 break; | 267 break; |
| 196 } | 268 } |
| 197 if (IsEntryInConflict(parent)) { | 269 if (IsEntryInConflict(parent)) { |
| 198 // We ignore all entries that are children of a conflicing item. Return | 270 // We ignore all entries that are children of a conflicing item. Return |
| 199 // false immediately to forget the traversal we've built up so far. | 271 // false immediately to forget the traversal we've built up so far. |
| 200 DVLOG(1) << "Parent was in conflict, omitting " << item; | 272 DVLOG(1) << "Parent was in conflict, omitting " << item; |
| 201 return false; | 273 return false; |
| 202 } | 274 } |
| 203 AddItemThenPredecessors(trans, | 275 AddItemThenPredecessors(ready_unsynced_set, |
| 204 ready_unsynced_set, | |
| 205 parent, | 276 parent, |
| 206 &item_dependencies); | 277 &dependencies); |
| 207 parent_id = parent.Get(syncable::PARENT_ID); | 278 parent_id = parent.Get(syncable::PARENT_ID); |
| 208 } | 279 } |
| 209 | 280 |
| 210 // Reverse what we added to get the correct order. | 281 // Reverse what we added to get the correct order. |
| 211 result->AppendReverse(item_dependencies); | 282 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 212 return true; | 283 return true; |
| 213 } | 284 } |
| 214 | 285 |
| 215 // Adds the given item to the list if it is unsynced and ready for commit. | 286 // Adds the given item to the list if it is unsynced and ready for commit. |
| 216 void GetCommitIdsCommand::TryAddItem(const std::set<int64>& ready_unsynced_set, | 287 void Traversal::TryAddItem(const std::set<int64>& ready_unsynced_set, |
| 217 const syncable::Entry& item, | 288 const syncable::Entry& item, |
| 218 OrderedCommitSet* result) const { | 289 syncable::Directory::Metahandles* result) const { |
| 219 DCHECK(item.Get(syncable::IS_UNSYNCED)); | 290 DCHECK(item.Get(syncable::IS_UNSYNCED)); |
| 220 int64 item_handle = item.Get(syncable::META_HANDLE); | 291 int64 item_handle = item.Get(syncable::META_HANDLE); |
| 221 if (ready_unsynced_set.count(item_handle) != 0) { | 292 if (ready_unsynced_set.count(item_handle) != 0) { |
| 222 result->AddCommitItem(item_handle, item.GetModelType()); | 293 result->push_back(item_handle); |
| 223 } | 294 } |
| 224 } | 295 } |
| 225 | 296 |
| 226 // Adds the given item, and all its unsynced predecessors. The traversal will | 297 // Adds the given item, and all its unsynced predecessors. The traversal will |
| 227 // be cut short if any item along the traversal is not IS_UNSYNCED, or if we | 298 // be cut short if any item along the traversal is not IS_UNSYNCED, or if we |
| 228 // detect that this area of the tree has already been traversed. Items that are | 299 // detect that this area of the tree has already been traversed. Items that are |
| 229 // not 'ready' for commit (see IsEntryReadyForCommit()) will not be added to the | 300 // not 'ready' for commit (see IsEntryReadyForCommit()) will not be added to the |
| 230 // list, though they will not stop the traversal. | 301 // list, though they will not stop the traversal. |
| 231 void GetCommitIdsCommand::AddItemThenPredecessors( | 302 void Traversal::AddItemThenPredecessors( |
| 232 syncable::BaseTransaction* trans, | |
| 233 const std::set<int64>& ready_unsynced_set, | 303 const std::set<int64>& ready_unsynced_set, |
| 234 const syncable::Entry& item, | 304 const syncable::Entry& item, |
| 235 OrderedCommitSet* result) const { | 305 syncable::Directory::Metahandles* result) const { |
| 236 int64 item_handle = item.Get(syncable::META_HANDLE); | 306 int64 item_handle = item.Get(syncable::META_HANDLE); |
| 237 if (commit_set_->HaveCommitItem(item_handle)) { | 307 if (HaveItem(item_handle)) { |
| 238 // We've already added this item to the commit set, and so must have | 308 // We've already added this item to the commit set, and so must have |
| 239 // already added the predecessors as well. | 309 // already added the predecessors as well. |
| 240 return; | 310 return; |
| 241 } | 311 } |
| 242 TryAddItem(ready_unsynced_set, item, result); | 312 TryAddItem(ready_unsynced_set, item, result); |
| 243 if (item.Get(syncable::IS_DEL)) | 313 if (item.Get(syncable::IS_DEL)) |
| 244 return; // Deleted items have no predecessors. | 314 return; // Deleted items have no predecessors. |
| 245 | 315 |
| 246 syncable::Id prev_id = item.GetPredecessorId(); | 316 syncable::Id prev_id = item.GetPredecessorId(); |
| 247 while (!prev_id.IsRoot()) { | 317 while (!prev_id.IsRoot()) { |
| 248 syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id); | 318 syncable::Entry prev(trans_, syncable::GET_BY_ID, prev_id); |
| 249 CHECK(prev.good()) << "Bad id when walking predecessors."; | 319 CHECK(prev.good()) << "Bad id when walking predecessors."; |
| 250 if (!prev.Get(syncable::IS_UNSYNCED)) { | 320 if (!prev.Get(syncable::IS_UNSYNCED)) { |
| 251 // We're interested in "runs" of unsynced items. This item breaks | 321 // We're interested in "runs" of unsynced items. This item breaks |
| 252 // the streak, so we stop traversing. | 322 // the streak, so we stop traversing. |
| 253 return; | 323 return; |
| 254 } | 324 } |
| 255 int64 handle = prev.Get(syncable::META_HANDLE); | 325 int64 handle = prev.Get(syncable::META_HANDLE); |
| 256 if (commit_set_->HaveCommitItem(handle)) { | 326 if (HaveItem(handle)) { |
| 257 // We've already added this item to the commit set, and so must have | 327 // We've already added this item to the commit set, and so must have |
| 258 // already added the predecessors as well. | 328 // already added the predecessors as well. |
| 259 return; | 329 return; |
| 260 } | 330 } |
| 261 TryAddItem(ready_unsynced_set, prev, result); | 331 TryAddItem(ready_unsynced_set, prev, result); |
| 262 prev_id = prev.GetPredecessorId(); | 332 prev_id = prev.GetPredecessorId(); |
| 263 } | 333 } |
| 264 } | 334 } |
| 265 | 335 |
| 266 // Same as AddItemThenPredecessor, but the traversal order will be reversed. | 336 // Same as AddItemThenPredecessor, but the traversal order will be reversed. |
| 267 void GetCommitIdsCommand::AddPredecessorsThenItem( | 337 void Traversal::AddPredecessorsThenItem( |
| 268 syncable::BaseTransaction* trans, | |
| 269 const ModelSafeRoutingInfo& routes, | |
| 270 const std::set<int64>& ready_unsynced_set, | 338 const std::set<int64>& ready_unsynced_set, |
| 271 const syncable::Entry& item, | 339 const syncable::Entry& item, |
| 272 OrderedCommitSet* result) const { | 340 syncable::Directory::Metahandles* result) const { |
| 273 OrderedCommitSet item_dependencies(routes); | 341 syncable::Directory::Metahandles dependencies; |
| 274 AddItemThenPredecessors(trans, ready_unsynced_set, item, &item_dependencies); | 342 AddItemThenPredecessors(ready_unsynced_set, item, &dependencies); |
| 275 | 343 |
| 276 // Reverse what we added to get the correct order. | 344 // Reverse what we added to get the correct order. |
| 277 result->AppendReverse(item_dependencies); | 345 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 278 } | 346 } |
| 279 | 347 |
| 280 bool GetCommitIdsCommand::IsCommitBatchFull() const { | 348 bool Traversal::IsFull() const { |
| 281 return commit_set_->Size() >= requested_commit_batch_size_; | 349 return out_->size() >= max_entries_; |
| 282 } | 350 } |
| 283 | 351 |
| 284 void GetCommitIdsCommand::AddCreatesAndMoves( | 352 bool Traversal::HaveItem(int64 handle) const { |
| 285 syncable::BaseTransaction* trans, | 353 return added_handles_.find(handle) != added_handles_.end(); |
| 286 const ModelSafeRoutingInfo& routes, | 354 } |
| 355 | |
| 356 void Traversal::AppendManyToTraversal( | |
| 357 const syncable::Directory::Metahandles& handles) { | |
| 358 out_->insert(out_->end(), handles.begin(), handles.end()); | |
| 359 added_handles_.insert(handles.begin(), handles.end()); | |
| 360 } | |
| 361 | |
| 362 void Traversal::AppendToTraversal(int64 metahandle) { | |
| 363 out_->push_back(metahandle); | |
| 364 added_handles_.insert(metahandle); | |
| 365 } | |
| 366 | |
| 367 void Traversal::AddCreatesAndMoves( | |
| 287 const std::set<int64>& ready_unsynced_set) { | 368 const std::set<int64>& ready_unsynced_set) { |
| 288 // Add moves and creates, and prepend their uncommitted parents. | 369 // Add moves and creates, and prepend their uncommitted parents. |
| 289 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 370 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
| 290 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 371 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
| 291 int64 metahandle = *iter; | 372 int64 metahandle = *iter; |
| 292 if (commit_set_->HaveCommitItem(metahandle)) | 373 if (HaveItem(metahandle)) |
| 293 continue; | 374 continue; |
| 294 | 375 |
| 295 syncable::Entry entry(trans, | 376 syncable::Entry entry(trans_, |
| 296 syncable::GET_BY_HANDLE, | 377 syncable::GET_BY_HANDLE, |
| 297 metahandle); | 378 metahandle); |
| 298 if (!entry.Get(syncable::IS_DEL)) { | 379 if (!entry.Get(syncable::IS_DEL)) { |
| 299 // We only commit an item + its dependencies if it and all its | 380 // We only commit an item + its dependencies if it and all its |
| 300 // dependencies are not in conflict. | 381 // dependencies are not in conflict. |
| 301 OrderedCommitSet item_dependencies(routes); | 382 syncable::Directory::Metahandles item_dependencies; |
| 302 if (AddUncommittedParentsAndTheirPredecessors( | 383 if (AddUncommittedParentsAndTheirPredecessors( |
| 303 trans, | |
| 304 routes, | |
| 305 ready_unsynced_set, | 384 ready_unsynced_set, |
| 306 entry, | 385 entry, |
| 307 &item_dependencies)) { | 386 &item_dependencies)) { |
| 308 AddPredecessorsThenItem(trans, | 387 AddPredecessorsThenItem(ready_unsynced_set, |
| 309 routes, | |
| 310 ready_unsynced_set, | |
| 311 entry, | 388 entry, |
| 312 &item_dependencies); | 389 &item_dependencies); |
| 313 commit_set_->Append(item_dependencies); | 390 AppendManyToTraversal(item_dependencies); |
| 314 } | 391 } |
| 315 } | 392 } |
| 316 } | 393 } |
| 317 | 394 |
| 318 // It's possible that we overcommitted while trying to expand dependent | 395 // It's possible that we overcommitted while trying to expand dependent |
| 319 // items. If so, truncate the set down to the allowed size. | 396 // items. If so, truncate the set down to the allowed size. |
| 320 commit_set_->Truncate(requested_commit_batch_size_); | 397 if (out_->size() > max_entries_) { |
| 398 out_->resize(max_entries_); | |
| 399 } | |
| 321 } | 400 } |
| 322 | 401 |
| 323 void GetCommitIdsCommand::AddDeletes( | 402 void Traversal::AddDeletes( |
| 324 syncable::BaseTransaction* trans, | |
| 325 const std::set<int64>& ready_unsynced_set) { | 403 const std::set<int64>& ready_unsynced_set) { |
| 326 set<syncable::Id> legal_delete_parents; | 404 set<syncable::Id> legal_delete_parents; |
| 327 | 405 |
| 328 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 406 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
| 329 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 407 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
| 330 int64 metahandle = *iter; | 408 int64 metahandle = *iter; |
| 331 if (commit_set_->HaveCommitItem(metahandle)) | 409 if (HaveItem(metahandle)) |
| 332 continue; | 410 continue; |
| 333 | 411 |
| 334 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, | 412 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, |
| 335 metahandle); | 413 metahandle); |
| 336 | 414 |
| 337 if (entry.Get(syncable::IS_DEL)) { | 415 if (entry.Get(syncable::IS_DEL)) { |
| 338 syncable::Entry parent(trans, syncable::GET_BY_ID, | 416 syncable::Entry parent(trans_, syncable::GET_BY_ID, |
| 339 entry.Get(syncable::PARENT_ID)); | 417 entry.Get(syncable::PARENT_ID)); |
| 340 // If the parent is deleted and unsynced, then any children of that | 418 // If the parent is deleted and unsynced, then any children of that |
| 341 // parent don't need to be added to the delete queue. | 419 // parent don't need to be added to the delete queue. |
| 342 // | 420 // |
| 343 // Note: the parent could be synced if there was an update deleting a | 421 // Note: the parent could be synced if there was an update deleting a |
| 344 // folder when we had a deleted all items in it. | 422 // folder when we had a deleted all items in it. |
| 345 // We may get more updates, or we may want to delete the entry. | 423 // We may get more updates, or we may want to delete the entry. |
| 346 if (parent.good() && | 424 if (parent.good() && |
| 347 parent.Get(syncable::IS_DEL) && | 425 parent.Get(syncable::IS_DEL) && |
| 348 parent.Get(syncable::IS_UNSYNCED)) { | 426 parent.Get(syncable::IS_UNSYNCED)) { |
| 349 // However, if an entry is moved, these rules can apply differently. | 427 // However, if an entry is moved, these rules can apply differently. |
| 350 // | 428 // |
| 351 // If the entry was moved, then the destination parent was deleted, | 429 // If the entry was moved, then the destination parent was deleted, |
| 352 // then we'll miss it in the roll up. We have to add it in manually. | 430 // then we'll miss it in the roll up. We have to add it in manually. |
| 353 // TODO(chron): Unit test for move / delete cases: | 431 // TODO(chron): Unit test for move / delete cases: |
| 354 // Case 1: Locally moved, then parent deleted | 432 // Case 1: Locally moved, then parent deleted |
| 355 // Case 2: Server moved, then locally issue recursive delete. | 433 // Case 2: Server moved, then locally issue recursive delete. |
| 356 if (entry.Get(syncable::ID).ServerKnows() && | 434 if (entry.Get(syncable::ID).ServerKnows() && |
| 357 entry.Get(syncable::PARENT_ID) != | 435 entry.Get(syncable::PARENT_ID) != |
| 358 entry.Get(syncable::SERVER_PARENT_ID)) { | 436 entry.Get(syncable::SERVER_PARENT_ID)) { |
| 359 DVLOG(1) << "Inserting moved and deleted entry, will be missed by " | 437 DVLOG(1) << "Inserting moved and deleted entry, will be missed by " |
| 360 << "delete roll." << entry.Get(syncable::ID); | 438 << "delete roll." << entry.Get(syncable::ID); |
| 361 | 439 |
| 362 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); | 440 AppendToTraversal(metahandle); |
| 363 } | 441 } |
| 364 | 442 |
| 365 // Skip this entry since it's a child of a parent that will be | 443 // Skip this entry since it's a child of a parent that will be |
| 366 // deleted. The server will unroll the delete and delete the | 444 // deleted. The server will unroll the delete and delete the |
| 367 // child as well. | 445 // child as well. |
| 368 continue; | 446 continue; |
| 369 } | 447 } |
| 370 | 448 |
| 371 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID)); | 449 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID)); |
| 372 } | 450 } |
| 373 } | 451 } |
| 374 | 452 |
| 375 // We could store all the potential entries with a particular parent during | 453 // We could store all the potential entries with a particular parent during |
| 376 // the above scan, but instead we rescan here. This is less efficient, but | 454 // the above scan, but instead we rescan here. This is less efficient, but |
| 377 // we're dropping memory alloc/dealloc in favor of linear scans of recently | 455 // we're dropping memory alloc/dealloc in favor of linear scans of recently |
| 378 // examined entries. | 456 // examined entries. |
| 379 // | 457 // |
| 380 // Scan through the UnsyncedMetaHandles again. If we have a deleted | 458 // Scan through the UnsyncedMetaHandles again. If we have a deleted |
| 381 // entry, then check if the parent is in legal_delete_parents. | 459 // entry, then check if the parent is in legal_delete_parents. |
| 382 // | 460 // |
| 383 // Parent being in legal_delete_parents means for the child: | 461 // Parent being in legal_delete_parents means for the child: |
| 384 // a recursive delete is not currently happening (no recent deletes in same | 462 // a recursive delete is not currently happening (no recent deletes in same |
| 385 // folder) | 463 // folder) |
| 386 // parent did expect at least one old deleted child | 464 // parent did expect at least one old deleted child |
| 387 // parent was not deleted | 465 // parent was not deleted |
| 388 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 466 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
| 389 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 467 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
| 390 int64 metahandle = *iter; | 468 int64 metahandle = *iter; |
| 391 if (commit_set_->HaveCommitItem(metahandle)) | 469 if (HaveItem(metahandle)) |
| 392 continue; | 470 continue; |
| 393 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, | 471 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, |
| 394 metahandle); | 472 metahandle); |
| 395 if (entry.Get(syncable::IS_DEL)) { | 473 if (entry.Get(syncable::IS_DEL)) { |
| 396 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); | 474 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); |
| 397 if (legal_delete_parents.count(parent_id)) { | 475 if (legal_delete_parents.count(parent_id)) { |
| 398 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); | 476 AppendToTraversal(metahandle); |
| 399 } | 477 } |
| 400 } | 478 } |
| 401 } | 479 } |
| 402 } | 480 } |
| 403 | 481 |
| 404 void GetCommitIdsCommand::BuildCommitIds( | 482 // Given a set of commit metahandles that are ready for commit |
| 483 // (|ready_unsynced_set|), sorts these into commit order and places up to | |
| 484 // |max_entries| of them in the output parameter |out|. | |
| 485 // | |
| 486 // In "commit order", the metahandles are ordered so that parents are before | |
| 487 // children, and predecessors are before successors. Deletions are always | |
| 488 // placed last. | |
|
tim (not reviewing)
2013/09/08 19:48:20
Wouldn't hurt to put this in the header file where
rlarocque
2013/09/09 17:41:29
Done.
| |
| 489 // | |
| 490 // Since the implementation of UniquePositions, it is probably no longer | |
|
tim (not reviewing)
2013/09/08 19:48:20
nit - It's better to succinctly state why things w
rlarocque
2013/09/09 17:41:29
I don't think it can be avoided in this case. The
| |
| 491 // necessary to put predecessors before successors. That functionality may be | |
| 492 // removed in the future. | |
|
tim (not reviewing)
2013/09/08 19:48:20
nit - bug or todo for things that "may be removed
rlarocque
2013/09/09 17:41:29
Done.
| |
| 493 void OrderCommitIds( | |
| 405 syncable::BaseTransaction* trans, | 494 syncable::BaseTransaction* trans, |
| 406 const ModelSafeRoutingInfo& routes, | 495 size_t max_entries, |
| 407 const std::set<int64>& ready_unsynced_set) { | 496 const std::set<int64>& ready_unsynced_set, |
| 497 syncable::Directory::Metahandles* out) { | |
| 408 // Commits follow these rules: | 498 // Commits follow these rules: |
| 409 // 1. Moves or creates are preceded by needed folder creates, from | 499 // 1. Moves or creates are preceded by needed folder creates, from |
| 410 // root to leaf. For folders whose contents are ordered, moves | 500 // root to leaf. For folders whose contents are ordered, moves |
| 411 // and creates appear in order. | 501 // and creates appear in order. |
| 412 // 2. Moves/Creates before deletes. | 502 // 2. Moves/Creates before deletes. |
| 413 // 3. Deletes, collapsed. | 503 // 3. Deletes, collapsed. |
| 414 // We commit deleted moves under deleted items as moves when collapsing | 504 // We commit deleted moves under deleted items as moves when collapsing |
| 415 // delete trees. | 505 // delete trees. |
| 416 | 506 |
| 507 Traversal traversal(trans, max_entries, out); | |
| 508 | |
| 417 // Add moves and creates, and prepend their uncommitted parents. | 509 // Add moves and creates, and prepend their uncommitted parents. |
| 418 AddCreatesAndMoves(trans, routes, ready_unsynced_set); | 510 traversal.AddCreatesAndMoves(ready_unsynced_set); |
| 419 | 511 |
| 420 // Add all deletes. | 512 // Add all deletes. |
| 421 AddDeletes(trans, ready_unsynced_set); | 513 traversal.AddDeletes(ready_unsynced_set); |
| 514 } | |
| 515 | |
| 516 } // namespace | |
| 517 | |
| 518 void GetCommitIds( | |
| 519 syncable::BaseTransaction* trans, | |
| 520 ModelTypeSet requested_types, | |
| 521 size_t commit_batch_size, | |
| 522 sessions::OrderedCommitSet* ordered_commit_set) { | |
| 523 for (ModelTypeSet::Iterator it = requested_types.First(); | |
| 524 it.Good(); it.Inc()) { | |
| 525 DCHECK_LE(ordered_commit_set->Size(), commit_batch_size); | |
| 526 if (ordered_commit_set->Size() >= commit_batch_size) | |
| 527 break; | |
| 528 size_t space_remaining = commit_batch_size - ordered_commit_set->Size(); | |
| 529 syncable::Directory::Metahandles out; | |
| 530 GetCommitIdsForType( | |
| 531 trans, | |
| 532 it.Get(), | |
| 533 space_remaining, | |
| 534 &out); | |
| 535 ordered_commit_set->AddCommitItems(out, it.Get()); | |
| 536 } | |
| 422 } | 537 } |
| 423 | 538 |
| 424 } // namespace syncer | 539 } // namespace syncer |
| OLD | NEW |