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

Unified Diff: chrome/browser/sync/engine/conflict_resolver.cc

Issue 371029: Remove unique naming. (Closed)
Patch Set: Ready and about to go in! Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/sync/engine/conflict_resolver.h ('k') | chrome/browser/sync/engine/get_commit_ids_command.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/sync/engine/conflict_resolver.cc
diff --git a/chrome/browser/sync/engine/conflict_resolver.cc b/chrome/browser/sync/engine/conflict_resolver.cc
old mode 100644
new mode 100755
index f67ea522372cca564dd4f5fffb711e3612de8366..1f7896ef8c69814d6c9d709dbcec1c66d83c2210
--- a/chrome/browser/sync/engine/conflict_resolver.cc
+++ b/chrome/browser/sync/engine/conflict_resolver.cc
@@ -23,9 +23,7 @@ using syncable::Directory;
using syncable::Entry;
using syncable::Id;
using syncable::MutableEntry;
-using syncable::Name;
using syncable::ScopedDirLookup;
-using syncable::SyncName;
using syncable::WriteTransaction;
namespace browser_sync {
@@ -38,88 +36,6 @@ ConflictResolver::ConflictResolver() {
ConflictResolver::~ConflictResolver() {
}
-namespace {
-// TODO(ncarter): Remove title/path conflicts and the code to resolve them.
-// This is historical cruft that seems to be actually reached by some users.
-inline PathString GetConflictPathnameBase(PathString base) {
- time_t time_since = time(NULL);
- struct tm* now = localtime(&time_since);
- // Use a fixed format as the locale's format may include '/' characters or
- // other illegal characters.
- PathString date = IntToPathString(now->tm_year + 1900);
- date.append(PSTR("-"));
- ++now->tm_mon; // tm_mon is 0-based.
- if (now->tm_mon < 10)
- date.append(PSTR("0"));
- date.append(IntToPathString(now->tm_mon));
- date.append(PSTR("-"));
- if (now->tm_mday < 10)
- date.append(PSTR("0"));
- date.append(IntToPathString(now->tm_mday));
- return base + PSTR(" (Edited on ") + date + PSTR(")");
-}
-
-// TODO(ncarter): Remove title/path conflicts and the code to resolve them.
-Name FindNewName(BaseTransaction* trans,
- Id parent_id,
- const SyncName& original_name) {
- const PathString name = original_name.value();
- // 255 is defined in our spec.
- const size_t allowed_length = kSyncProtocolMaxNameLengthBytes;
- // TODO(sync): How do we get length on other platforms? The limit is
- // checked in java on the server, so it's not the number of glyphs its the
- // number of 16 bit characters in the UTF-16 representation.
-
- // 10 characters for 32 bit numbers + 2 characters for brackets means 12
- // characters should be more than enough for the name. Doubling this ensures
- // that we will have enough space.
- COMPILE_ASSERT(kSyncProtocolMaxNameLengthBytes >= 24,
- maximum_name_too_short);
- CHECK(name.length() <= allowed_length);
-
- if (!Entry(trans,
- syncable::GET_BY_PARENTID_AND_DBNAME,
- parent_id,
- name).good())
- return Name::FromSyncName(original_name);
- PathString base = name;
- PathString ext;
- PathString::size_type ext_index = name.rfind('.');
- if (PathString::npos != ext_index && 0 != ext_index &&
- name.length() - ext_index < allowed_length / 2) {
- base = name.substr(0, ext_index);
- ext = name.substr(ext_index);
- }
-
- PathString name_base = GetConflictPathnameBase(base);
- if (name_base.length() + ext.length() > allowed_length) {
- name_base.resize(allowed_length - ext.length());
- TrimPathStringToValidCharacter(&name_base);
- }
- PathString new_name = name_base + ext;
- int n = 2;
- while (Entry(trans,
- syncable::GET_BY_PARENTID_AND_DBNAME,
- parent_id,
- new_name).good()) {
- PathString local_ext = PSTR("(");
- local_ext.append(IntToPathString(n));
- local_ext.append(PSTR(")"));
- local_ext.append(ext);
- if (name_base.length() + local_ext.length() > allowed_length) {
- name_base.resize(allowed_length - local_ext.length());
- TrimPathStringToValidCharacter(&name_base);
- }
- new_name = name_base + local_ext;
- n++;
- }
-
- CHECK(new_name.length() <= kSyncProtocolMaxNameLengthBytes);
- return Name(new_name);
-}
-
-} // namespace
-
void ConflictResolver::IgnoreLocalChanges(MutableEntry* entry) {
// An update matches local actions, merge the changes.
// This is a little fishy because we don't actually merge them.
@@ -151,8 +67,10 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
CHECK(entry.good());
// If an update fails, locally we have to be in a set or unsynced. We're not
// in a set here, so we must be unsynced.
- if (!entry.Get(syncable::IS_UNSYNCED))
+ if (!entry.Get(syncable::IS_UNSYNCED)) {
return NO_SYNC_PROGRESS;
+ }
+
if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE)) {
if (!entry.Get(syncable::PARENT_ID).ServerKnows()) {
LOG(INFO) << "Item conflicting because its parent not yet committed. "
@@ -164,6 +82,7 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
}
return NO_SYNC_PROGRESS;
}
+
if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) {
// we've both deleted it, so lets just drop the need to commit/update this
// entry.
@@ -180,7 +99,8 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
// Check if there's no changes.
// Verbose but easier to debug.
- bool name_matches = entry.SyncNameMatchesServerName();
+ bool name_matches = entry.Get(syncable::NON_UNIQUE_NAME) ==
+ entry.Get(syncable::SERVER_NON_UNIQUE_NAME);
bool parent_matches = entry.Get(syncable::PARENT_ID) ==
entry.Get(syncable::SERVER_PARENT_ID);
bool entry_deleted = entry.Get(syncable::IS_DEL);
@@ -208,7 +128,6 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
return NO_SYNC_PROGRESS;
}
}
- // METRIC conflict resolved by entry split;
// If the entry's deleted on the server, we can have a directory here.
entry.Put(syncable::IS_UNSYNCED, true);
@@ -225,162 +144,6 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
}
}
-namespace {
-
-bool NamesCollideWithChildrenOfFolder(BaseTransaction* trans,
- const Directory::ChildHandles& children,
- Id folder_id) {
- Directory::ChildHandles::const_iterator i = children.begin();
- while (i != children.end()) {
- Entry child(trans, syncable::GET_BY_HANDLE, *i);
- CHECK(child.good());
- if (Entry(trans,
- syncable::GET_BY_PARENTID_AND_DBNAME,
- folder_id,
- child.GetName().db_value()).good())
- return true;
- ++i;
- }
- return false;
-}
-
-void GiveEntryNewName(WriteTransaction* trans, MutableEntry* entry) {
- using namespace syncable;
- Name new_name =
- FindNewName(trans, entry->Get(syncable::PARENT_ID), entry->GetName());
- LOG(INFO) << "Resolving name clash, renaming " << *entry << " to "
- << new_name.db_value();
- entry->PutName(new_name);
- CHECK(entry->Get(syncable::IS_UNSYNCED));
-}
-
-} // namespace
-
-bool ConflictResolver::AttemptItemMerge(WriteTransaction* trans,
- MutableEntry* locally_named,
- MutableEntry* server_named) {
- // To avoid complications we only merge new entries with server entries.
- if (locally_named->Get(syncable::IS_DIR) !=
- server_named->Get(syncable::SERVER_IS_DIR) ||
- locally_named->Get(syncable::ID).ServerKnows() ||
- locally_named->Get(syncable::IS_UNAPPLIED_UPDATE) ||
- server_named->Get(syncable::IS_UNSYNCED))
- return false;
- Id local_id = locally_named->Get(syncable::ID);
- Id desired_id = server_named->Get(syncable::ID);
- if (locally_named->Get(syncable::IS_DIR)) {
- // Extra work for directory name clash. We have to make sure we don't have
- // clashing child items, and update the parent id the children of the new
- // entry.
- Directory::ChildHandles children;
- trans->directory()->GetChildHandles(trans, local_id, &children);
- if (NamesCollideWithChildrenOfFolder(trans, children, desired_id))
- return false;
-
- LOG(INFO) << "Merging local changes to: " << desired_id << ". "
- << *locally_named;
-
- server_named->Put(syncable::ID, trans->directory()->NextId());
- Directory::ChildHandles::iterator i;
- for (i = children.begin() ; i != children.end() ; ++i) {
- MutableEntry child_entry(trans, syncable::GET_BY_HANDLE, *i);
- CHECK(child_entry.good());
- CHECK(child_entry.Put(syncable::PARENT_ID, desired_id));
- CHECK(child_entry.Put(syncable::IS_UNSYNCED, true));
- Id id = child_entry.Get(syncable::ID);
- // We only note new entries for quicker merging next round.
- if (!id.ServerKnows())
- children_of_merged_dirs_.insert(id);
- }
- } else {
- if (!server_named->Get(syncable::IS_DEL))
- return false;
- }
-
- LOG(INFO) << "Identical client and server items merging server changes. " <<
- *locally_named << " server: " << *server_named;
-
- // Clear server_named's server data and mark it deleted so it goes away
- // quietly because it's now identical to a deleted local entry.
- // locally_named takes on the ID of the server entry.
- server_named->Put(syncable::ID, trans->directory()->NextId());
- locally_named->Put(syncable::ID, desired_id);
- locally_named->Put(syncable::IS_UNSYNCED, false);
- CopyServerFields(server_named, locally_named);
- ClearServerData(server_named);
- server_named->Put(syncable::IS_DEL, true);
- server_named->Put(syncable::BASE_VERSION, 0);
- CHECK(SUCCESS ==
- SyncerUtil::AttemptToUpdateEntryWithoutMerge(
- trans, locally_named, NULL));
- return true;
-}
-
-ConflictResolver::ServerClientNameClashReturn
-ConflictResolver::ProcessServerClientNameClash(WriteTransaction* trans,
- MutableEntry* locally_named,
- MutableEntry* server_named,
- SyncerSession* session) {
- if (!locally_named->ExistsOnClientBecauseDatabaseNameIsNonEmpty())
- return NO_CLASH; // Locally_named is a server update.
- if (locally_named->Get(syncable::IS_DEL) ||
- server_named->Get(syncable::SERVER_IS_DEL)) {
- return NO_CLASH;
- }
- if (locally_named->Get(syncable::PARENT_ID) !=
- server_named->Get(syncable::SERVER_PARENT_ID)) {
- return NO_CLASH; // Different parents.
- }
-
- PathString name = locally_named->GetSyncNameValue();
- if (0 != syncable::ComparePathNames(name,
- server_named->Get(syncable::SERVER_NAME))) {
- return NO_CLASH; // Different names.
- }
-
- // First try to merge.
- if (AttemptItemMerge(trans, locally_named, server_named)) {
- // METRIC conflict resolved by merge
- return SOLVED;
- }
- // We need to rename.
- if (!locally_named->Get(syncable::IS_UNSYNCED)) {
- LOG(ERROR) << "Locally named part of a name conflict not unsynced?";
- locally_named->Put(syncable::IS_UNSYNCED, true);
- }
- if (!server_named->Get(syncable::IS_UNAPPLIED_UPDATE)) {
- LOG(ERROR) << "Server named part of a name conflict not an update?";
- }
- GiveEntryNewName(trans, locally_named);
-
- // METRIC conflict resolved by rename
- return SOLVED;
-}
-
-ConflictResolver::ServerClientNameClashReturn
-ConflictResolver::ProcessNameClashesInSet(WriteTransaction* trans,
- ConflictSet* conflict_set,
- SyncerSession* session) {
- ConflictSet::const_iterator i,j;
- for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) {
- MutableEntry entryi(trans, syncable::GET_BY_ID, *i);
- if (!entryi.Get(syncable::IS_UNSYNCED) &&
- !entryi.Get(syncable::IS_UNAPPLIED_UPDATE))
- // This set is broken / doesn't make sense, this may be transient.
- return BOGUS_SET;
- for (j = conflict_set->begin() ; *i != *j ; ++j) {
- MutableEntry entryj(trans, syncable::GET_BY_ID, *j);
- ServerClientNameClashReturn rv =
- ProcessServerClientNameClash(trans, &entryi, &entryj, session);
- if (NO_CLASH == rv)
- rv = ProcessServerClientNameClash(trans, &entryj, &entryi, session);
- if (NO_CLASH != rv)
- return rv;
- }
- }
- return NO_CLASH;
-}
-
ConflictResolver::ConflictSetCountMapKey ConflictResolver::GetSetKey(
ConflictSet* set) {
// TODO(sync): Come up with a better scheme for set hashing. This scheme
@@ -481,6 +244,8 @@ bool AttemptToFixUnsyncedEntryInDeletedServerTree(WriteTransaction* trans,
return true;
}
+
+// TODO(chron): needs unit test badly
bool AttemptToFixUpdateEntryInDeletedLocalTree(WriteTransaction* trans,
ConflictSet* conflict_set,
const Entry& entry) {
@@ -540,18 +305,19 @@ bool AttemptToFixUpdateEntryInDeletedLocalTree(WriteTransaction* trans,
// Now we fix things up by undeleting all the folders in the item's path.
id = parent_id;
while (!id.IsRoot() && id != reroot_id) {
- if (!binary_search(conflict_set->begin(), conflict_set->end(), id))
+ if (!binary_search(conflict_set->begin(), conflict_set->end(), id)) {
break;
+ }
MutableEntry entry(trans, syncable::GET_BY_ID, id);
+
+ LOG(INFO) << "Undoing our deletion of " << entry
+ << ", will have name " << entry.Get(syncable::NON_UNIQUE_NAME);
+
Id parent_id = entry.Get(syncable::PARENT_ID);
- if (parent_id == reroot_id)
+ if (parent_id == reroot_id) {
parent_id = trans->root_id();
- Name old_name = entry.GetName();
- Name new_name = FindNewName(trans, parent_id, old_name);
- LOG(INFO) << "Undoing our deletion of " << entry <<
- ", will have name " << new_name.db_value();
- if (new_name != old_name || parent_id != entry.Get(syncable::PARENT_ID))
- CHECK(entry.PutParentIdAndName(parent_id, new_name));
+ }
+ entry.Put(syncable::PARENT_ID, parent_id);
entry.Put(syncable::IS_DEL, false);
id = entry.Get(syncable::PARENT_ID);
// METRIC conflict resolved by recreating dir tree.
@@ -576,6 +342,7 @@ bool AttemptToFixRemovedDirectoriesWithContent(WriteTransaction* trans,
} // namespace
+// TODO(sync): Eliminate conflict sets. They're not necessary.
bool ConflictResolver::ProcessConflictSet(WriteTransaction* trans,
ConflictSet* conflict_set,
int conflict_count,
@@ -597,13 +364,6 @@ bool ConflictResolver::ProcessConflictSet(WriteTransaction* trans,
LOG(INFO) << "Fixing a set containing " << set_size << " items";
- ServerClientNameClashReturn rv = ProcessNameClashesInSet(trans, conflict_set,
- session);
- if (SOLVED == rv)
- return true;
- if (NO_CLASH != rv)
- return false;
-
// Fix circular conflicts.
if (AttemptToFixCircularConflict(trans, conflict_set))
return true;
« no previous file with comments | « chrome/browser/sync/engine/conflict_resolver.h ('k') | chrome/browser/sync/engine/get_commit_ids_command.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698