1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 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/conflict_resolver.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <map>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_util.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/service_constants.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/sessions/status_controller.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/deprecated/event_sys-inl.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::map;
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::set;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::BaseTransaction;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Directory;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Entry;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Id;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::MutableEntry;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::ScopedDirLookup;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::WriteTransaction;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::ConflictProgress;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::StatusController;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT = 8;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConflictResolver::ConflictResolver() {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConflictResolver::~ConflictResolver() {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConflictResolver::IgnoreLocalChanges(MutableEntry* entry) {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // An update matches local actions, merge the changes.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is a little fishy because we don't actually merge them.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // In the future we should do a 3-way merge.
45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Server and local changes match, merging:" << entry;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // With IS_UNSYNCED false, changes should be merged.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // METRIC simple conflict resolved by merge.
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry->Put(syncable::IS_UNSYNCED, false);
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConflictResolver::OverwriteServerChanges(WriteTransaction* trans,
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              MutableEntry * entry) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is similar to an overwrite from the old client.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is equivalent to a scenario where we got the update before we'd
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // made our local client changes.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(chron): This is really a general property clobber. We clobber
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the server side property. Perhaps we should actually do property merging.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION));
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry->Put(syncable::IS_UNAPPLIED_UPDATE, false);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // METRIC conflict resolved by overwrite.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConflictResolver::ProcessSimpleConflictResult
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const Id& id) {
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MutableEntry entry(trans, syncable::GET_BY_ID, id);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Must be good as the entry won't have been cleaned up.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(entry.good());
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If an update fails, locally we have to be in a set or unsynced. We're not
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in a set here, so we must be unsynced.
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Get(syncable::IS_UNSYNCED)) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NO_SYNC_PROGRESS;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE)) {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry.Get(syncable::PARENT_ID).ServerKnows()) {
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Item conflicting because its parent not yet committed. Id: "
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << id;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "No set for conflicting entry id " << id << ". There should "
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                 "be an update/commit that will fix this soon. This message "
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                 "should not repeat.";
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NO_SYNC_PROGRESS;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we've both deleted it, so lets just drop the need to commit/update this
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // entry.
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry.Put(syncable::IS_UNSYNCED, false);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we've made changes, but they won't help syncing progress.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // METRIC simple conflict resolved by merge.
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NO_SYNC_PROGRESS;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Get(syncable::SERVER_IS_DEL)) {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This logic determines "client wins" vs. "server wins" strategy picking.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(nick): The current logic is arbitrary; instead, it ought to be made
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // consistent with the ModelAssociator behavior for a datatype.  It would
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // be nice if we could route this back to ModelAssociator code to pick one
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // of three options: CLIENT, SERVER, or MERGE.  Some datatypes (autofill)
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // are easily mergeable.
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool name_matches = entry.Get(syncable::NON_UNIQUE_NAME) ==
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        entry.Get(syncable::SERVER_NON_UNIQUE_NAME);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool parent_matches = entry.Get(syncable::PARENT_ID) ==
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    entry.Get(syncable::SERVER_PARENT_ID);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool entry_deleted = entry.Get(syncable::IS_DEL);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry_deleted && name_matches && parent_matches) {
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Resolving simple conflict, ignoring local changes for:"
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << entry;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IgnoreLocalChanges(&entry);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Resolving simple conflict, overwriting server changes for:"
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << entry;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OverwriteServerChanges(trans, &entry);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return SYNC_PROGRESS;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {  // SERVER_IS_DEL is true
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If a server deleted folder has local contents we should be in a set.
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry.Get(syncable::IS_DIR)) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Directory::ChildHandles children;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      trans->directory()->GetChildHandles(trans,
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          entry.Get(syncable::ID),
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          &children);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (0 != children.size()) {
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        VLOG(1) << "Entry is a server deleted directory with local contents, "
129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   "should be in a set. (race condition).";
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return NO_SYNC_PROGRESS;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The entry is deleted on the server but still exists locally.
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry.Get(syncable::UNIQUE_CLIENT_TAG).empty()) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we've got a client-unique tag, we can undelete while retaining
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // our present ID.
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      DCHECK_EQ(entry.Get(syncable::SERVER_VERSION), 0) << "For the server to "
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          "know to re-create, client-tagged items should revert to version 0 "
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          "when server-deleted.";
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OverwriteServerChanges(trans, &entry);
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Clobber the versions, just in case the above DCHECK is violated.
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.Put(syncable::SERVER_VERSION, 0);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.Put(syncable::BASE_VERSION, 0);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Otherwise, we've got to undelete by creating a new locally
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // uncommitted entry.
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SyncerUtil::SplitServerInformationIntoNewEntry(trans, &entry);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MutableEntry server_update(trans, syncable::GET_BY_ID, id);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(server_update.good());
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(server_update.Get(syncable::META_HANDLE) !=
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            entry.Get(syncable::META_HANDLE))
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          << server_update << entry;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return SYNC_PROGRESS;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochConflictResolver::ConflictSetCountMapKey ConflictResolver::GetSetKey(
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictSet* set) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sync): Come up with a better scheme for set hashing. This scheme
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will make debugging easy.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If this call to sort is removed, we need to add one before we use
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // binary_search in ProcessConflictSet.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sort(set->begin(), set->end());
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::stringstream rv;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ConflictSet::iterator i = set->begin() ; i != set->end() ; ++i )
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv << *i << ".";
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv.str();
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AttemptToFixCircularConflict(WriteTransaction* trans,
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  ConflictSet* conflict_set) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConflictSet::const_iterator i, j;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) {
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MutableEntry entryi(trans, syncable::GET_BY_ID, *i);
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entryi.Get(syncable::PARENT_ID) ==
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            entryi.Get(syncable::SERVER_PARENT_ID) ||
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !entryi.Get(syncable::IS_UNAPPLIED_UPDATE) ||
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !entryi.Get(syncable::IS_DIR)) {
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Id parentid = entryi.Get(syncable::SERVER_PARENT_ID);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create the entry here as it's the only place we could ever get a parentid
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that doesn't correspond to a real entry.
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry parent(trans, syncable::GET_BY_ID, parentid);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good())  // server parent update not received yet
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This loop walks upwards from the server parent. If we hit the root (0)
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // all is well. If we hit the entry we're examining it means applying the
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // parent id would cause a loop. We don't need more general loop detection
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // because we know our local tree is valid.
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (!parentid.IsRoot()) {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Entry parent(trans, syncable::GET_BY_ID, parentid);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(parent.good());
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (parentid == *i)
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;  // It's a loop.
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      parentid = parent.Get(syncable::PARENT_ID);
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parentid.IsRoot())
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Overwriting server changes to avoid loop: " << entryi;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entryi.Put(syncable::BASE_VERSION, entryi.Get(syncable::SERVER_VERSION));
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entryi.Put(syncable::IS_UNSYNCED, true);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entryi.Put(syncable::IS_UNAPPLIED_UPDATE, false);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // METRIC conflict resolved by breaking dir loop.
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AttemptToFixUnsyncedEntryInDeletedServerTree(WriteTransaction* trans,
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  ConflictSet* conflict_set,
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  const Entry& entry) {
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Get(syncable::IS_UNSYNCED) || entry.Get(syncable::IS_DEL))
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Id parentid = entry.Get(syncable::PARENT_ID);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MutableEntry parent(trans, syncable::GET_BY_ID, parentid);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent.good() || !parent.Get(syncable::IS_UNAPPLIED_UPDATE) ||
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !parent.Get(syncable::SERVER_IS_DEL) ||
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !binary_search(conflict_set->begin(), conflict_set->end(), parentid))
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We're trying to commit into a directory tree that's been deleted. To
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // solve this we recreate the directory tree.
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We do this in two parts, first we ensure the tree is unaltered since the
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // conflict was detected.
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Id id = parentid;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!id.IsRoot()) {
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!binary_search(conflict_set->begin(), conflict_set->end(), id))
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry parent(trans, syncable::GET_BY_ID, id);
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good() || !parent.Get(syncable::IS_UNAPPLIED_UPDATE) ||
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !parent.Get(syncable::SERVER_IS_DEL))
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    id = parent.Get(syncable::PARENT_ID);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now we fix up the entries.
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id = parentid;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!id.IsRoot()) {
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MutableEntry parent(trans, syncable::GET_BY_ID, id);
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!binary_search(conflict_set->begin(), conflict_set->end(), id))
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Giving directory a new id so we can undelete it " << parent;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ClearServerData(&parent);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncerUtil::ChangeEntryIDAndUpdateChildren(trans, &parent,
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        trans->directory()->NextId());
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent.Put(syncable::BASE_VERSION, 0);
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent.Put(syncable::IS_UNSYNCED, true);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    id = parent.Get(syncable::PARENT_ID);
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // METRIC conflict resolved by recreating dir tree.
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(chron): needs unit test badly
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AttemptToFixUpdateEntryInDeletedLocalTree(WriteTransaction* trans,
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               ConflictSet* conflict_set,
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               const Entry& entry) {
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE) ||
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.Get(syncable::SERVER_IS_DEL))
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Id parent_id = entry.Get(syncable::SERVER_PARENT_ID);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MutableEntry parent(trans, syncable::GET_BY_ID, parent_id);
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!parent.good() || !parent.Get(syncable::IS_DEL) ||
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    !binary_search(conflict_set->begin(), conflict_set->end(), parent_id)) {
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We've deleted a directory tree that's got contents on the server. We
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // recreate the directory to solve the problem.
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We do this in two parts, first we ensure the tree is unaltered since
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the conflict was detected.
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Id id = parent_id;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // As we will be crawling the path of deleted entries there's a chance we'll
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // end up having to reparent an item as there will be an invalid parent.
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Id reroot_id = syncable::kNullId;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Similarly crawling deleted items means we risk loops.
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int loop_detection = conflict_set->size();
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!id.IsRoot() && --loop_detection >= 0) {
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry parent(trans, syncable::GET_BY_ID, id);
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we get a bad parent, or a parent that's deleted on client and server
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we recreate the hierarchy in the root.
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.good()) {
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reroot_id = id;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(parent.Get(syncable::IS_DIR));
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!binary_search(conflict_set->begin(), conflict_set->end(), id)) {
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We've got to an entry that's not in the set. If it has been deleted
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // between set building and this point in time we return false. If it had
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // been deleted earlier it would have been in the set.
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(sync): Revisit syncer code organization to see if conflict
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // resolution can be done in the same transaction as set building.
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (parent.Get(syncable::IS_DEL))
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!parent.Get(syncable::IS_DEL) ||
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        parent.Get(syncable::SERVER_IS_DEL) ||
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !parent.Get(syncable::IS_UNSYNCED)) {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    id = parent.Get(syncable::PARENT_ID);
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we find we've been looping we re-root the hierarchy.
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (loop_detection < 0) {
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (id == entry.Get(syncable::ID))
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reroot_id = entry.Get(syncable::PARENT_ID);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reroot_id = id;
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now we fix things up by undeleting all the folders in the item's path.
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id = parent_id;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!id.IsRoot() && id != reroot_id) {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!binary_search(conflict_set->begin(), conflict_set->end(), id)) {
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MutableEntry entry(trans, syncable::GET_BY_ID, id);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Undoing our deletion of " << entry
325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            << ", will have name " << entry.Get(syncable::NON_UNIQUE_NAME);
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Id parent_id = entry.Get(syncable::PARENT_ID);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (parent_id == reroot_id) {
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      parent_id = trans->root_id();
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry.Put(syncable::PARENT_ID, parent_id);
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry.Put(syncable::IS_DEL, false);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    id = entry.Get(syncable::PARENT_ID);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // METRIC conflict resolved by recreating dir tree.
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool AttemptToFixRemovedDirectoriesWithContent(WriteTransaction* trans,
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               ConflictSet* conflict_set) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConflictSet::const_iterator i,j;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) {
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry entry(trans, syncable::GET_BY_ID, *i);
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (AttemptToFixUnsyncedEntryInDeletedServerTree(trans,
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        conflict_set, entry)) {
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (AttemptToFixUpdateEntryInDeletedLocalTree(trans, conflict_set, entry))
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(sync): Eliminate conflict sets. They're not necessary.
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ConflictResolver::ProcessConflictSet(WriteTransaction* trans,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          ConflictSet* conflict_set,
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          int conflict_count) {
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int set_size = conflict_set->size();
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (set_size < 2) {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Skipping conflict set because it has size " << set_size;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We can end up with sets of size one if we have a new item in a set that
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we tried to commit transactionally. This should not be a persistent
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // situation.
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (conflict_count < 3) {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Avoid resolving sets that could be the result of transient conflicts.
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Transient conflicts can occur because the client or server can be
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // slightly out of date.
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Fixing a set containing " << set_size << " items";
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Fix circular conflicts.
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (AttemptToFixCircularConflict(trans, conflict_set))
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check for problems involving contents of removed folders.
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (AttemptToFixRemovedDirectoriesWithContent(trans, conflict_set))
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtemplate <typename InputIt>
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ConflictResolver::LogAndSignalIfConflictStuck(
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTransaction* trans,
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int attempt_count,
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    InputIt begin,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    InputIt end,
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StatusController* status) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attempt_count < SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT) {
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't signal stuck if we're not up to date.
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (status->num_server_changes_remaining() > 0) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG(ERROR) << "[BUG] Conflict set cannot be resolved, has "
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             << end - begin << " items:";
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (InputIt i = begin ; i != end ; ++i) {
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry e(trans, syncable::GET_BY_ID, *i);
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (e.good())
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "  " << e;
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "  Bad ID:" << *i;
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->set_syncer_stuck(true);
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sync): If we're stuck for a while we need to alert the user, clear
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // cache or reset syncing. At the very least we should stop trying something
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that's obviously not working.
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ConflictResolver::ResolveSimpleConflicts(const ScopedDirLookup& dir,
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              StatusController* status) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool forward_progress = false;
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ConflictProgress& progress = status->conflict_progress();
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First iterate over simple conflict items (those that belong to no set).
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<Id>::const_iterator conflicting_item_it;
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (conflicting_item_it = progress.ConflictingItemsBeginConst();
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       conflicting_item_it != progress.ConflictingItemsEnd();
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++conflicting_item_it) {
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Id id = *conflicting_item_it;
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    map<Id, ConflictSet*>::const_iterator item_set_it =
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        progress.IdToConflictSetFind(id);
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (item_set_it == progress.IdToConflictSetEnd() ||
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0 == item_set_it->second) {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We have a simple conflict.
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      switch (ProcessSimpleConflict(&trans, id)) {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case NO_SYNC_PROGRESS:
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            int conflict_count = (simple_conflict_count_map_[id] += 2);
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            LogAndSignalIfConflictStuck(&trans, conflict_count,
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        &id, &id + 1, status);
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            break;
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          }
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case SYNC_PROGRESS:
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          forward_progress = true;
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reduce the simple_conflict_count for each item currently tracked.
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SimpleConflictCountMap::iterator i = simple_conflict_count_map_.begin();
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (i != simple_conflict_count_map_.end()) {
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (0 == --(i->second))
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      simple_conflict_count_map_.erase(i++);
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return forward_progress;
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir,
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        StatusController* status) {
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ConflictProgress& progress = status->conflict_progress();
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool rv = false;
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ResolveSimpleConflicts(dir, status))
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = true;
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<Id> children_of_dirs_merged_last_round;
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::swap(children_of_merged_dirs_, children_of_dirs_merged_last_round);
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<ConflictSet*>::const_iterator set_it;
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (set_it = progress.ConflictSetsBegin();
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       set_it != progress.ConflictSetsEnd();
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       set_it++) {
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictSet* conflict_set = *set_it;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ConflictSetCountMapKey key = GetSetKey(conflict_set);
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    conflict_set_count_map_[key] += 2;
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int conflict_count = conflict_set_count_map_[key];
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Keep a metric for new sets.
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (2 == conflict_count) {
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // METRIC conflict sets seen ++
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See if this set contains entries whose parents were merged last round.
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (SortedCollectionsIntersect(children_of_dirs_merged_last_round.begin(),
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   children_of_dirs_merged_last_round.end(),
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   conflict_set->begin(),
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   conflict_set->end())) {
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << "Accelerating resolution for hierarchical merge.";
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflict_count += 2;
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See if we should process this set.
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ProcessConflictSet(&trans, conflict_set, conflict_count)) {
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      rv = true;
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogAndSignalIfConflictStuck(&trans, conflict_count,
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                conflict_set->begin(),
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                conflict_set->end(), status);
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rv) {
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This code means we don't signal that syncing is stuck when any conflict
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // resolution has occured.
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(sync): As this will also reduce our sensitivity to problem
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // conditions and increase the time for cascading resolutions we may have to
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // revisit this code later, doing something more intelligent.
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    conflict_set_count_map_.clear();
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    simple_conflict_count_map_.clear();
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConflictSetCountMap::iterator i = conflict_set_count_map_.begin();
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (i != conflict_set_count_map_.end()) {
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (0 == --i->second) {
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflict_set_count_map_.erase(i++);
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // METRIC self resolved conflict sets ++.
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++i;
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
520