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