Chromium Code Reviews| 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 "sync/engine/sync_thread_sync_entity.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "sync/engine/non_blocking_sync_common.h" | |
| 9 #include "sync/internal_api/public/base/model_type.h" | |
| 10 #include "sync/syncable/syncable_util.h" | |
| 11 #include "sync/util/time.h" | |
| 12 | |
| 13 namespace syncer { | |
| 14 | |
| 15 SyncThreadSyncEntity* SyncThreadSyncEntity::FromServerUpdate( | |
| 16 const std::string& id_string, | |
| 17 const std::string& client_tag_hash, | |
| 18 int64 received_version) { | |
| 19 return new SyncThreadSyncEntity( | |
| 20 id_string, client_tag_hash, 0, received_version); | |
| 21 } | |
| 22 | |
| 23 SyncThreadSyncEntity* SyncThreadSyncEntity::FromCommitRequest( | |
| 24 const std::string& id_string, | |
| 25 const std::string& client_tag_hash, | |
| 26 int64 sequence_number, | |
| 27 int64 base_version, | |
| 28 base::Time ctime, | |
| 29 base::Time mtime, | |
| 30 const std::string& non_unique_name, | |
| 31 bool deleted, | |
| 32 const sync_pb::EntitySpecifics& specifics) { | |
| 33 return new SyncThreadSyncEntity(id_string, | |
| 34 client_tag_hash, | |
| 35 0, | |
| 36 0, | |
| 37 true, | |
| 38 sequence_number, | |
| 39 base_version, | |
| 40 ctime, | |
| 41 mtime, | |
| 42 non_unique_name, | |
| 43 deleted, | |
| 44 specifics); | |
| 45 } | |
| 46 | |
| 47 // Constructor that does not set any pending commit fields. | |
| 48 SyncThreadSyncEntity::SyncThreadSyncEntity( | |
| 49 const std::string& id, | |
| 50 const std::string& client_tag_hash, | |
| 51 int64 highest_commit_response_version, | |
| 52 int64 highest_gu_response_version) | |
| 53 : id_(id), | |
| 54 client_tag_hash_(client_tag_hash), | |
| 55 highest_commit_response_version_(highest_commit_response_version), | |
| 56 highest_gu_response_version_(highest_gu_response_version), | |
| 57 is_commit_pending_(false), | |
| 58 sequence_number_(0), | |
| 59 base_version_(0), | |
| 60 deleted_(false) { | |
| 61 } | |
| 62 | |
| 63 SyncThreadSyncEntity::SyncThreadSyncEntity( | |
| 64 const std::string& id, | |
| 65 const std::string& client_tag_hash, | |
| 66 int64 highest_commit_response_version, | |
| 67 int64 highest_gu_response_version, | |
| 68 bool is_commit_pending, | |
| 69 int64 sequence_number, | |
| 70 int64 base_version, | |
| 71 base::Time ctime, | |
| 72 base::Time mtime, | |
| 73 const std::string& non_unique_name, | |
| 74 bool deleted, | |
| 75 const sync_pb::EntitySpecifics& specifics) | |
| 76 : id_(id), | |
| 77 client_tag_hash_(client_tag_hash), | |
| 78 highest_commit_response_version_(highest_commit_response_version), | |
| 79 highest_gu_response_version_(highest_gu_response_version), | |
| 80 is_commit_pending_(is_commit_pending), | |
| 81 sequence_number_(sequence_number), | |
| 82 base_version_(base_version), | |
| 83 ctime_(ctime), | |
| 84 mtime_(mtime), | |
| 85 non_unique_name_(non_unique_name), | |
| 86 deleted_(deleted), | |
| 87 specifics_(specifics) { | |
| 88 } | |
| 89 | |
| 90 SyncThreadSyncEntity::~SyncThreadSyncEntity() { | |
| 91 } | |
| 92 | |
| 93 bool SyncThreadSyncEntity::IsCommitPending() const { | |
| 94 return is_commit_pending_; | |
| 95 } | |
| 96 | |
| 97 void SyncThreadSyncEntity::PrepareCommitProto( | |
| 98 sync_pb::SyncEntity* commit_entity, | |
| 99 int64* sequence_number) const { | |
| 100 // Set ID if we have a server-assigned ID. Otherwise, it will be up to | |
| 101 // our caller to assign a client-unique initial ID. | |
| 102 if (base_version_ != kUncommittedVersion) { | |
| 103 commit_entity->set_id_string(id_); | |
| 104 } | |
| 105 | |
| 106 commit_entity->set_client_defined_unique_tag(client_tag_hash_); | |
| 107 commit_entity->set_version(base_version_); | |
| 108 commit_entity->set_deleted(deleted_); | |
| 109 commit_entity->set_folder(false); | |
| 110 commit_entity->set_name(non_unique_name_); | |
| 111 if (!deleted_) { | |
| 112 commit_entity->set_ctime(TimeToProtoTime(ctime_)); | |
| 113 commit_entity->set_mtime(TimeToProtoTime(mtime_)); | |
| 114 commit_entity->mutable_specifics()->CopyFrom(specifics_); | |
| 115 } | |
| 116 | |
| 117 *sequence_number = sequence_number_; | |
| 118 } | |
| 119 | |
| 120 void SyncThreadSyncEntity::RequestCommit( | |
| 121 const std::string& id, | |
| 122 const std::string& client_tag_hash, | |
| 123 int64 sequence_number, | |
| 124 int64 base_version, | |
| 125 base::Time ctime, | |
| 126 base::Time mtime, | |
| 127 const std::string& non_unique_name, | |
| 128 bool deleted, | |
| 129 const sync_pb::EntitySpecifics& specifics) { | |
| 130 if (base_version < base_version_) { | |
| 131 NOTREACHED() << "Base version should never decrease"; | |
| 132 return; | |
| 133 } | |
| 134 | |
| 135 if (sequence_number < sequence_number_) { | |
| 136 NOTREACHED() << "Sequence number should never decrease"; | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 // Update our book-keeping counters. | |
| 141 base_version_ = base_version; | |
| 142 sequence_number_ = sequence_number; | |
| 143 | |
| 144 // Do our counter values indicate a conflict? If so, don't commit. | |
| 145 // | |
| 146 // There's no need to inform the model thread of the conflict. The | |
| 147 // conflicting update has already been posted to its task runner; it will | |
| 148 // figure it out as soon as it runs that task. | |
| 149 is_commit_pending_ = true; | |
| 150 if (IsInConflict()) { | |
| 151 ClearPendingCommit(); | |
| 152 return; | |
| 153 } | |
| 154 | |
| 155 // We don't commit deletions of server-unknown items. | |
| 156 if (deleted && !IsServerKnown()) { | |
| 157 ClearPendingCommit(); | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 // Otherwise, we should store the data associated with this pending commit | |
| 162 // so we're ready to commit at the next possible opportunity. | |
| 163 | |
| 164 // We intentionally don't update the id_ here. Good ID values come from the | |
| 165 // server and always pass through the sync thread first. There's no way the | |
| 166 // model thread could have a better ID value than we do. | |
| 167 | |
| 168 // This entity is identified by its client tag. That value can never change. | |
| 169 DCHECK_EQ(client_tag_hash_, client_tag_hash); | |
| 170 | |
| 171 // Set the fields for the pending commit. | |
| 172 ctime_ = ctime; | |
| 173 mtime_ = mtime; | |
| 174 non_unique_name_ = non_unique_name; | |
| 175 deleted_ = deleted; | |
| 176 specifics_ = specifics; | |
| 177 } | |
| 178 | |
| 179 void SyncThreadSyncEntity::ReceiveCommitResponse(const std::string& response_id, | |
| 180 int64 response_version, | |
| 181 int64 sequence_number) { | |
| 182 // Commit responses, especially after the first commit, can update our ID. | |
| 183 id_ = response_id; | |
| 184 | |
| 185 DCHECK_GT(response_version, highest_commit_response_version_) | |
| 186 << "Had expected higher response version." | |
| 187 << " id: " << id_; | |
| 188 | |
| 189 // Commits are synchronous, so there should there's no reason why the | |
|
Nicolas Zea
2014/05/28 23:56:16
nit: there should there's
rlarocque
2014/05/29 20:54:52
Done.
| |
| 190 // sequence numbers wouldn't match. | |
| 191 DCHECK_EQ(sequence_number_, sequence_number) | |
| 192 << "Unexpected sequence number mismatch." | |
| 193 << " id: " << id_; | |
| 194 | |
| 195 highest_commit_response_version_ = response_version; | |
| 196 | |
| 197 // Because an in-progress commit blocks the sync thread, we can assume that | |
| 198 // the item we just committed successfully is exactly the one we have now. | |
| 199 // Nothing changed it while the commit was happening. Since we're now in | |
| 200 // sync with the server, we can clear the pending commit. | |
| 201 ClearPendingCommit(); | |
| 202 } | |
| 203 | |
| 204 void SyncThreadSyncEntity::ReceiveUpdate(int64 version) { | |
| 205 highest_gu_response_version_ = | |
| 206 std::max(highest_gu_response_version_, version); | |
| 207 | |
| 208 if (IsInConflict()) { | |
| 209 // Incoming update clobbers the pending commit on the sync thread. | |
| 210 // The model thread can re-request this commit later if it wants to. | |
| 211 ClearPendingCommit(); | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 bool SyncThreadSyncEntity::IsInConflict() const { | |
| 216 if (!is_commit_pending_) | |
| 217 return false; | |
| 218 | |
| 219 if (highest_gu_response_version_ <= highest_commit_response_version_) { | |
| 220 // The most recent server state was created in a commit made by this | |
| 221 // client. We're fully up to date, and therefore not in conflict. | |
| 222 return false; | |
| 223 } else { | |
| 224 // The most recent server state was written by someone else. | |
| 225 // Did the model thread have the most up to date version when it issued the | |
| 226 // commit request? | |
| 227 if (base_version_ >= highest_gu_response_version_) { | |
| 228 return false; // Yes. | |
| 229 } else { | |
| 230 return true; // No. | |
| 231 } | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 bool SyncThreadSyncEntity::IsServerKnown() const { | |
| 236 return base_version_ != kUncommittedVersion; | |
| 237 } | |
| 238 | |
| 239 void SyncThreadSyncEntity::ClearPendingCommit() { | |
| 240 is_commit_pending_ = false; | |
| 241 specifics_.Clear(); | |
|
Nicolas Zea
2014/05/28 23:56:16
why clear the specific here?
rlarocque
2014/05/29 20:54:52
It's an optimization. At this point we've given u
Nicolas Zea
2014/06/02 20:27:17
Does the protobuf library actually free memory whe
rlarocque
2014/06/02 21:39:13
According to the documentation [1], protobufs can
| |
| 242 } | |
| 243 | |
| 244 } // namespace syncer | |
| OLD | NEW |