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

Unified Diff: chrome/browser/sync/backend_migrator.cc

Issue 7655055: [Sync] Make BackendMigrator not wait for full sync cycles (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address more comments Created 9 years, 4 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
« no previous file with comments | « chrome/browser/sync/backend_migrator.h ('k') | chrome/browser/sync/backend_migrator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/sync/backend_migrator.cc
diff --git a/chrome/browser/sync/backend_migrator.cc b/chrome/browser/sync/backend_migrator.cc
index 0c7c15ca039a4d3722997c0874aaccad9fd5c9e0..47fb4d67570f863f910f7e4aa91ae0140988ed8e 100644
--- a/chrome/browser/sync/backend_migrator.cc
+++ b/chrome/browser/sync/backend_migrator.cc
@@ -6,13 +6,16 @@
#include <algorithm>
+#include "base/message_loop.h"
#include "base/string_number_conversions.h"
-#include "chrome/browser/sync/glue/data_type_manager.h"
+#include "base/tracked_objects.h"
#include "chrome/browser/sync/internal_api/configure_reason.h"
+#include "chrome/browser/sync/internal_api/read_transaction.h"
#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/protocol/sync.pb.h"
#include "chrome/browser/sync/sessions/session_state.h"
+#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/common/chrome_notification_types.h"
-#include "content/browser/browser_thread.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
@@ -21,59 +24,108 @@ using syncable::ModelTypeSet;
namespace browser_sync {
using sessions::SyncSessionSnapshot;
+using syncable::ModelTypeToString;
-BackendMigrator::BackendMigrator(ProfileSyncService* service,
+MigrationObserver::~MigrationObserver() {}
+
+BackendMigrator::BackendMigrator(const std::string& name,
+ sync_api::UserShare* user_share,
+ ProfileSyncService* service,
DataTypeManager* manager)
- : state_(IDLE), service_(service), manager_(manager),
- restart_migration_(false),
- method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ : name_(name), user_share_(user_share), service_(service),
+ manager_(manager), state_(IDLE),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
Source<DataTypeManager>(manager_));
- service_->AddObserver(this);
}
BackendMigrator::~BackendMigrator() {
- service_->RemoveObserver(this);
}
-bool BackendMigrator::HasStartedMigrating() const {
- return state_ >= DISABLING_TYPES;
-}
+// Helper macros to log with the syncer thread name; useful when there
+// are multiple syncer threads involved.
+
+#define SLOG(severity) LOG(severity) << name_ << ": "
+
+#define SVLOG(verbose_level) VLOG(verbose_level) << name_ << ": "
void BackendMigrator::MigrateTypes(const syncable::ModelTypeSet& types) {
+ const ModelTypeSet old_to_migrate = to_migrate_;
{
ModelTypeSet temp;
std::set_union(to_migrate_.begin(), to_migrate_.end(),
types.begin(), types.end(),
std::inserter(temp, temp.end()));
- to_migrate_ = temp;
+ std::swap(temp, to_migrate_);
}
-
- if (HasStartedMigrating()) {
- VLOG(1) << "BackendMigrator::MigrateTypes: STARTED_MIGRATING early-out.";
- restart_migration_ = true;
+ SVLOG(1) << "MigrateTypes called with " << ModelTypeSetToString(types)
+ << ", old_to_migrate = " << ModelTypeSetToString(old_to_migrate)
+ << ", to_migrate_ = " << ModelTypeSetToString(to_migrate_);
+ if (old_to_migrate == to_migrate_) {
+ SVLOG(1) << "MigrateTypes called with no new types; ignoring";
return;
}
- if (manager_->state() != DataTypeManager::CONFIGURED) {
- VLOG(1) << "BackendMigrator::MigrateTypes: manager CONFIGURED early-out.";
- state_ = WAITING_TO_START;
+ if (state_ == IDLE)
+ ChangeState(WAITING_TO_START);
+
+ if (state_ == WAITING_TO_START) {
+ if (!TryStart())
+ SVLOG(1) << "Manager not configured; waiting";
return;
}
+ DCHECK_GT(state_, WAITING_TO_START);
+ // If we're already migrating, interrupt the current migration.
+ RestartMigration();
+}
+
+void BackendMigrator::AddMigrationObserver(MigrationObserver* observer) {
+ migration_observers_.AddObserver(observer);
+}
+
+bool BackendMigrator::HasMigrationObserver(
+ MigrationObserver* observer) const {
+ return migration_observers_.HasObserver(observer);
+}
+
+void BackendMigrator::RemoveMigrationObserver(MigrationObserver* observer) {
+ migration_observers_.RemoveObserver(observer);
+}
+
+void BackendMigrator::ChangeState(State new_state) {
+ state_ = new_state;
+ FOR_EACH_OBSERVER(MigrationObserver, migration_observers_,
+ OnMigrationStateChange());
+}
+
+bool BackendMigrator::TryStart() {
+ DCHECK_EQ(state_, WAITING_TO_START);
+ if (manager_->state() == DataTypeManager::CONFIGURED) {
+ RestartMigration();
+ return true;
+ }
+ return false;
+}
+
+void BackendMigrator::RestartMigration() {
// We'll now disable any running types that need to be migrated.
- state_ = DISABLING_TYPES;
+ ChangeState(DISABLING_TYPES);
ModelTypeSet full_set;
service_->GetPreferredDataTypes(&full_set);
ModelTypeSet difference;
std::set_difference(full_set.begin(), full_set.end(),
to_migrate_.begin(), to_migrate_.end(),
std::inserter(difference, difference.end()));
- VLOG(1) << "BackendMigrator disabling types; calling Configure.";
+ bool configure_with_nigori = to_migrate_.count(syncable::NIGORI) == 0;
+ SVLOG(1) << "BackendMigrator disabling types "
+ << ModelTypeSetToString(to_migrate_) << "; configuring "
+ << ModelTypeSetToString(difference)
+ << (configure_with_nigori ? " with nigori" : " without nigori");
// Add nigori for config or not based upon if the server told us to migrate
// nigori or not.
- if (to_migrate_.count(syncable::NIGORI) == 0) {
+ if (configure_with_nigori) {
manager_->Configure(difference, sync_api::CONFIGURE_REASON_MIGRATION);
} else {
manager_->ConfigureWithoutNigori(difference,
@@ -81,76 +133,70 @@ void BackendMigrator::MigrateTypes(const syncable::ModelTypeSet& types) {
}
}
-void BackendMigrator::OnStateChanged() {
- if (restart_migration_ == true) {
- VLOG(1) << "BackendMigrator restarting migration in OnStateChanged.";
- state_ = WAITING_TO_START;
- restart_migration_ = false;
- MigrateTypes(to_migrate_);
- return;
- }
-
- if (state_ != WAITING_FOR_PURGE)
+void BackendMigrator::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, type);
+ if (state_ == IDLE)
return;
- size_t num_empty_migrated_markers = 0;
- const SyncSessionSnapshot* snap = service_->GetLastSessionSnapshot();
- for (ModelTypeSet::const_iterator it = to_migrate_.begin();
- it != to_migrate_.end(); ++it) {
- if (snap->download_progress_markers[*it].empty())
- num_empty_migrated_markers++;
- }
+ // |manager_|'s methods aren't re-entrant, and we're notified from
+ // them, so post a task to avoid problems.
+ SVLOG(1) << "Posting OnConfigureDone from Observer";
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&BackendMigrator::OnConfigureDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ *Details<DataTypeManager::ConfigureResult>(details).ptr()));
+}
- if (num_empty_migrated_markers < to_migrate_.size())
- return;
+namespace {
- state_ = REENABLING_TYPES;
- ModelTypeSet full_set;
- service_->GetPreferredDataTypes(&full_set);
- VLOG(1) << "BackendMigrator re-enabling types.";
-
- // Don't use |to_migrate_| for the re-enabling because the user may have
- // chosen to disable types during the migration.
- manager_->Configure(full_set, sync_api::CONFIGURE_REASON_MIGRATION);
+syncable::ModelTypeSet GetUnsyncedDataTypes(sync_api::UserShare* user_share) {
+ sync_api::ReadTransaction trans(FROM_HERE, user_share);
+ syncable::ModelTypeSet unsynced_data_types;
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ syncable::ModelType type = syncable::ModelTypeFromInt(i);
+ sync_pb::DataTypeProgressMarker progress_marker;
+ trans.GetLookup()->GetDownloadProgress(type, &progress_marker);
+ if (progress_marker.token().empty()) {
+ unsynced_data_types.insert(type);
+ }
+ }
+ return unsynced_data_types;
}
-void BackendMigrator::Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK_EQ(chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, type);
- if (state_ == IDLE)
+} // namespace
+
+void BackendMigrator::OnConfigureDone(
+ const DataTypeManager::ConfigureResult& result) {
+ SVLOG(1) << "OnConfigureDone with requested types "
+ << ModelTypeSetToString(result.requested_types)
+ << ", status " << result.status
+ << ", and to_migrate_ = " << ModelTypeSetToString(to_migrate_);
+ if (state_ == WAITING_TO_START) {
+ if (!TryStart())
+ SVLOG(1) << "Manager still not configured; still waiting";
return;
+ }
- const DataTypeManager::ConfigureResult* result =
- Details<DataTypeManager::ConfigureResult>(details).ptr();
+ DCHECK_GT(state_, WAITING_TO_START);
ModelTypeSet intersection;
- std::set_intersection(result->requested_types.begin(),
- result->requested_types.end(), to_migrate_.begin(), to_migrate_.end(),
+ std::set_intersection(
+ result.requested_types.begin(), result.requested_types.end(),
+ to_migrate_.begin(), to_migrate_.end(),
std::inserter(intersection, intersection.end()));
-
- // The intersection check is to determine if our disable request was
- // interrupted by a user changing preferred types. May still need to purge.
- // It's pretty wild if we're in WAITING_FOR_PURGE here, because it would mean
- // that after our disable-config finished but before the purge, another config
- // was posted externally _and completed_, which means somehow the nudge to
- // purge was dropped, yet nudges are reliable.
- if (state_ == WAITING_TO_START || state_ == WAITING_FOR_PURGE ||
- (state_ == DISABLING_TYPES && !intersection.empty())) {
- state_ = WAITING_TO_START;
- restart_migration_ = false;
- VLOG(1) << "BackendMigrator::Observe posting MigrateTypes.";
- if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- method_factory_.NewRunnableMethod(&BackendMigrator::MigrateTypes,
- to_migrate_))) {
- // Unittests need this.
- // TODO(tim): Clean this up.
- MigrateTypes(to_migrate_);
- }
+ // This intersection check is to determine if our disable request
+ // was interrupted by a user changing preferred types.
+ if (state_ == DISABLING_TYPES && !intersection.empty()) {
+ SVLOG(1) << "Disable request interrupted by user changing types";
+ RestartMigration();
return;
}
- if (result->status != DataTypeManager::OK) {
+ if (result.status != DataTypeManager::OK) {
// If this fails, and we're disabling types, a type may or may not be
// disabled until the user restarts the browser. If this wasn't an abort,
// any failure will be reported as an unrecoverable error to the UI. If it
@@ -158,23 +204,39 @@ void BackendMigrator::Observe(int type,
// much we can do in any case besides wait until a restart to try again.
// The server will send down MIGRATION_DONE again for types needing
// migration as the type will still be enabled on restart.
- LOG(WARNING) << "Unable to migrate, configuration failed!";
- state_ = IDLE;
+ SLOG(WARNING) << "Unable to migrate, configuration failed!";
+ ChangeState(IDLE);
to_migrate_.clear();
return;
}
if (state_ == DISABLING_TYPES) {
- state_ = WAITING_FOR_PURGE;
- VLOG(1) << "BackendMigrator waiting for purge.";
+ const syncable::ModelTypeSet& unsynced_types =
+ GetUnsyncedDataTypes(user_share_);
+ if (!std::includes(unsynced_types.begin(), unsynced_types.end(),
+ to_migrate_.begin(), to_migrate_.end())) {
+ SLOG(WARNING) << "Set of unsynced types: "
+ << syncable::ModelTypeSetToString(unsynced_types)
+ << " does not contain types to migrate: "
+ << syncable::ModelTypeSetToString(to_migrate_)
+ << "; not re-enabling yet";
+ return;
+ }
+
+ ChangeState(REENABLING_TYPES);
+ // Don't use |to_migrate_| for the re-enabling because the user
+ // may have chosen to disable types during the migration.
+ ModelTypeSet full_set;
+ service_->GetPreferredDataTypes(&full_set);
+ SVLOG(1) << "BackendMigrator re-enabling types: "
+ << syncable::ModelTypeSetToString(full_set);
+ manager_->Configure(full_set, sync_api::CONFIGURE_REASON_MIGRATION);
} else if (state_ == REENABLING_TYPES) {
// We're done!
- state_ = IDLE;
+ ChangeState(IDLE);
- std::stringstream ss;
- std::copy(to_migrate_.begin(), to_migrate_.end(),
- std::ostream_iterator<syncable::ModelType>(ss, ","));
- VLOG(1) << "BackendMigrator: Migration complete for: " << ss.str();
+ SVLOG(1) << "BackendMigrator: Migration complete for: "
+ << syncable::ModelTypeSetToString(to_migrate_);
to_migrate_.clear();
}
}
@@ -183,4 +245,13 @@ BackendMigrator::State BackendMigrator::state() const {
return state_;
}
+syncable::ModelTypeSet
+ BackendMigrator::GetPendingMigrationTypesForTest() const {
+ return to_migrate_;
+}
+
+#undef SVLOG
+
+#undef SLOG
+
}; // namespace browser_sync
« no previous file with comments | « chrome/browser/sync/backend_migrator.h ('k') | chrome/browser/sync/backend_migrator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698