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

Unified Diff: sync/engine/get_commit_ids.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sync/engine/get_commit_ids.h ('k') | sync/engine/get_updates_delegate.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/engine/get_commit_ids.cc
diff --git a/sync/engine/get_commit_ids.cc b/sync/engine/get_commit_ids.cc
deleted file mode 100644
index a4c7f6b7f7944f97b1c2b44a37af5115608e7aec..0000000000000000000000000000000000000000
--- a/sync/engine/get_commit_ids.cc
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sync/engine/get_commit_ids.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <set>
-#include <vector>
-
-#include "base/macros.h"
-#include "sync/engine/syncer_util.h"
-#include "sync/syncable/directory.h"
-#include "sync/syncable/entry.h"
-#include "sync/syncable/nigori_handler.h"
-#include "sync/syncable/nigori_util.h"
-#include "sync/syncable/syncable_base_transaction.h"
-#include "sync/syncable/syncable_util.h"
-#include "sync/util/cryptographer.h"
-
-using std::set;
-using std::vector;
-
-namespace syncer {
-
-namespace {
-
-// Forward-declare some helper functions. This gives us more options for
-// ordering the function defintions within this file.
-
-// Filters |unsynced_handles| to remove all entries that do not belong to the
-// specified |requested_types|, or are not eligible for a commit at this time.
-void FilterUnreadyEntries(
- syncable::BaseTransaction* trans,
- ModelTypeSet requested_types,
- ModelTypeSet encrypted_types,
- bool passphrase_missing,
- const syncable::Directory::Metahandles& unsynced_handles,
- std::set<int64_t>* ready_unsynced_set);
-
-// Given a set of commit metahandles that are ready for commit
-// (|ready_unsynced_set|), sorts these into commit order and places up to
-// |max_entries| of them in the output parameter |out|.
-//
-// See the header file for an explanation of commit ordering.
-void OrderCommitIds(syncable::BaseTransaction* trans,
- size_t max_entries,
- const std::set<int64_t>& ready_unsynced_set,
- std::vector<int64_t>* out);
-
-} // namespace
-
-void GetCommitIdsForType(
- syncable::BaseTransaction* trans,
- ModelType type,
- size_t max_entries,
- syncable::Directory::Metahandles* out) {
- syncable::Directory* dir = trans->directory();
-
- // Gather the full set of unsynced items and store it in the session. They
- // are not in the correct order for commit.
- std::set<int64_t> ready_unsynced_set;
- syncable::Directory::Metahandles all_unsynced_handles;
- GetUnsyncedEntries(trans, &all_unsynced_handles);
-
- ModelTypeSet encrypted_types;
- bool passphrase_missing = false;
- Cryptographer* cryptographer = dir->GetCryptographer(trans);
- if (cryptographer) {
- encrypted_types = dir->GetNigoriHandler()->GetEncryptedTypes(trans);
- passphrase_missing = cryptographer->has_pending_keys();
- }
-
- // We filter out all unready entries from the set of unsynced handles. This
- // new set of ready and unsynced items is then what we use to determine what
- // is a candidate for commit. The caller is responsible for ensuring that no
- // throttled types are included among the requested_types.
- FilterUnreadyEntries(trans,
- ModelTypeSet(type),
- encrypted_types,
- passphrase_missing,
- all_unsynced_handles,
- &ready_unsynced_set);
-
- OrderCommitIds(trans, max_entries, ready_unsynced_set, out);
-
- for (size_t i = 0; i < out->size(); i++) {
- DVLOG(1) << "Debug commit batch result:" << (*out)[i];
- }
-}
-
-namespace {
-
-bool IsEntryInConflict(const syncable::Entry& entry) {
- if (entry.GetIsUnsynced() &&
- entry.GetServerVersion() > 0 &&
- (entry.GetServerVersion() > entry.GetBaseVersion())) {
- // The local and server versions don't match. The item must be in
- // conflict, so there's no point in attempting to commit.
- DCHECK(entry.GetIsUnappliedUpdate());
- DVLOG(1) << "Excluding entry from commit due to version mismatch "
- << entry;
- return true;
- }
- return false;
-}
-
-// Return true if this entry has any attachments that haven't yet been uploaded
-// to the server.
-bool HasAttachmentNotOnServer(const syncable::Entry& entry) {
- const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata();
- for (int i = 0; i < metadata.record_size(); ++i) {
- if (!metadata.record(i).is_on_server()) {
- return true;
- }
- }
- return false;
-}
-
-// An entry may not commit if any are true:
-// 1. It requires encryption (either the type is encrypted but a passphrase
-// is missing from the cryptographer, or the entry itself wasn't properly
-// encrypted).
-// 2. It's type is currently throttled.
-// 3. It's a delete but has not been committed.
-bool MayEntryCommit(ModelTypeSet requested_types,
- ModelTypeSet encrypted_types,
- bool passphrase_missing,
- const syncable::Entry& entry) {
- DCHECK(entry.GetIsUnsynced());
-
- const ModelType type = entry.GetModelType();
- // We special case the nigori node because even though it is considered an
- // "encrypted type", not all nigori node changes require valid encryption
- // (ex: sync_tabs).
- if ((type != NIGORI) && encrypted_types.Has(type) &&
- (passphrase_missing ||
- syncable::EntryNeedsEncryption(encrypted_types, entry))) {
- // This entry requires encryption but is not properly encrypted (possibly
- // due to the cryptographer not being initialized or the user hasn't
- // provided the most recent passphrase).
- DVLOG(1) << "Excluding entry from commit due to lack of encryption "
- << entry;
- return false;
- }
-
- // Ignore it if it's not in our set of requested types.
- if (!requested_types.Has(type))
- return false;
-
- if (entry.GetIsDel() && !entry.GetId().ServerKnows()) {
- // New clients (following the resolution of crbug.com/125381) should not
- // create such items. Old clients may have left some in the database
- // (crbug.com/132905), but we should now be cleaning them on startup.
- NOTREACHED() << "Found deleted and unsynced local item: " << entry;
- return false;
- }
-
- // Extra validity checks.
- syncable::Id id = entry.GetId();
- if (id == entry.GetParentId()) {
- CHECK(id.IsRoot()) << "Non-root item is self parenting." << entry;
- // If the root becomes unsynced it can cause us problems.
- NOTREACHED() << "Root item became unsynced " << entry;
- return false;
- }
-
- if (entry.IsRoot()) {
- NOTREACHED() << "Permanent item became unsynced " << entry;
- return false;
- }
-
- if (HasAttachmentNotOnServer(entry)) {
- // This entry is not ready to be sent to the server because it has one or
- // more attachments that have not yet been uploaded to the server. The idea
- // here is avoid propagating an entry with dangling attachment references.
- return false;
- }
-
- DVLOG(2) << "Entry is ready for commit: " << entry;
- return true;
-}
-
-bool SupportsHierarchy(const syncable::Entry& item) {
- // Types with explicit server supported hierarchy only.
- return IsTypeWithServerGeneratedRoot(item.GetModelType());
-}
-
-// Excludes ancestors of deleted conflicted items from
-// |ready_unsynced_set|.
-void ExcludeDeletedAncestors(
- syncable::BaseTransaction* trans,
- const std::vector<int64_t>& deleted_conflicted_items,
- std::set<int64_t>* ready_unsynced_set) {
- for (auto iter = deleted_conflicted_items.begin();
- iter != deleted_conflicted_items.end(); ++iter) {
- syncable::Entry item(trans, syncable::GET_BY_HANDLE, *iter);
- syncable::Id parent_id = item.GetParentId();
- DCHECK(!parent_id.IsNull());
-
- while (!parent_id.IsRoot()) {
- syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id);
- CHECK(parent.good()) << "Bad user-only parent in item path.";
- int64_t handle = parent.GetMetahandle();
-
- if (!parent.GetIsDel())
- break;
-
- auto ready_iter = ready_unsynced_set->find(handle);
- if (ready_iter == ready_unsynced_set->end())
- break;
-
- // Remove this entry from |ready_unsynced_set|.
- ready_unsynced_set->erase(ready_iter);
- parent_id = parent.GetParentId();
- }
- }
-}
-
-// Iterates over children of items from |conflicted_items| list that are in
-// |ready_unsynced_set|, exludes them from |ready_unsynced_set| and adds them
-// to |excluded_items| list.
-void ExcludeChildren(syncable::BaseTransaction* trans,
- const std::vector<int64_t>& conflicted_items,
- std::vector<int64_t>* excluded_items,
- std::set<int64_t>* ready_unsynced_set) {
- for (auto iter = conflicted_items.begin(); iter != conflicted_items.end();
- ++iter) {
- syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter);
-
- if (!entry.GetIsDir() || entry.GetIsDel())
- continue;
-
- std::vector<int64_t> children;
- entry.GetChildHandles(&children);
-
- for (std::vector<int64_t>::const_iterator child_iter = children.begin();
- child_iter != children.end(); ++child_iter) {
- // Collect all child handles that are in |ready_unsynced_set|.
- int64_t child_handle = *child_iter;
- auto ready_iter = ready_unsynced_set->find(child_handle);
- if (ready_iter != ready_unsynced_set->end()) {
- // Remove this entry from |ready_unsynced_set| and add it
- // to |excluded_items|.
- ready_unsynced_set->erase(ready_iter);
- excluded_items->push_back(child_handle);
- }
- }
- }
-}
-
-// Filters |unsynced_handles| to remove all entries that do not belong to the
-// specified |requested_types|, or are not eligible for a commit at this time.
-void FilterUnreadyEntries(
- syncable::BaseTransaction* trans,
- ModelTypeSet requested_types,
- ModelTypeSet encrypted_types,
- bool passphrase_missing,
- const syncable::Directory::Metahandles& unsynced_handles,
- std::set<int64_t>* ready_unsynced_set) {
- std::vector<int64_t> deleted_conflicted_items;
- std::vector<int64_t> conflicted_items;
-
- // Go over all unsynced handles, filter the ones that might be committed based
- // on type / encryption, then based on whether they are in conflict add them
- // to either |ready_unsynced_set| or one of the conflicted lists.
- for (auto iter = unsynced_handles.begin(); iter != unsynced_handles.end();
- ++iter) {
- syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter);
- // TODO(maniscalco): While we check if entry is ready to be committed, we
- // also need to check that all of its ancestors (parents, transitive) are
- // ready to be committed. Once attachments can prevent an entry from being
- // committable, this method must ensure all ancestors are ready for commit
- // (bug 356273).
- if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing,
- entry)) {
- if (IsEntryInConflict(entry)) {
- // Conflicting hierarchical entries might prevent their ancestors or
- // descendants from being committed.
- if (SupportsHierarchy(entry)) {
- if (entry.GetIsDel()) {
- deleted_conflicted_items.push_back(*iter);
- } else if (entry.GetIsDir()) {
- // Populate the initial version of |conflicted_items| with folder
- // items that are in conflict.
- conflicted_items.push_back(*iter);
- }
- }
- } else {
- ready_unsynced_set->insert(*iter);
- }
- }
- }
-
- // If there are any deleted conflicted entries, remove their deleted ancestors
- // from |ready_unsynced_set| as well.
- ExcludeDeletedAncestors(trans, deleted_conflicted_items, ready_unsynced_set);
-
- // Starting with conflicted_items containing conflicted folders go down and
- // exclude all descendants from |ready_unsynced_set|.
- while (!conflicted_items.empty()) {
- std::vector<int64_t> new_list;
- ExcludeChildren(trans, conflicted_items, &new_list, ready_unsynced_set);
- conflicted_items.swap(new_list);
- }
-}
-
-// This class helps to implement OrderCommitIds(). Its members track the
-// progress of a traversal while its methods extend it. It can return early if
-// the traversal reaches the desired size before the full traversal is complete.
-class Traversal {
- public:
- Traversal(syncable::BaseTransaction* trans,
- int64_t max_entries,
- syncable::Directory::Metahandles* out);
- ~Traversal();
-
- // First step of traversal building. Adds non-deleted items in order.
- void AddCreatesAndMoves(const std::set<int64_t>& ready_unsynced_set);
-
- // Second step of traverals building. Appends deleted items.
- void AddDeletes(const std::set<int64_t>& ready_unsynced_set);
-
- private:
- // The following functions do not modify the traversal directly. They return
- // their results in the |result| vector instead.
- void AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- syncable::Directory::Metahandles* result) const;
-
- bool TryAddItem(const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- syncable::Directory::Metahandles* result) const;
-
- void AddDeletedParents(const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- const syncable::Directory::Metahandles& traversed,
- syncable::Directory::Metahandles* result) const;
-
- // Returns true if we've collected enough items.
- bool IsFull() const;
-
- // Returns true if the specified handle is already in the traversal.
- bool HaveItem(int64_t handle) const;
-
- // Adds the specified handles to the traversal.
- void AppendManyToTraversal(const syncable::Directory::Metahandles& handles);
-
- // Adds the specifed handle to the traversal.
- void AppendToTraversal(int64_t handle);
-
- syncable::Directory::Metahandles* out_;
- std::set<int64_t> added_handles_;
- const size_t max_entries_;
- syncable::BaseTransaction* trans_;
-
- DISALLOW_COPY_AND_ASSIGN(Traversal);
-};
-
-Traversal::Traversal(syncable::BaseTransaction* trans,
- int64_t max_entries,
- syncable::Directory::Metahandles* out)
- : out_(out), max_entries_(max_entries), trans_(trans) {}
-
-Traversal::~Traversal() {}
-
-void Traversal::AddUncommittedParents(
- const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- syncable::Directory::Metahandles* result) const {
- DCHECK(SupportsHierarchy(item));
- syncable::Directory::Metahandles dependencies;
- syncable::Id parent_id = item.GetParentId();
-
- // Climb the tree adding entries leaf -> root.
- while (!parent_id.ServerKnows()) {
- syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id);
- CHECK(parent.good()) << "Bad user-only parent in item path.";
- int64_t handle = parent.GetMetahandle();
- if (HaveItem(handle)) {
- // We've already added this parent (and therefore all of its parents).
- // We can return early.
- break;
- }
-
- if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) {
- // The parent isn't in |ready_unsynced_set|.
- break;
- }
-
- parent_id = parent.GetParentId();
- }
-
- // Reverse what we added to get the correct order.
- result->insert(result->end(), dependencies.rbegin(), dependencies.rend());
-}
-
-// Adds the given item to the list if it is unsynced and ready for commit.
-bool Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- syncable::Directory::Metahandles* result) const {
- DCHECK(item.GetIsUnsynced());
- int64_t item_handle = item.GetMetahandle();
- if (ready_unsynced_set.count(item_handle) != 0) {
- result->push_back(item_handle);
- return true;
- }
- return false;
-}
-
-// Traverses the tree from bottom to top, adding the deleted parents of the
-// given |item|. Stops traversing if it encounters a non-deleted node, or
-// a node that was already listed in the |traversed| list.
-//
-// The result list is reversed before it is returned, so the resulting
-// traversal is in top to bottom order. Also note that this function appends
-// to the result list without clearing it.
-void Traversal::AddDeletedParents(
- const std::set<int64_t>& ready_unsynced_set,
- const syncable::Entry& item,
- const syncable::Directory::Metahandles& traversed,
- syncable::Directory::Metahandles* result) const {
- DCHECK(SupportsHierarchy(item));
- syncable::Directory::Metahandles dependencies;
- syncable::Id parent_id = item.GetParentId();
-
- // Climb the tree adding entries leaf -> root.
- while (!parent_id.IsRoot()) {
- syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id);
-
- if (!parent.good()) {
- // This is valid because the parent could have gone away a long time ago
- //
- // Consider the case where a folder is server-unknown and locally
- // deleted, and has a child that is server-known, deleted, and unsynced.
- // The parent could be dropped from memory at any time, but its child
- // needs to be committed first.
- break;
- }
- int64_t handle = parent.GetMetahandle();
- if (!parent.GetIsUnsynced()) {
- // In some rare cases, our parent can be both deleted and unsynced.
- // (ie. the server-unknown parent case).
- break;
- }
- if (!parent.GetIsDel()) {
- // We're not intersted in non-deleted parents.
- break;
- }
- if (std::find(traversed.begin(), traversed.end(), handle) !=
- traversed.end()) {
- // We've already added this parent (and therefore all of its parents).
- // We can return early.
- break;
- }
-
- if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) {
- // The parent isn't in ready_unsynced_set.
- break;
- }
-
- parent_id = parent.GetParentId();
- }
-
- // Reverse what we added to get the correct order.
- result->insert(result->end(), dependencies.rbegin(), dependencies.rend());
-}
-
-bool Traversal::IsFull() const {
- return out_->size() >= max_entries_;
-}
-
-bool Traversal::HaveItem(int64_t handle) const {
- return added_handles_.find(handle) != added_handles_.end();
-}
-
-void Traversal::AppendManyToTraversal(
- const syncable::Directory::Metahandles& handles) {
- out_->insert(out_->end(), handles.begin(), handles.end());
- added_handles_.insert(handles.begin(), handles.end());
-}
-
-void Traversal::AppendToTraversal(int64_t metahandle) {
- out_->push_back(metahandle);
- added_handles_.insert(metahandle);
-}
-
-void Traversal::AddCreatesAndMoves(
- const std::set<int64_t>& ready_unsynced_set) {
- // Add moves and creates, and prepend their uncommitted parents.
- for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin();
- !IsFull() && iter != ready_unsynced_set.end(); ++iter) {
- int64_t metahandle = *iter;
- if (HaveItem(metahandle))
- continue;
-
- syncable::Entry entry(trans_,
- syncable::GET_BY_HANDLE,
- metahandle);
- if (!entry.GetIsDel()) {
- if (SupportsHierarchy(entry)) {
- // We only commit an item + its dependencies if it and all its
- // dependencies are not in conflict.
- syncable::Directory::Metahandles item_dependencies;
- AddUncommittedParents(ready_unsynced_set, entry, &item_dependencies);
- TryAddItem(ready_unsynced_set, entry, &item_dependencies);
- AppendManyToTraversal(item_dependencies);
- } else {
- // No hierarchy dependencies, just commit the item itself.
- AppendToTraversal(metahandle);
- }
- }
- }
-
- // It's possible that we overcommitted while trying to expand dependent
- // items. If so, truncate the set down to the allowed size.
- if (out_->size() > max_entries_)
- out_->resize(max_entries_);
-}
-
-void Traversal::AddDeletes(const std::set<int64_t>& ready_unsynced_set) {
- syncable::Directory::Metahandles deletion_list;
-
- // Note: we iterate over all the unsynced set, regardless of the max size.
- // The max size is only enforced after the top-to-bottom order has been
- // reversed, in order to ensure children are always deleted before parents.
- for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin();
- iter != ready_unsynced_set.end(); ++iter) {
- int64_t metahandle = *iter;
-
- if (HaveItem(metahandle))
- continue;
-
- if (std::find(deletion_list.begin(), deletion_list.end(), metahandle) !=
- deletion_list.end()) {
- continue;
- }
-
- syncable::Entry entry(trans_, syncable::GET_BY_HANDLE,
- metahandle);
-
- if (entry.GetIsDel()) {
- if (SupportsHierarchy(entry)) {
- syncable::Directory::Metahandles parents;
- AddDeletedParents(ready_unsynced_set, entry, deletion_list, &parents);
- // Append parents and chilren in top to bottom order.
- deletion_list.insert(deletion_list.end(), parents.begin(),
- parents.end());
- }
- deletion_list.push_back(metahandle);
- }
- }
-
- // We've been gathering deletions in top to bottom order. Now we reverse the
- // order as we prepare the list.
- std::reverse(deletion_list.begin(), deletion_list.end());
- AppendManyToTraversal(deletion_list);
-
- // It's possible that we overcommitted while trying to expand dependent
- // items. If so, truncate the set down to the allowed size.
- if (out_->size() > max_entries_)
- out_->resize(max_entries_);
-}
-
-void OrderCommitIds(syncable::BaseTransaction* trans,
- size_t max_entries,
- const std::set<int64_t>& ready_unsynced_set,
- syncable::Directory::Metahandles* out) {
- // Commits follow these rules:
- // 1. Moves or creates are preceded by needed folder creates, from
- // root to leaf.
- // 2. Moves/Creates before deletes.
- // 3. Deletes, collapsed.
- // We commit deleted moves under deleted items as moves when collapsing
- // delete trees.
-
- Traversal traversal(trans, max_entries, out);
-
- // Add moves and creates, and prepend their uncommitted parents.
- traversal.AddCreatesAndMoves(ready_unsynced_set);
-
- // Add all deletes.
- traversal.AddDeletes(ready_unsynced_set);
-}
-
-} // namespace
-
-} // namespace syncer
« no previous file with comments | « sync/engine/get_commit_ids.h ('k') | sync/engine/get_updates_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698