| 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 |
| 78 syncable::Id FindLocalIdToUpdate( | 118 syncable::Id FindLocalIdToUpdate( |
| 79 syncable::BaseTransaction* trans, | 119 syncable::BaseTransaction* trans, |
| 80 const sync_pb::SyncEntity& update) { | 120 const sync_pb::SyncEntity& update) { |
| 81 // Expected entry points of this function: | 121 // Expected entry points of this function: |
| 82 // SyncEntity has NOT been applied to SERVER fields. | 122 // SyncEntity has NOT been applied to SERVER fields. |
| 83 // SyncEntity has NOT been applied to LOCAL fields. | 123 // SyncEntity has NOT been applied to LOCAL fields. |
| 84 // DB has not yet been modified, no entries created for this update. | 124 // DB has not yet been modified, no entries created for this update. |
| 85 | 125 |
| 86 const std::string& client_id = trans->directory()->cache_guid(); | 126 const std::string& client_id = trans->directory()->cache_guid(); |
| 87 const syncable::Id& update_id = SyncableIdFromProto(update.id_string()); | 127 const syncable::Id& update_id = SyncableIdFromProto(update.id_string()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 // Signal an error; drop this update on the floor. Note that | 160 // Signal an error; drop this update on the floor. Note that |
| 121 // we don't server delete the item, because we don't allow it to | 161 // we don't server delete the item, because we don't allow it to |
| 122 // exist locally at all. So the item will remain orphaned on | 162 // exist locally at all. So the item will remain orphaned on |
| 123 // the server, and we won't pay attention to it. | 163 // the server, and we won't pay attention to it. |
| 124 return syncable::Id(); | 164 return syncable::Id(); |
| 125 } | 165 } |
| 126 } | 166 } |
| 127 // Target this change to the existing local entry; later, | 167 // Target this change to the existing local entry; later, |
| 128 // we'll change the ID of the local entry to update_id | 168 // we'll change the ID of the local entry to update_id |
| 129 // if needed. | 169 // if needed. |
| 170 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, |
| 171 local_entry.GetIsDel(), update.deleted()); |
| 130 return local_entry.GetId(); | 172 return local_entry.GetId(); |
| 131 } else { | 173 } else { |
| 132 // Case 3: We have a local entry with the same client tag. | 174 // Case 3: We have a local entry with the same client tag. |
| 133 // We should change the ID of the local entry to the server entry. | 175 // We should change the ID of the local entry to the server entry. |
| 134 // This will result in an server ID with base version == 0, but that's | 176 // This will result in an server ID with base version == 0, but that's |
| 135 // a legal state for an item with a client tag. By changing the ID, | 177 // a legal state for an item with a client tag. By changing the ID, |
| 136 // update will now be applied to local_entry. | 178 // update will now be applied to local_entry. |
| 137 DCHECK(0 == local_entry.GetBaseVersion() || | 179 DCHECK(0 == local_entry.GetBaseVersion() || |
| 138 CHANGES_VERSION == local_entry.GetBaseVersion()); | 180 CHANGES_VERSION == local_entry.GetBaseVersion()); |
| 181 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, |
| 182 local_entry.GetIsDel(), update.deleted()); |
| 139 return local_entry.GetId(); | 183 return local_entry.GetId(); |
| 140 } | 184 } |
| 141 } | 185 } |
| 142 } else if (update.has_originator_cache_guid() && | 186 } else if (update.has_originator_cache_guid() && |
| 143 update.originator_cache_guid() == client_id) { | 187 update.originator_cache_guid() == client_id) { |
| 144 // If a commit succeeds, but the response does not come back fast enough | 188 // If a commit succeeds, but the response does not come back fast enough |
| 145 // then the syncer might assume that it was never committed. | 189 // then the syncer might assume that it was never committed. |
| 146 // The server will track the client that sent up the original commit and | 190 // The server will track the client that sent up the original commit and |
| 147 // return this in a get updates response. When this matches a local | 191 // return this in a get updates response. When this matches a local |
| 148 // uncommitted item, we must mutate our local item and version to pick up | 192 // uncommitted item, we must mutate our local item and version to pick up |
| (...skipping 26 matching lines...) Expand all Loading... |
| 175 // An entry should never be version 0 and SYNCED. | 219 // An entry should never be version 0 and SYNCED. |
| 176 DCHECK(local_entry.GetIsUnsynced()); | 220 DCHECK(local_entry.GetIsUnsynced()); |
| 177 | 221 |
| 178 // Just a quick sanity check. | 222 // Just a quick sanity check. |
| 179 DCHECK(!local_entry.GetId().ServerKnows()); | 223 DCHECK(!local_entry.GetId().ServerKnows()); |
| 180 | 224 |
| 181 DVLOG(1) << "Reuniting lost commit response IDs. server id: " | 225 DVLOG(1) << "Reuniting lost commit response IDs. server id: " |
| 182 << update_id << " local id: " << local_entry.GetId() | 226 << update_id << " local id: " << local_entry.GetId() |
| 183 << " new version: " << new_version; | 227 << " new version: " << new_version; |
| 184 | 228 |
| 229 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, |
| 230 local_entry.GetIsDel(), update.deleted()); |
| 185 return local_entry.GetId(); | 231 return local_entry.GetId(); |
| 186 } | 232 } |
| 187 } else if (update.has_server_defined_unique_tag() && | 233 } else if (update.has_server_defined_unique_tag() && |
| 188 !update.server_defined_unique_tag().empty()) { | 234 !update.server_defined_unique_tag().empty()) { |
| 189 // The client creates type root folders with a local ID on demand when a | 235 // The client creates type root folders with a local ID on demand when a |
| 190 // progress marker for the given type is initially set. | 236 // progress marker for the given type is initially set. |
| 191 // The server might also attempt to send a type root folder for the same | 237 // The server might also attempt to send a type root folder for the same |
| 192 // type (during the transition period until support for root folders is | 238 // type (during the transition period until support for root folders is |
| 193 // removed for new client versions). | 239 // removed for new client versions). |
| 194 // TODO(stanisc): crbug.com/438313: remove this once the transition to | 240 // TODO(stanisc): crbug.com/438313: remove this once the transition to |
| 195 // implicit root folders on the server is done. | 241 // implicit root folders on the server is done. |
| 196 syncable::Entry local_entry(trans, syncable::GET_BY_SERVER_TAG, | 242 syncable::Entry local_entry(trans, syncable::GET_BY_SERVER_TAG, |
| 197 update.server_defined_unique_tag()); | 243 update.server_defined_unique_tag()); |
| 198 if (local_entry.good() && !local_entry.GetId().ServerKnows()) { | 244 if (local_entry.good() && !local_entry.GetId().ServerKnows()) { |
| 199 DCHECK(local_entry.GetId() != update_id); | 245 DCHECK(local_entry.GetId() != update_id); |
| 246 VerifyLocalIdToUpdate(trans, local_entry.GetId(), update_id, |
| 247 local_entry.GetIsDel(), update.deleted()); |
| 200 return local_entry.GetId(); | 248 return local_entry.GetId(); |
| 201 } | 249 } |
| 202 } | 250 } |
| 203 | 251 |
| 204 // Fallback: target an entry having the server ID, creating one if needed. | 252 // Fallback: target an entry having the server ID, creating one if needed. |
| 205 return update_id; | 253 return update_id; |
| 206 } | 254 } |
| 207 | 255 |
| 208 UpdateAttemptResponse AttemptToUpdateEntry( | 256 UpdateAttemptResponse AttemptToUpdateEntry( |
| 209 syncable::WriteTransaction* const trans, | 257 syncable::WriteTransaction* const trans, |
| (...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 if (update.version() < target->GetServerVersion()) { | 717 if (update.version() < target->GetServerVersion()) { |
| 670 LOG(WARNING) << "Update older than current server version for " | 718 LOG(WARNING) << "Update older than current server version for " |
| 671 << *target << " Update:" | 719 << *target << " Update:" |
| 672 << SyncerProtoUtil::SyncEntityDebugString(update); | 720 << SyncerProtoUtil::SyncEntityDebugString(update); |
| 673 return VERIFY_SUCCESS; // Expected in new sync protocol. | 721 return VERIFY_SUCCESS; // Expected in new sync protocol. |
| 674 } | 722 } |
| 675 return VERIFY_UNDECIDED; | 723 return VERIFY_UNDECIDED; |
| 676 } | 724 } |
| 677 | 725 |
| 678 } // namespace syncer | 726 } // namespace syncer |
| OLD | NEW |