| Index: chrome/browser/sync/engine/get_commit_ids_command.cc
|
| diff --git a/chrome/browser/sync/engine/get_commit_ids_command.cc b/chrome/browser/sync/engine/get_commit_ids_command.cc
|
| deleted file mode 100644
|
| index 0bdaee0544a07201b54ab060a8ad68a758aead75..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/sync/engine/get_commit_ids_command.cc
|
| +++ /dev/null
|
| @@ -1,434 +0,0 @@
|
| -// Copyright (c) 2012 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 "chrome/browser/sync/engine/get_commit_ids_command.h"
|
| -
|
| -#include <set>
|
| -#include <utility>
|
| -#include <vector>
|
| -
|
| -#include "chrome/browser/sync/engine/nigori_util.h"
|
| -#include "chrome/browser/sync/engine/syncer_util.h"
|
| -#include "chrome/browser/sync/syncable/syncable.h"
|
| -#include "chrome/browser/sync/util/cryptographer.h"
|
| -
|
| -using std::set;
|
| -using std::vector;
|
| -
|
| -namespace browser_sync {
|
| -
|
| -using sessions::OrderedCommitSet;
|
| -using sessions::SyncSession;
|
| -using sessions::StatusController;
|
| -
|
| -GetCommitIdsCommand::GetCommitIdsCommand(int commit_batch_size)
|
| - : requested_commit_batch_size_(commit_batch_size) {}
|
| -
|
| -GetCommitIdsCommand::~GetCommitIdsCommand() {}
|
| -
|
| -SyncerError GetCommitIdsCommand::ExecuteImpl(SyncSession* session) {
|
| - // 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> ready_unsynced_set;
|
| - syncable::Directory::UnsyncedMetaHandles all_unsynced_handles;
|
| - SyncerUtil::GetUnsyncedEntries(session->write_transaction(),
|
| - &all_unsynced_handles);
|
| -
|
| - syncable::ModelTypeSet encrypted_types;
|
| - bool passphrase_missing = false;
|
| - Cryptographer* cryptographer =
|
| - session->context()->
|
| - directory()->GetCryptographer(session->write_transaction());
|
| - if (cryptographer) {
|
| - encrypted_types = cryptographer->GetEncryptedTypes();
|
| - passphrase_missing = cryptographer->has_pending_keys();
|
| - };
|
| -
|
| - const syncable::ModelTypeSet throttled_types =
|
| - session->context()->GetThrottledTypes();
|
| - // We filter out all unready entries from the set of unsynced handles. This
|
| - // new set of ready and unsynced items (which excludes throttled items as
|
| - // well) is then what we use to determine what is a candidate for commit.
|
| - FilterUnreadyEntries(session->write_transaction(),
|
| - throttled_types,
|
| - encrypted_types,
|
| - passphrase_missing,
|
| - all_unsynced_handles,
|
| - &ready_unsynced_set);
|
| -
|
| - BuildCommitIds(session->write_transaction(),
|
| - session->routing_info(),
|
| - ready_unsynced_set);
|
| -
|
| - StatusController* status = session->mutable_status_controller();
|
| - syncable::Directory::UnsyncedMetaHandles ready_unsynced_vector(
|
| - ready_unsynced_set.begin(), ready_unsynced_set.end());
|
| - status->set_unsynced_handles(ready_unsynced_vector);
|
| - const vector<syncable::Id>& verified_commit_ids =
|
| - ordered_commit_set_->GetAllCommitIds();
|
| -
|
| - for (size_t i = 0; i < verified_commit_ids.size(); i++)
|
| - DVLOG(1) << "Debug commit batch result:" << verified_commit_ids[i];
|
| -
|
| - status->set_commit_set(*ordered_commit_set_.get());
|
| - return SYNCER_OK;
|
| -}
|
| -
|
| -namespace {
|
| -
|
| -bool IsEntryInConflict(const syncable::Entry& entry) {
|
| - if (entry.Get(syncable::IS_UNSYNCED) &&
|
| - entry.Get(syncable::SERVER_VERSION) > 0 &&
|
| - (entry.Get(syncable::SERVER_VERSION) >
|
| - entry.Get(syncable::BASE_VERSION))) {
|
| - // 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.Get(syncable::IS_UNAPPLIED_UPDATE));
|
| - DVLOG(1) << "Excluding entry from commit due to version mismatch "
|
| - << entry;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// An entry is not considered ready for commit if any are true:
|
| -// 1. It's in conflict.
|
| -// 2. It requires encryption (either the type is encrypted but a passphrase
|
| -// is missing from the cryptographer, or the entry itself wasn't properly
|
| -// encrypted).
|
| -// 3. It's type is currently throttled.
|
| -// 4. It's a delete but has not been committed.
|
| -bool IsEntryReadyForCommit(syncable::ModelTypeSet throttled_types,
|
| - syncable::ModelTypeSet encrypted_types,
|
| - bool passphrase_missing,
|
| - const syncable::Entry& entry) {
|
| - DCHECK(entry.Get(syncable::IS_UNSYNCED));
|
| - if (IsEntryInConflict(entry))
|
| - return false;
|
| -
|
| - const syncable::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 != syncable::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;
|
| - }
|
| -
|
| - // Look at the throttled types.
|
| - if (throttled_types.Has(type))
|
| - return false;
|
| -
|
| - // Drop deleted uncommitted entries.
|
| - if (entry.Get(syncable::IS_DEL) && !entry.Get(syncable::ID).ServerKnows()) {
|
| - // TODO(zea): These will remain unsynced indefinitely. This is harmless,
|
| - // but we should clean them up somewhere.
|
| - DVLOG(1) << "Ignoring deleted and uncommitted item." << entry;
|
| - return false;
|
| - }
|
| -
|
| - // Extra validity checks.
|
| - syncable::Id id = entry.Get(syncable::ID);
|
| - if (id == entry.Get(syncable::PARENT_ID)) {
|
| - 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;
|
| - }
|
| -
|
| - DVLOG(2) << "Entry is ready for commit: " << entry;
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -void GetCommitIdsCommand::FilterUnreadyEntries(
|
| - syncable::BaseTransaction* trans,
|
| - syncable::ModelTypeSet throttled_types,
|
| - syncable::ModelTypeSet encrypted_types,
|
| - bool passphrase_missing,
|
| - const syncable::Directory::UnsyncedMetaHandles& unsynced_handles,
|
| - std::set<int64>* ready_unsynced_set) {
|
| - for (syncable::Directory::UnsyncedMetaHandles::const_iterator iter =
|
| - unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) {
|
| - syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter);
|
| - if (IsEntryReadyForCommit(throttled_types,
|
| - encrypted_types,
|
| - passphrase_missing,
|
| - entry)) {
|
| - ready_unsynced_set->insert(*iter);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors(
|
| - syncable::BaseTransaction* trans,
|
| - const ModelSafeRoutingInfo& routes,
|
| - const std::set<int64>& ready_unsynced_set,
|
| - const syncable::Entry& item,
|
| - sessions::OrderedCommitSet* result) const {
|
| - OrderedCommitSet item_dependencies(routes);
|
| - syncable::Id parent_id = item.Get(syncable::PARENT_ID);
|
| -
|
| - // 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 handle = parent.Get(syncable::META_HANDLE);
|
| - if (ordered_commit_set_->HaveCommitItem(handle)) {
|
| - // We've already added this parent (and therefore all of its parents).
|
| - // We can return early.
|
| - break;
|
| - }
|
| - if (!AddItemThenPredecessors(trans, ready_unsynced_set, parent,
|
| - &item_dependencies)) {
|
| - // There was a parent/predecessor in conflict. We return without adding
|
| - // anything to |ordered_commit_set_|.
|
| - DVLOG(1) << "Parent or parent's predecessor was in conflict, omitting "
|
| - << item;
|
| - return false;
|
| - }
|
| - parent_id = parent.Get(syncable::PARENT_ID);
|
| - }
|
| -
|
| - // Reverse what we added to get the correct order.
|
| - result->AppendReverse(item_dependencies);
|
| - return true;
|
| -}
|
| -
|
| -bool GetCommitIdsCommand::AddItem(const std::set<int64>& ready_unsynced_set,
|
| - const syncable::Entry& item,
|
| - OrderedCommitSet* result) const {
|
| - DCHECK(item.Get(syncable::IS_UNSYNCED));
|
| - // An item in conflict means that dependent items (successors and children)
|
| - // cannot be added either.
|
| - if (IsEntryInConflict(item))
|
| - return false;
|
| - int64 item_handle = item.Get(syncable::META_HANDLE);
|
| - if (ready_unsynced_set.count(item_handle) == 0) {
|
| - // It's not in conflict, but not ready for commit. Just return true without
|
| - // adding it to the commit set.
|
| - return true;
|
| - }
|
| - result->AddCommitItem(item_handle, item.Get(syncable::ID),
|
| - item.GetModelType());
|
| - return true;
|
| -}
|
| -
|
| -bool GetCommitIdsCommand::AddItemThenPredecessors(
|
| - syncable::BaseTransaction* trans,
|
| - const std::set<int64>& ready_unsynced_set,
|
| - const syncable::Entry& item,
|
| - OrderedCommitSet* result) const {
|
| - int64 item_handle = item.Get(syncable::META_HANDLE);
|
| - if (ordered_commit_set_->HaveCommitItem(item_handle)) {
|
| - // We've already added this item to the commit set, and so must have
|
| - // already added the predecessors as well.
|
| - return true;
|
| - }
|
| - if (!AddItem(ready_unsynced_set, item, result))
|
| - return false; // Item is in conflict.
|
| - if (item.Get(syncable::IS_DEL))
|
| - return true; // Deleted items have no predecessors.
|
| -
|
| - syncable::Id prev_id = item.Get(syncable::PREV_ID);
|
| - while (!prev_id.IsRoot()) {
|
| - syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id);
|
| - CHECK(prev.good()) << "Bad id when walking predecessors.";
|
| - if (!prev.Get(syncable::IS_UNSYNCED))
|
| - break;
|
| - int64 handle = prev.Get(syncable::META_HANDLE);
|
| - if (ordered_commit_set_->HaveCommitItem(handle)) {
|
| - // We've already added this item to the commit set, and so must have
|
| - // already added the predecessors as well.
|
| - return true;
|
| - }
|
| - if (!AddItem(ready_unsynced_set, prev, result))
|
| - return false; // Item is in conflict.
|
| - prev_id = prev.Get(syncable::PREV_ID);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool GetCommitIdsCommand::AddPredecessorsThenItem(
|
| - syncable::BaseTransaction* trans,
|
| - const ModelSafeRoutingInfo& routes,
|
| - const std::set<int64>& ready_unsynced_set,
|
| - const syncable::Entry& item,
|
| - OrderedCommitSet* result) const {
|
| - OrderedCommitSet item_dependencies(routes);
|
| - if (!AddItemThenPredecessors(trans, ready_unsynced_set, item,
|
| - &item_dependencies)) {
|
| - // Either the item or its predecessors are in conflict, so don't add any
|
| - // items to the commit set.
|
| - DVLOG(1) << "Predecessor was in conflict, omitting " << item;
|
| - return false;
|
| - }
|
| -
|
| - // Reverse what we added to get the correct order.
|
| - result->AppendReverse(item_dependencies);
|
| - return true;
|
| -}
|
| -
|
| -bool GetCommitIdsCommand::IsCommitBatchFull() const {
|
| - return ordered_commit_set_->Size() >= requested_commit_batch_size_;
|
| -}
|
| -
|
| -void GetCommitIdsCommand::AddCreatesAndMoves(
|
| - syncable::WriteTransaction* write_transaction,
|
| - const ModelSafeRoutingInfo& routes,
|
| - const std::set<int64>& ready_unsynced_set) {
|
| - // Add moves and creates, and prepend their uncommitted parents.
|
| - for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
|
| - !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
|
| - int64 metahandle = *iter;
|
| - if (ordered_commit_set_->HaveCommitItem(metahandle))
|
| - continue;
|
| -
|
| - syncable::Entry entry(write_transaction,
|
| - syncable::GET_BY_HANDLE,
|
| - metahandle);
|
| - if (!entry.Get(syncable::IS_DEL)) {
|
| - // We only commit an item + its dependencies if it and all its
|
| - // dependencies are not in conflict.
|
| - OrderedCommitSet item_dependencies(routes);
|
| - if (AddUncommittedParentsAndTheirPredecessors(
|
| - write_transaction,
|
| - routes,
|
| - ready_unsynced_set,
|
| - entry,
|
| - &item_dependencies) &&
|
| - AddPredecessorsThenItem(write_transaction,
|
| - routes,
|
| - ready_unsynced_set,
|
| - entry,
|
| - &item_dependencies)) {
|
| - ordered_commit_set_->Append(item_dependencies);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // It's possible that we overcommitted while trying to expand dependent
|
| - // items. If so, truncate the set down to the allowed size.
|
| - ordered_commit_set_->Truncate(requested_commit_batch_size_);
|
| -}
|
| -
|
| -void GetCommitIdsCommand::AddDeletes(
|
| - syncable::WriteTransaction* write_transaction,
|
| - const std::set<int64>& ready_unsynced_set) {
|
| - set<syncable::Id> legal_delete_parents;
|
| -
|
| - for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
|
| - !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
|
| - int64 metahandle = *iter;
|
| - if (ordered_commit_set_->HaveCommitItem(metahandle))
|
| - continue;
|
| -
|
| - syncable::Entry entry(write_transaction, syncable::GET_BY_HANDLE,
|
| - metahandle);
|
| -
|
| - if (entry.Get(syncable::IS_DEL)) {
|
| - syncable::Entry parent(write_transaction, syncable::GET_BY_ID,
|
| - entry.Get(syncable::PARENT_ID));
|
| - // If the parent is deleted and unsynced, then any children of that
|
| - // parent don't need to be added to the delete queue.
|
| - //
|
| - // Note: the parent could be synced if there was an update deleting a
|
| - // folder when we had a deleted all items in it.
|
| - // We may get more updates, or we may want to delete the entry.
|
| - if (parent.good() &&
|
| - parent.Get(syncable::IS_DEL) &&
|
| - parent.Get(syncable::IS_UNSYNCED)) {
|
| - // However, if an entry is moved, these rules can apply differently.
|
| - //
|
| - // If the entry was moved, then the destination parent was deleted,
|
| - // then we'll miss it in the roll up. We have to add it in manually.
|
| - // TODO(chron): Unit test for move / delete cases:
|
| - // Case 1: Locally moved, then parent deleted
|
| - // Case 2: Server moved, then locally issue recursive delete.
|
| - if (entry.Get(syncable::ID).ServerKnows() &&
|
| - entry.Get(syncable::PARENT_ID) !=
|
| - entry.Get(syncable::SERVER_PARENT_ID)) {
|
| - DVLOG(1) << "Inserting moved and deleted entry, will be missed by "
|
| - << "delete roll." << entry.Get(syncable::ID);
|
| -
|
| - ordered_commit_set_->AddCommitItem(metahandle,
|
| - entry.Get(syncable::ID),
|
| - entry.GetModelType());
|
| - }
|
| -
|
| - // Skip this entry since it's a child of a parent that will be
|
| - // deleted. The server will unroll the delete and delete the
|
| - // child as well.
|
| - continue;
|
| - }
|
| -
|
| - legal_delete_parents.insert(entry.Get(syncable::PARENT_ID));
|
| - }
|
| - }
|
| -
|
| - // We could store all the potential entries with a particular parent during
|
| - // the above scan, but instead we rescan here. This is less efficient, but
|
| - // we're dropping memory alloc/dealloc in favor of linear scans of recently
|
| - // examined entries.
|
| - //
|
| - // Scan through the UnsyncedMetaHandles again. If we have a deleted
|
| - // entry, then check if the parent is in legal_delete_parents.
|
| - //
|
| - // Parent being in legal_delete_parents means for the child:
|
| - // a recursive delete is not currently happening (no recent deletes in same
|
| - // folder)
|
| - // parent did expect at least one old deleted child
|
| - // parent was not deleted
|
| - for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
|
| - !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) {
|
| - int64 metahandle = *iter;
|
| - if (ordered_commit_set_->HaveCommitItem(metahandle))
|
| - continue;
|
| - syncable::MutableEntry entry(write_transaction, syncable::GET_BY_HANDLE,
|
| - metahandle);
|
| - if (entry.Get(syncable::IS_DEL)) {
|
| - syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
|
| - if (legal_delete_parents.count(parent_id)) {
|
| - ordered_commit_set_->AddCommitItem(metahandle, entry.Get(syncable::ID),
|
| - entry.GetModelType());
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void GetCommitIdsCommand::BuildCommitIds(
|
| - syncable::WriteTransaction* write_transaction,
|
| - const ModelSafeRoutingInfo& routes,
|
| - const std::set<int64>& ready_unsynced_set) {
|
| - ordered_commit_set_.reset(new OrderedCommitSet(routes));
|
| - // Commits follow these rules:
|
| - // 1. Moves or creates are preceded by needed folder creates, from
|
| - // root to leaf. For folders whose contents are ordered, moves
|
| - // and creates appear in order.
|
| - // 2. Moves/Creates before deletes.
|
| - // 3. Deletes, collapsed.
|
| - // We commit deleted moves under deleted items as moves when collapsing
|
| - // delete trees.
|
| -
|
| - // Add moves and creates, and prepend their uncommitted parents.
|
| - AddCreatesAndMoves(write_transaction, routes, ready_unsynced_set);
|
| -
|
| - // Add all deletes.
|
| - AddDeletes(write_transaction, ready_unsynced_set);
|
| -}
|
| -
|
| -} // namespace browser_sync
|
|
|