• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/directory_commit_contribution.h"
6 
7 #include "sync/engine/commit_util.h"
8 #include "sync/engine/get_commit_ids.h"
9 #include "sync/engine/syncer_util.h"
10 #include "sync/internal_api/public/sessions/commit_counters.h"
11 #include "sync/syncable/model_neutral_mutable_entry.h"
12 #include "sync/syncable/syncable_model_neutral_write_transaction.h"
13 
14 namespace syncer {
15 
16 using syncable::GET_BY_HANDLE;
17 using syncable::SYNCER;
18 
~DirectoryCommitContribution()19 DirectoryCommitContribution::~DirectoryCommitContribution() {
20   DCHECK(!syncing_bits_set_);
21 }
22 
23 // static.
Build(syncable::Directory * dir,ModelType type,size_t max_entries,DirectoryTypeDebugInfoEmitter * debug_info_emitter)24 scoped_ptr<DirectoryCommitContribution> DirectoryCommitContribution::Build(
25     syncable::Directory* dir,
26     ModelType type,
27     size_t max_entries,
28     DirectoryTypeDebugInfoEmitter* debug_info_emitter) {
29   DCHECK(debug_info_emitter);
30 
31   std::vector<int64> metahandles;
32 
33   syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir);
34   GetCommitIdsForType(&trans, type, max_entries, &metahandles);
35 
36   if (metahandles.empty())
37     return scoped_ptr<DirectoryCommitContribution>();
38 
39   google::protobuf::RepeatedPtrField<sync_pb::SyncEntity> entities;
40   for (std::vector<int64>::iterator it = metahandles.begin();
41        it != metahandles.end(); ++it) {
42     sync_pb::SyncEntity* entity = entities.Add();
43     syncable::ModelNeutralMutableEntry entry(&trans, GET_BY_HANDLE, *it);
44     commit_util::BuildCommitItem(entry, entity);
45     entry.PutSyncing(true);
46   }
47 
48   sync_pb::DataTypeContext context;
49   dir->GetDataTypeContext(&trans, type, &context);
50 
51   return scoped_ptr<DirectoryCommitContribution>(
52       new DirectoryCommitContribution(
53           metahandles,
54           entities,
55           context,
56           dir,
57           debug_info_emitter));
58 }
59 
AddToCommitMessage(sync_pb::ClientToServerMessage * msg)60 void DirectoryCommitContribution::AddToCommitMessage(
61     sync_pb::ClientToServerMessage* msg) {
62   DCHECK(syncing_bits_set_);
63   sync_pb::CommitMessage* commit_message = msg->mutable_commit();
64   entries_start_index_ = commit_message->entries_size();
65   std::copy(entities_.begin(),
66             entities_.end(),
67             RepeatedPtrFieldBackInserter(commit_message->mutable_entries()));
68   if (!context_.context().empty())
69     commit_message->add_client_contexts()->Swap(&context_);
70 
71   CommitCounters* counters = debug_info_emitter_->GetMutableCommitCounters();
72   counters->num_commits_attempted += entities_.size();
73 }
74 
ProcessCommitResponse(const sync_pb::ClientToServerResponse & response,sessions::StatusController * status)75 SyncerError DirectoryCommitContribution::ProcessCommitResponse(
76     const sync_pb::ClientToServerResponse& response,
77     sessions::StatusController* status) {
78   DCHECK(syncing_bits_set_);
79   const sync_pb::CommitResponse& commit_response = response.commit();
80 
81   int transient_error_commits = 0;
82   int conflicting_commits = 0;
83   int error_commits = 0;
84   int successes = 0;
85 
86   std::set<syncable::Id> deleted_folders;
87   {
88     syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
89     for (size_t i = 0; i < metahandles_.size(); ++i) {
90       sync_pb::CommitResponse::ResponseType response_type =
91           commit_util::ProcessSingleCommitResponse(
92               &trans,
93               commit_response.entryresponse(entries_start_index_ + i),
94               entities_.Get(i),
95               metahandles_[i],
96               &deleted_folders);
97       switch (response_type) {
98         case sync_pb::CommitResponse::INVALID_MESSAGE:
99           ++error_commits;
100           break;
101         case sync_pb::CommitResponse::CONFLICT:
102           ++conflicting_commits;
103           status->increment_num_server_conflicts();
104           break;
105         case sync_pb::CommitResponse::SUCCESS:
106           ++successes;
107           {
108             syncable::Entry e(&trans, GET_BY_HANDLE, metahandles_[i]);
109             if (e.GetModelType() == BOOKMARKS)
110               status->increment_num_successful_bookmark_commits();
111           }
112           status->increment_num_successful_commits();
113           break;
114         case sync_pb::CommitResponse::OVER_QUOTA:
115           // We handle over quota like a retry, which is same as transient.
116         case sync_pb::CommitResponse::RETRY:
117         case sync_pb::CommitResponse::TRANSIENT_ERROR:
118           ++transient_error_commits;
119           break;
120         default:
121           LOG(FATAL) << "Bad return from ProcessSingleCommitResponse";
122       }
123     }
124     MarkDeletedChildrenSynced(dir_, &trans, &deleted_folders);
125   }
126 
127   CommitCounters* counters = debug_info_emitter_->GetMutableCommitCounters();
128   counters->num_commits_success += successes;
129   counters->num_commits_conflict += transient_error_commits;
130   counters->num_commits_error += transient_error_commits;
131 
132   int commit_count = static_cast<int>(metahandles_.size());
133   if (commit_count == successes) {
134     return SYNCER_OK;
135   } else if (error_commits > 0) {
136     return SERVER_RETURN_UNKNOWN_ERROR;
137   } else if (transient_error_commits > 0) {
138     return SERVER_RETURN_TRANSIENT_ERROR;
139   } else if (conflicting_commits > 0) {
140     // This means that the server already has an item with this version, but
141     // we haven't seen that update yet.
142     //
143     // A well-behaved client should respond to this by proceeding to the
144     // download updates phase, fetching the conflicting items, then attempting
145     // to resolve the conflict.  That's not what this client does.
146     //
147     // We don't currently have any code to support that exceptional control
148     // flow.  Instead, we abort the current sync cycle and start a new one.  The
149     // end result is the same.
150     return SERVER_RETURN_CONFLICT;
151   } else {
152     LOG(FATAL) << "Inconsistent counts when processing commit response";
153     return SYNCER_OK;
154   }
155 }
156 
CleanUp()157 void DirectoryCommitContribution::CleanUp() {
158   DCHECK(syncing_bits_set_);
159   UnsetSyncingBits();
160   debug_info_emitter_->EmitCommitCountersUpdate();
161   debug_info_emitter_->EmitStatusCountersUpdate();
162 }
163 
GetNumEntries() const164 size_t DirectoryCommitContribution::GetNumEntries() const {
165   return metahandles_.size();
166 }
167 
DirectoryCommitContribution(const std::vector<int64> & metahandles,const google::protobuf::RepeatedPtrField<sync_pb::SyncEntity> & entities,const sync_pb::DataTypeContext & context,syncable::Directory * dir,DirectoryTypeDebugInfoEmitter * debug_info_emitter)168 DirectoryCommitContribution::DirectoryCommitContribution(
169     const std::vector<int64>& metahandles,
170     const google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>& entities,
171     const sync_pb::DataTypeContext& context,
172     syncable::Directory* dir,
173     DirectoryTypeDebugInfoEmitter* debug_info_emitter)
174     : dir_(dir),
175       metahandles_(metahandles),
176       entities_(entities),
177       context_(context),
178       entries_start_index_(0xDEADBEEF),
179       syncing_bits_set_(true),
180       debug_info_emitter_(debug_info_emitter) {}
181 
UnsetSyncingBits()182 void DirectoryCommitContribution::UnsetSyncingBits() {
183   syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
184   for (std::vector<int64>::const_iterator it = metahandles_.begin();
185        it != metahandles_.end(); ++it) {
186     syncable::ModelNeutralMutableEntry entry(&trans, GET_BY_HANDLE, *it);
187     entry.PutSyncing(false);
188   }
189   syncing_bits_set_ = false;
190 }
191 
192 }  // namespace syncer
193