• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sync/engine/syncer.h"
6 
7 #include "base/debug/trace_event.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/time/time.h"
12 #include "build/build_config.h"
13 #include "sync/engine/apply_control_data_updates.h"
14 #include "sync/engine/commit.h"
15 #include "sync/engine/commit_processor.h"
16 #include "sync/engine/conflict_resolver.h"
17 #include "sync/engine/get_updates_delegate.h"
18 #include "sync/engine/get_updates_processor.h"
19 #include "sync/engine/net/server_connection_manager.h"
20 #include "sync/engine/syncer_types.h"
21 #include "sync/internal_api/public/base/cancelation_signal.h"
22 #include "sync/internal_api/public/base/unique_position.h"
23 #include "sync/internal_api/public/util/syncer_error.h"
24 #include "sync/sessions/nudge_tracker.h"
25 #include "sync/syncable/directory.h"
26 #include "sync/syncable/mutable_entry.h"
27 #include "sync/syncable/syncable-inl.h"
28 
29 using base::Time;
30 using base::TimeDelta;
31 using sync_pb::ClientCommand;
32 
33 namespace syncer {
34 
35 // TODO(akalin): We may want to propagate this switch up
36 // eventually.
37 #if defined(OS_ANDROID) || defined(OS_IOS)
38 static const bool kCreateMobileBookmarksFolder = true;
39 #else
40 static const bool kCreateMobileBookmarksFolder = false;
41 #endif
42 
43 using sessions::StatusController;
44 using sessions::SyncSession;
45 using sessions::NudgeTracker;
46 
Syncer(syncer::CancelationSignal * cancelation_signal)47 Syncer::Syncer(syncer::CancelationSignal* cancelation_signal)
48     : cancelation_signal_(cancelation_signal) {
49 }
50 
~Syncer()51 Syncer::~Syncer() {}
52 
ExitRequested()53 bool Syncer::ExitRequested() {
54   return cancelation_signal_->IsSignalled();
55 }
56 
NormalSyncShare(ModelTypeSet request_types,const NudgeTracker & nudge_tracker,SyncSession * session)57 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
58                              const NudgeTracker& nudge_tracker,
59                              SyncSession* session) {
60   HandleCycleBegin(session);
61   if (nudge_tracker.IsGetUpdatesRequired() ||
62       session->context()->ShouldFetchUpdatesBeforeCommit()) {
63     VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
64     NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
65     GetUpdatesProcessor get_updates_processor(
66         session->context()->model_type_registry()->update_handler_map(),
67         normal_delegate);
68     if (!DownloadAndApplyUpdates(
69             request_types,
70             session,
71             &get_updates_processor,
72             kCreateMobileBookmarksFolder)) {
73       return HandleCycleEnd(session, nudge_tracker.GetLegacySource());
74     }
75   }
76 
77   VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
78   CommitProcessor commit_processor(
79       session->context()->model_type_registry()->commit_contributor_map());
80   SyncerError commit_result =
81       BuildAndPostCommits(request_types, session, &commit_processor);
82   session->mutable_status_controller()->set_commit_result(commit_result);
83 
84   return HandleCycleEnd(session, nudge_tracker.GetLegacySource());
85 }
86 
ConfigureSyncShare(ModelTypeSet request_types,sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,SyncSession * session)87 bool Syncer::ConfigureSyncShare(
88     ModelTypeSet request_types,
89     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
90     SyncSession* session) {
91   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
92   HandleCycleBegin(session);
93   ConfigureGetUpdatesDelegate configure_delegate(source);
94   GetUpdatesProcessor get_updates_processor(
95       session->context()->model_type_registry()->update_handler_map(),
96       configure_delegate);
97   DownloadAndApplyUpdates(
98       request_types,
99       session,
100       &get_updates_processor,
101       kCreateMobileBookmarksFolder);
102   return HandleCycleEnd(session, source);
103 }
104 
PollSyncShare(ModelTypeSet request_types,SyncSession * session)105 bool Syncer::PollSyncShare(ModelTypeSet request_types,
106                            SyncSession* session) {
107   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
108   HandleCycleBegin(session);
109   PollGetUpdatesDelegate poll_delegate;
110   GetUpdatesProcessor get_updates_processor(
111       session->context()->model_type_registry()->update_handler_map(),
112       poll_delegate);
113   DownloadAndApplyUpdates(
114       request_types,
115       session,
116       &get_updates_processor,
117       kCreateMobileBookmarksFolder);
118   return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC);
119 }
120 
DownloadAndApplyUpdates(ModelTypeSet request_types,SyncSession * session,GetUpdatesProcessor * get_updates_processor,bool create_mobile_bookmarks_folder)121 bool Syncer::DownloadAndApplyUpdates(
122     ModelTypeSet request_types,
123     SyncSession* session,
124     GetUpdatesProcessor* get_updates_processor,
125     bool create_mobile_bookmarks_folder) {
126   SyncerError download_result = UNSET;
127   do {
128     download_result = get_updates_processor->DownloadUpdates(
129         request_types,
130         session,
131         create_mobile_bookmarks_folder);
132   } while (download_result == SERVER_MORE_TO_DOWNLOAD);
133 
134   // Exit without applying if we're shutting down or an error was detected.
135   if (download_result != SYNCER_OK)
136     return false;
137   if (ExitRequested())
138     return false;
139 
140   {
141     TRACE_EVENT0("sync", "ApplyUpdates");
142 
143     // Control type updates always get applied first.
144     ApplyControlDataUpdates(session->context()->directory());
145 
146     // Apply upates to the other types.  May or may not involve cross-thread
147     // traffic, depending on the underlying update handlers and the GU type's
148     // delegate.
149     get_updates_processor->ApplyUpdates(request_types,
150                                         session->mutable_status_controller());
151 
152     session->context()->set_hierarchy_conflict_detected(
153         session->status_controller().num_hierarchy_conflicts() > 0);
154     session->SendEventNotification(SyncCycleEvent::STATUS_CHANGED);
155   }
156 
157   if (ExitRequested())
158     return false;
159   return true;
160 }
161 
BuildAndPostCommits(ModelTypeSet requested_types,sessions::SyncSession * session,CommitProcessor * commit_processor)162 SyncerError Syncer::BuildAndPostCommits(ModelTypeSet requested_types,
163                                         sessions::SyncSession* session,
164                                         CommitProcessor* commit_processor) {
165   // The ExitRequested() check is unnecessary, since we should start getting
166   // errors from the ServerConnectionManager if an exist has been requested.
167   // However, it doesn't hurt to check it anyway.
168   while (!ExitRequested()) {
169     scoped_ptr<Commit> commit(
170         Commit::Init(
171             requested_types,
172             session->context()->GetEnabledTypes(),
173             session->context()->max_commit_batch_size(),
174             session->context()->account_name(),
175             session->context()->directory()->cache_guid(),
176             commit_processor,
177             session->context()->extensions_activity()));
178     if (!commit) {
179       break;
180     }
181 
182     SyncerError error = commit->PostAndProcessResponse(
183         session,
184         session->mutable_status_controller(),
185         session->context()->extensions_activity());
186     commit->CleanUp();
187     if (error != SYNCER_OK) {
188       return error;
189     }
190   }
191 
192   return SYNCER_OK;
193 }
194 
HandleCycleBegin(SyncSession * session)195 void Syncer::HandleCycleBegin(SyncSession* session) {
196   session->mutable_status_controller()->UpdateStartTime();
197   session->SendEventNotification(SyncCycleEvent::SYNC_CYCLE_BEGIN);
198 }
199 
HandleCycleEnd(SyncSession * session,sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source)200 bool Syncer::HandleCycleEnd(
201     SyncSession* session,
202     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
203   if (!ExitRequested()) {
204     session->SendSyncCycleEndEventNotification(source);
205     return true;
206   } else {
207     return false;
208   }
209 }
210 
211 }  // namespace syncer
212