1// Copyright (c) 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#ifndef CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_REGISTRAR_H_
6#define CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_REGISTRAR_H_
7
8#include <map>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/compiler_specific.h"
13#include "base/memory/ref_counted.h"
14#include "base/synchronization/lock.h"
15#include "base/threading/thread.h"
16#include "sync/internal_api/public/base/model_type.h"
17#include "sync/internal_api/public/engine/model_safe_worker.h"
18#include "sync/internal_api/public/sync_manager.h"
19
20class Profile;
21
22namespace base {
23class MessageLoop;
24}
25
26namespace syncer {
27struct UserShare;
28}  // namespace syncer
29
30namespace browser_sync {
31
32class ChangeProcessor;
33class UIModelWorker;
34
35// A class that keep track of the workers, change processors, and
36// routing info for the enabled sync types, and also routes change
37// events to the right processors.
38class SyncBackendRegistrar : public syncer::SyncManager::ChangeDelegate,
39                             public syncer::WorkerLoopDestructionObserver {
40 public:
41  // |name| is used for debugging.  Does not take ownership of |profile| or
42  // |sync_loop|.  Must be created on the UI thread.
43  SyncBackendRegistrar(const std::string& name,
44                       Profile* profile,
45                       scoped_ptr<base::Thread> sync_thread);
46
47  // SyncBackendRegistrar must be destroyed as follows:
48  //
49  //   1) On the UI thread, call RequestWorkerStopOnUIThread().
50  //   2) UI posts task to shut down syncer on sync thread.
51  //   3) If sync is disabled, call ReleaseSyncThread() on the UI thread.
52  //   3) UI posts SyncBackendRegistrar::ShutDown() on sync thread to
53  //      unregister workers from observing destruction of their working loops.
54  //   4) Workers notify registrar when unregistration finishes or working
55  //      loops are destroyed. Registrar destroys itself on last worker
56  //      notification. Sync thread will be stopped if ownership was not
57  //      released.
58  virtual ~SyncBackendRegistrar();
59
60  // Informs the SyncBackendRegistrar of the currently enabled set of types.
61  // These types will be placed in the passive group.  This function should be
62  // called exactly once during startup.
63  void SetInitialTypes(syncer::ModelTypeSet initial_types);
64
65  // Returns whether or not we are currently syncing encryption keys.
66  // Must be called on the UI thread.
67  bool IsNigoriEnabled() const;
68
69  // Removes all types in |types_to_remove| from the routing info and
70  // adds all the types in |types_to_add| to the routing info that are
71  // not already there (initially put in the passive group).
72  // |types_to_remove| and |types_to_add| must be disjoint.  Returns
73  // the set of newly-added types.  Must be called on the UI thread.
74  syncer::ModelTypeSet ConfigureDataTypes(
75      syncer::ModelTypeSet types_to_add,
76      syncer::ModelTypeSet types_to_remove);
77
78  // Returns the set of enabled types as of the last configuration. Note that
79  // this might be different from the current types in the routing info due
80  // to DeactiveDataType being called separately from ConfigureDataTypes.
81  syncer::ModelTypeSet GetLastConfiguredTypes() const;
82
83  // Must be called from the UI thread. (See destructor comment.)
84  void RequestWorkerStopOnUIThread();
85
86  // Activates the given data type (which should belong to the given
87  // group) and starts the given change processor.  Must be called
88  // from |group|'s native thread.
89  void ActivateDataType(syncer::ModelType type,
90                        syncer::ModelSafeGroup group,
91                        ChangeProcessor* change_processor,
92                        syncer::UserShare* user_share);
93
94  // Deactivates the given type if necessary.  Must be called from the
95  // UI thread and not |type|'s native thread.  Yes, this is
96  // surprising: see http://crbug.com/92804.
97  void DeactivateDataType(syncer::ModelType type);
98
99  // Returns true only between calls to ActivateDataType(type, ...)
100  // and DeactivateDataType(type).  Used only by tests.
101  bool IsTypeActivatedForTest(syncer::ModelType type) const;
102
103  // SyncManager::ChangeDelegate implementation.  May be called from
104  // any thread.
105  virtual void OnChangesApplied(
106      syncer::ModelType model_type,
107      int64 model_version,
108      const syncer::BaseTransaction* trans,
109      const syncer::ImmutableChangeRecordList& changes) OVERRIDE;
110  virtual void OnChangesComplete(syncer::ModelType model_type) OVERRIDE;
111
112  void GetWorkers(std::vector<syncer::ModelSafeWorker*>* out);
113  void GetModelSafeRoutingInfo(syncer::ModelSafeRoutingInfo* out);
114
115  // syncer::WorkerLoopDestructionObserver implementation.
116  virtual void OnWorkerLoopDestroyed(syncer::ModelSafeGroup group) OVERRIDE;
117
118  // Release ownership of |sync_thread_|. Called when sync is disabled.
119  scoped_ptr<base::Thread> ReleaseSyncThread();
120
121  // Unregister workers from loop destruction observation.
122  void Shutdown();
123
124  base::Thread* sync_thread();
125
126 private:
127  typedef std::map<syncer::ModelSafeGroup,
128      scoped_refptr<syncer::ModelSafeWorker> > WorkerMap;
129  typedef std::map<syncer::ModelType, ChangeProcessor*>
130      ProcessorMap;
131
132  // Callback after workers unregister from observing destruction of their
133  // working loops.
134  void OnWorkerUnregistrationDone(syncer::ModelSafeGroup group);
135
136  void RemoveWorker(syncer::ModelSafeGroup group);
137
138  // Returns the change processor for the given model, or NULL if none
139  // exists.  Must be called from |group|'s native thread.
140  ChangeProcessor* GetProcessor(syncer::ModelType type) const;
141
142  // Must be called with |lock_| held.  Simply returns the change
143  // processor for the given type, if it exists.  May be called from
144  // any thread.
145  ChangeProcessor* GetProcessorUnsafe(syncer::ModelType type) const;
146
147  // Return true if |model_type| lives on the current thread.  Must be
148  // called with |lock_| held.  May be called on any thread.
149  bool IsCurrentThreadSafeForModel(
150      syncer::ModelType model_type) const;
151
152  // Name used for debugging.
153  const std::string name_;
154
155  Profile* const profile_;
156
157  // Protects all variables below.
158  mutable base::Lock lock_;
159
160  // We maintain ownership of all workers.  In some cases, we need to
161  // ensure shutdown occurs in an expected sequence by Stop()ing
162  // certain workers.  They are guaranteed to be valid because we only
163  // destroy elements of |workers_| after the syncapi has been
164  // destroyed.  Unless a worker is no longer needed because all types
165  // that get routed to it have been disabled (from syncing). In that
166  // case, we'll destroy on demand *after* routing any dependent types
167  // to syncer::GROUP_PASSIVE, so that the syncapi doesn't call into garbage.
168  // If a key is present, it means at least one ModelType that routes
169  // to that model safe group is being synced.
170  WorkerMap workers_;
171  syncer::ModelSafeRoutingInfo routing_info_;
172
173  // The change processors that handle the different data types.
174  ProcessorMap processors_;
175
176  // The types that were enabled as of the last configuration. Updated on each
177  // call to ConfigureDataTypes as well as SetInitialTypes.
178  syncer::ModelTypeSet last_configured_types_;
179
180  // Parks stopped workers because they may still be referenced by syncer.
181  std::vector<scoped_refptr<syncer::ModelSafeWorker> > stopped_workers_;
182
183  // Declare |sync_thread_| at the end so that it will be destroyed before
184  // objects above because tasks on sync thread depend on those objects,
185  // e.g. Shutdown() depends on |lock_|, SyncManager::Init() depends on
186  // workers, etc.
187  scoped_ptr<base::Thread> sync_thread_;
188
189  DISALLOW_COPY_AND_ASSIGN(SyncBackendRegistrar);
190};
191
192}  // namespace browser_sync
193
194#endif  // CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_REGISTRAR_H_
195