| 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   DCHECK_GE(base_version, base_version_) |  | 
|  131       << "Base version should never decrease"; |  | 
|  132  |  | 
|  133   DCHECK_GE(sequence_number, sequence_number_) |  | 
|  134       << "Sequence number should never decrease"; |  | 
|  135  |  | 
|  136   // Update our book-keeping counters. |  | 
|  137   base_version_ = base_version; |  | 
|  138   sequence_number_ = sequence_number; |  | 
|  139  |  | 
|  140   // Do our counter values indicate a conflict?  If so, don't commit. |  | 
|  141   // |  | 
|  142   // There's no need to inform the model thread of the conflict.  The |  | 
|  143   // conflicting update has already been posted to its task runner; it will |  | 
|  144   // figure it out as soon as it runs that task. |  | 
|  145   is_commit_pending_ = true; |  | 
|  146   if (IsInConflict()) { |  | 
|  147     ClearPendingCommit(); |  | 
|  148     return; |  | 
|  149   } |  | 
|  150  |  | 
|  151   // We don't commit deletions of server-unknown items. |  | 
|  152   if (deleted && !IsServerKnown()) { |  | 
|  153     ClearPendingCommit(); |  | 
|  154     return; |  | 
|  155   } |  | 
|  156  |  | 
|  157   // Otherwise, we should store the data associated with this pending commit |  | 
|  158   // so we're ready to commit at the next possible opportunity. |  | 
|  159  |  | 
|  160   // We intentionally don't update the id_ here.  Good ID values come from the |  | 
|  161   // server and always pass through the sync thread first.  There's no way the |  | 
|  162   // model thread could have a better ID value than we do. |  | 
|  163  |  | 
|  164   // This entity is identified by its client tag.  That value can never change. |  | 
|  165   DCHECK_EQ(client_tag_hash_, client_tag_hash); |  | 
|  166  |  | 
|  167   // Set the fields for the pending commit. |  | 
|  168   ctime_ = ctime; |  | 
|  169   mtime_ = mtime; |  | 
|  170   non_unique_name_ = non_unique_name; |  | 
|  171   deleted_ = deleted; |  | 
|  172   specifics_ = specifics; |  | 
|  173 } |  | 
|  174  |  | 
|  175 void SyncThreadSyncEntity::ReceiveCommitResponse(const std::string& response_id, |  | 
|  176                                                  int64 response_version, |  | 
|  177                                                  int64 sequence_number) { |  | 
|  178   // Commit responses, especially after the first commit, can update our ID. |  | 
|  179   id_ = response_id; |  | 
|  180  |  | 
|  181   DCHECK_GT(response_version, highest_commit_response_version_) |  | 
|  182       << "Had expected higher response version." |  | 
|  183       << " id: " << id_; |  | 
|  184  |  | 
|  185   // Commits are synchronous, so there's no reason why the sequence numbers |  | 
|  186   // wouldn't match. |  | 
|  187   DCHECK_EQ(sequence_number_, sequence_number) |  | 
|  188       << "Unexpected sequence number mismatch." |  | 
|  189       << " id: " << id_; |  | 
|  190  |  | 
|  191   highest_commit_response_version_ = response_version; |  | 
|  192  |  | 
|  193   // Because an in-progress commit blocks the sync thread, we can assume that |  | 
|  194   // the item we just committed successfully is exactly the one we have now. |  | 
|  195   // Nothing changed it while the commit was happening.  Since we're now in |  | 
|  196   // sync with the server, we can clear the pending commit. |  | 
|  197   ClearPendingCommit(); |  | 
|  198 } |  | 
|  199  |  | 
|  200 void SyncThreadSyncEntity::ReceiveUpdate(int64 version) { |  | 
|  201   highest_gu_response_version_ = |  | 
|  202       std::max(highest_gu_response_version_, version); |  | 
|  203  |  | 
|  204   if (IsInConflict()) { |  | 
|  205     // Incoming update clobbers the pending commit on the sync thread. |  | 
|  206     // The model thread can re-request this commit later if it wants to. |  | 
|  207     ClearPendingCommit(); |  | 
|  208   } |  | 
|  209 } |  | 
|  210  |  | 
|  211 bool SyncThreadSyncEntity::IsInConflict() const { |  | 
|  212   if (!is_commit_pending_) |  | 
|  213     return false; |  | 
|  214  |  | 
|  215   if (highest_gu_response_version_ <= highest_commit_response_version_) { |  | 
|  216     // The most recent server state was created in a commit made by this |  | 
|  217     // client.  We're fully up to date, and therefore not in conflict. |  | 
|  218     return false; |  | 
|  219   } else { |  | 
|  220     // The most recent server state was written by someone else. |  | 
|  221     // Did the model thread have the most up to date version when it issued the |  | 
|  222     // commit request? |  | 
|  223     if (base_version_ >= highest_gu_response_version_) { |  | 
|  224       return false;  // Yes. |  | 
|  225     } else { |  | 
|  226       return true;  // No. |  | 
|  227     } |  | 
|  228   } |  | 
|  229 } |  | 
|  230  |  | 
|  231 bool SyncThreadSyncEntity::IsServerKnown() const { |  | 
|  232   return base_version_ != kUncommittedVersion; |  | 
|  233 } |  | 
|  234  |  | 
|  235 void SyncThreadSyncEntity::ClearPendingCommit() { |  | 
|  236   is_commit_pending_ = false; |  | 
|  237  |  | 
|  238   // Clearing the specifics might free up some memory.  It can't hurt to try. |  | 
|  239   specifics_.Clear(); |  | 
|  240 } |  | 
|  241  |  | 
|  242 }  // namespace syncer |  | 
| OLD | NEW |