| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/sync/core/processor_entity_tracker.h" | |
| 6 | |
| 7 #include "base/base64.h" | |
| 8 #include "base/sha1.h" | |
| 9 #include "components/sync/base/time.h" | |
| 10 #include "components/sync/core/non_blocking_sync_common.h" | |
| 11 #include "components/sync/syncable/syncable_util.h" | |
| 12 | |
| 13 namespace syncer { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 void HashSpecifics(const sync_pb::EntitySpecifics& specifics, | |
| 18 std::string* hash) { | |
| 19 DCHECK_GT(specifics.ByteSize(), 0); | |
| 20 base::Base64Encode(base::SHA1HashString(specifics.SerializeAsString()), hash); | |
| 21 } | |
| 22 | |
| 23 } // namespace | |
| 24 | |
| 25 std::unique_ptr<ProcessorEntityTracker> ProcessorEntityTracker::CreateNew( | |
| 26 const std::string& storage_key, | |
| 27 const std::string& client_tag_hash, | |
| 28 const std::string& id, | |
| 29 base::Time creation_time) { | |
| 30 // Initialize metadata | |
| 31 sync_pb::EntityMetadata metadata; | |
| 32 metadata.set_client_tag_hash(client_tag_hash); | |
| 33 if (!id.empty()) | |
| 34 metadata.set_server_id(id); | |
| 35 metadata.set_sequence_number(0); | |
| 36 metadata.set_acked_sequence_number(0); | |
| 37 metadata.set_server_version(kUncommittedVersion); | |
| 38 metadata.set_creation_time(TimeToProtoTime(creation_time)); | |
| 39 | |
| 40 return std::unique_ptr<ProcessorEntityTracker>( | |
| 41 new ProcessorEntityTracker(storage_key, &metadata)); | |
| 42 } | |
| 43 | |
| 44 std::unique_ptr<ProcessorEntityTracker> | |
| 45 ProcessorEntityTracker::CreateFromMetadata(const std::string& storage_key, | |
| 46 sync_pb::EntityMetadata* metadata) { | |
| 47 return std::unique_ptr<ProcessorEntityTracker>( | |
| 48 new ProcessorEntityTracker(storage_key, metadata)); | |
| 49 } | |
| 50 | |
| 51 ProcessorEntityTracker::ProcessorEntityTracker( | |
| 52 const std::string& storage_key, | |
| 53 sync_pb::EntityMetadata* metadata) | |
| 54 : storage_key_(storage_key), | |
| 55 commit_requested_sequence_number_(metadata->acked_sequence_number()) { | |
| 56 DCHECK(metadata->has_client_tag_hash()); | |
| 57 DCHECK(metadata->has_creation_time()); | |
| 58 metadata_.Swap(metadata); | |
| 59 } | |
| 60 | |
| 61 ProcessorEntityTracker::~ProcessorEntityTracker() {} | |
| 62 | |
| 63 void ProcessorEntityTracker::CacheCommitData(EntityData* data) { | |
| 64 DCHECK(data); | |
| 65 if (data->client_tag_hash.empty()) { | |
| 66 data->client_tag_hash = metadata_.client_tag_hash(); | |
| 67 } | |
| 68 CacheCommitData(data->PassToPtr()); | |
| 69 } | |
| 70 | |
| 71 void ProcessorEntityTracker::CacheCommitData(const EntityDataPtr& data_ptr) { | |
| 72 DCHECK(RequiresCommitData()); | |
| 73 commit_data_ = data_ptr; | |
| 74 DCHECK(HasCommitData()); | |
| 75 } | |
| 76 | |
| 77 bool ProcessorEntityTracker::HasCommitData() const { | |
| 78 return !commit_data_->client_tag_hash.empty(); | |
| 79 } | |
| 80 | |
| 81 bool ProcessorEntityTracker::MatchesData(const EntityData& data) const { | |
| 82 return metadata_.is_deleted() ? data.is_deleted() | |
| 83 : MatchesSpecificsHash(data.specifics); | |
| 84 } | |
| 85 | |
| 86 bool ProcessorEntityTracker::MatchesBaseData(const EntityData& data) const { | |
| 87 DCHECK(IsUnsynced()); | |
| 88 if (data.is_deleted() || metadata_.base_specifics_hash().empty()) { | |
| 89 return false; | |
| 90 } | |
| 91 std::string hash; | |
| 92 HashSpecifics(data.specifics, &hash); | |
| 93 return hash == metadata_.base_specifics_hash(); | |
| 94 } | |
| 95 | |
| 96 bool ProcessorEntityTracker::IsUnsynced() const { | |
| 97 return metadata_.sequence_number() > metadata_.acked_sequence_number(); | |
| 98 } | |
| 99 | |
| 100 bool ProcessorEntityTracker::RequiresCommitRequest() const { | |
| 101 return metadata_.sequence_number() > commit_requested_sequence_number_; | |
| 102 } | |
| 103 | |
| 104 bool ProcessorEntityTracker::RequiresCommitData() const { | |
| 105 return RequiresCommitRequest() && !HasCommitData() && !metadata_.is_deleted(); | |
| 106 } | |
| 107 | |
| 108 bool ProcessorEntityTracker::CanClearMetadata() const { | |
| 109 return metadata_.is_deleted() && !IsUnsynced(); | |
| 110 } | |
| 111 | |
| 112 bool ProcessorEntityTracker::UpdateIsReflection(int64_t update_version) const { | |
| 113 return metadata_.server_version() >= update_version; | |
| 114 } | |
| 115 | |
| 116 void ProcessorEntityTracker::RecordIgnoredUpdate( | |
| 117 const UpdateResponseData& update) { | |
| 118 DCHECK(metadata_.server_id().empty() || | |
| 119 metadata_.server_id() == update.entity->id); | |
| 120 metadata_.set_server_id(update.entity->id); | |
| 121 metadata_.set_server_version(update.response_version); | |
| 122 // Either these already matched, acked was just bumped to squash a pending | |
| 123 // commit and this should follow, or the pending commit needs to be requeued. | |
| 124 commit_requested_sequence_number_ = metadata_.acked_sequence_number(); | |
| 125 } | |
| 126 | |
| 127 void ProcessorEntityTracker::RecordAcceptedUpdate( | |
| 128 const UpdateResponseData& update) { | |
| 129 DCHECK(!IsUnsynced()); | |
| 130 RecordIgnoredUpdate(update); | |
| 131 metadata_.set_is_deleted(update.entity->is_deleted()); | |
| 132 metadata_.set_modification_time( | |
| 133 TimeToProtoTime(update.entity->modification_time)); | |
| 134 UpdateSpecificsHash(update.entity->specifics); | |
| 135 } | |
| 136 | |
| 137 void ProcessorEntityTracker::RecordForcedUpdate( | |
| 138 const UpdateResponseData& update) { | |
| 139 DCHECK(IsUnsynced()); | |
| 140 // There was a conflict and the server just won it. Explicitly ack all | |
| 141 // pending commits so they are never enqueued again. | |
| 142 metadata_.set_acked_sequence_number(metadata_.sequence_number()); | |
| 143 commit_data_.reset(); | |
| 144 RecordAcceptedUpdate(update); | |
| 145 } | |
| 146 | |
| 147 void ProcessorEntityTracker::MakeLocalChange(std::unique_ptr<EntityData> data) { | |
| 148 DCHECK(!metadata_.client_tag_hash().empty()); | |
| 149 DCHECK_EQ(metadata_.client_tag_hash(), data->client_tag_hash); | |
| 150 | |
| 151 if (data->modification_time.is_null()) { | |
| 152 data->modification_time = base::Time::Now(); | |
| 153 } | |
| 154 | |
| 155 IncrementSequenceNumber(); | |
| 156 UpdateSpecificsHash(data->specifics); | |
| 157 metadata_.set_modification_time(TimeToProtoTime(data->modification_time)); | |
| 158 metadata_.set_is_deleted(false); | |
| 159 | |
| 160 data->id = metadata_.server_id(); | |
| 161 data->creation_time = ProtoTimeToTime(metadata_.creation_time()); | |
| 162 commit_data_.reset(); | |
| 163 CacheCommitData(data.get()); | |
| 164 } | |
| 165 | |
| 166 void ProcessorEntityTracker::Delete() { | |
| 167 IncrementSequenceNumber(); | |
| 168 metadata_.set_modification_time(TimeToProtoTime(base::Time::Now())); | |
| 169 metadata_.set_is_deleted(true); | |
| 170 metadata_.clear_specifics_hash(); | |
| 171 // Clear any cached pending commit data. | |
| 172 commit_data_.reset(); | |
| 173 } | |
| 174 | |
| 175 void ProcessorEntityTracker::InitializeCommitRequestData( | |
| 176 CommitRequestData* request) { | |
| 177 if (!metadata_.is_deleted()) { | |
| 178 DCHECK(HasCommitData()); | |
| 179 DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash()); | |
| 180 request->entity = commit_data_; | |
| 181 } else { | |
| 182 // Make an EntityData with empty specifics to indicate deletion. This is | |
| 183 // done lazily here to simplify loading a pending deletion on startup. | |
| 184 EntityData data; | |
| 185 data.client_tag_hash = metadata_.client_tag_hash(); | |
| 186 data.id = metadata_.server_id(); | |
| 187 data.creation_time = ProtoTimeToTime(metadata_.creation_time()); | |
| 188 data.modification_time = ProtoTimeToTime(metadata_.modification_time()); | |
| 189 request->entity = data.PassToPtr(); | |
| 190 } | |
| 191 | |
| 192 request->sequence_number = metadata_.sequence_number(); | |
| 193 request->base_version = metadata_.server_version(); | |
| 194 request->specifics_hash = metadata_.specifics_hash(); | |
| 195 commit_requested_sequence_number_ = metadata_.sequence_number(); | |
| 196 } | |
| 197 | |
| 198 void ProcessorEntityTracker::ReceiveCommitResponse( | |
| 199 const CommitResponseData& data) { | |
| 200 DCHECK_EQ(metadata_.client_tag_hash(), data.client_tag_hash); | |
| 201 DCHECK_GT(data.sequence_number, metadata_.acked_sequence_number()); | |
| 202 DCHECK_GT(data.response_version, metadata_.server_version()); | |
| 203 | |
| 204 // The server can assign us a new ID in a commit response. | |
| 205 metadata_.set_server_id(data.id); | |
| 206 metadata_.set_acked_sequence_number(data.sequence_number); | |
| 207 metadata_.set_server_version(data.response_version); | |
| 208 if (!IsUnsynced()) { | |
| 209 // Clear pending commit data if there hasn't been another commit request | |
| 210 // since the one that is currently getting acked. | |
| 211 commit_data_.reset(); | |
| 212 metadata_.clear_base_specifics_hash(); | |
| 213 } else { | |
| 214 metadata_.set_base_specifics_hash(data.specifics_hash); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 void ProcessorEntityTracker::ClearTransientSyncState() { | |
| 219 // If we have any unacknowledged commit requests outstanding, they've been | |
| 220 // dropped and we should forget about them. | |
| 221 commit_requested_sequence_number_ = metadata_.acked_sequence_number(); | |
| 222 } | |
| 223 | |
| 224 void ProcessorEntityTracker::IncrementSequenceNumber() { | |
| 225 DCHECK(metadata_.has_sequence_number()); | |
| 226 if (!IsUnsynced()) { | |
| 227 // Update the base specifics hash if this entity wasn't already out of sync. | |
| 228 metadata_.set_base_specifics_hash(metadata_.specifics_hash()); | |
| 229 } | |
| 230 metadata_.set_sequence_number(metadata_.sequence_number() + 1); | |
| 231 } | |
| 232 | |
| 233 bool ProcessorEntityTracker::MatchesSpecificsHash( | |
| 234 const sync_pb::EntitySpecifics& specifics) const { | |
| 235 DCHECK(!metadata_.is_deleted()); | |
| 236 std::string hash; | |
| 237 HashSpecifics(specifics, &hash); | |
| 238 return hash == metadata_.specifics_hash(); | |
| 239 } | |
| 240 | |
| 241 void ProcessorEntityTracker::UpdateSpecificsHash( | |
| 242 const sync_pb::EntitySpecifics& specifics) { | |
| 243 if (specifics.ByteSize() > 0) { | |
| 244 HashSpecifics(specifics, metadata_.mutable_specifics_hash()); | |
| 245 } else { | |
| 246 metadata_.clear_specifics_hash(); | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 } // namespace syncer | |
| OLD | NEW |