1 // Copyright (c) 2012 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 "components/sync/engine_impl/syncer.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram_functions.h"
13 #include "base/trace_event/trace_event.h"
14 #include "components/sync/engine/sync_engine_switches.h"
15 #include "components/sync/engine_impl/cancelation_signal.h"
16 #include "components/sync/engine_impl/commit.h"
17 #include "components/sync/engine_impl/commit_processor.h"
18 #include "components/sync/engine_impl/cycle/nudge_tracker.h"
19 #include "components/sync/engine_impl/cycle/sync_cycle.h"
20 #include "components/sync/engine_impl/get_updates_delegate.h"
21 #include "components/sync/engine_impl/get_updates_processor.h"
22 #include "components/sync/engine_impl/net/server_connection_manager.h"
23
24 namespace syncer {
25
26 namespace {
27
HandleCycleBegin(SyncCycle * cycle)28 void HandleCycleBegin(SyncCycle* cycle) {
29 cycle->mutable_status_controller()->UpdateStartTime();
30 cycle->SendEventNotification(SyncCycleEvent::SYNC_CYCLE_BEGIN);
31 }
32
33 } // namespace
34
Syncer(CancelationSignal * cancelation_signal)35 Syncer::Syncer(CancelationSignal* cancelation_signal)
36 : cancelation_signal_(cancelation_signal), is_syncing_(false) {}
37
~Syncer()38 Syncer::~Syncer() {}
39
IsSyncing() const40 bool Syncer::IsSyncing() const {
41 return is_syncing_;
42 }
43
NormalSyncShare(ModelTypeSet request_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)44 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
45 NudgeTracker* nudge_tracker,
46 SyncCycle* cycle) {
47 base::AutoReset<bool> is_syncing(&is_syncing_, true);
48 HandleCycleBegin(cycle);
49 if (nudge_tracker->IsGetUpdatesRequired(request_types)) {
50 VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
51 if (!DownloadAndApplyUpdates(&request_types, cycle,
52 NormalGetUpdatesDelegate(*nudge_tracker))) {
53 return HandleCycleEnd(cycle, nudge_tracker->GetOrigin());
54 }
55 }
56
57 SyncerError commit_result =
58 BuildAndPostCommits(request_types, nudge_tracker, cycle);
59 cycle->mutable_status_controller()->set_commit_result(commit_result);
60
61 return HandleCycleEnd(cycle, nudge_tracker->GetOrigin());
62 }
63
ConfigureSyncShare(const ModelTypeSet & request_types,sync_pb::SyncEnums::GetUpdatesOrigin origin,SyncCycle * cycle)64 bool Syncer::ConfigureSyncShare(const ModelTypeSet& request_types,
65 sync_pb::SyncEnums::GetUpdatesOrigin origin,
66 SyncCycle* cycle) {
67 base::AutoReset<bool> is_syncing(&is_syncing_, true);
68
69 // It is possible during configuration that datatypes get unregistered from
70 // ModelTypeRegistry before scheduled configure sync cycle gets executed.
71 // This happens either because DataTypeController::LoadModels fail and type
72 // need to be stopped or during shutdown when all datatypes are stopped. When
73 // it happens we should adjust set of types to download to only include
74 // registered types.
75 ModelTypeSet still_enabled_types =
76 Intersection(request_types, cycle->context()->GetEnabledTypes());
77 VLOG(1) << "Configuring types " << ModelTypeSetToString(still_enabled_types);
78 HandleCycleBegin(cycle);
79 DownloadAndApplyUpdates(&still_enabled_types, cycle,
80 ConfigureGetUpdatesDelegate(origin));
81 return HandleCycleEnd(cycle, origin);
82 }
83
PollSyncShare(ModelTypeSet request_types,SyncCycle * cycle)84 bool Syncer::PollSyncShare(ModelTypeSet request_types, SyncCycle* cycle) {
85 base::AutoReset<bool> is_syncing(&is_syncing_, true);
86 VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
87 HandleCycleBegin(cycle);
88 DownloadAndApplyUpdates(&request_types, cycle, PollGetUpdatesDelegate());
89 return HandleCycleEnd(cycle, sync_pb::SyncEnums::PERIODIC);
90 }
91
DownloadAndApplyUpdates(ModelTypeSet * request_types,SyncCycle * cycle,const GetUpdatesDelegate & delegate)92 bool Syncer::DownloadAndApplyUpdates(ModelTypeSet* request_types,
93 SyncCycle* cycle,
94 const GetUpdatesDelegate& delegate) {
95 // CommitOnlyTypes() should not be included in the GetUpdates, but should be
96 // included in the Commit. We are given a set of types for our SyncShare,
97 // and we must do this filtering. Note that |request_types| is also an out
98 // param, see below where we update it.
99 ModelTypeSet requested_commit_only_types =
100 Intersection(*request_types, CommitOnlyTypes());
101 ModelTypeSet download_types =
102 Difference(*request_types, requested_commit_only_types);
103 GetUpdatesProcessor get_updates_processor(
104 cycle->context()->model_type_registry()->update_handler_map(), delegate);
105 SyncerError download_result;
106 do {
107 download_result =
108 get_updates_processor.DownloadUpdates(&download_types, cycle);
109 } while (download_result.value() == SyncerError::SERVER_MORE_TO_DOWNLOAD);
110
111 // It is our responsibility to propagate the removal of types that occurred in
112 // GetUpdatesProcessor::DownloadUpdates().
113 *request_types = Union(download_types, requested_commit_only_types);
114
115 // Exit without applying if we're shutting down or an error was detected.
116 if (download_result.value() != SyncerError::SYNCER_OK || ExitRequested())
117 return false;
118
119 {
120 TRACE_EVENT0("sync", "ApplyUpdates");
121
122 // Apply updates to the other types. May or may not involve cross-thread
123 // traffic, depending on the underlying update handlers and the GU type's
124 // delegate.
125 get_updates_processor.ApplyUpdates(download_types,
126 cycle->mutable_status_controller());
127
128 cycle->context()->set_hierarchy_conflict_detected(
129 cycle->status_controller().num_hierarchy_conflicts() > 0);
130 cycle->SendEventNotification(SyncCycleEvent::STATUS_CHANGED);
131 }
132
133 return !ExitRequested();
134 }
135
BuildAndPostCommits(const ModelTypeSet & request_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)136 SyncerError Syncer::BuildAndPostCommits(const ModelTypeSet& request_types,
137 NudgeTracker* nudge_tracker,
138 SyncCycle* cycle) {
139 VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
140
141 CommitProcessor commit_processor(
142 request_types,
143 cycle->context()->model_type_registry()->commit_contributor_map());
144 // The ExitRequested() check is unnecessary, since we should start getting
145 // errors from the ServerConnectionManager if an exist has been requested.
146 // However, it doesn't hurt to check it anyway.
147 while (!ExitRequested()) {
148 std::unique_ptr<Commit> commit(Commit::Init(
149 cycle->context()->GetEnabledTypes(),
150 cycle->context()->max_commit_batch_size(),
151 cycle->context()->account_name(), cycle->context()->cache_guid(),
152 cycle->context()->cookie_jar_mismatch(),
153 cycle->context()->cookie_jar_empty(), cycle->context()->single_client(),
154 &commit_processor, cycle->context()->extensions_activity()));
155 if (!commit) {
156 break;
157 }
158
159 SyncerError error = commit->PostAndProcessResponse(
160 nudge_tracker, cycle, cycle->mutable_status_controller(),
161 cycle->context()->extensions_activity());
162 base::UmaHistogramEnumeration("Sync.CommitResponse", error.value());
163 for (ModelType type : commit->GetContributingDataTypes()) {
164 const std::string kPrefix = "Sync.CommitResponse.";
165 base::UmaHistogramEnumeration(kPrefix + ModelTypeToHistogramSuffix(type),
166 error.value());
167 }
168 if (error.value() != SyncerError::SYNCER_OK) {
169 return error;
170 }
171 }
172
173 return SyncerError(SyncerError::SYNCER_OK);
174 }
175
ExitRequested()176 bool Syncer::ExitRequested() {
177 return cancelation_signal_->IsSignalled();
178 }
179
HandleCycleEnd(SyncCycle * cycle,sync_pb::SyncEnums::GetUpdatesOrigin origin)180 bool Syncer::HandleCycleEnd(SyncCycle* cycle,
181 sync_pb::SyncEnums::GetUpdatesOrigin origin) {
182 if (ExitRequested())
183 return false;
184
185 bool success =
186 !HasSyncerError(cycle->status_controller().model_neutral_state());
187 if (success && origin == sync_pb::SyncEnums::PERIODIC) {
188 cycle->mutable_status_controller()->UpdatePollTime();
189 }
190 cycle->SendSyncCycleEndEventNotification(origin);
191
192 return success;
193 }
194
195 } // namespace syncer
196