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