diff options
author | rlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-02 04:08:20 +0000 |
---|---|---|
committer | rlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-02 04:08:20 +0000 |
commit | 457eaeb40454ac430d095da7f99f79b010167a6d (patch) | |
tree | a48fd1aba11f3bf826b6e354f1700e138f02b6f6 /sync/engine/process_commit_response_command_unittest.cc | |
parent | aa5d4d980164c325f35667d40d38090cb869d100 (diff) | |
download | chromium_src-457eaeb40454ac430d095da7f99f79b010167a6d.zip chromium_src-457eaeb40454ac430d095da7f99f79b010167a6d.tar.gz chromium_src-457eaeb40454ac430d095da7f99f79b010167a6d.tar.bz2 |
sync: Bookmark unique position end-to-end support
This change rewrites the bookmark positioning system to use absolute,
arbitrary-precision, unique positions from end-to-end.
First, it introduces the concept of a UNIQUE_BOOKMARK_TAG. This has a
similar format to the UNIQUE_CLIENT_TAG, though bookmarks have never
supported unique tags previously. For new items, it is initialized
based on the bookmark's originator client item ID (ie. the "c-" style
ID) and the originator's cache_guid. These values should be globally
unique.
Many previously created items that exist in the database do not have
this information available. Non-committed items will still have this
information, and will have their tags set correctly. Previously
committed items will have server style IDs and no hint as to what the
originator_cache_guid is. In that common case, we will initialize the
tag with a "fake" one based solely on the server ID. This has the
advantage of being something that all existing clients will agree on,
even it if new clients and updated items/the server will disagree with
them.
To bring everyone back into sync, whenever they receive an update
clients will access the included originator_cache_guid and
originator_client_item_id fields and reset the UNIQUE_BOOKMARK_TAG field
according to the values they find there. Over time, clients should
converge towards the same tag values.
Next, this change adds the UNIQUE_POSITION and SERVER_UNIQUE_POSITION
fields to each entry. See the UniquePosition class documentation for
more information on their behaviour. New items should have their local
position updated when they are first inserted into the list, which
should happen shortly after they are initialized. Existing items will
have these fields populated from the SERVER_ORDINAL_IN_PARENT field and
the genrated UNIQUE_BOOKMARK_TAG. Unfortunately, all outstanding local
changes will be lost during the migration.
With the addition of UNIQUE_POSITION fields comes the removal of the
PREV_ID and NEXT_ID fields. This required significant refactoring of
the Directory so it could continue to support the PutPredecessor(),
GetPredecessorId(), GetSuccessorId() and GetFirstChildId() functions. A
new class, ParentChildIndex, has been introduced to contain some of the
complexity introduced by the new system. See that class' documentation
for more information.
Communication with the server has also been affected by this change.
The client will now set the unique_position field on every update. It
will also set the legacy server_position_in_parent field with a value
derrived from a truncation of its local UNIQUE_POSITION. This replaces
the existing server position in parent calculation through
interpolation.
The receipt of updates has been changed as well. If the client receives
an update with a unique_position, it will apply it. If the update was
written by an older client, it will contain only the
server_position_in_parent. In that case, the client will use that
position and the unique tag derrived from the update to construct a
unique position that approximates the server_position_in_parent value.
This will work well if the clients have not exceeded the available
precision in an int64. Otherwise, some spurious re-positioning may
occur.
Finally, all these changes required some updates to the tests. Some
arbitrary position assertions had to be updated, since the arbitrary
ordering has changed. Some test helpers have been updated to no longer
automatically place bookmarks at the end of the list; that logic has
been moved to the tests themselves.
BUG=145412, 126505, 147715, 101852, 107744, 112203, 123429, 177521, 20011
Review URL: https://chromiumcodereview.appspot.com/11885024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191767 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/engine/process_commit_response_command_unittest.cc')
-rw-r--r-- | sync/engine/process_commit_response_command_unittest.cc | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/sync/engine/process_commit_response_command_unittest.cc b/sync/engine/process_commit_response_command_unittest.cc index 5c96424..0d25c01 100644 --- a/sync/engine/process_commit_response_command_unittest.cc +++ b/sync/engine/process_commit_response_command_unittest.cc @@ -32,11 +32,13 @@ namespace syncer { using sessions::SyncSession; using syncable::BASE_VERSION; using syncable::Entry; +using syncable::ID; using syncable::IS_DIR; using syncable::IS_UNSYNCED; using syncable::Id; using syncable::MutableEntry; using syncable::NON_UNIQUE_NAME; +using syncable::UNIQUE_POSITION; using syncable::UNITTEST; using syncable::WriteTransaction; @@ -132,7 +134,6 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest { else entry_response->set_id_string(id_factory_.NewServerId().GetServerId()); entry_response->set_version(next_new_revision_++); - entry_response->set_position_in_parent(next_server_position_++); // If the ID of our parent item committed earlier in the batch was // rewritten, rewrite it in the entry response. This matches @@ -218,7 +219,6 @@ TEST_F(ProcessCommitResponseCommandTest, MultipleCommitIdProjections) { Entry b2(&trans, syncable::GET_BY_HANDLE, bookmark2_handle); CheckEntry(&b1, "bookmark 1", BOOKMARKS, new_fid); CheckEntry(&b2, "bookmark 2", BOOKMARKS, new_fid); - ASSERT_TRUE(b2.GetSuccessorId().IsRoot()); // Look at the prefs and autofill items. Entry p1(&trans, syncable::GET_BY_HANDLE, pref1_handle); @@ -230,7 +230,6 @@ TEST_F(ProcessCommitResponseCommandTest, MultipleCommitIdProjections) { Entry a2(&trans, syncable::GET_BY_HANDLE, autofill2_handle); CheckEntry(&a1, "Autofill 1", AUTOFILL, id_factory_.root()); CheckEntry(&a2, "Autofill 2", AUTOFILL, id_factory_.root()); - ASSERT_TRUE(a2.GetSuccessorId().IsRoot()); } // In this test, we test processing a commit response for a commit batch that @@ -256,25 +255,31 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) { // Verify that the item is reachable. { - Id child_id; syncable::ReadTransaction trans(FROM_HERE, directory()); syncable::Entry root(&trans, syncable::GET_BY_ID, id_factory_.root()); ASSERT_TRUE(root.good()); - ASSERT_TRUE(directory()->GetFirstChildId( - &trans, id_factory_.root(), &child_id)); + Id child_id = root.GetFirstChildId(); ASSERT_EQ(folder_id, child_id); } // The first 25 children of the parent folder will be part of the commit - // batch. + // batch. They will be placed left to right in order of creation. int batch_size = 25; int i = 0; + Id prev_id = TestIdFactory::root(); for (; i < batch_size; ++i) { // Alternate between new and old child items, just for kicks. Id id = (i % 4 < 2) ? id_factory_.NewLocalId() : id_factory_.NewServerId(); - CreateUnprocessedCommitResult( + int64 handle = CreateUnprocessedCommitResult( id, folder_id, base::StringPrintf("Item %d", i), false, BOOKMARKS, &commit_set, &request, &response); + { + syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + syncable::MutableEntry e(&trans, syncable::GET_BY_HANDLE, handle); + ASSERT_TRUE(e.good()); + e.PutPredecessor(prev_id); + } + prev_id = id; } // The second 25 children will be unsynced items but NOT part of the commit // batch. When the ID of the parent folder changes during the commit, @@ -283,9 +288,17 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) { for (; i < 2*batch_size; ++i) { // Alternate between new and old child items, just for kicks. Id id = (i % 4 < 2) ? id_factory_.NewLocalId() : id_factory_.NewServerId(); + int64 handle = -1; test_entry_factory_->CreateUnsyncedItem( id, folder_id, base::StringPrintf("Item %d", i), - false, BOOKMARKS, NULL); + false, BOOKMARKS, &handle); + { + syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + syncable::MutableEntry e(&trans, syncable::GET_BY_HANDLE, handle); + ASSERT_TRUE(e.good()); + e.PutPredecessor(prev_id); + } + prev_id = id; } // Process the commit response for the parent folder and the first @@ -299,9 +312,9 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) { syncable::ReadTransaction trans(FROM_HERE, directory()); // Lookup the parent folder by finding a child of the root. We can't use // folder_id here, because it changed during the commit. - Id new_fid; - ASSERT_TRUE(directory()->GetFirstChildId( - &trans, id_factory_.root(), &new_fid)); + syncable::Entry root(&trans, syncable::GET_BY_ID, id_factory_.root()); + ASSERT_TRUE(root.good()); + Id new_fid = root.GetFirstChildId(); ASSERT_FALSE(new_fid.IsRoot()); EXPECT_TRUE(new_fid.ServerKnows()); EXPECT_FALSE(folder_id.ServerKnows()); @@ -313,8 +326,8 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) { ASSERT_LT(0, parent.Get(BASE_VERSION)) << "Parent should have a valid (positive) server base revision"; - Id cid; - ASSERT_TRUE(directory()->GetFirstChildId(&trans, new_fid, &cid)); + Id cid = parent.GetFirstChildId(); + int child_count = 0; // Now loop over all the children of the parent folder, verifying // that they are in their original order by checking to see that their |