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