| OLD | NEW |
| (Empty) |
| 1 // Copyright 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 "components/sync/driver/glue/sync_backend_registrar.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <cstddef> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/ptr_util.h" | |
| 13 #include "components/sync/model/change_processor.h" | |
| 14 #include "components/sync/syncable/user_share.h" | |
| 15 | |
| 16 namespace syncer { | |
| 17 | |
| 18 SyncBackendRegistrar::SyncBackendRegistrar( | |
| 19 const std::string& name, | |
| 20 ModelSafeWorkerFactory worker_factory) | |
| 21 : name_(name) { | |
| 22 DCHECK(!worker_factory.is_null()); | |
| 23 MaybeAddWorker(worker_factory, GROUP_DB); | |
| 24 MaybeAddWorker(worker_factory, GROUP_FILE); | |
| 25 MaybeAddWorker(worker_factory, GROUP_UI); | |
| 26 MaybeAddWorker(worker_factory, GROUP_PASSIVE); | |
| 27 MaybeAddWorker(worker_factory, GROUP_HISTORY); | |
| 28 MaybeAddWorker(worker_factory, GROUP_PASSWORD); | |
| 29 } | |
| 30 | |
| 31 void SyncBackendRegistrar::RegisterNonBlockingType(ModelType type) { | |
| 32 DCHECK(ui_thread_checker_.CalledOnValidThread()); | |
| 33 base::AutoLock lock(lock_); | |
| 34 // There may have been a previously successful sync of a type when passive, | |
| 35 // which is now NonBlocking. We're not sure what order these two sets of types | |
| 36 // are being registered in, so guard against SetInitialTypes(...) having been | |
| 37 // already called by undoing everything to these types. | |
| 38 if (routing_info_.find(type) != routing_info_.end() && | |
| 39 routing_info_[type] != GROUP_NON_BLOCKING) { | |
| 40 routing_info_.erase(type); | |
| 41 last_configured_types_.Remove(type); | |
| 42 } | |
| 43 non_blocking_types_.Put(type); | |
| 44 } | |
| 45 | |
| 46 void SyncBackendRegistrar::SetInitialTypes(ModelTypeSet initial_types) { | |
| 47 base::AutoLock lock(lock_); | |
| 48 | |
| 49 // This function should be called only once, shortly after construction. The | |
| 50 // routing info at that point is expected to be empty. | |
| 51 DCHECK(routing_info_.empty()); | |
| 52 | |
| 53 // Set our initial state to reflect the current status of the sync directory. | |
| 54 // This will ensure that our calculations in ConfigureDataTypes() will always | |
| 55 // return correct results. | |
| 56 for (ModelTypeSet::Iterator it = initial_types.First(); it.Good(); it.Inc()) { | |
| 57 // If this type is also registered as NonBlocking, assume that it shouldn't | |
| 58 // be registered as passive. The NonBlocking path will eventually take care | |
| 59 // of adding to routing_info_ later on. | |
| 60 if (!non_blocking_types_.Has(it.Get())) { | |
| 61 routing_info_[it.Get()] = GROUP_PASSIVE; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 if (!workers_.count(GROUP_HISTORY)) { | |
| 66 LOG_IF(WARNING, initial_types.Has(TYPED_URLS)) | |
| 67 << "History store disabled, cannot sync Omnibox History"; | |
| 68 routing_info_.erase(TYPED_URLS); | |
| 69 } | |
| 70 | |
| 71 if (!workers_.count(GROUP_PASSWORD)) { | |
| 72 LOG_IF(WARNING, initial_types.Has(PASSWORDS)) | |
| 73 << "Password store not initialized, cannot sync passwords"; | |
| 74 routing_info_.erase(PASSWORDS); | |
| 75 } | |
| 76 | |
| 77 // Although this can re-set NonBlocking types, this should be idempotent. | |
| 78 last_configured_types_ = GetRoutingInfoTypes(routing_info_); | |
| 79 } | |
| 80 | |
| 81 void SyncBackendRegistrar::AddRestoredNonBlockingType(ModelType type) { | |
| 82 DCHECK(ui_thread_checker_.CalledOnValidThread()); | |
| 83 base::AutoLock lock(lock_); | |
| 84 DCHECK(non_blocking_types_.Has(type)); | |
| 85 DCHECK(routing_info_.find(type) == routing_info_.end()); | |
| 86 routing_info_[type] = GROUP_NON_BLOCKING; | |
| 87 last_configured_types_.Put(type); | |
| 88 } | |
| 89 | |
| 90 bool SyncBackendRegistrar::IsNigoriEnabled() const { | |
| 91 DCHECK(ui_thread_checker_.CalledOnValidThread()); | |
| 92 base::AutoLock lock(lock_); | |
| 93 return routing_info_.find(NIGORI) != routing_info_.end(); | |
| 94 } | |
| 95 | |
| 96 ModelTypeSet SyncBackendRegistrar::ConfigureDataTypes( | |
| 97 ModelTypeSet types_to_add, | |
| 98 ModelTypeSet types_to_remove) { | |
| 99 DCHECK(Intersection(types_to_add, types_to_remove).Empty()); | |
| 100 ModelTypeSet filtered_types_to_add = types_to_add; | |
| 101 if (workers_.count(GROUP_HISTORY) == 0) { | |
| 102 LOG(WARNING) << "No history worker -- removing TYPED_URLS"; | |
| 103 filtered_types_to_add.Remove(TYPED_URLS); | |
| 104 } | |
| 105 if (workers_.count(GROUP_PASSWORD) == 0) { | |
| 106 LOG(WARNING) << "No password worker -- removing PASSWORDS"; | |
| 107 filtered_types_to_add.Remove(PASSWORDS); | |
| 108 } | |
| 109 | |
| 110 base::AutoLock lock(lock_); | |
| 111 ModelTypeSet newly_added_types; | |
| 112 for (ModelTypeSet::Iterator it = filtered_types_to_add.First(); it.Good(); | |
| 113 it.Inc()) { | |
| 114 // Add a newly specified data type corresponding initial group into the | |
| 115 // routing_info, if it does not already exist. | |
| 116 if (routing_info_.count(it.Get()) == 0) { | |
| 117 routing_info_[it.Get()] = GetInitialGroupForType(it.Get()); | |
| 118 newly_added_types.Put(it.Get()); | |
| 119 } | |
| 120 } | |
| 121 for (ModelTypeSet::Iterator it = types_to_remove.First(); it.Good(); | |
| 122 it.Inc()) { | |
| 123 routing_info_.erase(it.Get()); | |
| 124 } | |
| 125 | |
| 126 // TODO(akalin): Use SVLOG/SLOG if we add any more logging. | |
| 127 DVLOG(1) << name_ << ": Adding types " << ModelTypeSetToString(types_to_add) | |
| 128 << " (with newly-added types " | |
| 129 << ModelTypeSetToString(newly_added_types) << ") and removing types " | |
| 130 << ModelTypeSetToString(types_to_remove) | |
| 131 << " to get new routing info " | |
| 132 << ModelSafeRoutingInfoToString(routing_info_); | |
| 133 last_configured_types_ = GetRoutingInfoTypes(routing_info_); | |
| 134 | |
| 135 return newly_added_types; | |
| 136 } | |
| 137 | |
| 138 ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const { | |
| 139 return last_configured_types_; | |
| 140 } | |
| 141 | |
| 142 void SyncBackendRegistrar::RequestWorkerStopOnUIThread() { | |
| 143 DCHECK(ui_thread_checker_.CalledOnValidThread()); | |
| 144 base::AutoLock lock(lock_); | |
| 145 for (const auto& kv : workers_) { | |
| 146 kv.second->RequestStop(); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 void SyncBackendRegistrar::ActivateDataType(ModelType type, | |
| 151 ModelSafeGroup group, | |
| 152 ChangeProcessor* change_processor, | |
| 153 UserShare* user_share) { | |
| 154 DVLOG(1) << "Activate: " << ModelTypeToString(type); | |
| 155 | |
| 156 base::AutoLock lock(lock_); | |
| 157 // Ensure that the given data type is in the PASSIVE group. | |
| 158 ModelSafeRoutingInfo::iterator i = routing_info_.find(type); | |
| 159 DCHECK(i != routing_info_.end()); | |
| 160 DCHECK_EQ(i->second, GROUP_PASSIVE); | |
| 161 routing_info_[type] = group; | |
| 162 | |
| 163 // Add the data type's change processor to the list of change | |
| 164 // processors so it can receive updates. | |
| 165 DCHECK_EQ(processors_.count(type), 0U); | |
| 166 processors_[type] = change_processor; | |
| 167 | |
| 168 // Start the change processor. | |
| 169 change_processor->Start(user_share); | |
| 170 DCHECK(GetProcessorUnsafe(type)); | |
| 171 } | |
| 172 | |
| 173 void SyncBackendRegistrar::DeactivateDataType(ModelType type) { | |
| 174 DVLOG(1) << "Deactivate: " << ModelTypeToString(type); | |
| 175 | |
| 176 DCHECK(ui_thread_checker_.CalledOnValidThread() || IsControlType(type)); | |
| 177 base::AutoLock lock(lock_); | |
| 178 | |
| 179 routing_info_.erase(type); | |
| 180 ignore_result(processors_.erase(type)); | |
| 181 DCHECK(!GetProcessorUnsafe(type)); | |
| 182 } | |
| 183 | |
| 184 bool SyncBackendRegistrar::IsTypeActivatedForTest(ModelType type) const { | |
| 185 return GetProcessor(type) != nullptr; | |
| 186 } | |
| 187 | |
| 188 void SyncBackendRegistrar::OnChangesApplied( | |
| 189 ModelType model_type, | |
| 190 int64_t model_version, | |
| 191 const BaseTransaction* trans, | |
| 192 const ImmutableChangeRecordList& changes) { | |
| 193 ChangeProcessor* processor = GetProcessor(model_type); | |
| 194 if (!processor) | |
| 195 return; | |
| 196 | |
| 197 processor->ApplyChangesFromSyncModel(trans, model_version, changes); | |
| 198 } | |
| 199 | |
| 200 void SyncBackendRegistrar::OnChangesComplete(ModelType model_type) { | |
| 201 ChangeProcessor* processor = GetProcessor(model_type); | |
| 202 if (!processor) | |
| 203 return; | |
| 204 | |
| 205 // This call just notifies the processor that it can commit; it | |
| 206 // already buffered any changes it plans to makes so needs no | |
| 207 // further information. | |
| 208 processor->CommitChangesFromSyncModel(); | |
| 209 } | |
| 210 | |
| 211 void SyncBackendRegistrar::GetWorkers( | |
| 212 std::vector<scoped_refptr<ModelSafeWorker>>* out) { | |
| 213 base::AutoLock lock(lock_); | |
| 214 out->clear(); | |
| 215 for (const auto& kv : workers_) { | |
| 216 out->push_back(kv.second.get()); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 void SyncBackendRegistrar::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { | |
| 221 base::AutoLock lock(lock_); | |
| 222 ModelSafeRoutingInfo copy(routing_info_); | |
| 223 out->swap(copy); | |
| 224 } | |
| 225 | |
| 226 ChangeProcessor* SyncBackendRegistrar::GetProcessor(ModelType type) const { | |
| 227 base::AutoLock lock(lock_); | |
| 228 ChangeProcessor* processor = GetProcessorUnsafe(type); | |
| 229 if (!processor) | |
| 230 return nullptr; | |
| 231 | |
| 232 // We can only check if |processor| exists, as otherwise the type is | |
| 233 // mapped to GROUP_PASSIVE. | |
| 234 CHECK(IsCurrentThreadSafeForModel(type)); | |
| 235 return processor; | |
| 236 } | |
| 237 | |
| 238 ChangeProcessor* SyncBackendRegistrar::GetProcessorUnsafe( | |
| 239 ModelType type) const { | |
| 240 lock_.AssertAcquired(); | |
| 241 auto it = processors_.find(type); | |
| 242 | |
| 243 // Until model association happens for a datatype, it will not | |
| 244 // appear in the processors list. During this time, it is OK to | |
| 245 // drop changes on the floor (since model association has not | |
| 246 // happened yet). When the data type is activated, model | |
| 247 // association takes place then the change processor is added to the | |
| 248 // |processors_| list. | |
| 249 if (it == processors_.end()) | |
| 250 return nullptr; | |
| 251 | |
| 252 return it->second; | |
| 253 } | |
| 254 | |
| 255 bool SyncBackendRegistrar::IsCurrentThreadSafeForModel( | |
| 256 ModelType model_type) const { | |
| 257 lock_.AssertAcquired(); | |
| 258 ModelSafeGroup group = GetGroupForModelType(model_type, routing_info_); | |
| 259 DCHECK_NE(GROUP_NON_BLOCKING, group); | |
| 260 | |
| 261 if (group == GROUP_PASSIVE) { | |
| 262 return IsControlType(model_type); | |
| 263 } | |
| 264 | |
| 265 auto it = workers_.find(group); | |
| 266 DCHECK(it != workers_.end()); | |
| 267 return it->second->IsOnModelThread(); | |
| 268 } | |
| 269 | |
| 270 SyncBackendRegistrar::~SyncBackendRegistrar() { | |
| 271 // All data types should have been deactivated by now. | |
| 272 DCHECK(processors_.empty()); | |
| 273 } | |
| 274 | |
| 275 void SyncBackendRegistrar::MaybeAddWorker(ModelSafeWorkerFactory worker_factory, | |
| 276 ModelSafeGroup group) { | |
| 277 scoped_refptr<ModelSafeWorker> worker = worker_factory.Run(group); | |
| 278 if (worker) { | |
| 279 DCHECK(workers_.find(group) == workers_.end()); | |
| 280 workers_[group] = worker; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 ModelSafeGroup SyncBackendRegistrar::GetInitialGroupForType( | |
| 285 ModelType type) const { | |
| 286 return non_blocking_types_.Has(type) ? GROUP_NON_BLOCKING : GROUP_PASSIVE; | |
| 287 } | |
| 288 | |
| 289 } // namespace syncer | |
| OLD | NEW |