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

Side by Side Diff: chrome/browser/sync/glue/data_type_manager_impl2.cc

Issue 6528042: sync: rewrite DataTypeManagerImpl without pause/resume logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome
Patch Set: gypi Created 9 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/sync/glue/data_type_manager_impl2.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "chrome/browser/browser_thread.h"
10 #include "chrome/browser/sync/glue/data_type_controller.h"
11 #include "chrome/browser/sync/glue/sync_backend_host.h"
12 #include "chrome/common/notification_details.h"
13 #include "chrome/common/notification_service.h"
14 #include "chrome/common/notification_source.h"
15
16 namespace browser_sync {
17
18 namespace {
19
20 static const syncable::ModelType kStartOrder[] = {
21 syncable::NIGORI,
Nicolas Zea 2011/02/16 18:40:53 Presumably this is just for the sake of being comp
tim (not reviewing) 2011/02/17 21:27:25 Done.
22 syncable::BOOKMARKS,
23 syncable::PREFERENCES,
24 syncable::AUTOFILL,
25 syncable::AUTOFILL_PROFILE,
26 syncable::EXTENSIONS,
27 syncable::APPS,
28 syncable::THEMES,
29 syncable::TYPED_URLS,
30 syncable::PASSWORDS,
31 syncable::SESSIONS,
32 };
33
34 COMPILE_ASSERT(arraysize(kStartOrder) ==
35 syncable::MODEL_TYPE_COUNT - syncable::FIRST_REAL_MODEL_TYPE,
36 kStartOrder_IncorrectSize);
37
38 // Comparator used when sorting data type controllers.
39 class SortComparator : public std::binary_function<DataTypeController*,
40 DataTypeController*,
41 bool> {
42 public:
43 explicit SortComparator(std::map<syncable::ModelType, int>* order)
44 : order_(order) { }
45
46 // Returns true if lhs precedes rhs.
47 bool operator() (DataTypeController* lhs, DataTypeController* rhs) {
48 return (*order_)[lhs->type()] < (*order_)[rhs->type()];
49 }
50
51 private:
52 std::map<syncable::ModelType, int>* order_;
53 };
54
55 } // namespace
56
57 DataTypeManagerImpl2::DataTypeManagerImpl2(SyncBackendHost* backend,
58 const DataTypeController::TypeMap& controllers)
59 : backend_(backend),
60 controllers_(controllers),
61 state_(DataTypeManager::STOPPED),
62 current_dtc_(NULL),
63 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
64 DCHECK(backend_);
65 // Ensure all data type controllers are stopped.
66 for (DataTypeController::TypeMap::const_iterator it = controllers_.begin();
67 it != controllers_.end(); ++it) {
68 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
69 }
70
71 // Build a ModelType -> order map for sorting.
72 for (int i = 0; i < static_cast<int>(arraysize(kStartOrder)); i++)
73 start_order_[kStartOrder[i]] = i;
74 }
75
76 DataTypeManagerImpl2::~DataTypeManagerImpl2() {}
77
78 void DataTypeManagerImpl2::Configure(const TypeSet& desired_types) {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
80 if (state_ == STOPPING) {
81 // You can not set a configuration while stopping.
82 LOG(ERROR) << "Configuration set while stopping.";
83 return;
84 }
85
86 last_requested_types_ = desired_types;
87 // Add any data type controllers into the needs_start_ list that are
88 // currently NOT_RUNNING or STOPPING.
89 needs_start_.clear();
90 for (TypeSet::const_iterator it = desired_types.begin();
91 it != desired_types.end(); ++it) {
92 DataTypeController::TypeMap::const_iterator dtc = controllers_.find(*it);
93 if (dtc != controllers_.end() &&
94 (dtc->second->state() == DataTypeController::NOT_RUNNING ||
95 dtc->second->state() == DataTypeController::STOPPING)) {
96 needs_start_.push_back(dtc->second.get());
97 VLOG(1) << "Will start " << dtc->second->name();
98 }
99 }
100 // Sort these according to kStartOrder.
101 std::sort(needs_start_.begin(),
102 needs_start_.end(),
103 SortComparator(&start_order_));
104
105 // Add any data type controllers into that needs_stop_ list that are
106 // currently MODEL_STARTING, ASSOCIATING, or RUNNING.
107 needs_stop_.clear();
108 for (DataTypeController::TypeMap::const_iterator it = controllers_.begin();
109 it != controllers_.end(); ++it) {
110 DataTypeController* dtc = (*it).second;
111 if (desired_types.count(dtc->type()) == 0 && (
112 dtc->state() == DataTypeController::MODEL_STARTING ||
113 dtc->state() == DataTypeController::ASSOCIATING ||
114 dtc->state() == DataTypeController::RUNNING)) {
115 needs_stop_.push_back(dtc);
116 VLOG(1) << "Will stop " << dtc->name();
117 }
118 }
119 // Sort these according to kStartOrder.
120 std::sort(needs_stop_.begin(),
121 needs_stop_.end(),
122 SortComparator(&start_order_));
123
124 // If nothing changed, we're done.
125 if (needs_start_.size() == 0 && needs_stop_.size() == 0) {
126 state_ = CONFIGURED;
127 NotifyStart();
128 NotifyDone(OK);
129 return;
130 }
131
132 Restart();
133 }
134
135 void DataTypeManagerImpl2::Restart() {
136 VLOG(1) << "Restarting...";
137
138 // If we are currently waiting for an asynchronous process to
139 // complete, change our state to RESTARTING so those processes know
140 // that we want to start over when they finish.
141 if (state_ == DOWNLOAD_PENDING || state_ == CONFIGURING) {
142 state_ = RESTARTING;
143 return;
144 }
145
146 DCHECK(state_ == STOPPED || state_ == RESTARTING || state_ == CONFIGURED);
147 current_dtc_ = NULL;
148
149 // Starting from a "steady state" (stopped or configured) state
150 // should send a start notification.
151 if (state_ == STOPPED || state_ == CONFIGURED)
152 NotifyStart();
153
154 // Stop requested data types.
155 for (size_t i = 0; i < needs_stop_.size(); ++i) {
156 VLOG(1) << "Stopping " << needs_stop_[i]->name();
157 needs_stop_[i]->Stop();
158 }
159 needs_stop_.clear();
160
161 // Tell the backend about the new set of data types we wish to sync.
162 // The task will be invoked when updates are downloaded.
163 state_ = DOWNLOAD_PENDING;
164 backend_->ConfigureDataTypes(
165 controllers_,
166 last_requested_types_,
167 method_factory_.NewRunnableMethod(&DataTypeManagerImpl2::DownloadReady));
168 }
169
170 void DataTypeManagerImpl2::DownloadReady() {
171 DCHECK(state_ == DOWNLOAD_PENDING || state_ == RESTARTING);
172
173 // If we had a restart while waiting for downloads, just restart.
174 // Note: Restart() can cause DownloadReady to be directly invoked, so we post
175 // a task to avoid re-entrancy issues.
176 if (state_ == RESTARTING) {
177 MessageLoop::current()->PostTask(FROM_HERE,
178 method_factory_.NewRunnableMethod(&DataTypeManagerImpl2::Restart));
179 return;
180 }
181
182 state_ = CONFIGURING;
183 StartNextType();
184 }
185
186 void DataTypeManagerImpl2::StartNextType() {
187 // If there are any data types left to start, start the one at the
188 // front of the list.
189 if (needs_start_.size() > 0) {
190 current_dtc_ = needs_start_[0];
191 VLOG(1) << "Starting " << current_dtc_->name();
192 current_dtc_->Start(
193 NewCallback(this, &DataTypeManagerImpl2::TypeStartCallback));
194 return;
195 }
196
197 // If no more data types need starting, we're done. Resume the sync
Nicolas Zea 2011/02/16 18:40:53 "Resume sync backend" no longer applicable, right?
tim (not reviewing) 2011/02/17 21:27:25 Done.
198 // backend to finish.
199 DCHECK_EQ(state_, CONFIGURING);
200 state_ = CONFIGURED;
201 NotifyDone(OK);
202 }
203
204 void DataTypeManagerImpl2::TypeStartCallback(
205 DataTypeController::StartResult result) {
206 // When the data type controller invokes this callback, it must be
207 // on the UI thread.
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 DCHECK(current_dtc_);
210
211 if (state_ == RESTARTING) {
212 // If configuration changed while this data type was starting, we
213 // need to reset. Resume the syncer.
Nicolas Zea 2011/02/16 18:40:53 Same here.
tim (not reviewing) 2011/02/17 21:27:25 Done.
214 Restart();
215 return;
216 } else if (state_ == STOPPING) {
217 // If we reach this callback while stopping, this means that
218 // DataTypeManager::Stop() was called while the current data type
219 // was starting. Now that it has finished starting, we can finish
220 // stopping the DataTypeManager. This is considered an ABORT.
221 FinishStopAndNotify(ABORTED);
222 return;
223 } else if (state_ == STOPPED) {
224 // If our state_ is STOPPED, we have already stopped all of the data
225 // types. We should not be getting callbacks from stopped data types.
226 LOG(ERROR) << "Start callback called by stopped data type!";
227 return;
228 }
229
230 // We're done with the data type at the head of the list -- remove it.
231 DataTypeController* started_dtc = current_dtc_;
232 DCHECK(needs_start_.size());
233 DCHECK_EQ(needs_start_[0], started_dtc);
234 needs_start_.erase(needs_start_.begin());
235 current_dtc_ = NULL;
236
237 // If the type started normally, continue to the next type.
238 // If the type is waiting for the cryptographer, continue to the next type.
239 // Once the cryptographer is ready, we'll attempt to restart this type.
240 if (result == DataTypeController::NEEDS_CRYPTO ||
241 result == DataTypeController::OK ||
242 result == DataTypeController::OK_FIRST_RUN) {
243 StartNextType();
244 return;
245 }
246
247 // Any other result is a fatal error. Shut down any types we've
248 // managed to start up to this point and pass the result to the
249 // callback.
250 VLOG(1) << "Failed " << started_dtc->name();
251 ConfigureResult configure_result = DataTypeManager::ABORTED;
252 switch (result) {
253 case DataTypeController::ABORTED:
254 configure_result = DataTypeManager::ABORTED;
255 break;
256 case DataTypeController::ASSOCIATION_FAILED:
257 configure_result = DataTypeManager::ASSOCIATION_FAILED;
258 break;
259 case DataTypeController::UNRECOVERABLE_ERROR:
260 configure_result = DataTypeManager::UNRECOVERABLE_ERROR;
261 break;
262 default:
263 NOTREACHED();
264 break;
265 }
266 FinishStopAndNotify(configure_result);
267 }
268
269 void DataTypeManagerImpl2::Stop() {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 if (state_ == STOPPED)
272 return;
273
274 // If we are currently configuring, then the current type is in a
275 // partially started state. Abort the startup of the current type,
276 // which will synchronously invoke the start callback.
277 if (state_ == CONFIGURING) {
278 state_ = STOPPING;
279 current_dtc_->Stop();
280 return;
281 }
282
283 const bool download_pending = state_ == DOWNLOAD_PENDING;
284 state_ = STOPPING;
285 if (download_pending) {
286 // If Stop() is called while waiting for download, cancel all
287 // outstanding tasks.
288 method_factory_.RevokeAll();
289 FinishStopAndNotify(ABORTED);
290 return;
291 }
292
293 FinishStop();
294 }
295
296 void DataTypeManagerImpl2::FinishStop() {
297 DCHECK(state_== CONFIGURING || state_ == STOPPING);
298 // Simply call the Stop() method on all running data types.
299 for (DataTypeController::TypeMap::const_iterator it = controllers_.begin();
300 it != controllers_.end(); ++it) {
301 DataTypeController* dtc = (*it).second;
302 if (dtc->state() != DataTypeController::NOT_RUNNING &&
303 dtc->state() != DataTypeController::STOPPING) {
304 dtc->Stop();
305 VLOG(1) << "Stopped " << dtc->name();
306 }
307 }
308 state_ = STOPPED;
309 }
310
311 void DataTypeManagerImpl2::FinishStopAndNotify(ConfigureResult result) {
312 FinishStop();
313 NotifyDone(result);
314 }
315
316 void DataTypeManagerImpl2::NotifyStart() {
317 NotificationService::current()->Notify(
318 NotificationType::SYNC_CONFIGURE_START,
319 Source<DataTypeManager>(this),
320 NotificationService::NoDetails());
321 }
322
323 void DataTypeManagerImpl2::NotifyDone(ConfigureResult result) {
324 NotificationService::current()->Notify(
325 NotificationType::SYNC_CONFIGURE_DONE,
326 Source<DataTypeManager>(this),
327 Details<ConfigureResult>(&result));
328 }
329
330 const DataTypeController::TypeMap& DataTypeManagerImpl2::controllers() {
331 return controllers_;
332 }
333
334 DataTypeManager::State DataTypeManagerImpl2::state() {
335 return state_;
336 }
337
338 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/data_type_manager_impl2.h ('k') | chrome/browser/sync/glue/data_type_manager_impl2_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698