| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/engine/syncer_util.h" | 5 #include "chrome/browser/sync/engine/syncer_util.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 syncable::WriteTransaction* trans, | 125 syncable::WriteTransaction* trans, |
| 126 syncable::MutableEntry* entry, | 126 syncable::MutableEntry* entry, |
| 127 const syncable::Id& new_id) { | 127 const syncable::Id& new_id) { |
| 128 syncable::Directory::ChildHandles children; | 128 syncable::Directory::ChildHandles children; |
| 129 ChangeEntryIDAndUpdateChildren(trans, entry, new_id, &children); | 129 ChangeEntryIDAndUpdateChildren(trans, entry, new_id, &children); |
| 130 } | 130 } |
| 131 | 131 |
| 132 // static | 132 // static |
| 133 void SyncerUtil::AttemptReuniteClientTag(syncable::WriteTransaction* trans, | 133 void SyncerUtil::AttemptReuniteClientTag(syncable::WriteTransaction* trans, |
| 134 const SyncEntity& server_entry) { | 134 const SyncEntity& server_entry) { |
| 135 if (!server_entry.has_client_defined_unique_tag() || |
| 136 server_entry.client_defined_unique_tag().empty()) { |
| 137 return; |
| 138 } |
| 135 | 139 |
| 136 // Expected entry points of this function: | 140 // Expected entry points of this function: |
| 137 // SyncEntity has NOT been applied to SERVER fields. | 141 // SyncEntity has NOT been applied to SERVER fields. |
| 138 // SyncEntity has NOT been applied to LOCAL fields. | 142 // SyncEntity has NOT been applied to LOCAL fields. |
| 139 // DB has not yet been modified, no entries created for this update. | 143 // DB has not yet been modified, no entries created for this update. |
| 140 | 144 |
| 141 // When a server sends down a client tag, the following cases can occur: | 145 // When a server sends down a client tag, the following cases can occur: |
| 142 // 1) Client has entry for tag already, ID is server style, matches | 146 // 1) Client has entry for tag already, ID is server style, matches |
| 143 // 2) Client has entry for tag already, ID is server, doesn't match. | 147 // 2) Client has entry for tag already, ID is server, doesn't match. |
| 144 // 3) Client has entry for tag already, ID is local, (never matches) | 148 // 3) Client has entry for tag already, ID is local, (never matches) |
| 145 // 4) Client has no entry for tag | 149 // 4) Client has no entry for tag |
| 146 | 150 |
| 147 // Case 1, we don't have to do anything since the update will | 151 // Case 1, we don't have to do anything since the update will |
| 148 // work just fine. Update will end up in the proper entry, via ID lookup. | 152 // work just fine. Update will end up in the proper entry, via ID lookup. |
| 149 // Case 2 - Should never happen. We'd need to change the | 153 // Case 2 - Should never happen. We'd need to change the |
| 150 // ID of the local entry, we refuse. We'll skip this in VERIFY. | 154 // ID of the local entry, we refuse. We'll skip this in VERIFY. |
| 151 // Case 3 - We need to replace the local ID with the server ID. Conflict | 155 // Case 3 - We need to replace the local ID with the server ID so that |
| 152 // resolution must occur, but this is prior to update application! This case | 156 // this update gets targeted at the correct local entry; we expect conflict |
| 153 // should be rare. For now, clobber client changes entirely. | 157 // resolution to occur. |
| 154 // Case 4 - Perfect. Same as case 1. | 158 // Case 4 - Perfect. Same as case 1. |
| 155 | 159 |
| 156 syncable::MutableEntry local_entry(trans, syncable::GET_BY_CLIENT_TAG, | 160 syncable::MutableEntry local_entry(trans, syncable::GET_BY_CLIENT_TAG, |
| 157 server_entry.client_defined_unique_tag()); | 161 server_entry.client_defined_unique_tag()); |
| 158 | 162 |
| 159 // The SyncAPI equivalent of this function will return !good if IS_DEL. | 163 // The SyncAPI equivalent of this function will return !good if IS_DEL. |
| 160 // The syncable version will return good even if IS_DEL. | 164 // The syncable version will return good even if IS_DEL. |
| 161 // TODO(chron): Unit test the case with IS_DEL and make sure. | 165 // TODO(chron): Unit test the case with IS_DEL and make sure. |
| 162 if (local_entry.good()) { | 166 if (local_entry.good()) { |
| 163 if (local_entry.Get(ID).ServerKnows()) { | 167 if (local_entry.Get(ID).ServerKnows()) { |
| 164 // In release config, this will just continue and we'll | 168 // In release config, this will just continue and we'll |
| 165 // throw VERIFY_FAIL later. | 169 // throw VERIFY_FAIL later. |
| 166 // This is Case 1 on success, Case 2 if it fails. | 170 // This is Case 1 on success, Case 2 if it fails. |
| 167 DCHECK(local_entry.Get(ID) == server_entry.id()); | 171 DCHECK(local_entry.Get(ID) == server_entry.id()); |
| 168 } else { | 172 } else { |
| 169 // Case 3: We have a local entry with the same client tag. | 173 // Case 3: We have a local entry with the same client tag. |
| 170 // We can't have two updates with the same client tag though. | 174 // We should change the ID of the local entry to the server entry. |
| 171 // One of these has to go. Let's delete the client entry and move it | 175 // This will result in an server ID with base version == 0, but that's |
| 172 // aside. This will cause a delete + create. The client API user must | 176 // a legal state for an item with a client tag. By changing the ID, |
| 173 // handle this correctly. In this situation the client must have created | 177 // server_entry will now be applied to local_entry. |
| 174 // this entry but not yet committed it for the first time. Usually the | 178 ChangeEntryIDAndUpdateChildren(trans, &local_entry, server_entry.id()); |
| 175 // client probably wants the server data for this instead. | 179 DCHECK(0 == local_entry.Get(BASE_VERSION) || |
| 176 // Other strategies to handle this are a bit flaky. | 180 CHANGES_VERSION == local_entry.Get(BASE_VERSION)); |
| 177 DCHECK(local_entry.Get(IS_UNAPPLIED_UPDATE) == false); | |
| 178 local_entry.Put(IS_UNSYNCED, false); | |
| 179 local_entry.Put(IS_DEL, true); | |
| 180 // Needs to get out of the index before our update can be put in. | |
| 181 local_entry.Put(UNIQUE_CLIENT_TAG, ""); | |
| 182 } | 181 } |
| 183 } | 182 } |
| 184 // Case 4: Client has no entry for tag, all green. | 183 // Case 4: Client has no entry for tag, all green. |
| 185 } | 184 } |
| 186 | 185 |
| 187 // static | 186 // static |
| 188 void SyncerUtil::AttemptReuniteLostCommitResponses( | 187 void SyncerUtil::AttemptReuniteLostCommitResponses( |
| 189 syncable::WriteTransaction* trans, | 188 syncable::WriteTransaction* trans, |
| 190 const SyncEntity& server_entry, | 189 const SyncEntity& server_entry, |
| 191 const string& client_id) { | 190 const string& client_id) { |
| 192 // If a commit succeeds, but the response does not come back fast enough | 191 // If a commit succeeds, but the response does not come back fast enough |
| 193 // then the syncer might assume that it was never committed. | 192 // then the syncer might assume that it was never committed. |
| 194 // The server will track the client that sent up the original commit and | 193 // The server will track the client that sent up the original commit and |
| 195 // return this in a get updates response. When this matches a local | 194 // return this in a get updates response. When this matches a local |
| 196 // uncommitted item, we must mutate our local item and version to pick up | 195 // uncommitted item, we must mutate our local item and version to pick up |
| 197 // the committed version of the same item whose commit response was lost. | 196 // the committed version of the same item whose commit response was lost. |
| 198 // There is however still a race condition if the server has not | 197 // There is however still a race condition if the server has not |
| 199 // completed the commit by the time the syncer tries to get updates | 198 // completed the commit by the time the syncer tries to get updates |
| 200 // again. To mitigate this, we need to have the server time out in | 199 // again. To mitigate this, we need to have the server time out in |
| 201 // a reasonable span, our commit batches have to be small enough | 200 // a reasonable span, our commit batches have to be small enough |
| 202 // to process within our HTTP response "assumed alive" time. | 201 // to process within our HTTP response "assumed alive" time. |
| 203 | 202 |
| 204 // We need to check if we have a that didn't get its server | 203 // We need to check if we have an entry that didn't get its server |
| 205 // id updated correctly. The server sends down a client ID | 204 // id updated correctly. The server sends down a client ID |
| 206 // and a local (negative) id. If we have a entry by that | 205 // and a local (negative) id. If we have a entry by that |
| 207 // description, we should update the ID and version to the | 206 // description, we should update the ID and version to the |
| 208 // server side ones to avoid multiple commits to the same name. | 207 // server side ones to avoid multiple commits to the same name. |
| 209 if (server_entry.has_originator_cache_guid() && | 208 if (server_entry.has_originator_cache_guid() && |
| 210 server_entry.originator_cache_guid() == client_id) { | 209 server_entry.originator_cache_guid() == client_id) { |
| 211 syncable::Id server_id = syncable::Id::CreateFromClientString( | 210 syncable::Id server_id = syncable::Id::CreateFromClientString( |
| 212 server_entry.originator_client_item_id()); | 211 server_entry.originator_client_item_id()); |
| 213 CHECK(!server_id.ServerKnows()); | 212 DCHECK(!server_id.ServerKnows()); |
| 214 syncable::MutableEntry local_entry(trans, GET_BY_ID, server_id); | 213 syncable::MutableEntry local_entry(trans, GET_BY_ID, server_id); |
| 215 | 214 |
| 216 // If it exists, then our local client lost a commit response. | 215 // If it exists, then our local client lost a commit response. |
| 217 if (local_entry.good() && !local_entry.Get(IS_DEL)) { | 216 if (local_entry.good() && !local_entry.Get(IS_DEL)) { |
| 218 int64 old_version = local_entry.Get(BASE_VERSION); | 217 int64 old_version = local_entry.Get(BASE_VERSION); |
| 219 int64 new_version = server_entry.version(); | 218 int64 new_version = server_entry.version(); |
| 220 CHECK(old_version <= 0); | 219 DCHECK(old_version <= 0); |
| 221 CHECK(new_version > 0); | 220 DCHECK(new_version > 0); |
| 222 // Otherwise setting the base version could cause a consistency failure. | 221 // Otherwise setting the base version could cause a consistency failure. |
| 223 // An entry should never be version 0 and SYNCED. | 222 // An entry should never be version 0 and SYNCED. |
| 224 CHECK(local_entry.Get(IS_UNSYNCED)); | 223 DCHECK(local_entry.Get(IS_UNSYNCED)); |
| 225 | 224 |
| 226 // Just a quick sanity check. | 225 // Just a quick sanity check. |
| 227 CHECK(!local_entry.Get(ID).ServerKnows()); | 226 DCHECK(!local_entry.Get(ID).ServerKnows()); |
| 228 | 227 |
| 229 LOG(INFO) << "Reuniting lost commit response IDs" << | 228 LOG(INFO) << "Reuniting lost commit response IDs" << |
| 230 " server id: " << server_entry.id() << " local id: " << | 229 " server id: " << server_entry.id() << " local id: " << |
| 231 local_entry.Get(ID) << " new version: " << new_version; | 230 local_entry.Get(ID) << " new version: " << new_version; |
| 232 | 231 |
| 233 local_entry.Put(BASE_VERSION, new_version); | 232 local_entry.Put(BASE_VERSION, new_version); |
| 234 | 233 |
| 235 ChangeEntryIDAndUpdateChildren(trans, &local_entry, server_entry.id()); | 234 ChangeEntryIDAndUpdateChildren(trans, &local_entry, server_entry.id()); |
| 236 | 235 |
| 237 // We need to continue normal processing on this update after we | 236 // We need to continue normal processing on this update after we |
| 238 // reunited its ID. | 237 // reunited its ID. |
| 239 } | 238 } |
| 240 // !local_entry.Good() means we don't have a left behind entry for this | 239 // !local_entry.Good() means we don't have a left behind entry for this |
| 241 // ID. We successfully committed before. In the future we should get rid | 240 // ID in sync database. This could happen if we crashed after successfully |
| 242 // of this system and just have client side generated IDs as a whole. | 241 // committing an item that never was flushed to disk. |
| 243 } | 242 } |
| 244 } | 243 } |
| 245 | 244 |
| 246 // static | 245 // static |
| 247 UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry( | 246 UpdateAttemptResponse SyncerUtil::AttemptToUpdateEntry( |
| 248 syncable::WriteTransaction* const trans, | 247 syncable::WriteTransaction* const trans, |
| 249 syncable::MutableEntry* const entry, | 248 syncable::MutableEntry* const entry, |
| 250 ConflictResolver* resolver, | 249 ConflictResolver* resolver, |
| 251 Cryptographer* cryptographer) { | 250 Cryptographer* cryptographer) { |
| 252 | 251 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 | 344 |
| 346 } // namespace | 345 } // namespace |
| 347 | 346 |
| 348 // Pass in name and checksum because of UTF8 conversion. | 347 // Pass in name and checksum because of UTF8 conversion. |
| 349 // static | 348 // static |
| 350 void SyncerUtil::UpdateServerFieldsFromUpdate( | 349 void SyncerUtil::UpdateServerFieldsFromUpdate( |
| 351 MutableEntry* local_entry, | 350 MutableEntry* local_entry, |
| 352 const SyncEntity& server_entry, | 351 const SyncEntity& server_entry, |
| 353 const string& name) { | 352 const string& name) { |
| 354 if (server_entry.deleted()) { | 353 if (server_entry.deleted()) { |
| 354 if (local_entry->Get(SERVER_IS_DEL)) { |
| 355 // If we already think the item is server-deleted, we're done. |
| 356 // Skipping these cases prevents our committed deletions from coming |
| 357 // back and overriding subsequent undeletions. For non-deleted items, |
| 358 // the version number check has a similar effect. |
| 359 return; |
| 360 } |
| 355 // The server returns very lightweight replies for deletions, so we don't | 361 // The server returns very lightweight replies for deletions, so we don't |
| 356 // clobber a bunch of fields on delete. | 362 // clobber a bunch of fields on delete. |
| 357 local_entry->Put(SERVER_IS_DEL, true); | 363 local_entry->Put(SERVER_IS_DEL, true); |
| 358 local_entry->Put(SERVER_VERSION, | 364 if (!local_entry->Get(UNIQUE_CLIENT_TAG).empty()) { |
| 359 std::max(local_entry->Get(SERVER_VERSION), | 365 // Items identified by the client unique tag are undeletable; when |
| 360 local_entry->Get(BASE_VERSION)) + 1L); | 366 // they're deleted, they go back to version 0. |
| 367 local_entry->Put(SERVER_VERSION, 0); |
| 368 } else { |
| 369 // Otherwise, fake a server version by bumping the local number. |
| 370 local_entry->Put(SERVER_VERSION, |
| 371 std::max(local_entry->Get(SERVER_VERSION), |
| 372 local_entry->Get(BASE_VERSION)) + 1); |
| 373 } |
| 361 local_entry->Put(IS_UNAPPLIED_UPDATE, true); | 374 local_entry->Put(IS_UNAPPLIED_UPDATE, true); |
| 362 return; | 375 return; |
| 363 } | 376 } |
| 364 | 377 |
| 365 CHECK(local_entry->Get(ID) == server_entry.id()) | 378 DCHECK(local_entry->Get(ID) == server_entry.id()) |
| 366 << "ID Changing not supported here"; | 379 << "ID Changing not supported here"; |
| 367 local_entry->Put(SERVER_PARENT_ID, server_entry.parent_id()); | 380 local_entry->Put(SERVER_PARENT_ID, server_entry.parent_id()); |
| 368 local_entry->Put(SERVER_NON_UNIQUE_NAME, name); | 381 local_entry->Put(SERVER_NON_UNIQUE_NAME, name); |
| 369 local_entry->Put(SERVER_VERSION, server_entry.version()); | 382 local_entry->Put(SERVER_VERSION, server_entry.version()); |
| 370 local_entry->Put(SERVER_CTIME, | 383 local_entry->Put(SERVER_CTIME, |
| 371 ServerTimeToClientTime(server_entry.ctime())); | 384 ServerTimeToClientTime(server_entry.ctime())); |
| 372 local_entry->Put(SERVER_MTIME, | 385 local_entry->Put(SERVER_MTIME, |
| 373 ServerTimeToClientTime(server_entry.mtime())); | 386 ServerTimeToClientTime(server_entry.mtime())); |
| 374 local_entry->Put(SERVER_IS_DIR, server_entry.IsFolder()); | 387 local_entry->Put(SERVER_IS_DIR, server_entry.IsFolder()); |
| 375 if (server_entry.has_server_defined_unique_tag()) { | 388 if (server_entry.has_server_defined_unique_tag()) { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 LOG(INFO) << "Splitting server information, local entry: " << *entry << | 511 LOG(INFO) << "Splitting server information, local entry: " << *entry << |
| 499 " server entry: " << new_entry; | 512 " server entry: " << new_entry; |
| 500 } | 513 } |
| 501 | 514 |
| 502 // This function is called on an entry when we can update the user-facing data | 515 // This function is called on an entry when we can update the user-facing data |
| 503 // from the server data. | 516 // from the server data. |
| 504 // static | 517 // static |
| 505 void SyncerUtil::UpdateLocalDataFromServerData( | 518 void SyncerUtil::UpdateLocalDataFromServerData( |
| 506 syncable::WriteTransaction* trans, | 519 syncable::WriteTransaction* trans, |
| 507 syncable::MutableEntry* entry) { | 520 syncable::MutableEntry* entry) { |
| 508 CHECK(!entry->Get(IS_UNSYNCED)); | 521 DCHECK(!entry->Get(IS_UNSYNCED)); |
| 509 CHECK(entry->Get(IS_UNAPPLIED_UPDATE)); | 522 DCHECK(entry->Get(IS_UNAPPLIED_UPDATE)); |
| 510 | 523 |
| 511 LOG(INFO) << "Updating entry : " << *entry; | 524 LOG(INFO) << "Updating entry : " << *entry; |
| 512 // Start by setting the properties that determine the model_type. | 525 // Start by setting the properties that determine the model_type. |
| 513 entry->Put(SPECIFICS, entry->Get(SERVER_SPECIFICS)); | 526 entry->Put(SPECIFICS, entry->Get(SERVER_SPECIFICS)); |
| 514 entry->Put(IS_DIR, entry->Get(SERVER_IS_DIR)); | 527 entry->Put(IS_DIR, entry->Get(SERVER_IS_DIR)); |
| 515 // This strange dance around the IS_DEL flag avoids problems when setting | 528 // This strange dance around the IS_DEL flag avoids problems when setting |
| 516 // the name. | 529 // the name. |
| 517 // TODO(chron): Is this still an issue? Unit test this codepath. | 530 // TODO(chron): Is this still an issue? Unit test this codepath. |
| 518 if (entry->Get(SERVER_IS_DEL)) { | 531 if (entry->Get(SERVER_IS_DEL)) { |
| 519 entry->Put(IS_DEL, true); | 532 entry->Put(IS_DEL, true); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 return VERIFY_FAIL; | 729 return VERIFY_FAIL; |
| 717 } | 730 } |
| 718 } | 731 } |
| 719 | 732 |
| 720 if (!deleted && | 733 if (!deleted && |
| 721 (same_id->Get(SERVER_IS_DEL) || | 734 (same_id->Get(SERVER_IS_DEL) || |
| 722 (!same_id->Get(IS_UNSYNCED) && same_id->Get(IS_DEL) && | 735 (!same_id->Get(IS_UNSYNCED) && same_id->Get(IS_DEL) && |
| 723 same_id->Get(BASE_VERSION) > 0))) { | 736 same_id->Get(BASE_VERSION) > 0))) { |
| 724 // An undelete. The latter case in the above condition is for | 737 // An undelete. The latter case in the above condition is for |
| 725 // when the server does not give us an update following the | 738 // when the server does not give us an update following the |
| 726 // commit of a delete, before undeleting. Undeletion is possible | 739 // commit of a delete, before undeleting. |
| 727 // in the server's storage backend, so it's possible on the client, | 740 // Undeletion is common for items that reuse the client-unique tag. |
| 728 // though not expected to be something that is commonly possible. | |
| 729 VerifyResult result = | 741 VerifyResult result = |
| 730 SyncerUtil::VerifyUndelete(trans, entry, same_id); | 742 SyncerUtil::VerifyUndelete(trans, entry, same_id); |
| 731 if (VERIFY_UNDECIDED != result) | 743 if (VERIFY_UNDECIDED != result) |
| 732 return result; | 744 return result; |
| 733 } | 745 } |
| 734 } | 746 } |
| 735 if (same_id->Get(BASE_VERSION) > 0) { | 747 if (same_id->Get(BASE_VERSION) > 0) { |
| 736 // We've committed this entry in the past. | 748 // We've committed this entry in the past. |
| 737 if (is_directory != same_id->Get(IS_DIR) || | 749 if (is_directory != same_id->Get(IS_DIR) || |
| 738 model_type != same_id->GetModelType()) { | 750 model_type != same_id->GetModelType()) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 762 } | 774 } |
| 763 return VERIFY_SUCCESS; | 775 return VERIFY_SUCCESS; |
| 764 } | 776 } |
| 765 | 777 |
| 766 // Assumes we have an existing entry; verify an update that seems to be | 778 // Assumes we have an existing entry; verify an update that seems to be |
| 767 // expressing an 'undelete' | 779 // expressing an 'undelete' |
| 768 // static | 780 // static |
| 769 VerifyResult SyncerUtil::VerifyUndelete(syncable::WriteTransaction* trans, | 781 VerifyResult SyncerUtil::VerifyUndelete(syncable::WriteTransaction* trans, |
| 770 const SyncEntity& entry, | 782 const SyncEntity& entry, |
| 771 syncable::MutableEntry* same_id) { | 783 syncable::MutableEntry* same_id) { |
| 784 // TODO(nick): We hit this path for items deleted items that the server |
| 785 // tells us to re-create; only deleted items with positive base versions |
| 786 // will hit this path. However, it's not clear how such an undeletion |
| 787 // would actually succeed on the server; in the protocol, a base |
| 788 // version of 0 is required to undelete an object. This codepath |
| 789 // should be deprecated in favor of client-tag style undeletion |
| 790 // (where items go to version 0 when they're deleted), or else |
| 791 // removed entirely (if this type of undeletion is indeed impossible). |
| 772 CHECK(same_id->good()); | 792 CHECK(same_id->good()); |
| 773 LOG(INFO) << "Server update is attempting undelete. " << *same_id | 793 LOG(INFO) << "Server update is attempting undelete. " << *same_id |
| 774 << "Update:" << SyncerProtoUtil::SyncEntityDebugString(entry); | 794 << "Update:" << SyncerProtoUtil::SyncEntityDebugString(entry); |
| 775 // Move the old one aside and start over. It's too tricky to get the old one | 795 // Move the old one aside and start over. It's too tricky to get the old one |
| 776 // back into a state that would pass CheckTreeInvariants(). | 796 // back into a state that would pass CheckTreeInvariants(). |
| 777 if (same_id->Get(IS_DEL)) { | 797 if (same_id->Get(IS_DEL)) { |
| 798 DCHECK(same_id->Get(UNIQUE_CLIENT_TAG).empty()) |
| 799 << "Doing move-aside undeletion on client-tagged item."; |
| 778 same_id->Put(ID, trans->directory()->NextId()); | 800 same_id->Put(ID, trans->directory()->NextId()); |
| 779 same_id->Put(UNIQUE_CLIENT_TAG, ""); | 801 same_id->Put(UNIQUE_CLIENT_TAG, ""); |
| 780 same_id->Put(BASE_VERSION, CHANGES_VERSION); | 802 same_id->Put(BASE_VERSION, CHANGES_VERSION); |
| 781 same_id->Put(SERVER_VERSION, 0); | 803 same_id->Put(SERVER_VERSION, 0); |
| 782 return VERIFY_SUCCESS; | 804 return VERIFY_SUCCESS; |
| 783 } | 805 } |
| 784 if (entry.version() < same_id->Get(SERVER_VERSION)) { | 806 if (entry.version() < same_id->Get(SERVER_VERSION)) { |
| 785 LOG(WARNING) << "Update older than current server version for" << | 807 LOG(WARNING) << "Update older than current server version for" << |
| 786 *same_id << "Update:" << SyncerProtoUtil::SyncEntityDebugString(entry); | 808 *same_id << "Update:" << SyncerProtoUtil::SyncEntityDebugString(entry); |
| 787 return VERIFY_SUCCESS; // Expected in new sync protocol. | 809 return VERIFY_SUCCESS; // Expected in new sync protocol. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 | 863 |
| 842 // |update_entry| is considered to be somewhere after |candidate|, so store | 864 // |update_entry| is considered to be somewhere after |candidate|, so store |
| 843 // it as the upper bound. | 865 // it as the upper bound. |
| 844 closest_sibling = candidate.Get(ID); | 866 closest_sibling = candidate.Get(ID); |
| 845 } | 867 } |
| 846 | 868 |
| 847 return closest_sibling; | 869 return closest_sibling; |
| 848 } | 870 } |
| 849 | 871 |
| 850 } // namespace browser_sync | 872 } // namespace browser_sync |
| OLD | NEW |