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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync/engine/all_status.cc
===================================================================
--- chrome/browser/sync/engine/all_status.cc (revision 0)
+++ chrome/browser/sync/engine/all_status.cc (revision 0)
@@ -0,0 +1,335 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync/engine/all_status.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/port.h"
+#include "base/rand_util.h"
+#include "chrome/browser/sync/engine/auth_watcher.h"
+#include "chrome/browser/sync/engine/net/gaia_authenticator.h"
+#include "chrome/browser/sync/engine/net/server_connection_manager.h"
+#include "chrome/browser/sync/engine/syncer.h"
+#include "chrome/browser/sync/engine/syncer_thread.h"
+#include "chrome/browser/sync/engine/syncproto.h"
+#include "chrome/browser/sync/notifier/listener/talk_mediator.h"
+#include "chrome/browser/sync/protocol/service_constants.h"
+#include "chrome/browser/sync/syncable/directory_manager.h"
+#include "chrome/browser/sync/util/event_sys-inl.h"
+
+namespace browser_sync {
+
+static const time_t kMinSyncObserveInterval = 10; // seconds
+
+// Backoff interval randomization factor.
+static const int kBackoffRandomizationFactor = 2;
+
+const char* AllStatus::GetSyncStatusString(SyncStatus icon) {
+ const char* strings[] = {"OFFLINE", "OFFLINE_UNSYNCED", "SYNCING", "READY",
+ "CONFLICT", "OFFLINE_UNUSABLE"};
+ COMPILE_ASSERT(ARRAYSIZE(strings) == ICON_STATUS_COUNT, enum_indexed_array);
+ if (icon < 0 || icon >= ARRAYSIZE(strings))
+ LOG(FATAL) << "Illegal Icon State:" << icon;
+ return strings[icon];
+}
+
+static const AllStatus::Status init_status =
+ { AllStatus::OFFLINE };
+
+static const AllStatusEvent shutdown_event =
+ { AllStatusEvent::SHUTDOWN, init_status };
+
+AllStatus::AllStatus() : channel_(new Channel(shutdown_event)),
+ status_(init_status) {
+ status_.initial_sync_ended = true;
+ status_.notifications_enabled = false;
+}
+
+AllStatus::~AllStatus() {
+ delete channel_;
+}
+
+void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) {
+ conn_mgr_hookup_.reset(NewEventListenerHookup(conn_mgr->channel(), this,
+ &AllStatus::HandleServerConnectionEvent));
+}
+
+void AllStatus::WatchAuthenticator(GaiaAuthenticator* gaia) {
+ gaia_hookup_.reset(NewEventListenerHookup(gaia->channel(), this,
+ &AllStatus::HandleGaiaAuthEvent));
+}
+
+void AllStatus::WatchAuthWatcher(AuthWatcher* auth_watcher) {
+ authwatcher_hookup_.reset(
+ NewEventListenerHookup(auth_watcher->channel(), this,
+ &AllStatus::HandleAuthWatcherEvent));
+}
+
+void AllStatus::WatchSyncerThread(SyncerThread* syncer_thread) {
+ syncer_thread_hookup_.reset(
+ NewEventListenerHookup(syncer_thread->channel(), this,
+ &AllStatus::HandleSyncerEvent));
+}
+
+AllStatus::Status AllStatus::CreateBlankStatus() const {
+ Status status = status_;
+ status.syncing = true;
+ status.unsynced_count = 0;
+ status.conflicting_count = 0;
+ status.initial_sync_ended = false;
+ status.syncer_stuck = false;
+ status.max_consecutive_errors = 0;
+ status.server_broken = false;
+ status.updates_available = 0;
+ status.updates_received = 0;
+ return status;
+}
+
+AllStatus::Status AllStatus::CalcSyncing(const SyncerEvent &event) const {
+ Status status = CreateBlankStatus();
+ SyncerStatus syncerStatus(event.last_session);
+ status.unsynced_count += syncerStatus.unsynced_count();
+ status.conflicting_count += syncerStatus.conflicting_commits();
+ if (syncerStatus.current_sync_timestamp() ==
+ syncerStatus.servers_latest_timestamp()) {
+ status.conflicting_count += syncerStatus.conflicting_updates();
+ }
+ status.syncing |= syncerStatus.syncing();
+ // Show a syncer as syncing if it's got stalled updates.
+ status.syncing = event.last_session->ShouldSyncAgain();
+ status.initial_sync_ended |= syncerStatus.IsShareUsable();
+ status.syncer_stuck |= syncerStatus.syncer_stuck();
+ if (syncerStatus.consecutive_errors() > status.max_consecutive_errors)
+ status.max_consecutive_errors = syncerStatus.consecutive_errors();
+
+ // 100 is an arbitrary limit.
+ if (syncerStatus.consecutive_transient_error_commits() > 100)
+ status.server_broken = true;
+
+ status.updates_available += syncerStatus.servers_latest_timestamp();
+ status.updates_received += syncerStatus.current_sync_timestamp();
+ return status;
+}
+
+AllStatus::Status AllStatus::CalcSyncing() const {
+ return CreateBlankStatus();
+}
+
+int AllStatus::CalcStatusChanges(Status* old_status) {
+ int what_changed = 0;
+
+ // Calculate what changed and what the new icon should be.
+ if (status_.syncing != old_status->syncing)
+ what_changed |= AllStatusEvent::SYNCING;
+ if (status_.unsynced_count != old_status->unsynced_count)
+ what_changed |= AllStatusEvent::UNSYNCED_COUNT;
+ if (status_.server_up != old_status->server_up)
+ what_changed |= AllStatusEvent::SERVER_UP;
+ if (status_.server_reachable != old_status->server_reachable)
+ what_changed |= AllStatusEvent::SERVER_REACHABLE;
+ if (status_.notifications_enabled != old_status->notifications_enabled)
+ what_changed |= AllStatusEvent::NOTIFICATIONS_ENABLED;
+ if (status_.notifications_received != old_status->notifications_received)
+ what_changed |= AllStatusEvent::NOTIFICATIONS_RECEIVED;
+ if (status_.notifications_sent != old_status->notifications_sent)
+ what_changed |= AllStatusEvent::NOTIFICATIONS_SENT;
+ if (status_.initial_sync_ended != old_status->initial_sync_ended)
+ what_changed |= AllStatusEvent::INITIAL_SYNC_ENDED;
+ if (status_.authenticated != old_status->authenticated)
+ what_changed |= AllStatusEvent::AUTHENTICATED;
+
+ const bool unsynced_changes = status_.unsynced_count > 0;
+ const bool online = status_.authenticated &&
+ status_.server_reachable && status_.server_up && !status_.server_broken;
+ if (online) {
+ if (status_.syncer_stuck)
+ status_.icon = CONFLICT;
+ else if (unsynced_changes || status_.syncing)
+ status_.icon = SYNCING;
+ else
+ status_.icon = READY;
+ } else if (!status_.initial_sync_ended) {
+ status_.icon = OFFLINE_UNUSABLE;
+ } else if (unsynced_changes) {
+ status_.icon = OFFLINE_UNSYNCED;
+ } else {
+ status_.icon = OFFLINE;
+ }
+
+ if (status_.icon != old_status->icon)
+ what_changed |= AllStatusEvent::ICON;
+
+ if (0 == what_changed)
+ return 0;
+ *old_status = status_;
+ return what_changed;
+}
+
+void AllStatus::HandleGaiaAuthEvent(const GaiaAuthEvent& gaia_event) {
+ ScopedStatusLockWithNotify lock(this);
+ switch (gaia_event.what_happened) {
+ case GaiaAuthEvent::GAIA_AUTH_FAILED:
+ status_.authenticated = false;
+ break;
+ case GaiaAuthEvent::GAIA_AUTH_SUCCEEDED:
+ status_.authenticated = true;
+ break;
+ default:
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ }
+}
+
+void AllStatus::HandleAuthWatcherEvent(const AuthWatcherEvent& auth_event) {
+ ScopedStatusLockWithNotify lock(this);
+ switch (auth_event.what_happened) {
+ case AuthWatcherEvent::GAIA_AUTH_FAILED:
+ case AuthWatcherEvent::SERVICE_AUTH_FAILED:
+ case AuthWatcherEvent::SERVICE_CONNECTION_FAILED:
+ case AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START:
+ status_.authenticated = false;
+ break;
+ case AuthWatcherEvent::AUTH_SUCCEEDED:
+ // If we've already calculated that the server is reachable, since we've
+ // successfully authenticated, we can be confident that the server is up.
+ if (status_.server_reachable)
+ status_.server_up = true;
+
+ if (!status_.authenticated) {
+ status_.authenticated = true;
+ status_ = CalcSyncing();
+ } else {
+ lock.set_notify_plan(DONT_NOTIFY);
+ }
+ break;
+ default:
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ }
+}
+
+void AllStatus::HandleSyncerEvent(const SyncerEvent& event) {
+ ScopedStatusLockWithNotify lock(this);
+ switch (event.what_happened) {
+ case SyncerEvent::SYNC_CYCLE_ENDED:
+ case SyncerEvent::COMMITS_SUCCEEDED:
+ break;
+ case SyncerEvent::STATUS_CHANGED:
+ status_ = CalcSyncing(event);
+ break;
+ case SyncerEvent::SHUTDOWN_USE_WITH_CARE:
+ // We're safe to use this value here because we don't call into the syncer
+ // or block on any processes.
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ case SyncerEvent::OVER_QUOTA:
+ LOG(WARNING) << "User has gone over quota.";
+ lock.NotifyOverQuota();
+ break;
+ case SyncerEvent::REQUEST_SYNC_NUDGE:
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ default:
+ LOG(ERROR) << "Unrecognized Syncer Event: " << event.what_happened;
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ }
+}
+
+void AllStatus::HandleServerConnectionEvent(
+ const ServerConnectionEvent& event) {
+ if (ServerConnectionEvent::STATUS_CHANGED == event.what_happened) {
+ ScopedStatusLockWithNotify lock(this);
+ status_.server_up = IsGoodReplyFromServer(event.connection_code);
+ status_.server_reachable = event.server_reachable;
+ }
+}
+
+void AllStatus::WatchTalkMediator(const TalkMediator* mediator) {
+ status_.notifications_enabled = false;
+ talk_mediator_hookup_.reset(
+ NewEventListenerHookup(mediator->channel(), this,
+ &AllStatus::HandleTalkMediatorEvent));
+}
+
+void AllStatus::HandleTalkMediatorEvent(
+ const TalkMediatorEvent& event) {
+ ScopedStatusLockWithNotify lock(this);
+ switch (event.what_happened) {
+ case TalkMediatorEvent::SUBSCRIPTIONS_ON:
+ status_.notifications_enabled = true;
+ break;
+ case TalkMediatorEvent::LOGOUT_SUCCEEDED:
+ case TalkMediatorEvent::SUBSCRIPTIONS_OFF:
+ case TalkMediatorEvent::TALKMEDIATOR_DESTROYED:
+ status_.notifications_enabled = false;
+ break;
+ case TalkMediatorEvent::NOTIFICATION_RECEIVED:
+ status_.notifications_received++;
+ break;
+ case TalkMediatorEvent::NOTIFICATION_SENT:
+ status_.notifications_sent++;
+ break;
+ case TalkMediatorEvent::LOGIN_SUCCEEDED:
+ default:
+ lock.set_notify_plan(DONT_NOTIFY);
+ break;
+ }
+}
+
+AllStatus::Status AllStatus::status() const {
+ MutexLock lock(&mutex_);
+ return status_;
+}
+
+int AllStatus::GetRecommendedDelaySeconds(int base_delay_seconds) {
+ if (base_delay_seconds >= kMaxBackoffSeconds)
+ return kMaxBackoffSeconds;
+
+ // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
+ int backoff_s = (0 == base_delay_seconds) ? 1 :
+ base_delay_seconds * kBackoffRandomizationFactor;
+
+ // Flip a coin to randomize backoff interval by +/- 50%.
+ int rand_sign = base::RandInt(0, 1) * 2 - 1;
+
+ // Truncation is adequate for rounding here.
+ backoff_s = backoff_s +
+ (rand_sign * (base_delay_seconds / kBackoffRandomizationFactor));
+
+ // Cap the backoff interval.
+ backoff_s = std::min(backoff_s, kMaxBackoffSeconds);
+
+ return backoff_s;
+}
+
+int AllStatus::GetRecommendedDelay(int base_delay_ms) const {
+ return GetRecommendedDelaySeconds(base_delay_ms / 1000) * 1000;
+}
+
+ScopedStatusLockWithNotify::ScopedStatusLockWithNotify(AllStatus* allstatus)
+ : allstatus_(allstatus), plan_(NOTIFY_IF_STATUS_CHANGED) {
+ event_.what_changed = 0;
+ allstatus->mutex_.Lock();
+ event_.status = allstatus->status_;
+}
+
+ScopedStatusLockWithNotify::~ScopedStatusLockWithNotify() {
+ if (DONT_NOTIFY == plan_) {
+ allstatus_->mutex_.Unlock();
+ return;
+ }
+ event_.what_changed |= allstatus_->CalcStatusChanges(&event_.status);
+ allstatus_->mutex_.Unlock();
+ if (event_.what_changed)
+ allstatus_->channel()->NotifyListeners(event_);
+}
+
+void ScopedStatusLockWithNotify::NotifyOverQuota() {
+ event_.what_changed |= AllStatusEvent::OVER_QUOTA;
+}
+
+} // namespace browser_sync
Property changes on: chrome\browser\sync\engine\all_status.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698