1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/service/backend_migrator.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
namespace syncer {
MigrationObserver::~MigrationObserver() = default;
BackendMigrator::BackendMigrator(
const std::string& name,
DataTypeManager* manager,
const base::RepeatingClosure& reconfigure_callback,
const base::RepeatingClosure& migration_done_callback)
: name_(name),
manager_(manager),
reconfigure_callback_(reconfigure_callback),
migration_done_callback_(migration_done_callback),
state_(IDLE) {
DCHECK(!reconfigure_callback_.is_null());
DCHECK(!migration_done_callback_.is_null());
}
BackendMigrator::~BackendMigrator() = default;
// Helper macros to log with the syncer thread name; useful when there
// are multiple syncer threads involved.
#define SLOG(severity) LOG(severity) << name_ << ": "
#define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
void BackendMigrator::MigrateTypes(DataTypeSet types) {
const DataTypeSet old_to_migrate = to_migrate_;
to_migrate_.PutAll(types);
SDVLOG(1) << "MigrateTypes called with " << DataTypeSetToDebugString(types)
<< ", old_to_migrate = " << DataTypeSetToDebugString(old_to_migrate)
<< ", to_migrate_ = " << DataTypeSetToDebugString(to_migrate_);
if (old_to_migrate == to_migrate_) {
SDVLOG(1) << "MigrateTypes called with no new types; ignoring";
return;
}
if (state_ == IDLE) {
ChangeState(WAITING_TO_START);
}
if (state_ == WAITING_TO_START) {
if (!TryStart()) {
SDVLOG(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);
}
void BackendMigrator::RemoveMigrationObserver(MigrationObserver* observer) {
migration_observers_.RemoveObserver(observer);
}
void BackendMigrator::ChangeState(State new_state) {
state_ = new_state;
for (MigrationObserver& observer : migration_observers_) {
observer.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.
ChangeState(DISABLING_TYPES);
SDVLOG(1) << "BackendMigrator disabling types "
<< DataTypeSetToDebugString(to_migrate_);
manager_->PurgeForMigration(to_migrate_);
}
void BackendMigrator::OnConfigureDone(
const DataTypeManager::ConfigureResult& result) {
if (state_ == IDLE) {
return;
}
// `manager_`'s methods aren't re-entrant, and we're notified from
// them, so post a task to avoid problems.
SDVLOG(1) << "Posting OnConfigureDoneImpl";
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&BackendMigrator::OnConfigureDoneImpl,
weak_ptr_factory_.GetWeakPtr(), result));
}
void BackendMigrator::OnConfigureDoneImpl(
const DataTypeManager::ConfigureResult& result) {
SDVLOG(1) << "OnConfigureDone with requested types "
<< DataTypeSetToDebugString(result.requested_types) << ", status "
<< result.status
<< ", and to_migrate_ = " << DataTypeSetToDebugString(to_migrate_);
if (state_ == WAITING_TO_START) {
if (!TryStart()) {
SDVLOG(1) << "Manager still not configured; still waiting";
}
return;
}
DCHECK_GT(state_, WAITING_TO_START);
const DataTypeSet intersection =
Intersection(result.requested_types, 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()) {
SDVLOG(1) << "Disable request interrupted by user changing types";
RestartMigration();
return;
}
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
// was an abort, then typically things are shutting down anyway. There isn't
// 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.
SLOG(WARNING) << "Unable to migrate, configuration failed!";
ChangeState(IDLE);
to_migrate_.Clear();
return;
}
if (state_ == DISABLING_TYPES) {
DataTypeSet stopped_types = manager_->GetStoppedDataTypesExcludingNigori();
// NIGORI does not have a controller and is hence not managed by
// DataTypeManager, which means it's never returned in
// GetStoppedDataTypesExcludingNigori(). Luckily, there's no need to wait
// until NIGORI is purged, because that takes effect immediately.
// TODO(crbug.com/40154783): try to find better way to implement this logic.
stopped_types.Put(NIGORI);
if (!stopped_types.HasAll(to_migrate_)) {
SLOG(WARNING) << "Set of stopped types: "
<< DataTypeSetToDebugString(stopped_types)
<< " does not contain types to migrate: "
<< DataTypeSetToDebugString(to_migrate_)
<< "; not re-enabling yet due to "
<< DataTypeSetToDebugString(
Difference(to_migrate_, stopped_types));
return;
}
ChangeState(REENABLING_TYPES);
SDVLOG(1) << "BackendMigrator triggering reconfiguration";
reconfigure_callback_.Run();
} else if (state_ == REENABLING_TYPES) {
// We're done!
ChangeState(IDLE);
SDVLOG(1) << "BackendMigrator: Migration complete for: "
<< DataTypeSetToDebugString(to_migrate_);
to_migrate_.Clear();
migration_done_callback_.Run();
}
}
BackendMigrator::State BackendMigrator::state() const {
return state_;
}
DataTypeSet BackendMigrator::GetPendingMigrationTypesForTest() const {
return to_migrate_;
}
#undef SDVLOG
#undef SLOG
} // namespace syncer
|