| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/process_updates_util.h" | 5 #include "sync/engine/process_updates_util.h" |
| 6 | 6 |
| 7 #include "base/location.h" | 7 #include "base/location.h" |
| 8 #include "sync/engine/syncer_proto_util.h" | 8 #include "sync/engine/syncer_proto_util.h" |
| 9 #include "sync/engine/syncer_types.h" |
| 9 #include "sync/engine/syncer_util.h" | 10 #include "sync/engine/syncer_util.h" |
| 10 #include "sync/syncable/directory.h" | 11 #include "sync/syncable/directory.h" |
| 11 #include "sync/syncable/model_neutral_mutable_entry.h" | 12 #include "sync/syncable/model_neutral_mutable_entry.h" |
| 12 #include "sync/syncable/syncable_model_neutral_write_transaction.h" | 13 #include "sync/syncable/syncable_model_neutral_write_transaction.h" |
| 13 #include "sync/syncable/syncable_proto_util.h" | 14 #include "sync/syncable/syncable_proto_util.h" |
| 14 #include "sync/syncable/syncable_util.h" | 15 #include "sync/syncable/syncable_util.h" |
| 15 #include "sync/util/cryptographer.h" | 16 #include "sync/util/cryptographer.h" |
| 16 | 17 |
| 17 namespace syncer { | 18 namespace syncer { |
| 18 | 19 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 // Unique client tags will have their version set to zero when they're | 68 // Unique client tags will have their version set to zero when they're |
| 68 // deleted. The usual version comparison logic won't be able to detect | 69 // deleted. The usual version comparison logic won't be able to detect |
| 69 // reflections of these items. Instead, we assume any received tombstones | 70 // reflections of these items. Instead, we assume any received tombstones |
| 70 // are reflections. That should be correct most of the time. | 71 // are reflections. That should be correct most of the time. |
| 71 return false; | 72 return false; |
| 72 } | 73 } |
| 73 | 74 |
| 74 return existing_version < update.version(); | 75 return existing_version < update.version(); |
| 75 } | 76 } |
| 76 | 77 |
| 77 } // namespace | |
| 78 | |
| 79 void PartitionUpdatesByType( | |
| 80 const sync_pb::GetUpdatesResponse& updates, | |
| 81 ModelTypeSet requested_types, | |
| 82 TypeSyncEntityMap* updates_by_type) { | |
| 83 int update_count = updates.entries().size(); | |
| 84 for (ModelTypeSet::Iterator it = requested_types.First(); | |
| 85 it.Good(); it.Inc()) { | |
| 86 updates_by_type->insert(std::make_pair(it.Get(), SyncEntityList())); | |
| 87 } | |
| 88 for (int i = 0; i < update_count; ++i) { | |
| 89 const sync_pb::SyncEntity& update = updates.entries(i); | |
| 90 ModelType type = GetModelType(update); | |
| 91 if (!IsRealDataType(type)) { | |
| 92 NOTREACHED() << "Received update with invalid type."; | |
| 93 continue; | |
| 94 } | |
| 95 | |
| 96 TypeSyncEntityMap::iterator it = updates_by_type->find(type); | |
| 97 if (it == updates_by_type->end()) { | |
| 98 DLOG(WARNING) << "Skipping update for unexpected type " | |
| 99 << ModelTypeToString(type); | |
| 100 continue; | |
| 101 } | |
| 102 | |
| 103 it->second.push_back(&update); | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 void ProcessDownloadedUpdates( | |
| 108 syncable::Directory* dir, | |
| 109 syncable::ModelNeutralWriteTransaction* trans, | |
| 110 ModelType type, | |
| 111 const SyncEntityList& applicable_updates, | |
| 112 sessions::StatusController* status) { | |
| 113 for (SyncEntityList::const_iterator update_it = applicable_updates.begin(); | |
| 114 update_it != applicable_updates.end(); ++update_it) { | |
| 115 DCHECK_EQ(type, GetModelType(**update_it)); | |
| 116 if (!UpdateContainsNewVersion(trans, **update_it)) | |
| 117 status->increment_num_reflected_updates_downloaded_by(1); | |
| 118 if ((*update_it)->deleted()) | |
| 119 status->increment_num_tombstone_updates_downloaded_by(1); | |
| 120 VerifyResult verify_result = VerifyUpdate(trans, **update_it, type); | |
| 121 if (verify_result != VERIFY_SUCCESS && verify_result != VERIFY_UNDELETE) | |
| 122 continue; | |
| 123 ProcessUpdate(**update_it, dir->GetCryptographer(trans), trans); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 namespace { | |
| 128 | |
| 129 // In the event that IDs match, but tags differ AttemptReuniteClient tag | 78 // In the event that IDs match, but tags differ AttemptReuniteClient tag |
| 130 // will have refused to unify the update. | 79 // will have refused to unify the update. |
| 131 // We should not attempt to apply it at all since it violates consistency | 80 // We should not attempt to apply it at all since it violates consistency |
| 132 // rules. | 81 // rules. |
| 133 VerifyResult VerifyTagConsistency( | 82 VerifyResult VerifyTagConsistency( |
| 134 const sync_pb::SyncEntity& entry, | 83 const sync_pb::SyncEntity& entry, |
| 135 const syncable::ModelNeutralMutableEntry& same_id) { | 84 const syncable::ModelNeutralMutableEntry& same_id) { |
| 136 if (entry.has_client_defined_unique_tag() && | 85 if (entry.has_client_defined_unique_tag() && |
| 137 entry.client_defined_unique_tag() != | 86 entry.client_defined_unique_tag() != |
| 138 same_id.GetUniqueClientTag()) { | 87 same_id.GetUniqueClientTag()) { |
| 139 return VERIFY_FAIL; | 88 return VERIFY_FAIL; |
| 140 } | 89 } |
| 141 return VERIFY_UNDECIDED; | 90 return VERIFY_UNDECIDED; |
| 142 } | 91 } |
| 143 | 92 |
| 144 } // namespace | 93 // Checks whether or not an update is fit for processing. |
| 145 | 94 // |
| 95 // The answer may be "no" if the update appears invalid, or it's not releveant |
| 96 // (ie. a delete for an item we've never heard of), or other reasons. |
| 146 VerifyResult VerifyUpdate( | 97 VerifyResult VerifyUpdate( |
| 147 syncable::ModelNeutralWriteTransaction* trans, | 98 syncable::ModelNeutralWriteTransaction* trans, |
| 148 const sync_pb::SyncEntity& entry, | 99 const sync_pb::SyncEntity& entry, |
| 149 ModelType requested_type) { | 100 ModelType requested_type) { |
| 150 syncable::Id id = SyncableIdFromProto(entry.id_string()); | 101 syncable::Id id = SyncableIdFromProto(entry.id_string()); |
| 151 VerifyResult result = VERIFY_FAIL; | 102 VerifyResult result = VERIFY_FAIL; |
| 152 | 103 |
| 153 const bool deleted = entry.has_deleted() && entry.deleted(); | 104 const bool deleted = entry.has_deleted() && entry.deleted(); |
| 154 const bool is_directory = IsFolder(entry); | 105 const bool is_directory = IsFolder(entry); |
| 155 const ModelType model_type = GetModelType(entry); | 106 const ModelType model_type = GetModelType(entry); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 result = VerifyUpdateConsistency(trans, entry, deleted, | 145 result = VerifyUpdateConsistency(trans, entry, deleted, |
| 195 is_directory, model_type, &same_id); | 146 is_directory, model_type, &same_id); |
| 196 } | 147 } |
| 197 | 148 |
| 198 if (VERIFY_UNDECIDED == result) | 149 if (VERIFY_UNDECIDED == result) |
| 199 result = VERIFY_SUCCESS; // No news is good news. | 150 result = VERIFY_SUCCESS; // No news is good news. |
| 200 | 151 |
| 201 return result; // This might be VERIFY_SUCCESS as well | 152 return result; // This might be VERIFY_SUCCESS as well |
| 202 } | 153 } |
| 203 | 154 |
| 204 namespace { | |
| 205 // Returns true if the entry is still ok to process. | 155 // Returns true if the entry is still ok to process. |
| 206 bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans, | 156 bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans, |
| 207 const sync_pb::SyncEntity& entry, | 157 const sync_pb::SyncEntity& entry, |
| 208 syncable::ModelNeutralMutableEntry* same_id) { | 158 syncable::ModelNeutralMutableEntry* same_id) { |
| 209 | 159 |
| 210 const bool deleted = entry.has_deleted() && entry.deleted(); | 160 const bool deleted = entry.has_deleted() && entry.deleted(); |
| 211 const bool is_directory = IsFolder(entry); | 161 const bool is_directory = IsFolder(entry); |
| 212 const ModelType model_type = GetModelType(entry); | 162 const ModelType model_type = GetModelType(entry); |
| 213 | 163 |
| 214 return VERIFY_SUCCESS == VerifyUpdateConsistency(trans, | 164 return VERIFY_SUCCESS == VerifyUpdateConsistency(trans, |
| 215 entry, | 165 entry, |
| 216 deleted, | 166 deleted, |
| 217 is_directory, | 167 is_directory, |
| 218 model_type, | 168 model_type, |
| 219 same_id); | 169 same_id); |
| 220 } | 170 } |
| 221 } // namespace | |
| 222 | 171 |
| 223 // Process a single update. Will avoid touching global state. | 172 // Process a single update. Will avoid touching global state. |
| 173 // |
| 174 // If the update passes a series of checks, this function will copy |
| 175 // the SyncEntity's data into the SERVER side of the syncable::Directory. |
| 224 void ProcessUpdate( | 176 void ProcessUpdate( |
| 225 const sync_pb::SyncEntity& update, | 177 const sync_pb::SyncEntity& update, |
| 226 const Cryptographer* cryptographer, | 178 const Cryptographer* cryptographer, |
| 227 syncable::ModelNeutralWriteTransaction* const trans) { | 179 syncable::ModelNeutralWriteTransaction* const trans) { |
| 228 const syncable::Id& server_id = SyncableIdFromProto(update.id_string()); | 180 const syncable::Id& server_id = SyncableIdFromProto(update.id_string()); |
| 229 const std::string name = SyncerProtoUtil::NameFromSyncEntity(update); | 181 const std::string name = SyncerProtoUtil::NameFromSyncEntity(update); |
| 230 | 182 |
| 231 // Look to see if there's a local item that should recieve this update, | 183 // Look to see if there's a local item that should recieve this update, |
| 232 // maybe due to a duplicate client tag or a lost commit response. | 184 // maybe due to a duplicate client tag or a lost commit response. |
| 233 syncable::Id local_id = FindLocalIdToUpdate(trans, update); | 185 syncable::Id local_id = FindLocalIdToUpdate(trans, update); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 // changes, so we clear BASE_SERVER_SPECIFICS. | 271 // changes, so we clear BASE_SERVER_SPECIFICS. |
| 320 target_entry.PutBaseServerSpecifics( | 272 target_entry.PutBaseServerSpecifics( |
| 321 sync_pb::EntitySpecifics()); | 273 sync_pb::EntitySpecifics()); |
| 322 } | 274 } |
| 323 | 275 |
| 324 UpdateServerFieldsFromUpdate(&target_entry, update, name); | 276 UpdateServerFieldsFromUpdate(&target_entry, update, name); |
| 325 | 277 |
| 326 return; | 278 return; |
| 327 } | 279 } |
| 328 | 280 |
| 281 } // namespace |
| 282 |
| 283 void ProcessDownloadedUpdates( |
| 284 syncable::Directory* dir, |
| 285 syncable::ModelNeutralWriteTransaction* trans, |
| 286 ModelType type, |
| 287 const SyncEntityList& applicable_updates, |
| 288 sessions::StatusController* status) { |
| 289 for (SyncEntityList::const_iterator update_it = applicable_updates.begin(); |
| 290 update_it != applicable_updates.end(); ++update_it) { |
| 291 DCHECK_EQ(type, GetModelType(**update_it)); |
| 292 if (!UpdateContainsNewVersion(trans, **update_it)) |
| 293 status->increment_num_reflected_updates_downloaded_by(1); |
| 294 if ((*update_it)->deleted()) |
| 295 status->increment_num_tombstone_updates_downloaded_by(1); |
| 296 VerifyResult verify_result = VerifyUpdate(trans, **update_it, type); |
| 297 if (verify_result != VERIFY_SUCCESS && verify_result != VERIFY_UNDELETE) |
| 298 continue; |
| 299 ProcessUpdate(**update_it, dir->GetCryptographer(trans), trans); |
| 300 } |
| 301 } |
| 302 |
| 329 } // namespace syncer | 303 } // namespace syncer |
| OLD | NEW |