1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <sstream>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/format_macros.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_util.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/update_applicator.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/sessions/sync_session.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::ConflictProgress;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::StatusController;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::SyncSession;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::UpdateProgress;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::set;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::string;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::vector;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBuildAndProcessConflictSetsCommand::BuildAndProcessConflictSetsCommand() {}
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBuildAndProcessConflictSetsCommand::~BuildAndProcessConflictSetsCommand() {}
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BuildAndProcessConflictSetsCommand::ModelChangingExecuteImpl(
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncSession* session) {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  session->status_controller()->update_conflict_sets_built(
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BuildAndProcessConflictSets(session));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSets(
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncSession* session) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::ScopedDirLookup dir(session->context()->directory_manager(),
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                session->context()->account_name());
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dir.good())
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool had_single_direction_sets = false;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {  // Scope for transaction.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BuildConflictSets(&trans,
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        session->status_controller()->mutable_conflict_progress());
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    had_single_direction_sets = ProcessSingleDirectionConflictSets(&trans,
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        session->context()->resolver(),
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        session->context()->directory_manager()->GetCryptographer(&trans),
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        session->status_controller(), session->routing_info());
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We applied some updates transactionally, lets try syncing again.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (had_single_direction_sets)
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BuildAndProcessConflictSetsCommand::ProcessSingleDirectionConflictSets(
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* trans, ConflictResolver* resolver,
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cryptographer* cryptographer, StatusController* status,
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes) {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool rv = false;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<ConflictSet*>::const_iterator all_sets_iterator;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (all_sets_iterator = status->conflict_progress().ConflictSetsBegin();
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       all_sets_iterator != status->conflict_progress().ConflictSetsEnd();) {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ConflictSet* conflict_set = *all_sets_iterator;
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK_GE(conflict_set->size(), 2U);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We scan the set to see if it consists of changes of only one type.
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictSet::const_iterator i;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t unsynced_count = 0, unapplied_count = 0;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (i = conflict_set->begin(); i != conflict_set->end(); ++i) {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syncable::Entry entry(trans, syncable::GET_BY_ID, *i);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(entry.good());
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (entry.Get(syncable::IS_UNSYNCED))
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        unsynced_count++;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (entry.Get(syncable::IS_UNAPPLIED_UPDATE))
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        unapplied_count++;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (conflict_set->size() == unsynced_count && 0 == unapplied_count) {
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Skipped transactional commit attempt.";
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (conflict_set->size() == unapplied_count && 0 == unsynced_count &&
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ApplyUpdatesTransactionally(trans, conflict_set, resolver,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      cryptographer, routes, status)) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      rv = true;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++all_sets_iterator;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid StoreLocalDataForUpdateRollback(syncable::Entry* entry,
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     syncable::EntryKernel* backup) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(!entry->Get(syncable::IS_UNSYNCED)) << " Storing Rollback data for "
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "entry that's unsynced." << *entry;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(entry->Get(syncable::IS_UNAPPLIED_UPDATE)) << " Storing Rollback data "
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "for entry that's not an unapplied update." << *entry;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *backup = entry->GetKernelCopy();
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RollbackEntry(syncable::WriteTransaction* trans,
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   syncable::EntryKernel* backup) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE,
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               backup->ref(syncable::META_HANDLE));
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(entry.good());
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)))
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::NON_UNIQUE_NAME, backup->ref(syncable::NON_UNIQUE_NAME));
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::PARENT_ID, backup->ref(syncable::PARENT_ID));
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!backup->ref(syncable::IS_DEL)) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry.PutPredecessor(backup->ref(syncable::PREV_ID)))
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (backup->ref(syncable::PREV_ID) != entry.Get(syncable::PREV_ID))
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::CTIME, backup->ref(syncable::CTIME));
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::MTIME, backup->ref(syncable::MTIME));
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION));
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR));
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL));
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::ID, backup->ref(syncable::ID));
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry.Put(syncable::IS_UNAPPLIED_UPDATE,
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            backup->ref(syncable::IS_UNAPPLIED_UPDATE));
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PlaceEntriesAtRoot(syncable::WriteTransaction* trans,
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      const vector<syncable::Id>* ids) {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    vector<syncable::Id>::const_iterator it;
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (it = ids->begin(); it != ids->end(); ++it) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry.Put(syncable::PARENT_ID, trans->root_id());
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally(
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* trans,
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const vector<syncable::Id>* const update_set,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictResolver* resolver,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cryptographer* cryptographer,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes,
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StatusController* status) {
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The handles in the |update_set| order.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  vector<int64> handles;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Holds the same Ids as update_set, but sorted so that runs of adjacent
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // nodes appear in order.
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  vector<syncable::Id> rollback_ids;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rollback_ids.reserve(update_set->size());
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tracks what's added to |rollback_ids|.
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::MetahandleSet rollback_ids_inserted_items;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  vector<syncable::Id>::const_iterator it;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 1. Build |rollback_ids| in the order required for successful rollback.
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    Specifically, for positions to come out right, restoring an item
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    requires that its predecessor in the sibling order is properly
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    restored first.
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 2. Build |handles|, the list of handles for ApplyUpdates.
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (it = update_set->begin(); it != update_set->end(); ++it) {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry entry(trans, syncable::GET_BY_ID, *it);
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncerUtil::AddPredecessorsThenItem(trans, &entry,
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        syncable::IS_UNAPPLIED_UPDATE, &rollback_ids_inserted_items,
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &rollback_ids);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handles.push_back(entry.Get(syncable::META_HANDLE));
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(rollback_ids.size(), update_set->size());
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(rollback_ids_inserted_items.size(), update_set->size());
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 3. Store the information needed to rollback if the transaction fails.
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Do this before modifying anything to keep the next/prev values intact.
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  vector<syncable::EntryKernel> rollback_data(rollback_ids.size());
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < rollback_ids.size(); ++i) {
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry entry(trans, syncable::GET_BY_ID, rollback_ids[i]);
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StoreLocalDataForUpdateRollback(&entry, &rollback_data[i]);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 4. Use the preparer to move things to an initial starting state where
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // nothing in the set is a child of anything else.  If
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we've correctly calculated the set, the server tree is valid and no
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // changes have occurred locally we should be able to apply updates from this
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // state.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PlaceEntriesAtRoot(trans, update_set);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 5. Use the usual apply updates from the special start state we've just
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // prepared.
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateApplicator applicator(resolver, cryptographer,
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              handles.begin(), handles.end(),
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              routes, status->group_restriction());
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (applicator.AttemptOneApplication(trans)) {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Keep going till all updates are applied.
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!applicator.AllUpdatesApplied()) {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Transactional Apply Failed, Rolling back.";
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We have to move entries into the temp dir again. e.g. if a swap was in a
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // set with other failing updates, the swap may have gone through, meaning
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the roll back needs to be transactional. But as we're going to a known
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // good state we should always succeed.
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PlaceEntriesAtRoot(trans, update_set);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Rollback all entries.
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < rollback_data.size(); ++i) {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(RollbackEntry(trans, &rollback_data[i]));
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;  // Don't save progress -- we just undid it.
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  applicator.SaveProgressIntoSessionState(status->mutable_conflict_progress(),
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          status->mutable_update_progress());
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BuildAndProcessConflictSetsCommand::BuildConflictSets(
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans,
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictProgress* conflict_progress) {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  conflict_progress->CleanupSets();
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<syncable::Id>::iterator i = conflict_progress->ConflictingItemsBegin();
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (i != conflict_progress->ConflictingItemsEnd()) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry entry(trans, syncable::GET_BY_ID, *i);
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!entry.good() ||
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        (!entry.Get(syncable::IS_UNSYNCED) &&
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick         !entry.Get(syncable::IS_UNAPPLIED_UPDATE))) {
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This can happen very rarely. It means we had a simply conflicting item
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // that randomly committed; its ID could have changed during the commit.
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // We drop the entry as it's no longer conflicting.
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflict_progress->EraseConflictingItemById(*(i++));
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry.ExistsOnClientBecauseNameIsNonEmpty() &&
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       (entry.Get(syncable::IS_DEL) || entry.Get(syncable::SERVER_IS_DEL))) {
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       // If we're deleted on client or server we can't be in a complex set.
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool new_parent =
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        entry.Get(syncable::PARENT_ID) != entry.Get(syncable::SERVER_PARENT_ID);
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (new_parent)
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MergeSetsForIntroducedLoops(trans, &entry, conflict_progress);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MergeSetsForNonEmptyDirectories(trans, &entry, conflict_progress);
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ++i;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BuildAndProcessConflictSetsCommand::MergeSetsForIntroducedLoops(
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans, syncable::Entry* entry,
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictProgress* conflict_progress) {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This code crawls up from the item in question until it gets to the root
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // or itself. If it gets to the root it does nothing. If it finds a loop all
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // moved unsynced entries in the list of crawled entries have their sets
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // merged with the entry.
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sync): Build test cases to cover this function when the argument list
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // has settled.
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent.good()) {
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't check for loop if the server parent is deleted.
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parent.Get(syncable::IS_DEL))
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  vector<syncable::Id> conflicting_entries;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!parent_id.IsRoot()) {
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good()) {
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Bad parent in loop check, skipping. Bad parent id: "
276731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << parent_id << " entry: " << *entry;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent.Get(syncable::IS_UNSYNCED) &&
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        entry->Get(syncable::PARENT_ID) !=
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            entry->Get(syncable::SERVER_PARENT_ID))
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflicting_entries.push_back(parent_id);
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent_id = parent.Get(syncable::PARENT_ID);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent_id == entry->Get(syncable::ID))
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parent_id.IsRoot())
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < conflicting_entries.size(); i++) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    conflict_progress->MergeSets(entry->Get(syncable::ID),
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 conflicting_entries[i]);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ServerDeletedPathChecker {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool CausingConflict(const syncable::Entry& e,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const syncable::Entry& log_entry) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(e.good()) << "Missing parent in path of: " << log_entry;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (e.Get(syncable::IS_UNAPPLIED_UPDATE) &&
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        e.Get(syncable::SERVER_IS_DEL)) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(!e.Get(syncable::IS_DEL)) << " Inconsistency in local tree. "
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            "syncable::Entry: " << e << " Leaf: " << log_entry;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(!e.Get(syncable::IS_DEL)) << " Deleted entry has children. "
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            "syncable::Entry: " << e << " Leaf: " << log_entry;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // returns 0 if we should stop investigating the path.
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static syncable::Id GetAndExamineParent(syncable::BaseTransaction* trans,
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          const syncable::Id& id,
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          const syncable::Id& check_id,
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const syncable::Entry& log_entry) {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry parent(trans, syncable::GET_BY_ID, id);
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(parent.good()) << "Tree inconsitency, missing id" << id << " "
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        << log_entry;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Id parent_id = parent.Get(syncable::PARENT_ID);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(parent_id != check_id) << "Loop in dir tree! "
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << log_entry << " " << parent;
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return parent_id;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass LocallyDeletedPathChecker {
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool CausingConflict(const syncable::Entry& e,
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const syncable::Entry& log_entry) {
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return e.good() && e.Get(syncable::IS_DEL) && e.Get(syncable::IS_UNSYNCED);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // returns 0 if we should stop investigating the path.
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static syncable::Id GetAndExamineParent(syncable::BaseTransaction* trans,
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          const syncable::Id& id,
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                          const syncable::Id& check_id,
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const syncable::Entry& log_entry) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry parent(trans, syncable::GET_BY_ID, id);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good())
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return syncable::kNullId;
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Id parent_id = parent.Get(syncable::PARENT_ID);
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent_id == check_id)
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return syncable::kNullId;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return parent_id;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtemplate <typename Checker>
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrawlDeletedTreeMergingSets(syncable::BaseTransaction* trans,
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const syncable::Entry& entry,
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 ConflictProgress* conflict_progress,
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 Checker checker) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id double_step_parent_id = parent_id;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This block builds sets where we've got an entry in a directory the server
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // wants to delete.
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Here we're walking up the tree to find all entries that the pass checks
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // deleted. We can be extremely strict here as anything unexpected means
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // invariants in the local hierarchy have been broken.
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!parent_id.IsRoot()) {
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!double_step_parent_id.IsRoot()) {
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Checks to ensure we don't loop.
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      double_step_parent_id = checker.GetAndExamineParent(
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          trans, double_step_parent_id, parent_id, entry);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      double_step_parent_id = checker.GetAndExamineParent(
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          trans, double_step_parent_id, parent_id, entry);
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (checker.CausingConflict(parent, entry)) {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflict_progress->MergeSets(entry.Get(syncable::ID),
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   parent.Get(syncable::ID));
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent_id = parent.Get(syncable::PARENT_ID);
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BuildAndProcessConflictSetsCommand::MergeSetsForNonEmptyDirectories(
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans, syncable::Entry* entry,
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictProgress* conflict_progress) {
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry->Get(syncable::IS_UNSYNCED) && !entry->Get(syncable::IS_DEL)) {
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ServerDeletedPathChecker checker;
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CrawlDeletedTreeMergingSets(trans, *entry, conflict_progress, checker);
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry->Get(syncable::IS_UNAPPLIED_UPDATE) &&
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !entry->Get(syncable::SERVER_IS_DEL)) {
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry parent(trans, syncable::GET_BY_ID,
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           entry->Get(syncable::SERVER_PARENT_ID));
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID);
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good())
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LocallyDeletedPathChecker checker;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!checker.CausingConflict(parent, *entry))
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    conflict_progress->MergeSets(entry->Get(syncable::ID),
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 parent.Get(syncable::ID));
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CrawlDeletedTreeMergingSets(trans, parent, conflict_progress, checker);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
409