• 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/conflict_resolver.h"
16 #include "sync/engine/download.h"
17 #include "sync/engine/net/server_connection_manager.h"
18 #include "sync/engine/syncer_types.h"
19 #include "sync/internal_api/public/base/cancelation_signal.h"
20 #include "sync/internal_api/public/base/unique_position.h"
21 #include "sync/internal_api/public/util/syncer_error.h"
22 #include "sync/sessions/nudge_tracker.h"
23 #include "sync/syncable/directory.h"
24 #include "sync/syncable/mutable_entry.h"
25 #include "sync/syncable/syncable-inl.h"
26 
27 using base::Time;
28 using base::TimeDelta;
29 using sync_pb::ClientCommand;
30 
31 namespace syncer {
32 
33 // TODO(akalin): We may want to propagate this switch up
34 // eventually.
35 #if defined(OS_ANDROID) || defined(OS_IOS)
36 static const bool kCreateMobileBookmarksFolder = true;
37 #else
38 static const bool kCreateMobileBookmarksFolder = false;
39 #endif
40 
41 using sessions::StatusController;
42 using sessions::SyncSession;
43 using sessions::NudgeTracker;
44 
Syncer(syncer::CancelationSignal * cancelation_signal)45 Syncer::Syncer(syncer::CancelationSignal* cancelation_signal)
46     : cancelation_signal_(cancelation_signal) {
47 }
48 
~Syncer()49 Syncer::~Syncer() {}
50 
ExitRequested()51 bool Syncer::ExitRequested() {
52   return cancelation_signal_->IsSignalled();
53 }
54 
NormalSyncShare(ModelTypeSet request_types,const NudgeTracker & nudge_tracker,SyncSession * session)55 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
56                              const NudgeTracker& nudge_tracker,
57                              SyncSession* session) {
58   HandleCycleBegin(session);
59   VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
60   if (nudge_tracker.IsGetUpdatesRequired() ||
61       session->context()->ShouldFetchUpdatesBeforeCommit()) {
62     if (!DownloadAndApplyUpdates(
63             request_types,
64             session,
65             base::Bind(&download::BuildNormalDownloadUpdates,
66                        session,
67                        kCreateMobileBookmarksFolder,
68                        request_types,
69                        base::ConstRef(nudge_tracker)))) {
70       return HandleCycleEnd(session, nudge_tracker.updates_source());
71     }
72   }
73 
74   VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
75   SyncerError commit_result = BuildAndPostCommits(request_types, session);
76   session->mutable_status_controller()->set_commit_result(commit_result);
77 
78   return HandleCycleEnd(session, nudge_tracker.updates_source());
79 }
80 
ConfigureSyncShare(ModelTypeSet request_types,sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,SyncSession * session)81 bool Syncer::ConfigureSyncShare(
82     ModelTypeSet request_types,
83     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
84     SyncSession* session) {
85   HandleCycleBegin(session);
86   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
87   DownloadAndApplyUpdates(
88       request_types,
89       session,
90       base::Bind(&download::BuildDownloadUpdatesForConfigure,
91                  session,
92                  kCreateMobileBookmarksFolder,
93                  source,
94                  request_types));
95   return HandleCycleEnd(session, source);
96 }
97 
PollSyncShare(ModelTypeSet request_types,SyncSession * session)98 bool Syncer::PollSyncShare(ModelTypeSet request_types,
99                            SyncSession* session) {
100   HandleCycleBegin(session);
101   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
102   DownloadAndApplyUpdates(
103       request_types,
104       session,
105       base::Bind(&download::BuildDownloadUpdatesForPoll,
106                  session,
107                  kCreateMobileBookmarksFolder,
108                  request_types));
109   return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC);
110 }
111 
ApplyUpdates(SyncSession * session)112 void Syncer::ApplyUpdates(SyncSession* session) {
113   TRACE_EVENT0("sync", "ApplyUpdates");
114 
115   ApplyControlDataUpdates(session->context()->directory());
116 
117   UpdateHandlerMap* handler_map = session->context()->update_handler_map();
118   for (UpdateHandlerMap::iterator it = handler_map->begin();
119        it != handler_map->end(); ++it) {
120     it->second->ApplyUpdates(session->mutable_status_controller());
121   }
122 
123   session->context()->set_hierarchy_conflict_detected(
124       session->status_controller().num_hierarchy_conflicts() > 0);
125 
126   session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED);
127 }
128 
DownloadAndApplyUpdates(ModelTypeSet request_types,SyncSession * session,base::Callback<void (sync_pb::ClientToServerMessage *)> build_fn)129 bool Syncer::DownloadAndApplyUpdates(
130     ModelTypeSet request_types,
131     SyncSession* session,
132     base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn) {
133   SyncerError download_result = UNSET;
134   do {
135     TRACE_EVENT0("sync", "DownloadUpdates");
136     sync_pb::ClientToServerMessage msg;
137     build_fn.Run(&msg);
138     download_result =
139         download::ExecuteDownloadUpdates(request_types, session, &msg);
140     session->mutable_status_controller()->set_last_download_updates_result(
141         download_result);
142   } while (download_result == SERVER_MORE_TO_DOWNLOAD);
143 
144   // Exit without applying if we're shutting down or an error was detected.
145   if (download_result != SYNCER_OK)
146     return false;
147   if (ExitRequested())
148     return false;
149 
150   ApplyUpdates(session);
151   if (ExitRequested())
152     return false;
153   return true;
154 }
155 
BuildAndPostCommits(ModelTypeSet requested_types,sessions::SyncSession * session)156 SyncerError Syncer::BuildAndPostCommits(ModelTypeSet requested_types,
157                                         sessions::SyncSession* session) {
158   // The ExitRequested() check is unnecessary, since we should start getting
159   // errors from the ServerConnectionManager if an exist has been requested.
160   // However, it doesn't hurt to check it anyway.
161   while (!ExitRequested()) {
162     scoped_ptr<Commit> commit(
163         Commit::Init(
164             requested_types,
165             session->context()->max_commit_batch_size(),
166             session->context()->account_name(),
167             session->context()->directory()->cache_guid(),
168             session->context()->commit_contributor_map(),
169             session->context()->extensions_activity()));
170     if (!commit) {
171       break;
172     }
173 
174     SyncerError error = commit->PostAndProcessResponse(
175         session,
176         session->mutable_status_controller(),
177         session->context()->extensions_activity());
178     commit->CleanUp();
179     if (error != SYNCER_OK) {
180       return error;
181     }
182   }
183 
184   return SYNCER_OK;
185 }
186 
HandleCycleBegin(SyncSession * session)187 void Syncer::HandleCycleBegin(SyncSession* session) {
188   session->mutable_status_controller()->UpdateStartTime();
189   session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN);
190 }
191 
HandleCycleEnd(SyncSession * session,sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source)192 bool Syncer::HandleCycleEnd(
193     SyncSession* session,
194     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
195   if (!ExitRequested()) {
196     session->SendSyncCycleEndEventNotification(source);
197     return true;
198   } else {
199     return false;
200   }
201 }
202 
203 }  // namespace syncer
204