Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: chrome/browser/sync/engine/all_status.cc

Issue 194065: Initial commit of sync engine code to browser/sync.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Fixes to gtest include path, reverted syncapi. Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 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 "chrome/browser/sync/engine/all_status.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/port.h"
11 #include "base/rand_util.h"
12 #include "chrome/browser/sync/engine/auth_watcher.h"
13 #include "chrome/browser/sync/engine/net/gaia_authenticator.h"
14 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
15 #include "chrome/browser/sync/engine/syncer.h"
16 #include "chrome/browser/sync/engine/syncer_thread.h"
17 #include "chrome/browser/sync/engine/syncproto.h"
18 #include "chrome/browser/sync/notifier/listener/talk_mediator.h"
19 #include "chrome/browser/sync/protocol/service_constants.h"
20 #include "chrome/browser/sync/syncable/directory_manager.h"
21 #include "chrome/browser/sync/util/event_sys-inl.h"
22
23 namespace browser_sync {
24
25 static const time_t kMinSyncObserveInterval = 10; // seconds
26
27 // Backoff interval randomization factor.
28 static const int kBackoffRandomizationFactor = 2;
29
30 const char* AllStatus::GetSyncStatusString(SyncStatus icon) {
31 const char* strings[] = {"OFFLINE", "OFFLINE_UNSYNCED", "SYNCING", "READY",
32 "CONFLICT", "OFFLINE_UNUSABLE"};
33 COMPILE_ASSERT(ARRAYSIZE(strings) == ICON_STATUS_COUNT, enum_indexed_array);
34 if (icon < 0 || icon >= ARRAYSIZE(strings))
35 LOG(FATAL) << "Illegal Icon State:" << icon;
36 return strings[icon];
37 }
38
39 static const AllStatus::Status init_status =
40 { AllStatus::OFFLINE };
41
42 static const AllStatusEvent shutdown_event =
43 { AllStatusEvent::SHUTDOWN, init_status };
44
45 AllStatus::AllStatus() : channel_(new Channel(shutdown_event)),
46 status_(init_status) {
47 status_.initial_sync_ended = true;
48 status_.notifications_enabled = false;
49 }
50
51 AllStatus::~AllStatus() {
52 delete channel_;
53 }
54
55 void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) {
56 conn_mgr_hookup_.reset(NewEventListenerHookup(conn_mgr->channel(), this,
57 &AllStatus::HandleServerConnectionEvent));
58 }
59
60 void AllStatus::WatchAuthenticator(GaiaAuthenticator* gaia) {
61 gaia_hookup_.reset(NewEventListenerHookup(gaia->channel(), this,
62 &AllStatus::HandleGaiaAuthEvent));
63 }
64
65 void AllStatus::WatchAuthWatcher(AuthWatcher* auth_watcher) {
66 authwatcher_hookup_.reset(
67 NewEventListenerHookup(auth_watcher->channel(), this,
68 &AllStatus::HandleAuthWatcherEvent));
69 }
70
71 void AllStatus::WatchSyncerThread(SyncerThread* syncer_thread) {
72 syncer_thread_hookup_.reset(
73 NewEventListenerHookup(syncer_thread->channel(), this,
74 &AllStatus::HandleSyncerEvent));
75 }
76
77 AllStatus::Status AllStatus::CreateBlankStatus() const {
78 Status status = status_;
79 status.syncing = true;
80 status.unsynced_count = 0;
81 status.conflicting_count = 0;
82 status.initial_sync_ended = false;
83 status.syncer_stuck = false;
84 status.max_consecutive_errors = 0;
85 status.server_broken = false;
86 status.updates_available = 0;
87 status.updates_received = 0;
88 return status;
89 }
90
91 AllStatus::Status AllStatus::CalcSyncing(const SyncerEvent &event) const {
92 Status status = CreateBlankStatus();
93 SyncerStatus syncerStatus(event.last_session);
94 status.unsynced_count += syncerStatus.unsynced_count();
95 status.conflicting_count += syncerStatus.conflicting_commits();
96 if (syncerStatus.current_sync_timestamp() ==
97 syncerStatus.servers_latest_timestamp()) {
98 status.conflicting_count += syncerStatus.conflicting_updates();
99 }
100 status.syncing |= syncerStatus.syncing();
101 // Show a syncer as syncing if it's got stalled updates.
102 status.syncing = event.last_session->ShouldSyncAgain();
103 status.initial_sync_ended |= syncerStatus.IsShareUsable();
104 status.syncer_stuck |= syncerStatus.syncer_stuck();
105 if (syncerStatus.consecutive_errors() > status.max_consecutive_errors)
106 status.max_consecutive_errors = syncerStatus.consecutive_errors();
107
108 // 100 is an arbitrary limit.
109 if (syncerStatus.consecutive_transient_error_commits() > 100)
110 status.server_broken = true;
111
112 status.updates_available += syncerStatus.servers_latest_timestamp();
113 status.updates_received += syncerStatus.current_sync_timestamp();
114 return status;
115 }
116
117 AllStatus::Status AllStatus::CalcSyncing() const {
118 return CreateBlankStatus();
119 }
120
121 int AllStatus::CalcStatusChanges(Status* old_status) {
122 int what_changed = 0;
123
124 // Calculate what changed and what the new icon should be.
125 if (status_.syncing != old_status->syncing)
126 what_changed |= AllStatusEvent::SYNCING;
127 if (status_.unsynced_count != old_status->unsynced_count)
128 what_changed |= AllStatusEvent::UNSYNCED_COUNT;
129 if (status_.server_up != old_status->server_up)
130 what_changed |= AllStatusEvent::SERVER_UP;
131 if (status_.server_reachable != old_status->server_reachable)
132 what_changed |= AllStatusEvent::SERVER_REACHABLE;
133 if (status_.notifications_enabled != old_status->notifications_enabled)
134 what_changed |= AllStatusEvent::NOTIFICATIONS_ENABLED;
135 if (status_.notifications_received != old_status->notifications_received)
136 what_changed |= AllStatusEvent::NOTIFICATIONS_RECEIVED;
137 if (status_.notifications_sent != old_status->notifications_sent)
138 what_changed |= AllStatusEvent::NOTIFICATIONS_SENT;
139 if (status_.initial_sync_ended != old_status->initial_sync_ended)
140 what_changed |= AllStatusEvent::INITIAL_SYNC_ENDED;
141 if (status_.authenticated != old_status->authenticated)
142 what_changed |= AllStatusEvent::AUTHENTICATED;
143
144 const bool unsynced_changes = status_.unsynced_count > 0;
145 const bool online = status_.authenticated &&
146 status_.server_reachable && status_.server_up && !status_.server_broken;
147 if (online) {
148 if (status_.syncer_stuck)
149 status_.icon = CONFLICT;
150 else if (unsynced_changes || status_.syncing)
151 status_.icon = SYNCING;
152 else
153 status_.icon = READY;
154 } else if (!status_.initial_sync_ended) {
155 status_.icon = OFFLINE_UNUSABLE;
156 } else if (unsynced_changes) {
157 status_.icon = OFFLINE_UNSYNCED;
158 } else {
159 status_.icon = OFFLINE;
160 }
161
162 if (status_.icon != old_status->icon)
163 what_changed |= AllStatusEvent::ICON;
164
165 if (0 == what_changed)
166 return 0;
167 *old_status = status_;
168 return what_changed;
169 }
170
171 void AllStatus::HandleGaiaAuthEvent(const GaiaAuthEvent& gaia_event) {
172 ScopedStatusLockWithNotify lock(this);
173 switch (gaia_event.what_happened) {
174 case GaiaAuthEvent::GAIA_AUTH_FAILED:
175 status_.authenticated = false;
176 break;
177 case GaiaAuthEvent::GAIA_AUTH_SUCCEEDED:
178 status_.authenticated = true;
179 break;
180 default:
181 lock.set_notify_plan(DONT_NOTIFY);
182 break;
183 }
184 }
185
186 void AllStatus::HandleAuthWatcherEvent(const AuthWatcherEvent& auth_event) {
187 ScopedStatusLockWithNotify lock(this);
188 switch (auth_event.what_happened) {
189 case AuthWatcherEvent::GAIA_AUTH_FAILED:
190 case AuthWatcherEvent::SERVICE_AUTH_FAILED:
191 case AuthWatcherEvent::SERVICE_CONNECTION_FAILED:
192 case AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START:
193 status_.authenticated = false;
194 break;
195 case AuthWatcherEvent::AUTH_SUCCEEDED:
196 // If we've already calculated that the server is reachable, since we've
197 // successfully authenticated, we can be confident that the server is up.
198 if (status_.server_reachable)
199 status_.server_up = true;
200
201 if (!status_.authenticated) {
202 status_.authenticated = true;
203 status_ = CalcSyncing();
204 } else {
205 lock.set_notify_plan(DONT_NOTIFY);
206 }
207 break;
208 default:
209 lock.set_notify_plan(DONT_NOTIFY);
210 break;
211 }
212 }
213
214 void AllStatus::HandleSyncerEvent(const SyncerEvent& event) {
215 ScopedStatusLockWithNotify lock(this);
216 switch (event.what_happened) {
217 case SyncerEvent::SYNC_CYCLE_ENDED:
218 case SyncerEvent::COMMITS_SUCCEEDED:
219 break;
220 case SyncerEvent::STATUS_CHANGED:
221 status_ = CalcSyncing(event);
222 break;
223 case SyncerEvent::SHUTDOWN_USE_WITH_CARE:
224 // We're safe to use this value here because we don't call into the syncer
225 // or block on any processes.
226 lock.set_notify_plan(DONT_NOTIFY);
227 break;
228 case SyncerEvent::OVER_QUOTA:
229 LOG(WARNING) << "User has gone over quota.";
230 lock.NotifyOverQuota();
231 break;
232 case SyncerEvent::REQUEST_SYNC_NUDGE:
233 lock.set_notify_plan(DONT_NOTIFY);
234 break;
235 default:
236 LOG(ERROR) << "Unrecognized Syncer Event: " << event.what_happened;
237 lock.set_notify_plan(DONT_NOTIFY);
238 break;
239 }
240 }
241
242 void AllStatus::HandleServerConnectionEvent(
243 const ServerConnectionEvent& event) {
244 if (ServerConnectionEvent::STATUS_CHANGED == event.what_happened) {
245 ScopedStatusLockWithNotify lock(this);
246 status_.server_up = IsGoodReplyFromServer(event.connection_code);
247 status_.server_reachable = event.server_reachable;
248 }
249 }
250
251 void AllStatus::WatchTalkMediator(const TalkMediator* mediator) {
252 status_.notifications_enabled = false;
253 talk_mediator_hookup_.reset(
254 NewEventListenerHookup(mediator->channel(), this,
255 &AllStatus::HandleTalkMediatorEvent));
256 }
257
258 void AllStatus::HandleTalkMediatorEvent(
259 const TalkMediatorEvent& event) {
260 ScopedStatusLockWithNotify lock(this);
261 switch (event.what_happened) {
262 case TalkMediatorEvent::SUBSCRIPTIONS_ON:
263 status_.notifications_enabled = true;
264 break;
265 case TalkMediatorEvent::LOGOUT_SUCCEEDED:
266 case TalkMediatorEvent::SUBSCRIPTIONS_OFF:
267 case TalkMediatorEvent::TALKMEDIATOR_DESTROYED:
268 status_.notifications_enabled = false;
269 break;
270 case TalkMediatorEvent::NOTIFICATION_RECEIVED:
271 status_.notifications_received++;
272 break;
273 case TalkMediatorEvent::NOTIFICATION_SENT:
274 status_.notifications_sent++;
275 break;
276 case TalkMediatorEvent::LOGIN_SUCCEEDED:
277 default:
278 lock.set_notify_plan(DONT_NOTIFY);
279 break;
280 }
281 }
282
283 AllStatus::Status AllStatus::status() const {
284 MutexLock lock(&mutex_);
285 return status_;
286 }
287
288 int AllStatus::GetRecommendedDelaySeconds(int base_delay_seconds) {
289 if (base_delay_seconds >= kMaxBackoffSeconds)
290 return kMaxBackoffSeconds;
291
292 // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
293 int backoff_s = (0 == base_delay_seconds) ? 1 :
294 base_delay_seconds * kBackoffRandomizationFactor;
295
296 // Flip a coin to randomize backoff interval by +/- 50%.
297 int rand_sign = base::RandInt(0, 1) * 2 - 1;
298
299 // Truncation is adequate for rounding here.
300 backoff_s = backoff_s +
301 (rand_sign * (base_delay_seconds / kBackoffRandomizationFactor));
302
303 // Cap the backoff interval.
304 backoff_s = std::min(backoff_s, kMaxBackoffSeconds);
305
306 return backoff_s;
307 }
308
309 int AllStatus::GetRecommendedDelay(int base_delay_ms) const {
310 return GetRecommendedDelaySeconds(base_delay_ms / 1000) * 1000;
311 }
312
313 ScopedStatusLockWithNotify::ScopedStatusLockWithNotify(AllStatus* allstatus)
314 : allstatus_(allstatus), plan_(NOTIFY_IF_STATUS_CHANGED) {
315 event_.what_changed = 0;
316 allstatus->mutex_.Lock();
317 event_.status = allstatus->status_;
318 }
319
320 ScopedStatusLockWithNotify::~ScopedStatusLockWithNotify() {
321 if (DONT_NOTIFY == plan_) {
322 allstatus_->mutex_.Unlock();
323 return;
324 }
325 event_.what_changed |= allstatus_->CalcStatusChanges(&event_.status);
326 allstatus_->mutex_.Unlock();
327 if (event_.what_changed)
328 allstatus_->channel()->NotifyListeners(event_);
329 }
330
331 void ScopedStatusLockWithNotify::NotifyOverQuota() {
332 event_.what_changed |= AllStatusEvent::OVER_QUOTA;
333 }
334
335 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698