1 // Copyright 2013 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.
5 #include "sync/engine/sync_directory_commit_contribution.h"
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/syncable/model_neutral_mutable_entry.h"
11 #include "sync/syncable/syncable_model_neutral_write_transaction.h"
15 using syncable::GET_BY_HANDLE;
16 using syncable::SYNCER;
18 SyncDirectoryCommitContribution::~SyncDirectoryCommitContribution() {
19 DCHECK(!syncing_bits_set_);
23 SyncDirectoryCommitContribution* SyncDirectoryCommitContribution::Build(
24 syncable::Directory* dir,
27 std::vector<int64> metahandles;
29 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir);
30 GetCommitIdsForType(&trans, type, max_entries, &metahandles);
32 if (metahandles.empty())
35 google::protobuf::RepeatedPtrField<sync_pb::SyncEntity> entities;
36 for (std::vector<int64>::iterator it = metahandles.begin();
37 it != metahandles.end(); ++it) {
38 sync_pb::SyncEntity* entity = entities.Add();
39 syncable::ModelNeutralMutableEntry entry(&trans, GET_BY_HANDLE, *it);
40 commit_util::BuildCommitItem(entry, entity);
41 entry.PutSyncing(true);
44 return new SyncDirectoryCommitContribution(metahandles, entities, dir);
47 void SyncDirectoryCommitContribution::AddToCommitMessage(
48 sync_pb::ClientToServerMessage* msg) {
49 DCHECK(syncing_bits_set_);
50 sync_pb::CommitMessage* commit_message = msg->mutable_commit();
51 entries_start_index_ = commit_message->entries_size();
52 std::copy(entities_.begin(),
54 RepeatedPtrFieldBackInserter(commit_message->mutable_entries()));
57 SyncerError SyncDirectoryCommitContribution::ProcessCommitResponse(
58 const sync_pb::ClientToServerResponse& response,
59 sessions::StatusController* status) {
60 DCHECK(syncing_bits_set_);
61 const sync_pb::CommitResponse& commit_response = response.commit();
63 int transient_error_commits = 0;
64 int conflicting_commits = 0;
65 int error_commits = 0;
68 std::set<syncable::Id> deleted_folders;
70 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
71 for (size_t i = 0; i < metahandles_.size(); ++i) {
72 sync_pb::CommitResponse::ResponseType response_type =
73 commit_util::ProcessSingleCommitResponse(
75 commit_response.entryresponse(entries_start_index_ + i),
79 switch (response_type) {
80 case sync_pb::CommitResponse::INVALID_MESSAGE:
83 case sync_pb::CommitResponse::CONFLICT:
84 ++conflicting_commits;
85 status->increment_num_server_conflicts();
87 case sync_pb::CommitResponse::SUCCESS:
90 syncable::Entry e(&trans, GET_BY_HANDLE, metahandles_[i]);
91 if (e.GetModelType() == BOOKMARKS)
92 status->increment_num_successful_bookmark_commits();
94 status->increment_num_successful_commits();
96 case sync_pb::CommitResponse::OVER_QUOTA:
97 // We handle over quota like a retry, which is same as transient.
98 case sync_pb::CommitResponse::RETRY:
99 case sync_pb::CommitResponse::TRANSIENT_ERROR:
100 ++transient_error_commits;
103 LOG(FATAL) << "Bad return from ProcessSingleCommitResponse";
106 MarkDeletedChildrenSynced(dir_, &trans, &deleted_folders);
109 int commit_count = static_cast<int>(metahandles_.size());
110 if (commit_count == successes) {
112 } else if (error_commits > 0) {
113 return SERVER_RETURN_UNKNOWN_ERROR;
114 } else if (transient_error_commits > 0) {
115 return SERVER_RETURN_TRANSIENT_ERROR;
116 } else if (conflicting_commits > 0) {
117 // This means that the server already has an item with this version, but
118 // we haven't seen that update yet.
120 // A well-behaved client should respond to this by proceeding to the
121 // download updates phase, fetching the conflicting items, then attempting
122 // to resolve the conflict. That's not what this client does.
124 // We don't currently have any code to support that exceptional control
125 // flow. Instead, we abort the current sync cycle and start a new one. The
126 // end result is the same.
127 return SERVER_RETURN_CONFLICT;
129 LOG(FATAL) << "Inconsistent counts when processing commit response";
134 void SyncDirectoryCommitContribution::CleanUp() {
135 DCHECK(syncing_bits_set_);
139 size_t SyncDirectoryCommitContribution::GetNumEntries() const {
140 return metahandles_.size();
143 SyncDirectoryCommitContribution::SyncDirectoryCommitContribution(
144 const std::vector<int64>& metahandles,
145 const google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>& entities,
146 syncable::Directory* dir)
148 metahandles_(metahandles),
150 entries_start_index_(0xDEADBEEF),
151 syncing_bits_set_(true) {
154 void SyncDirectoryCommitContribution::UnsetSyncingBits() {
155 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
156 for (std::vector<int64>::const_iterator it = metahandles_.begin();
157 it != metahandles_.end(); ++it) {
158 syncable::ModelNeutralMutableEntry entry(&trans, GET_BY_HANDLE, *it);
159 entry.PutSyncing(false);
161 syncing_bits_set_ = false;
164 } // namespace syncer