- add sources.
[platform/framework/web/crosswalk.git] / src / sync / engine / sync_directory_commit_contribution.cc
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.
4
5 #include "sync/engine/sync_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/syncable/model_neutral_mutable_entry.h"
11 #include "sync/syncable/syncable_model_neutral_write_transaction.h"
12
13 namespace syncer {
14
15 using syncable::GET_BY_HANDLE;
16 using syncable::SYNCER;
17
18 SyncDirectoryCommitContribution::~SyncDirectoryCommitContribution() {
19   DCHECK(!syncing_bits_set_);
20 }
21
22 // static.
23 SyncDirectoryCommitContribution* SyncDirectoryCommitContribution::Build(
24     syncable::Directory* dir,
25     ModelType type,
26     size_t max_entries) {
27   std::vector<int64> metahandles;
28
29   syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir);
30   GetCommitIdsForType(&trans, type, max_entries, &metahandles);
31
32   if (metahandles.empty())
33     return NULL;
34
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);
42   }
43
44   return new SyncDirectoryCommitContribution(metahandles, entities, dir);
45 }
46
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(),
53             entities_.end(),
54             RepeatedPtrFieldBackInserter(commit_message->mutable_entries()));
55 }
56
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();
62
63   int transient_error_commits = 0;
64   int conflicting_commits = 0;
65   int error_commits = 0;
66   int successes = 0;
67
68   std::set<syncable::Id> deleted_folders;
69   {
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(
74               &trans,
75               commit_response.entryresponse(entries_start_index_ + i),
76               entities_.Get(i),
77               metahandles_[i],
78               &deleted_folders);
79       switch (response_type) {
80         case sync_pb::CommitResponse::INVALID_MESSAGE:
81           ++error_commits;
82           break;
83         case sync_pb::CommitResponse::CONFLICT:
84           ++conflicting_commits;
85           status->increment_num_server_conflicts();
86           break;
87         case sync_pb::CommitResponse::SUCCESS:
88           ++successes;
89           {
90             syncable::Entry e(&trans, GET_BY_HANDLE, metahandles_[i]);
91             if (e.GetModelType() == BOOKMARKS)
92               status->increment_num_successful_bookmark_commits();
93           }
94           status->increment_num_successful_commits();
95           break;
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;
101           break;
102         default:
103           LOG(FATAL) << "Bad return from ProcessSingleCommitResponse";
104       }
105     }
106     MarkDeletedChildrenSynced(dir_, &trans, &deleted_folders);
107   }
108
109   int commit_count = static_cast<int>(metahandles_.size());
110   if (commit_count == successes) {
111     return SYNCER_OK;
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.
119     //
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.
123     //
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;
128   } else {
129     LOG(FATAL) << "Inconsistent counts when processing commit response";
130     return SYNCER_OK;
131   }
132 }
133
134 void SyncDirectoryCommitContribution::CleanUp() {
135   DCHECK(syncing_bits_set_);
136   UnsetSyncingBits();
137 }
138
139 size_t SyncDirectoryCommitContribution::GetNumEntries() const {
140   return metahandles_.size();
141 }
142
143 SyncDirectoryCommitContribution::SyncDirectoryCommitContribution(
144     const std::vector<int64>& metahandles,
145     const google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>& entities,
146     syncable::Directory* dir)
147   : dir_(dir),
148     metahandles_(metahandles),
149     entities_(entities),
150     entries_start_index_(0xDEADBEEF),
151     syncing_bits_set_(true) {
152 }
153
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);
160   }
161   syncing_bits_set_ = false;
162 }
163
164 }  // namespace syncer