Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "components/sync/engine_impl/get_commit_ids.h" | 5 #include "components/sync/engine_impl/get_commit_ids.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "components/sync/base/cryptographer.h" | 10 #include "components/sync/base/cryptographer.h" |
| 11 #include "components/sync/engine_impl/syncer_util.h" | 11 #include "components/sync/engine_impl/syncer_util.h" |
| 12 #include "components/sync/syncable/entry.h" | 12 #include "components/sync/syncable/entry.h" |
| 13 #include "components/sync/syncable/nigori_handler.h" | 13 #include "components/sync/syncable/nigori_handler.h" |
| 14 #include "components/sync/syncable/nigori_util.h" | 14 #include "components/sync/syncable/nigori_util.h" |
| 15 #include "components/sync/syncable/syncable_base_transaction.h" | 15 #include "components/sync/syncable/syncable_base_transaction.h" |
| 16 #include "components/sync/syncable/syncable_util.h" | 16 #include "components/sync/syncable/syncable_util.h" |
| 17 | 17 |
| 18 using std::set; | 18 namespace syncer { |
| 19 using std::vector; | |
| 20 | 19 |
| 21 namespace syncer { | 20 using syncable::Directory; |
| 21 using syncable::Entry; | |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 // Forward-declare some helper functions. This gives us more options for | 25 bool IsEntryInConflict(const Entry& entry) { |
| 26 // ordering the function defintions within this file. | |
| 27 | |
| 28 // Filters |unsynced_handles| to remove all entries that do not belong to the | |
| 29 // specified |requested_types|, or are not eligible for a commit at this time. | |
| 30 void FilterUnreadyEntries( | |
| 31 syncable::BaseTransaction* trans, | |
| 32 ModelTypeSet requested_types, | |
| 33 ModelTypeSet encrypted_types, | |
| 34 bool passphrase_missing, | |
| 35 const syncable::Directory::Metahandles& unsynced_handles, | |
| 36 std::set<int64_t>* ready_unsynced_set); | |
| 37 | |
| 38 // Given a set of commit metahandles that are ready for commit | |
| 39 // (|ready_unsynced_set|), sorts these into commit order and places up to | |
| 40 // |max_entries| of them in the output parameter |out|. | |
| 41 // | |
| 42 // See the header file for an explanation of commit ordering. | |
| 43 void OrderCommitIds(syncable::BaseTransaction* trans, | |
| 44 size_t max_entries, | |
| 45 const std::set<int64_t>& ready_unsynced_set, | |
| 46 std::vector<int64_t>* out); | |
| 47 | |
| 48 } // namespace | |
| 49 | |
| 50 void GetCommitIdsForType(syncable::BaseTransaction* trans, | |
| 51 ModelType type, | |
| 52 size_t max_entries, | |
| 53 syncable::Directory::Metahandles* out) { | |
| 54 syncable::Directory* dir = trans->directory(); | |
| 55 | |
| 56 // Gather the full set of unsynced items and store it in the cycle. They | |
| 57 // are not in the correct order for commit. | |
| 58 std::set<int64_t> ready_unsynced_set; | |
| 59 syncable::Directory::Metahandles all_unsynced_handles; | |
| 60 GetUnsyncedEntries(trans, &all_unsynced_handles); | |
| 61 | |
| 62 ModelTypeSet encrypted_types; | |
| 63 bool passphrase_missing = false; | |
| 64 Cryptographer* cryptographer = dir->GetCryptographer(trans); | |
| 65 if (cryptographer) { | |
| 66 encrypted_types = dir->GetNigoriHandler()->GetEncryptedTypes(trans); | |
| 67 passphrase_missing = cryptographer->has_pending_keys(); | |
| 68 } | |
| 69 | |
| 70 // We filter out all unready entries from the set of unsynced handles. This | |
| 71 // new set of ready and unsynced items is then what we use to determine what | |
| 72 // is a candidate for commit. The caller is responsible for ensuring that no | |
| 73 // throttled types are included among the requested_types. | |
| 74 FilterUnreadyEntries(trans, ModelTypeSet(type), encrypted_types, | |
| 75 passphrase_missing, all_unsynced_handles, | |
| 76 &ready_unsynced_set); | |
| 77 | |
| 78 OrderCommitIds(trans, max_entries, ready_unsynced_set, out); | |
| 79 | |
| 80 for (size_t i = 0; i < out->size(); i++) { | |
| 81 DVLOG(1) << "Debug commit batch result:" << (*out)[i]; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 namespace { | |
| 86 | |
| 87 bool IsEntryInConflict(const syncable::Entry& entry) { | |
| 88 if (entry.GetIsUnsynced() && entry.GetServerVersion() > 0 && | 26 if (entry.GetIsUnsynced() && entry.GetServerVersion() > 0 && |
| 89 (entry.GetServerVersion() > entry.GetBaseVersion())) { | 27 (entry.GetServerVersion() > entry.GetBaseVersion())) { |
| 90 // The local and server versions don't match. The item must be in | 28 // The local and server versions don't match. The item must be in |
| 91 // conflict, so there's no point in attempting to commit. | 29 // conflict, so there's no point in attempting to commit. |
| 92 DCHECK(entry.GetIsUnappliedUpdate()); | 30 DCHECK(entry.GetIsUnappliedUpdate()); |
| 93 DVLOG(1) << "Excluding entry from commit due to version mismatch " << entry; | 31 DVLOG(1) << "Excluding entry from commit due to version mismatch " << entry; |
| 94 return true; | 32 return true; |
| 95 } | 33 } |
| 96 return false; | 34 return false; |
| 97 } | 35 } |
| 98 | 36 |
| 99 // Return true if this entry has any attachments that haven't yet been uploaded | 37 // Return true if this entry has any attachments that haven't yet been uploaded |
| 100 // to the server. | 38 // to the server. |
| 101 bool HasAttachmentNotOnServer(const syncable::Entry& entry) { | 39 bool HasAttachmentNotOnServer(const Entry& entry) { |
| 102 const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata(); | 40 const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata(); |
| 103 for (int i = 0; i < metadata.record_size(); ++i) { | 41 for (int i = 0; i < metadata.record_size(); ++i) { |
| 104 if (!metadata.record(i).is_on_server()) { | 42 if (!metadata.record(i).is_on_server()) { |
| 105 return true; | 43 return true; |
| 106 } | 44 } |
| 107 } | 45 } |
| 108 return false; | 46 return false; |
| 109 } | 47 } |
| 110 | 48 |
| 111 // An entry may not commit if any are true: | 49 // An entry may not commit if any are true: |
| 112 // 1. It requires encryption (either the type is encrypted but a passphrase | 50 // 1. It requires encryption (either the type is encrypted but a passphrase |
| 113 // is missing from the cryptographer, or the entry itself wasn't properly | 51 // is missing from the cryptographer, or the entry itself wasn't properly |
| 114 // encrypted). | 52 // encrypted). |
| 115 // 2. It's type is currently throttled. | 53 // 2. It's type is currently throttled. |
| 116 // 3. It's a delete but has not been committed. | 54 // 3. It's a delete but has not been committed. |
| 117 bool MayEntryCommit(ModelTypeSet requested_types, | 55 bool MayEntryCommit(ModelTypeSet requested_types, |
| 118 ModelTypeSet encrypted_types, | 56 ModelTypeSet encrypted_types, |
| 119 bool passphrase_missing, | 57 bool passphrase_missing, |
| 120 const syncable::Entry& entry) { | 58 const Entry& entry) { |
| 121 DCHECK(entry.GetIsUnsynced()); | 59 DCHECK(entry.GetIsUnsynced()); |
| 122 | 60 |
| 123 const ModelType type = entry.GetModelType(); | 61 const ModelType type = entry.GetModelType(); |
| 124 // We special case the nigori node because even though it is considered an | 62 // We special case the nigori node because even though it is considered an |
| 125 // "encrypted type", not all nigori node changes require valid encryption | 63 // "encrypted type", not all nigori node changes require valid encryption |
| 126 // (ex: sync_tabs). | 64 // (ex: sync_tabs). |
| 127 if ((type != NIGORI) && encrypted_types.Has(type) && | 65 if ((type != NIGORI) && encrypted_types.Has(type) && |
| 128 (passphrase_missing || | 66 (passphrase_missing || EntryNeedsEncryption(encrypted_types, entry))) { |
| 129 syncable::EntryNeedsEncryption(encrypted_types, entry))) { | |
|
pavely
2017/04/17 19:22:20
This change works because of ADL. It expands set o
skym
2017/04/17 20:22:43
Whoops, a casualty of search and replace. Added it
| |
| 130 // This entry requires encryption but is not properly encrypted (possibly | 67 // This entry requires encryption but is not properly encrypted (possibly |
| 131 // due to the cryptographer not being initialized or the user hasn't | 68 // due to the cryptographer not being initialized or the user hasn't |
| 132 // provided the most recent passphrase). | 69 // provided the most recent passphrase). |
| 133 DVLOG(1) << "Excluding entry from commit due to lack of encryption " | 70 DVLOG(1) << "Excluding entry from commit due to lack of encryption " |
| 134 << entry; | 71 << entry; |
| 135 return false; | 72 return false; |
| 136 } | 73 } |
| 137 | 74 |
| 138 // Ignore it if it's not in our set of requested types. | 75 // Ignore it if it's not in our set of requested types. |
| 139 if (!requested_types.Has(type)) | 76 if (!requested_types.Has(type)) |
| 140 return false; | 77 return false; |
| 141 | 78 |
| 142 if (entry.GetIsDel() && !entry.GetId().ServerKnows()) { | 79 if (entry.GetIsDel() && !entry.GetId().ServerKnows()) { |
| 143 // New clients (following the resolution of crbug.com/125381) should not | 80 // New clients (following the resolution of crbug.com/125381) should not |
| 144 // create such items. Old clients may have left some in the database | 81 // create such items. Old clients may have left some in the database |
| 145 // (crbug.com/132905), but we should now be cleaning them on startup. | 82 // (crbug.com/132905), but we should now be cleaning them on startup. |
| 146 NOTREACHED() << "Found deleted and unsynced local item: " << entry; | 83 NOTREACHED() << "Found deleted and unsynced local item: " << entry; |
| 147 return false; | 84 return false; |
| 148 } | 85 } |
| 149 | 86 |
| 150 // Extra validity checks. | 87 // Extra validity checks. |
| 151 syncable::Id id = entry.GetId(); | 88 syncable::Id id = entry.GetId(); |
| 152 if (id == entry.GetParentId()) { | 89 if (id == entry.GetParentId()) { |
| 153 CHECK(id.IsRoot()) << "Non-root item is self parenting." << entry; | 90 CHECK(id.IsRoot()) << "Non-root item is self parenting." << entry; |
| 154 // If the root becomes unsynced it can cause us problems. | 91 // If the root becomes unsynced it can cause us problems. |
| 155 NOTREACHED() << "Root item became unsynced " << entry; | 92 NOTREACHED() << "Root item became unsynced " << entry; |
| 156 return false; | 93 return false; |
| 157 } | 94 } |
| 158 | 95 |
| 159 if (entry.IsRoot()) { | 96 if (entry.IsRoot()) { |
| 160 NOTREACHED() << "Permanent item became unsynced " << entry; | 97 NOTREACHED() << "Permanent item became unsynced " << entry; |
| 161 return false; | 98 return false; |
| 162 } | 99 } |
| 163 | 100 |
| 164 if (HasAttachmentNotOnServer(entry)) { | 101 if (HasAttachmentNotOnServer(entry)) { |
| 165 // This entry is not ready to be sent to the server because it has one or | 102 // This entry is not ready to be sent to the server because it has one or |
| 166 // more attachments that have not yet been uploaded to the server. The idea | 103 // more attachments that have not yet been uploaded to the server. The idea |
| 167 // here is avoid propagating an entry with dangling attachment references. | 104 // here is avoid propagating an entry with dangling attachment references. |
| 168 return false; | 105 return false; |
| 169 } | 106 } |
| 170 | 107 |
| 171 DVLOG(2) << "Entry is ready for commit: " << entry; | 108 DVLOG(2) << "Entry is ready for commit: " << entry; |
| 172 return true; | 109 return true; |
| 173 } | 110 } |
| 174 | 111 |
| 175 bool SupportsHierarchy(const syncable::Entry& item) { | 112 bool SupportsHierarchy(const Entry& item) { |
| 176 // Types with explicit server supported hierarchy only. | 113 // Types with explicit server supported hierarchy only. |
| 177 return IsTypeWithServerGeneratedRoot(item.GetModelType()); | 114 return IsTypeWithServerGeneratedRoot(item.GetModelType()); |
| 178 } | 115 } |
| 179 | 116 |
| 180 // Excludes ancestors of deleted conflicted items from | |
| 181 // |ready_unsynced_set|. | |
| 182 void ExcludeDeletedAncestors( | |
| 183 syncable::BaseTransaction* trans, | |
| 184 const std::vector<int64_t>& deleted_conflicted_items, | |
| 185 std::set<int64_t>* ready_unsynced_set) { | |
| 186 for (auto iter = deleted_conflicted_items.begin(); | |
| 187 iter != deleted_conflicted_items.end(); ++iter) { | |
| 188 syncable::Entry item(trans, syncable::GET_BY_HANDLE, *iter); | |
| 189 syncable::Id parent_id = item.GetParentId(); | |
| 190 DCHECK(!parent_id.IsNull()); | |
| 191 | |
| 192 while (!parent_id.IsRoot()) { | |
| 193 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); | |
| 194 CHECK(parent.good()) << "Bad user-only parent in item path."; | |
| 195 int64_t handle = parent.GetMetahandle(); | |
| 196 | |
| 197 if (!parent.GetIsDel()) | |
| 198 break; | |
| 199 | |
| 200 auto ready_iter = ready_unsynced_set->find(handle); | |
| 201 if (ready_iter == ready_unsynced_set->end()) | |
| 202 break; | |
| 203 | |
| 204 // Remove this entry from |ready_unsynced_set|. | |
| 205 ready_unsynced_set->erase(ready_iter); | |
| 206 parent_id = parent.GetParentId(); | |
| 207 } | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 // Iterates over children of items from |conflicted_items| list that are in | 117 // Iterates over children of items from |conflicted_items| list that are in |
| 212 // |ready_unsynced_set|, exludes them from |ready_unsynced_set| and adds them | 118 // |ready_unsynced_set|, excludes them from |ready_unsynced_set| and adds them |
| 213 // to |excluded_items| list. | 119 // to |excluded_items| list. |
| 214 void ExcludeChildren(syncable::BaseTransaction* trans, | 120 void ExcludeChildren(syncable::BaseTransaction* trans, |
| 215 const std::vector<int64_t>& conflicted_items, | 121 const std::vector<int64_t>& conflicted_items, |
| 216 std::vector<int64_t>* excluded_items, | 122 std::vector<int64_t>* excluded_items, |
| 217 std::set<int64_t>* ready_unsynced_set) { | 123 std::set<int64_t>* ready_unsynced_set) { |
| 218 for (auto iter = conflicted_items.begin(); iter != conflicted_items.end(); | 124 for (const int64_t& handle : conflicted_items) { |
| 219 ++iter) { | 125 Entry entry(trans, syncable::GET_BY_HANDLE, handle); |
| 220 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); | |
| 221 | 126 |
| 222 if (!entry.GetIsDir() || entry.GetIsDel()) | 127 if (!entry.GetIsDir() || entry.GetIsDel()) |
| 223 continue; | 128 continue; |
| 224 | 129 |
| 225 std::vector<int64_t> children; | 130 std::vector<int64_t> children; |
| 226 entry.GetChildHandles(&children); | 131 entry.GetChildHandles(&children); |
| 227 | 132 |
| 228 for (std::vector<int64_t>::const_iterator child_iter = children.begin(); | 133 for (const int64_t& child_handle : children) { |
| 229 child_iter != children.end(); ++child_iter) { | |
| 230 // Collect all child handles that are in |ready_unsynced_set|. | 134 // Collect all child handles that are in |ready_unsynced_set|. |
| 231 int64_t child_handle = *child_iter; | |
| 232 auto ready_iter = ready_unsynced_set->find(child_handle); | 135 auto ready_iter = ready_unsynced_set->find(child_handle); |
| 233 if (ready_iter != ready_unsynced_set->end()) { | 136 if (ready_iter != ready_unsynced_set->end()) { |
| 234 // Remove this entry from |ready_unsynced_set| and add it | 137 // Remove this entry from |ready_unsynced_set| and add it |
| 235 // to |excluded_items|. | 138 // to |excluded_items|. |
| 236 ready_unsynced_set->erase(ready_iter); | 139 ready_unsynced_set->erase(ready_iter); |
| 237 excluded_items->push_back(child_handle); | 140 excluded_items->push_back(child_handle); |
| 238 } | 141 } |
| 239 } | 142 } |
| 240 } | 143 } |
| 241 } | 144 } |
| 242 | 145 |
| 243 // Filters |unsynced_handles| to remove all entries that do not belong to the | 146 // This class helps to implement OrderCommitIds(). Its members track the |
| 244 // specified |requested_types|, or are not eligible for a commit at this time. | 147 // progress of a traversal while its methods extend it. It can return early if |
| 245 void FilterUnreadyEntries( | |
| 246 syncable::BaseTransaction* trans, | |
| 247 ModelTypeSet requested_types, | |
| 248 ModelTypeSet encrypted_types, | |
| 249 bool passphrase_missing, | |
| 250 const syncable::Directory::Metahandles& unsynced_handles, | |
| 251 std::set<int64_t>* ready_unsynced_set) { | |
| 252 std::vector<int64_t> deleted_conflicted_items; | |
| 253 std::vector<int64_t> conflicted_items; | |
| 254 | |
| 255 // Go over all unsynced handles, filter the ones that might be committed based | |
| 256 // on type / encryption, then based on whether they are in conflict add them | |
| 257 // to either |ready_unsynced_set| or one of the conflicted lists. | |
| 258 for (auto iter = unsynced_handles.begin(); iter != unsynced_handles.end(); | |
| 259 ++iter) { | |
| 260 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); | |
| 261 // TODO(maniscalco): While we check if entry is ready to be committed, we | |
| 262 // also need to check that all of its ancestors (parents, transitive) are | |
| 263 // ready to be committed. Once attachments can prevent an entry from being | |
| 264 // committable, this method must ensure all ancestors are ready for commit | |
| 265 // (bug 356273). | |
| 266 if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing, | |
| 267 entry)) { | |
| 268 if (IsEntryInConflict(entry)) { | |
| 269 // Conflicting hierarchical entries might prevent their ancestors or | |
| 270 // descendants from being committed. | |
| 271 if (SupportsHierarchy(entry)) { | |
| 272 if (entry.GetIsDel()) { | |
| 273 deleted_conflicted_items.push_back(*iter); | |
| 274 } else if (entry.GetIsDir()) { | |
| 275 // Populate the initial version of |conflicted_items| with folder | |
| 276 // items that are in conflict. | |
| 277 conflicted_items.push_back(*iter); | |
| 278 } | |
| 279 } | |
| 280 } else { | |
| 281 ready_unsynced_set->insert(*iter); | |
| 282 } | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 // If there are any deleted conflicted entries, remove their deleted ancestors | |
| 287 // from |ready_unsynced_set| as well. | |
| 288 ExcludeDeletedAncestors(trans, deleted_conflicted_items, ready_unsynced_set); | |
| 289 | |
| 290 // Starting with conflicted_items containing conflicted folders go down and | |
| 291 // exclude all descendants from |ready_unsynced_set|. | |
| 292 while (!conflicted_items.empty()) { | |
| 293 std::vector<int64_t> new_list; | |
| 294 ExcludeChildren(trans, conflicted_items, &new_list, ready_unsynced_set); | |
| 295 conflicted_items.swap(new_list); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 // This class helps to implement OrderCommitIds(). Its members track the | |
| 300 // progress of a traversal while its methods extend it. It can return early if | |
| 301 // the traversal reaches the desired size before the full traversal is complete. | 148 // the traversal reaches the desired size before the full traversal is complete. |
| 302 class Traversal { | 149 class Traversal { |
| 303 public: | 150 public: |
| 304 Traversal(syncable::BaseTransaction* trans, | 151 Traversal(syncable::BaseTransaction* trans, |
| 305 int64_t max_entries, | 152 int64_t max_entries, |
| 306 syncable::Directory::Metahandles* out); | 153 Directory::Metahandles* out); |
| 307 ~Traversal(); | 154 ~Traversal(); |
| 308 | 155 |
| 309 // First step of traversal building. Adds non-deleted items in order. | 156 // First step of traversal building. Adds non-deleted items in order. |
| 310 void AddCreatesAndMoves(const std::set<int64_t>& ready_unsynced_set); | 157 void AddCreatesAndMoves(const std::set<int64_t>& ready_unsynced_set); |
| 311 | 158 |
| 312 // Second step of traverals building. Appends deleted items. | 159 // Second step of traverals building. Appends deleted items. |
| 313 void AddDeletes(const std::set<int64_t>& ready_unsynced_set); | 160 void AddDeletes(const std::set<int64_t>& ready_unsynced_set); |
| 314 | 161 |
| 315 private: | 162 private: |
| 316 // The following functions do not modify the traversal directly. They return | 163 // The following functions do not modify the traversal directly. They return |
| 317 // their results in the |result| vector instead. | 164 // their results in the |result| vector instead. |
| 318 void AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, | 165 void AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, |
| 319 const syncable::Entry& item, | 166 const Entry& item, |
| 320 syncable::Directory::Metahandles* result) const; | 167 Directory::Metahandles* result) const; |
| 321 | 168 |
| 322 bool TryAddItem(const std::set<int64_t>& ready_unsynced_set, | 169 bool TryAddItem(const std::set<int64_t>& ready_unsynced_set, |
| 323 const syncable::Entry& item, | 170 const Entry& item, |
| 324 syncable::Directory::Metahandles* result) const; | 171 Directory::Metahandles* result) const; |
| 325 | 172 |
| 326 void AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, | 173 void AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, |
| 327 const syncable::Entry& item, | 174 const Entry& item, |
| 328 const syncable::Directory::Metahandles& traversed, | 175 const Directory::Metahandles& traversed, |
| 329 syncable::Directory::Metahandles* result) const; | 176 Directory::Metahandles* result) const; |
| 330 | 177 |
| 331 // Returns true if we've collected enough items. | 178 // Returns true if we've collected enough items. |
| 332 bool IsFull() const; | 179 bool IsFull() const; |
| 333 | 180 |
| 334 // Returns true if the specified handle is already in the traversal. | 181 // Returns true if the specified handle is already in the traversal. |
| 335 bool HaveItem(int64_t handle) const; | 182 bool HaveItem(int64_t handle) const; |
| 336 | 183 |
| 337 // Adds the specified handles to the traversal. | 184 // Adds the specified handles to the traversal. |
| 338 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles); | 185 void AppendManyToTraversal(const Directory::Metahandles& handles); |
| 339 | 186 |
| 340 // Adds the specifed handle to the traversal. | 187 // Adds the specified handle to the traversal. |
| 341 void AppendToTraversal(int64_t handle); | 188 void AppendToTraversal(int64_t handle); |
| 342 | 189 |
| 343 syncable::Directory::Metahandles* out_; | 190 Directory::Metahandles* out_; |
| 344 std::set<int64_t> added_handles_; | 191 std::set<int64_t> added_handles_; |
| 345 const size_t max_entries_; | 192 const size_t max_entries_; |
| 346 syncable::BaseTransaction* trans_; | 193 syncable::BaseTransaction* trans_; |
| 347 | 194 |
| 348 DISALLOW_COPY_AND_ASSIGN(Traversal); | 195 DISALLOW_COPY_AND_ASSIGN(Traversal); |
| 349 }; | 196 }; |
| 350 | 197 |
| 351 Traversal::Traversal(syncable::BaseTransaction* trans, | 198 Traversal::Traversal(syncable::BaseTransaction* trans, |
| 352 int64_t max_entries, | 199 int64_t max_entries, |
| 353 syncable::Directory::Metahandles* out) | 200 Directory::Metahandles* out) |
| 354 : out_(out), max_entries_(max_entries), trans_(trans) {} | 201 : out_(out), max_entries_(max_entries), trans_(trans) {} |
| 355 | 202 |
| 356 Traversal::~Traversal() {} | 203 Traversal::~Traversal() {} |
| 357 | 204 |
| 358 void Traversal::AddUncommittedParents( | 205 void Traversal::AddUncommittedParents( |
| 359 const std::set<int64_t>& ready_unsynced_set, | 206 const std::set<int64_t>& ready_unsynced_set, |
| 360 const syncable::Entry& item, | 207 const Entry& item, |
| 361 syncable::Directory::Metahandles* result) const { | 208 Directory::Metahandles* result) const { |
| 362 DCHECK(SupportsHierarchy(item)); | 209 DCHECK(SupportsHierarchy(item)); |
| 363 syncable::Directory::Metahandles dependencies; | 210 Directory::Metahandles dependencies; |
| 364 syncable::Id parent_id = item.GetParentId(); | 211 syncable::Id parent_id = item.GetParentId(); |
| 365 | 212 |
| 366 // Climb the tree adding entries leaf -> root. | 213 // Climb the tree adding entries leaf -> root. |
| 367 while (!parent_id.ServerKnows()) { | 214 while (!parent_id.ServerKnows()) { |
| 368 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); | 215 Entry parent(trans_, syncable::GET_BY_ID, parent_id); |
| 369 CHECK(parent.good()) << "Bad user-only parent in item path."; | 216 CHECK(parent.good()) << "Bad user-only parent in item path."; |
| 370 int64_t handle = parent.GetMetahandle(); | 217 int64_t handle = parent.GetMetahandle(); |
| 371 if (HaveItem(handle)) { | 218 if (HaveItem(handle)) { |
| 372 // We've already added this parent (and therefore all of its parents). | 219 // We've already added this parent (and therefore all of its parents). |
| 373 // We can return early. | 220 // We can return early. |
| 374 break; | 221 break; |
| 375 } | 222 } |
| 376 | 223 |
| 377 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { | 224 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { |
| 378 // The parent isn't in |ready_unsynced_set|. | 225 // The parent isn't in |ready_unsynced_set|. |
| 379 break; | 226 break; |
| 380 } | 227 } |
| 381 | 228 |
| 382 parent_id = parent.GetParentId(); | 229 parent_id = parent.GetParentId(); |
| 383 } | 230 } |
| 384 | 231 |
| 385 // Reverse what we added to get the correct order. | 232 // Reverse what we added to get the correct order. |
| 386 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); | 233 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 387 } | 234 } |
| 388 | 235 |
| 389 // Adds the given item to the list if it is unsynced and ready for commit. | 236 // Adds the given item to the list if it is unsynced and ready for commit. |
| 390 bool Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, | 237 bool Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, |
| 391 const syncable::Entry& item, | 238 const Entry& item, |
| 392 syncable::Directory::Metahandles* result) const { | 239 Directory::Metahandles* result) const { |
| 393 DCHECK(item.GetIsUnsynced()); | 240 DCHECK(item.GetIsUnsynced()); |
| 394 int64_t item_handle = item.GetMetahandle(); | 241 int64_t item_handle = item.GetMetahandle(); |
| 395 if (ready_unsynced_set.count(item_handle) != 0) { | 242 if (ready_unsynced_set.count(item_handle) != 0) { |
| 396 result->push_back(item_handle); | 243 result->push_back(item_handle); |
| 397 return true; | 244 return true; |
| 398 } | 245 } |
| 399 return false; | 246 return false; |
| 400 } | 247 } |
| 401 | 248 |
| 402 // Traverses the tree from bottom to top, adding the deleted parents of the | 249 // Traverses the tree from bottom to top, adding the deleted parents of the |
| 403 // given |item|. Stops traversing if it encounters a non-deleted node, or | 250 // given |item|. Stops traversing if it encounters a non-deleted node, or |
| 404 // a node that was already listed in the |traversed| list. | 251 // a node that was already listed in the |traversed| list. |
| 405 // | 252 // |
| 406 // The result list is reversed before it is returned, so the resulting | 253 // The result list is reversed before it is returned, so the resulting |
| 407 // traversal is in top to bottom order. Also note that this function appends | 254 // traversal is in top to bottom order. Also note that this function appends |
| 408 // to the result list without clearing it. | 255 // to the result list without clearing it. |
| 409 void Traversal::AddDeletedParents( | 256 void Traversal::AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, |
| 410 const std::set<int64_t>& ready_unsynced_set, | 257 const Entry& item, |
| 411 const syncable::Entry& item, | 258 const Directory::Metahandles& traversed, |
| 412 const syncable::Directory::Metahandles& traversed, | 259 Directory::Metahandles* result) const { |
| 413 syncable::Directory::Metahandles* result) const { | |
| 414 DCHECK(SupportsHierarchy(item)); | 260 DCHECK(SupportsHierarchy(item)); |
| 415 syncable::Directory::Metahandles dependencies; | 261 Directory::Metahandles dependencies; |
| 416 syncable::Id parent_id = item.GetParentId(); | 262 syncable::Id parent_id = item.GetParentId(); |
| 417 | 263 |
| 418 // Climb the tree adding entries leaf -> root. | 264 // Climb the tree adding entries leaf -> root. |
| 419 while (!parent_id.IsRoot()) { | 265 while (!parent_id.IsRoot()) { |
| 420 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); | 266 Entry parent(trans_, syncable::GET_BY_ID, parent_id); |
| 421 | 267 |
| 422 if (!parent.good()) { | 268 if (!parent.good()) { |
| 423 // This is valid because the parent could have gone away a long time ago | 269 // This is valid because the parent could have gone away a long time ago. |
| 424 // | 270 // |
| 425 // Consider the case where a folder is server-unknown and locally | 271 // Consider the case where a folder is server-unknown and locally |
| 426 // deleted, and has a child that is server-known, deleted, and unsynced. | 272 // deleted, and has a child that is server-known, deleted, and unsynced. |
| 427 // The parent could be dropped from memory at any time, but its child | 273 // The parent could be dropped from memory at any time, but its child |
| 428 // needs to be committed first. | 274 // needs to be committed first. |
| 429 break; | 275 break; |
| 430 } | 276 } |
| 431 int64_t handle = parent.GetMetahandle(); | 277 int64_t handle = parent.GetMetahandle(); |
| 432 if (!parent.GetIsUnsynced()) { | 278 if (!parent.GetIsUnsynced()) { |
| 433 // In some rare cases, our parent can be both deleted and unsynced. | 279 // In some rare cases, our parent can be both deleted and unsynced. |
| 434 // (ie. the server-unknown parent case). | 280 // (ie. the server-unknown parent case). |
| 435 break; | 281 break; |
| 436 } | 282 } |
| 437 if (!parent.GetIsDel()) { | 283 if (!parent.GetIsDel()) { |
| 438 // We're not intersted in non-deleted parents. | 284 // We're not interested in non-deleted parents. |
| 439 break; | 285 break; |
| 440 } | 286 } |
| 441 if (std::find(traversed.begin(), traversed.end(), handle) != | 287 if (std::find(traversed.begin(), traversed.end(), handle) != |
| 442 traversed.end()) { | 288 traversed.end()) { |
| 443 // We've already added this parent (and therefore all of its parents). | 289 // We've already added this parent (and therefore all of its parents). |
| 444 // We can return early. | 290 // We can return early. |
| 445 break; | 291 break; |
| 446 } | 292 } |
| 447 | 293 |
| 448 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { | 294 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { |
| 449 // The parent isn't in ready_unsynced_set. | 295 // The parent isn't in ready_unsynced_set. |
| 450 break; | 296 break; |
| 451 } | 297 } |
| 452 | 298 |
| 453 parent_id = parent.GetParentId(); | 299 parent_id = parent.GetParentId(); |
| 454 } | 300 } |
| 455 | 301 |
| 456 // Reverse what we added to get the correct order. | 302 // Reverse what we added to get the correct order. |
| 457 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); | 303 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 458 } | 304 } |
| 459 | 305 |
| 460 bool Traversal::IsFull() const { | 306 bool Traversal::IsFull() const { |
| 461 return out_->size() >= max_entries_; | 307 return out_->size() >= max_entries_; |
| 462 } | 308 } |
| 463 | 309 |
| 464 bool Traversal::HaveItem(int64_t handle) const { | 310 bool Traversal::HaveItem(int64_t handle) const { |
| 465 return added_handles_.find(handle) != added_handles_.end(); | 311 return added_handles_.find(handle) != added_handles_.end(); |
| 466 } | 312 } |
| 467 | 313 |
| 468 void Traversal::AppendManyToTraversal( | 314 void Traversal::AppendManyToTraversal(const Directory::Metahandles& handles) { |
| 469 const syncable::Directory::Metahandles& handles) { | |
| 470 out_->insert(out_->end(), handles.begin(), handles.end()); | 315 out_->insert(out_->end(), handles.begin(), handles.end()); |
| 471 added_handles_.insert(handles.begin(), handles.end()); | 316 added_handles_.insert(handles.begin(), handles.end()); |
| 472 } | 317 } |
| 473 | 318 |
| 474 void Traversal::AppendToTraversal(int64_t metahandle) { | 319 void Traversal::AppendToTraversal(int64_t handle) { |
| 475 out_->push_back(metahandle); | 320 out_->push_back(handle); |
| 476 added_handles_.insert(metahandle); | 321 added_handles_.insert(handle); |
| 477 } | 322 } |
| 478 | 323 |
| 479 void Traversal::AddCreatesAndMoves( | 324 void Traversal::AddCreatesAndMoves( |
| 480 const std::set<int64_t>& ready_unsynced_set) { | 325 const std::set<int64_t>& ready_unsynced_set) { |
| 481 // Add moves and creates, and prepend their uncommitted parents. | 326 // Add moves and creates, and prepend their uncommitted parents. |
| 482 for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin(); | 327 for (const int64_t& handle : ready_unsynced_set) { |
| 483 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { | 328 if (IsFull()) { |
| 484 int64_t metahandle = *iter; | 329 break; |
| 485 if (HaveItem(metahandle)) | 330 } |
| 331 if (HaveItem(handle)) | |
| 486 continue; | 332 continue; |
| 487 | 333 |
| 488 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, metahandle); | 334 Entry entry(trans_, syncable::GET_BY_HANDLE, handle); |
| 489 if (!entry.GetIsDel()) { | 335 if (!entry.GetIsDel()) { |
| 490 if (SupportsHierarchy(entry)) { | 336 if (SupportsHierarchy(entry)) { |
| 491 // We only commit an item + its dependencies if it and all its | 337 // We only commit an item + its dependencies if it and all its |
| 492 // dependencies are not in conflict. | 338 // dependencies are not in conflict. |
| 493 syncable::Directory::Metahandles item_dependencies; | 339 Directory::Metahandles item_dependencies; |
| 494 AddUncommittedParents(ready_unsynced_set, entry, &item_dependencies); | 340 AddUncommittedParents(ready_unsynced_set, entry, &item_dependencies); |
| 495 TryAddItem(ready_unsynced_set, entry, &item_dependencies); | 341 TryAddItem(ready_unsynced_set, entry, &item_dependencies); |
| 496 AppendManyToTraversal(item_dependencies); | 342 AppendManyToTraversal(item_dependencies); |
| 497 } else { | 343 } else { |
| 498 // No hierarchy dependencies, just commit the item itself. | 344 // No hierarchy dependencies, just commit the item itself. |
| 499 AppendToTraversal(metahandle); | 345 AppendToTraversal(handle); |
| 500 } | 346 } |
| 501 } | 347 } |
| 502 } | 348 } |
| 503 | 349 |
| 504 // It's possible that we overcommitted while trying to expand dependent | 350 // It's possible that we over committed while trying to expand dependent |
| 505 // items. If so, truncate the set down to the allowed size. | 351 // items. If so, truncate the set down to the allowed size. This is safe |
| 352 // because we've ordered such that ancestors come before children. | |
| 506 if (out_->size() > max_entries_) | 353 if (out_->size() > max_entries_) |
| 507 out_->resize(max_entries_); | 354 out_->resize(max_entries_); |
| 508 } | 355 } |
| 509 | 356 |
| 510 void Traversal::AddDeletes(const std::set<int64_t>& ready_unsynced_set) { | 357 void Traversal::AddDeletes(const std::set<int64_t>& ready_unsynced_set) { |
| 511 syncable::Directory::Metahandles deletion_list; | 358 Directory::Metahandles deletion_list; |
| 512 | 359 |
| 513 // Note: we iterate over all the unsynced set, regardless of the max size. | 360 // Note: we iterate over all the unsynced set, regardless of the max size. |
| 514 // The max size is only enforced after the top-to-bottom order has been | 361 // The max size is only enforced after the top-to-bottom order has been |
| 515 // reversed, in order to ensure children are always deleted before parents. | 362 // reversed, in order to ensure children are always deleted before parents. |
| 516 for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin(); | 363 // We cannot bail early when full because we need to guarantee that children |
| 517 iter != ready_unsynced_set.end(); ++iter) { | 364 // are always deleted before parents/ancestors. |
| 518 int64_t metahandle = *iter; | 365 for (const int64_t& handle : ready_unsynced_set) { |
| 519 | 366 if (HaveItem(handle)) |
| 520 if (HaveItem(metahandle)) | |
| 521 continue; | 367 continue; |
| 522 | 368 |
| 523 if (std::find(deletion_list.begin(), deletion_list.end(), metahandle) != | 369 if (std::find(deletion_list.begin(), deletion_list.end(), handle) != |
| 524 deletion_list.end()) { | 370 deletion_list.end()) { |
| 525 continue; | 371 continue; |
| 526 } | 372 } |
| 527 | 373 |
| 528 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, metahandle); | 374 Entry entry(trans_, syncable::GET_BY_HANDLE, handle); |
| 529 | 375 |
| 530 if (entry.GetIsDel()) { | 376 if (entry.GetIsDel()) { |
| 531 if (SupportsHierarchy(entry)) { | 377 if (SupportsHierarchy(entry)) { |
| 532 syncable::Directory::Metahandles parents; | 378 Directory::Metahandles parents; |
| 533 AddDeletedParents(ready_unsynced_set, entry, deletion_list, &parents); | 379 AddDeletedParents(ready_unsynced_set, entry, deletion_list, &parents); |
| 534 // Append parents and chilren in top to bottom order. | 380 // Append parents and children in top to bottom order. |
| 535 deletion_list.insert(deletion_list.end(), parents.begin(), | 381 deletion_list.insert(deletion_list.end(), parents.begin(), |
| 536 parents.end()); | 382 parents.end()); |
| 537 } | 383 } |
| 538 deletion_list.push_back(metahandle); | 384 deletion_list.push_back(handle); |
| 539 } | 385 } |
| 540 } | 386 } |
| 541 | 387 |
| 542 // We've been gathering deletions in top to bottom order. Now we reverse the | 388 // We've been gathering deletions in top to bottom order. Now we reverse the |
| 543 // order as we prepare the list. | 389 // order as we prepare the list. |
| 544 std::reverse(deletion_list.begin(), deletion_list.end()); | 390 std::reverse(deletion_list.begin(), deletion_list.end()); |
| 545 AppendManyToTraversal(deletion_list); | 391 AppendManyToTraversal(deletion_list); |
| 546 | 392 |
| 547 // It's possible that we overcommitted while trying to expand dependent | 393 // It's possible that we over committed while trying to expand dependent |
| 548 // items. If so, truncate the set down to the allowed size. | 394 // items. If so, truncate the set down to the allowed size. This is safe |
| 395 // because of the reverse above, which should guarantee the leafy nodes are | |
| 396 // in the front of the ancestors nodes. | |
| 549 if (out_->size() > max_entries_) | 397 if (out_->size() > max_entries_) |
| 550 out_->resize(max_entries_); | 398 out_->resize(max_entries_); |
| 551 } | 399 } |
| 552 | 400 |
| 401 // Excludes ancestors of deleted conflicted items from | |
| 402 // |ready_unsynced_set|. | |
| 403 void ExcludeDeletedAncestors( | |
| 404 syncable::BaseTransaction* trans, | |
| 405 const std::vector<int64_t>& deleted_conflicted_items, | |
| 406 std::set<int64_t>* ready_unsynced_set) { | |
| 407 for (const int64_t& deleted_conflicted_handle : deleted_conflicted_items) { | |
| 408 Entry item(trans, syncable::GET_BY_HANDLE, deleted_conflicted_handle); | |
| 409 syncable::Id parent_id = item.GetParentId(); | |
| 410 DCHECK(!parent_id.IsNull()); | |
| 411 | |
| 412 while (!parent_id.IsRoot()) { | |
| 413 Entry parent(trans, syncable::GET_BY_ID, parent_id); | |
| 414 CHECK(parent.good()) << "Bad user-only parent in item path."; | |
| 415 int64_t handle = parent.GetMetahandle(); | |
| 416 | |
| 417 if (!parent.GetIsDel()) | |
| 418 break; | |
| 419 | |
| 420 auto ready_iter = ready_unsynced_set->find(handle); | |
| 421 if (ready_iter == ready_unsynced_set->end()) | |
| 422 break; | |
| 423 | |
| 424 // Remove this entry from |ready_unsynced_set|. | |
| 425 ready_unsynced_set->erase(ready_iter); | |
| 426 parent_id = parent.GetParentId(); | |
| 427 } | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 // Filters |unsynced_handles| to remove all entries that do not belong to the | |
| 432 // specified |requested_types|, or are not eligible for a commit at this time. | |
| 433 void FilterUnreadyEntries(syncable::BaseTransaction* trans, | |
| 434 ModelTypeSet requested_types, | |
| 435 ModelTypeSet encrypted_types, | |
| 436 bool passphrase_missing, | |
| 437 const Directory::Metahandles& unsynced_handles, | |
| 438 std::set<int64_t>* ready_unsynced_set) { | |
| 439 std::vector<int64_t> deleted_conflicted_items; | |
| 440 std::vector<int64_t> conflicted_items; | |
| 441 | |
| 442 // Go over all unsynced handles, filter the ones that might be committed based | |
| 443 // on type / encryption, then based on whether they are in conflict add them | |
| 444 // to either |ready_unsynced_set| or one of the conflicted lists. | |
| 445 for (const int64_t& handle : unsynced_handles) { | |
| 446 Entry entry(trans, syncable::GET_BY_HANDLE, handle); | |
| 447 // TODO(maniscalco): While we check if entry is ready to be committed, we | |
| 448 // also need to check that all of its ancestors (parents, transitive) are | |
| 449 // ready to be committed. Once attachments can prevent an entry from being | |
| 450 // committable, this method must ensure all ancestors are ready for commit | |
| 451 // (crbug.com/356273). | |
| 452 if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing, | |
| 453 entry)) { | |
| 454 if (IsEntryInConflict(entry)) { | |
| 455 // Conflicting hierarchical entries might prevent their ancestors or | |
| 456 // descendants from being committed. | |
| 457 if (SupportsHierarchy(entry)) { | |
| 458 if (entry.GetIsDel()) { | |
| 459 deleted_conflicted_items.push_back(handle); | |
| 460 } else if (entry.GetIsDir()) { | |
| 461 // Populate the initial version of |conflicted_items| with folder | |
| 462 // items that are in conflict. | |
| 463 conflicted_items.push_back(handle); | |
| 464 } | |
| 465 } | |
| 466 } else { | |
| 467 ready_unsynced_set->insert(handle); | |
| 468 } | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 // If there are any deleted conflicted entries, remove their deleted ancestors | |
| 473 // from |ready_unsynced_set| as well. | |
| 474 ExcludeDeletedAncestors(trans, deleted_conflicted_items, ready_unsynced_set); | |
| 475 | |
| 476 // Starting with conflicted_items containing conflicted folders go down and | |
| 477 // exclude all descendants from |ready_unsynced_set|. | |
| 478 while (!conflicted_items.empty()) { | |
| 479 std::vector<int64_t> new_list; | |
| 480 ExcludeChildren(trans, conflicted_items, &new_list, ready_unsynced_set); | |
| 481 conflicted_items.swap(new_list); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 // Given a set of commit metahandles that are ready for commit | |
| 486 // (|ready_unsynced_set|), sorts these into commit order and places up to | |
| 487 // |max_entries| of them in the output parameter |out|. | |
| 488 // | |
| 489 // See the header file for an explanation of commit ordering. | |
| 553 void OrderCommitIds(syncable::BaseTransaction* trans, | 490 void OrderCommitIds(syncable::BaseTransaction* trans, |
| 554 size_t max_entries, | 491 size_t max_entries, |
| 555 const std::set<int64_t>& ready_unsynced_set, | 492 const std::set<int64_t>& ready_unsynced_set, |
| 556 syncable::Directory::Metahandles* out) { | 493 Directory::Metahandles* out) { |
| 557 // Commits follow these rules: | 494 // Commits follow these rules: |
| 558 // 1. Moves or creates are preceded by needed folder creates, from | 495 // 1. Moves or creates are preceded by needed folder creates, from |
| 559 // root to leaf. | 496 // root to leaf. |
| 560 // 2. Moves/Creates before deletes. | 497 // 2. Moves/Creates before deletes. |
| 561 // 3. Deletes, collapsed. | 498 // 3. Deletes, collapsed. |
| 562 // We commit deleted moves under deleted items as moves when collapsing | 499 // We commit deleted moves under deleted items as moves when collapsing |
| 563 // delete trees. | 500 // delete trees. |
| 564 | 501 |
| 565 Traversal traversal(trans, max_entries, out); | 502 Traversal traversal(trans, max_entries, out); |
| 566 | 503 |
| 567 // Add moves and creates, and prepend their uncommitted parents. | 504 // Add moves and creates, and prepend their uncommitted parents. |
| 568 traversal.AddCreatesAndMoves(ready_unsynced_set); | 505 traversal.AddCreatesAndMoves(ready_unsynced_set); |
| 569 | 506 |
| 570 // Add all deletes. | 507 // Add all deletes. |
| 571 traversal.AddDeletes(ready_unsynced_set); | 508 traversal.AddDeletes(ready_unsynced_set); |
| 572 } | 509 } |
| 573 | 510 |
| 574 } // namespace | 511 } // namespace |
| 575 | 512 |
| 513 void GetCommitIdsForType(syncable::BaseTransaction* trans, | |
| 514 ModelType type, | |
| 515 size_t max_entries, | |
| 516 Directory::Metahandles* out) { | |
| 517 Directory* dir = trans->directory(); | |
| 518 | |
| 519 // Gather the full set of unsynced items and store it in the cycle. They | |
| 520 // are not in the correct order for commit. | |
| 521 std::set<int64_t> ready_unsynced_set; | |
| 522 Directory::Metahandles all_unsynced_handles; | |
| 523 GetUnsyncedEntries(trans, &all_unsynced_handles); | |
| 524 | |
| 525 ModelTypeSet encrypted_types; | |
| 526 bool passphrase_missing = false; | |
| 527 Cryptographer* cryptographer = dir->GetCryptographer(trans); | |
| 528 if (cryptographer) { | |
| 529 encrypted_types = dir->GetNigoriHandler()->GetEncryptedTypes(trans); | |
| 530 passphrase_missing = cryptographer->has_pending_keys(); | |
| 531 } | |
| 532 | |
| 533 // We filter out all unready entries from the set of unsynced handles. This | |
| 534 // new set of ready and unsynced items is then what we use to determine what | |
| 535 // is a candidate for commit. The caller is responsible for ensuring that no | |
| 536 // throttled types are included among the requested_types. | |
| 537 FilterUnreadyEntries(trans, ModelTypeSet(type), encrypted_types, | |
| 538 passphrase_missing, all_unsynced_handles, | |
| 539 &ready_unsynced_set); | |
| 540 | |
| 541 OrderCommitIds(trans, max_entries, ready_unsynced_set, out); | |
| 542 | |
| 543 for (const int64_t& handle : *out) { | |
| 544 DVLOG(1) << "Debug commit batch result:" << handle; | |
| 545 } | |
| 546 } | |
| 547 | |
| 576 } // namespace syncer | 548 } // namespace syncer |
| OLD | NEW |