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 <cstddef> | |
8 #include <utility> | |
9 | |
10 #include "base/compiler_specific.h" | |
11 #include "base/logging.h" | |
12 #include "base/message_loop/message_loop.h" | |
13 #include "components/sync/core/user_share.h" | |
14 #include "components/sync_driver/change_processor.h" | |
15 #include "components/sync_driver/sync_client.h" | |
16 | |
17 namespace browser_sync { | |
18 | |
19 SyncBackendRegistrar::SyncBackendRegistrar( | |
20 const std::string& name, | |
21 sync_driver::SyncClient* sync_client, | |
22 std::unique_ptr<base::Thread> sync_thread, | |
23 const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread, | |
24 const scoped_refptr<base::SingleThreadTaskRunner>& db_thread, | |
25 const scoped_refptr<base::SingleThreadTaskRunner>& file_thread) | |
26 : name_(name), | |
27 sync_client_(sync_client), | |
28 ui_thread_(ui_thread), | |
29 db_thread_(db_thread), | |
30 file_thread_(file_thread) { | |
31 DCHECK(ui_thread_->BelongsToCurrentThread()); | |
32 DCHECK(sync_client_); | |
33 | |
34 sync_thread_ = std::move(sync_thread); | |
35 if (!sync_thread_) { | |
36 sync_thread_.reset(new base::Thread("Chrome_SyncThread")); | |
37 base::Thread::Options options; | |
38 options.timer_slack = base::TIMER_SLACK_MAXIMUM; | |
39 CHECK(sync_thread_->StartWithOptions(options)); | |
40 } | |
41 | |
42 MaybeAddWorker(syncer::GROUP_DB); | |
43 MaybeAddWorker(syncer::GROUP_FILE); | |
44 MaybeAddWorker(syncer::GROUP_UI); | |
45 MaybeAddWorker(syncer::GROUP_PASSIVE); | |
46 MaybeAddWorker(syncer::GROUP_HISTORY); | |
47 MaybeAddWorker(syncer::GROUP_PASSWORD); | |
48 | |
49 // Must have at least one worker for SyncBackendRegistrar to be destroyed | |
50 // correctly, as it is destroyed after the last worker dies. | |
51 DCHECK_GT(workers_.size(), 0u); | |
52 } | |
53 | |
54 void SyncBackendRegistrar::RegisterNonBlockingType(syncer::ModelType type) { | |
55 DCHECK(ui_thread_->BelongsToCurrentThread()); | |
56 base::AutoLock lock(lock_); | |
57 DCHECK(routing_info_.find(type) == routing_info_.end() || | |
58 routing_info_[type] == syncer::GROUP_NON_BLOCKING); | |
59 non_blocking_types_.Put(type); | |
60 } | |
61 | |
62 void SyncBackendRegistrar::SetInitialTypes(syncer::ModelTypeSet initial_types) { | |
63 base::AutoLock lock(lock_); | |
64 | |
65 // This function should be called only once, shortly after construction. The | |
66 // routing info at that point is expected to be empty. | |
67 DCHECK(routing_info_.empty()); | |
68 | |
69 // Set our initial state to reflect the current status of the sync directory. | |
70 // This will ensure that our calculations in ConfigureDataTypes() will always | |
71 // return correct results. | |
72 for (syncer::ModelTypeSet::Iterator it = initial_types.First(); it.Good(); | |
73 it.Inc()) { | |
74 routing_info_[it.Get()] = GetInitialGroupForType(it.Get()); | |
75 } | |
76 | |
77 if (!workers_.count(syncer::GROUP_HISTORY)) { | |
78 LOG_IF(WARNING, initial_types.Has(syncer::TYPED_URLS)) | |
79 << "History store disabled, cannot sync Omnibox History"; | |
80 routing_info_.erase(syncer::TYPED_URLS); | |
81 } | |
82 | |
83 if (!workers_.count(syncer::GROUP_PASSWORD)) { | |
84 LOG_IF(WARNING, initial_types.Has(syncer::PASSWORDS)) | |
85 << "Password store not initialized, cannot sync passwords"; | |
86 routing_info_.erase(syncer::PASSWORDS); | |
87 } | |
88 | |
89 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_); | |
90 } | |
91 | |
92 void SyncBackendRegistrar::AddRestoredNonBlockingType(syncer::ModelType type) { | |
93 DCHECK(ui_thread_->BelongsToCurrentThread()); | |
94 base::AutoLock lock(lock_); | |
95 DCHECK(non_blocking_types_.Has(type)); | |
96 DCHECK(routing_info_.find(type) == routing_info_.end()); | |
97 routing_info_[type] = syncer::GROUP_NON_BLOCKING; | |
98 last_configured_types_.Put(type); | |
99 } | |
100 | |
101 bool SyncBackendRegistrar::IsNigoriEnabled() const { | |
102 DCHECK(ui_thread_->BelongsToCurrentThread()); | |
103 base::AutoLock lock(lock_); | |
104 return routing_info_.find(syncer::NIGORI) != routing_info_.end(); | |
105 } | |
106 | |
107 syncer::ModelTypeSet SyncBackendRegistrar::ConfigureDataTypes( | |
108 syncer::ModelTypeSet types_to_add, | |
109 syncer::ModelTypeSet types_to_remove) { | |
110 DCHECK(Intersection(types_to_add, types_to_remove).Empty()); | |
111 syncer::ModelTypeSet filtered_types_to_add = types_to_add; | |
112 if (workers_.count(syncer::GROUP_HISTORY) == 0) { | |
113 LOG(WARNING) << "No history worker -- removing TYPED_URLS"; | |
114 filtered_types_to_add.Remove(syncer::TYPED_URLS); | |
115 } | |
116 if (workers_.count(syncer::GROUP_PASSWORD) == 0) { | |
117 LOG(WARNING) << "No password worker -- removing PASSWORDS"; | |
118 filtered_types_to_add.Remove(syncer::PASSWORDS); | |
119 } | |
120 | |
121 base::AutoLock lock(lock_); | |
122 syncer::ModelTypeSet newly_added_types; | |
123 for (syncer::ModelTypeSet::Iterator it = filtered_types_to_add.First(); | |
124 it.Good(); it.Inc()) { | |
125 // Add a newly specified data type as syncer::GROUP_PASSIVE into the | |
126 // routing_info, if it does not already exist. | |
127 if (routing_info_.count(it.Get()) == 0) { | |
128 routing_info_[it.Get()] = GetInitialGroupForType(it.Get()); | |
129 newly_added_types.Put(it.Get()); | |
130 } | |
131 } | |
132 for (syncer::ModelTypeSet::Iterator it = types_to_remove.First(); it.Good(); | |
133 it.Inc()) { | |
134 routing_info_.erase(it.Get()); | |
135 } | |
136 | |
137 // TODO(akalin): Use SVLOG/SLOG if we add any more logging. | |
138 DVLOG(1) << name_ << ": Adding types " | |
139 << syncer::ModelTypeSetToString(types_to_add) | |
140 << " (with newly-added types " | |
141 << syncer::ModelTypeSetToString(newly_added_types) | |
142 << ") and removing types " | |
143 << syncer::ModelTypeSetToString(types_to_remove) | |
144 << " to get new routing info " | |
145 << syncer::ModelSafeRoutingInfoToString(routing_info_); | |
146 last_configured_types_ = syncer::GetRoutingInfoTypes(routing_info_); | |
147 | |
148 return newly_added_types; | |
149 } | |
150 | |
151 syncer::ModelTypeSet SyncBackendRegistrar::GetLastConfiguredTypes() const { | |
152 return last_configured_types_; | |
153 } | |
154 | |
155 void SyncBackendRegistrar::RequestWorkerStopOnUIThread() { | |
156 DCHECK(ui_thread_->BelongsToCurrentThread()); | |
157 base::AutoLock lock(lock_); | |
158 for (WorkerMap::const_iterator it = workers_.begin(); it != workers_.end(); | |
159 ++it) { | |
160 it->second->RequestStop(); | |
161 } | |
162 } | |
163 | |
164 void SyncBackendRegistrar::ActivateDataType( | |
165 syncer::ModelType type, | |
166 syncer::ModelSafeGroup group, | |
167 sync_driver::ChangeProcessor* change_processor, | |
168 syncer::UserShare* user_share) { | |
169 DVLOG(1) << "Activate: " << syncer::ModelTypeToString(type); | |
170 | |
171 base::AutoLock lock(lock_); | |
172 // Ensure that the given data type is in the PASSIVE group. | |
173 syncer::ModelSafeRoutingInfo::iterator i = routing_info_.find(type); | |
174 DCHECK(i != routing_info_.end()); | |
175 DCHECK_EQ(i->second, syncer::GROUP_PASSIVE); | |
176 routing_info_[type] = group; | |
177 | |
178 // Add the data type's change processor to the list of change | |
179 // processors so it can receive updates. | |
180 DCHECK_EQ(processors_.count(type), 0U); | |
181 processors_[type] = change_processor; | |
182 | |
183 // Start the change processor. | |
184 change_processor->Start(user_share); | |
185 DCHECK(GetProcessorUnsafe(type)); | |
186 } | |
187 | |
188 void SyncBackendRegistrar::DeactivateDataType(syncer::ModelType type) { | |
189 DVLOG(1) << "Deactivate: " << syncer::ModelTypeToString(type); | |
190 | |
191 DCHECK(ui_thread_->BelongsToCurrentThread() || IsControlType(type)); | |
192 base::AutoLock lock(lock_); | |
193 | |
194 routing_info_.erase(type); | |
195 ignore_result(processors_.erase(type)); | |
196 DCHECK(!GetProcessorUnsafe(type)); | |
197 } | |
198 | |
199 bool SyncBackendRegistrar::IsTypeActivatedForTest( | |
200 syncer::ModelType type) const { | |
201 return GetProcessor(type) != NULL; | |
202 } | |
203 | |
204 void SyncBackendRegistrar::OnChangesApplied( | |
205 syncer::ModelType model_type, | |
206 int64_t model_version, | |
207 const syncer::BaseTransaction* trans, | |
208 const syncer::ImmutableChangeRecordList& changes) { | |
209 sync_driver::ChangeProcessor* processor = GetProcessor(model_type); | |
210 if (!processor) | |
211 return; | |
212 | |
213 processor->ApplyChangesFromSyncModel(trans, model_version, changes); | |
214 } | |
215 | |
216 void SyncBackendRegistrar::OnChangesComplete(syncer::ModelType model_type) { | |
217 sync_driver::ChangeProcessor* processor = GetProcessor(model_type); | |
218 if (!processor) | |
219 return; | |
220 | |
221 // This call just notifies the processor that it can commit; it | |
222 // already buffered any changes it plans to makes so needs no | |
223 // further information. | |
224 processor->CommitChangesFromSyncModel(); | |
225 } | |
226 | |
227 void SyncBackendRegistrar::GetWorkers( | |
228 std::vector<scoped_refptr<syncer::ModelSafeWorker>>* out) { | |
229 base::AutoLock lock(lock_); | |
230 out->clear(); | |
231 for (WorkerMap::const_iterator it = workers_.begin(); it != workers_.end(); | |
232 ++it) { | |
233 out->push_back(it->second.get()); | |
234 } | |
235 } | |
236 | |
237 void SyncBackendRegistrar::GetModelSafeRoutingInfo( | |
238 syncer::ModelSafeRoutingInfo* out) { | |
239 base::AutoLock lock(lock_); | |
240 syncer::ModelSafeRoutingInfo copy(routing_info_); | |
241 out->swap(copy); | |
242 } | |
243 | |
244 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessor( | |
245 syncer::ModelType type) const { | |
246 base::AutoLock lock(lock_); | |
247 sync_driver::ChangeProcessor* processor = GetProcessorUnsafe(type); | |
248 if (!processor) | |
249 return NULL; | |
250 | |
251 // We can only check if |processor| exists, as otherwise the type is | |
252 // mapped to syncer::GROUP_PASSIVE. | |
253 CHECK(IsCurrentThreadSafeForModel(type)); | |
254 return processor; | |
255 } | |
256 | |
257 sync_driver::ChangeProcessor* SyncBackendRegistrar::GetProcessorUnsafe( | |
258 syncer::ModelType type) const { | |
259 lock_.AssertAcquired(); | |
260 std::map<syncer::ModelType, sync_driver::ChangeProcessor*>::const_iterator | |
261 it = processors_.find(type); | |
262 | |
263 // Until model association happens for a datatype, it will not | |
264 // appear in the processors list. During this time, it is OK to | |
265 // drop changes on the floor (since model association has not | |
266 // happened yet). When the data type is activated, model | |
267 // association takes place then the change processor is added to the | |
268 // |processors_| list. | |
269 if (it == processors_.end()) | |
270 return NULL; | |
271 | |
272 return it->second; | |
273 } | |
274 | |
275 bool SyncBackendRegistrar::IsCurrentThreadSafeForModel( | |
276 syncer::ModelType model_type) const { | |
277 lock_.AssertAcquired(); | |
278 return IsOnThreadForGroup(model_type, | |
279 GetGroupForModelType(model_type, routing_info_)); | |
280 } | |
281 | |
282 bool SyncBackendRegistrar::IsOnThreadForGroup( | |
283 syncer::ModelType type, | |
284 syncer::ModelSafeGroup group) const { | |
285 switch (group) { | |
286 case syncer::GROUP_PASSIVE: | |
287 return IsControlType(type); | |
288 case syncer::GROUP_UI: | |
289 return ui_thread_->BelongsToCurrentThread(); | |
290 case syncer::GROUP_DB: | |
291 return db_thread_->BelongsToCurrentThread(); | |
292 case syncer::GROUP_FILE: | |
293 return file_thread_->BelongsToCurrentThread(); | |
294 case syncer::GROUP_HISTORY: | |
295 // TODO(sync): How to check we're on the right thread? | |
296 return type == syncer::TYPED_URLS; | |
297 case syncer::GROUP_PASSWORD: | |
298 // TODO(sync): How to check we're on the right thread? | |
299 return type == syncer::PASSWORDS; | |
300 case syncer::GROUP_NON_BLOCKING: | |
301 // IsOnThreadForGroup shouldn't be called for non-blocking types. | |
302 return false; | |
303 } | |
304 NOTREACHED(); | |
305 return false; | |
306 } | |
307 | |
308 SyncBackendRegistrar::~SyncBackendRegistrar() { | |
309 DCHECK(workers_.empty()); | |
310 } | |
311 | |
312 void SyncBackendRegistrar::OnWorkerLoopDestroyed(syncer::ModelSafeGroup group) { | |
313 RemoveWorker(group); | |
314 } | |
315 | |
316 void SyncBackendRegistrar::MaybeAddWorker(syncer::ModelSafeGroup group) { | |
317 const scoped_refptr<syncer::ModelSafeWorker> worker = | |
318 sync_client_->CreateModelWorkerForGroup(group, this); | |
319 if (worker) { | |
320 DCHECK(workers_.find(group) == workers_.end()); | |
321 workers_[group] = worker; | |
322 workers_[group]->RegisterForLoopDestruction(); | |
323 } | |
324 } | |
325 | |
326 void SyncBackendRegistrar::OnWorkerUnregistrationDone( | |
327 syncer::ModelSafeGroup group) { | |
328 RemoveWorker(group); | |
329 } | |
330 | |
331 void SyncBackendRegistrar::RemoveWorker(syncer::ModelSafeGroup group) { | |
332 DVLOG(1) << "Remove " << ModelSafeGroupToString(group) << " worker."; | |
333 | |
334 bool last_worker = false; | |
335 { | |
336 base::AutoLock al(lock_); | |
337 WorkerMap::iterator it = workers_.find(group); | |
338 CHECK(it != workers_.end()); | |
339 stopped_workers_.push_back(it->second); | |
340 workers_.erase(it); | |
341 last_worker = workers_.empty(); | |
342 } | |
343 | |
344 if (last_worker) { | |
345 // Self-destruction after last worker. | |
346 DVLOG(1) << "Destroy registrar on loop of " | |
347 << ModelSafeGroupToString(group); | |
348 delete this; | |
349 } | |
350 } | |
351 | |
352 std::unique_ptr<base::Thread> SyncBackendRegistrar::ReleaseSyncThread() { | |
353 return std::move(sync_thread_); | |
354 } | |
355 | |
356 void SyncBackendRegistrar::Shutdown() { | |
357 // All data types should have been deactivated by now. | |
358 DCHECK(processors_.empty()); | |
359 | |
360 // Unregister worker from observing loop destruction. | |
361 base::AutoLock al(lock_); | |
362 for (WorkerMap::iterator it = workers_.begin(); it != workers_.end(); ++it) { | |
363 it->second->UnregisterForLoopDestruction( | |
364 base::Bind(&SyncBackendRegistrar::OnWorkerUnregistrationDone, | |
365 base::Unretained(this))); | |
366 } | |
367 } | |
368 | |
369 base::Thread* SyncBackendRegistrar::sync_thread() { | |
370 return sync_thread_.get(); | |
371 } | |
372 | |
373 syncer::ModelSafeGroup SyncBackendRegistrar::GetInitialGroupForType( | |
374 syncer::ModelType type) const { | |
375 if (non_blocking_types_.Has(type)) | |
376 return syncer::GROUP_NON_BLOCKING; | |
377 else | |
378 return syncer::GROUP_PASSIVE; | |
379 } | |
380 | |
381 } // namespace browser_sync | |
OLD | NEW |