| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "sync/engine/syncer_util.h" | 5 #include "sync/engine/syncer_util.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 using syncable::SERVER_UNIQUE_POSITION; | 68 using syncable::SERVER_UNIQUE_POSITION; |
| 69 using syncable::SERVER_VERSION; | 69 using syncable::SERVER_VERSION; |
| 70 using syncable::SPECIFICS; | 70 using syncable::SPECIFICS; |
| 71 using syncable::SYNCER; | 71 using syncable::SYNCER; |
| 72 using syncable::UNIQUE_BOOKMARK_TAG; | 72 using syncable::UNIQUE_BOOKMARK_TAG; |
| 73 using syncable::UNIQUE_CLIENT_TAG; | 73 using syncable::UNIQUE_CLIENT_TAG; |
| 74 using syncable::UNIQUE_POSITION; | 74 using syncable::UNIQUE_POSITION; |
| 75 using syncable::UNIQUE_SERVER_TAG; | 75 using syncable::UNIQUE_SERVER_TAG; |
| 76 using syncable::WriteTransaction; | 76 using syncable::WriteTransaction; |
| 77 | 77 |
| 78 // TODO (stanisc): crbug.com/362467: remove this function once | |
| 79 // issue 362467 is fixed. | |
| 80 // Validates that the local ID picked by FindLocalIdToUpdate doesn't | |
| 81 // conflict with already existing item with update_id. | |
| 82 void VerifyLocalIdToUpdate(syncable::BaseTransaction* trans, | |
| 83 const syncable::Id& local_id, | |
| 84 const syncable::Id& update_id, | |
| 85 bool local_deleted, | |
| 86 bool deleted_in_update) { | |
| 87 if (local_id == update_id) { | |
| 88 // ID matches, everything is good. | |
| 89 return; | |
| 90 } | |
| 91 | |
| 92 // If the ID doesn't match, it means that an entry with |local_id| has been | |
| 93 // picked and an entry with |update_id| isn't supposed to exist. | |
| 94 syncable::Entry update_entry(trans, GET_BY_ID, update_id); | |
| 95 if (!update_entry.good()) | |
| 96 return; | |
| 97 | |
| 98 // Fail early so that the crash dump indicates which of the cases below | |
| 99 // has triggered the issue. | |
| 100 // Crash dumps don't always preserve data. The 2 separate cases below are | |
| 101 // to make it easy to see the the state of item with |update_id| in the | |
| 102 // crash dump. | |
| 103 if (update_entry.GetIsDel()) { | |
| 104 LOG(FATAL) << "VerifyLocalIdToUpdate: existing deleted entry " << update_id | |
| 105 << " conflicts with local entry " << local_id | |
| 106 << " picked by an update.\n" | |
| 107 << "Local item deleted: " << local_deleted | |
| 108 << ", deleted flag in update: " << deleted_in_update; | |
| 109 } else { | |
| 110 LOG(FATAL) << "VerifyLocalIdToUpdate: existing entry " << update_id | |
| 111 << " conflicts with local entry " << local_id | |
| 112 << " picked by an update.\n" | |
| 113 << "Local item deleted: " << local_deleted | |
| 114 << ", deleted flag in update: " << deleted_in_update; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 syncable::Id FindLocalIdToUpdate( | 78 syncable::Id FindLocalIdToUpdate( |
| 119 syncable::BaseTransaction* trans, | 79 syncable::BaseTransaction* trans, |
| 120 const sync_pb::SyncEntity& update) { | 80 const sync_pb::SyncEntity& update) { |
| 121 // Expected entry points of this function: | 81 // Expected entry points of this function: |
| 122 // SyncEntity has NOT been applied to SERVER fields. | 82 // SyncEntity has NOT been applied to SERVER fields. |
| 123 // SyncEntity has NOT been applied to LOCAL fields. | 83 // SyncEntity has NOT been applied to LOCAL fields. |
| 124 // DB has not yet been modified, no entries created for this update. | 84 // DB has not yet been modified, no entries created for this update. |
| 125 | 85 |
| 126 const std::string& client_id = trans->directory()->cache_guid(); | 86 const std::string& client_id = trans->directory()->cache_guid(); |
| 127 const syncable::Id& update_id = SyncableIdFromProto(update.id_string()); | 87 const syncable::Id& update_id = SyncableIdFromProto(update.id_string()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 // Signal an error; drop this update on the floor. Note that | 120 // Signal an error; drop this update on the floor. Note that |
| 161 // we don't server delete the item, because we don't allow it to | 121 // we don't server delete the item, because we don't allow it to |
| 162 // exist locally at all. So the item will remain orphaned on | 122 // exist locally at all. So the item will remain orphaned on |
| 163 // the server, and we won't pay attention to it. | 123 // the server, and we won't pay attention to it. |
| 164 return syncable::Id(); | 124 return syncable::Id(); |
| 165 } | 125 } |
| 166 } | 126 } |
| 167 // Target this change to the existing local entry; later, | 127 // Target this change to the existing local entry; later, |
| 168 // we'll change the ID of the local entry to update_id | 128 // we'll change the ID of the local entry to update_id |
| 169 // if needed. | 129 // if needed. |
| 170 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, | |
| 171 local_entry.GetIsDel(), update.deleted()); | |
| 172 return local_entry.GetId(); | 130 return local_entry.GetId(); |
| 173 } else { | 131 } else { |
| 174 // Case 3: We have a local entry with the same client tag. | 132 // Case 3: We have a local entry with the same client tag. |
| 175 // We should change the ID of the local entry to the server entry. | 133 // We should change the ID of the local entry to the server entry. |
| 176 // This will result in an server ID with base version == 0, but that's | 134 // This will result in an server ID with base version == 0, but that's |
| 177 // a legal state for an item with a client tag. By changing the ID, | 135 // a legal state for an item with a client tag. By changing the ID, |
| 178 // update will now be applied to local_entry. | 136 // update will now be applied to local_entry. |
| 179 DCHECK(0 == local_entry.GetBaseVersion() || | 137 DCHECK(0 == local_entry.GetBaseVersion() || |
| 180 CHANGES_VERSION == local_entry.GetBaseVersion()); | 138 CHANGES_VERSION == local_entry.GetBaseVersion()); |
| 181 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, | |
| 182 local_entry.GetIsDel(), update.deleted()); | |
| 183 return local_entry.GetId(); | 139 return local_entry.GetId(); |
| 184 } | 140 } |
| 185 } | 141 } |
| 186 } else if (update.has_originator_cache_guid() && | 142 } else if (update.has_originator_cache_guid() && |
| 187 update.originator_cache_guid() == client_id) { | 143 update.originator_cache_guid() == client_id) { |
| 188 // If a commit succeeds, but the response does not come back fast enough | 144 // If a commit succeeds, but the response does not come back fast enough |
| 189 // then the syncer might assume that it was never committed. | 145 // then the syncer might assume that it was never committed. |
| 190 // The server will track the client that sent up the original commit and | 146 // The server will track the client that sent up the original commit and |
| 191 // return this in a get updates response. When this matches a local | 147 // return this in a get updates response. When this matches a local |
| 192 // uncommitted item, we must mutate our local item and version to pick up | 148 // uncommitted item, we must mutate our local item and version to pick up |
| (...skipping 26 matching lines...) Expand all Loading... |
| 219 // An entry should never be version 0 and SYNCED. | 175 // An entry should never be version 0 and SYNCED. |
| 220 DCHECK(local_entry.GetIsUnsynced()); | 176 DCHECK(local_entry.GetIsUnsynced()); |
| 221 | 177 |
| 222 // Just a quick sanity check. | 178 // Just a quick sanity check. |
| 223 DCHECK(!local_entry.GetId().ServerKnows()); | 179 DCHECK(!local_entry.GetId().ServerKnows()); |
| 224 | 180 |
| 225 DVLOG(1) << "Reuniting lost commit response IDs. server id: " | 181 DVLOG(1) << "Reuniting lost commit response IDs. server id: " |
| 226 << update_id << " local id: " << local_entry.GetId() | 182 << update_id << " local id: " << local_entry.GetId() |
| 227 << " new version: " << new_version; | 183 << " new version: " << new_version; |
| 228 | 184 |
| 229 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, | |
| 230 local_entry.GetIsDel(), update.deleted()); | |
| 231 return local_entry.GetId(); | 185 return local_entry.GetId(); |
| 232 } | 186 } |
| 233 } else if (update.has_server_defined_unique_tag() && | 187 } else if (update.has_server_defined_unique_tag() && |
| 234 !update.server_defined_unique_tag().empty()) { | 188 !update.server_defined_unique_tag().empty()) { |
| 235 // The client creates type root folders with a local ID on demand when a | 189 // The client creates type root folders with a local ID on demand when a |
| 236 // progress marker for the given type is initially set. | 190 // progress marker for the given type is initially set. |
| 237 // The server might also attempt to send a type root folder for the same | 191 // The server might also attempt to send a type root folder for the same |
| 238 // type (during the transition period until support for root folders is | 192 // type (during the transition period until support for root folders is |
| 239 // removed for new client versions). | 193 // removed for new client versions). |
| 240 // TODO(stanisc): crbug.com/438313: remove this once the transition to | 194 // TODO(stanisc): crbug.com/438313: remove this once the transition to |
| 241 // implicit root folders on the server is done. | 195 // implicit root folders on the server is done. |
| 242 syncable::Entry local_entry(trans, syncable::GET_BY_SERVER_TAG, | 196 syncable::Entry local_entry(trans, syncable::GET_BY_SERVER_TAG, |
| 243 update.server_defined_unique_tag()); | 197 update.server_defined_unique_tag()); |
| 244 if (local_entry.good() && !local_entry.GetId().ServerKnows()) { | 198 if (local_entry.good() && !local_entry.GetId().ServerKnows()) { |
| 245 DCHECK(local_entry.GetId() != update_id); | 199 DCHECK(local_entry.GetId() != update_id); |
| 246 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, | |
| 247 local_entry.GetIsDel(), update.deleted()); | |
| 248 return local_entry.GetId(); | 200 return local_entry.GetId(); |
| 249 } | 201 } |
| 250 } | 202 } |
| 251 | 203 |
| 252 // Fallback: target an entry having the server ID, creating one if needed. | 204 // Fallback: target an entry having the server ID, creating one if needed. |
| 253 return update_id; | 205 return update_id; |
| 254 } | 206 } |
| 255 | 207 |
| 256 UpdateAttemptResponse AttemptToUpdateEntry( | 208 UpdateAttemptResponse AttemptToUpdateEntry( |
| 257 syncable::WriteTransaction* const trans, | 209 syncable::WriteTransaction* const trans, |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 if (update.version() < target->GetServerVersion()) { | 669 if (update.version() < target->GetServerVersion()) { |
| 718 LOG(WARNING) << "Update older than current server version for " | 670 LOG(WARNING) << "Update older than current server version for " |
| 719 << *target << " Update:" | 671 << *target << " Update:" |
| 720 << SyncerProtoUtil::SyncEntityDebugString(update); | 672 << SyncerProtoUtil::SyncEntityDebugString(update); |
| 721 return VERIFY_SUCCESS; // Expected in new sync protocol. | 673 return VERIFY_SUCCESS; // Expected in new sync protocol. |
| 722 } | 674 } |
| 723 return VERIFY_UNDECIDED; | 675 return VERIFY_UNDECIDED; |
| 724 } | 676 } |
| 725 | 677 |
| 726 } // namespace syncer | 678 } // namespace syncer |
| OLD | NEW |