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

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

Issue 6811003: [Sync] Make generic non-frontend thread datatype controller. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Copy paste :( Created 9 years, 8 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/non_frontend_data_type_controller.h"
6
7 #include "base/logging.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/sync/glue/change_processor.h"
10 #include "chrome/browser/sync/glue/model_associator.h"
11 #include "chrome/browser/sync/profile_sync_factory.h"
12 #include "chrome/browser/sync/profile_sync_service.h"
13 #include "chrome/browser/sync/syncable/model_type.h"
14 #include "content/browser/browser_thread.h"
15
16 namespace browser_sync {
17
18 NonFrontendDataTypeController::NonFrontendDataTypeController()
19 : profile_sync_factory_(NULL),
20 profile_(NULL),
21 profile_sync_service_(NULL),
22 abort_association_(false),
23 abort_association_complete_(false, false),
24 datatype_stopped_(false, false) {}
25
26 NonFrontendDataTypeController::NonFrontendDataTypeController(
27 ProfileSyncFactory* profile_sync_factory,
28 Profile* profile)
29 : profile_sync_factory_(profile_sync_factory),
30 profile_(profile),
31 profile_sync_service_(profile->GetProfileSyncService()),
32 state_(NOT_RUNNING),
33 abort_association_(false),
34 abort_association_complete_(false, false),
35 datatype_stopped_(false, false) {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
37 DCHECK(profile_sync_factory_);
38 DCHECK(profile_);
39 DCHECK(profile_sync_service_);
40 }
41
42 NonFrontendDataTypeController::~NonFrontendDataTypeController() {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44 }
45
46 void NonFrontendDataTypeController::Start(StartCallback* start_callback) {
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
48 DCHECK(start_callback);
49 if (state_ != NOT_RUNNING) {
50 start_callback->Run(BUSY, FROM_HERE);
51 delete start_callback;
52 return;
53 }
54
55 start_callback_.reset(start_callback);
56 abort_association_ = false;
57
58 state_ = MODEL_STARTING;
59 if (!StartModels()) {
60 // If we are waiting for some external service to load before associating
61 // or we failed to start the models, we exit early. state_ will control
62 // what we perform next.
63 DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
64 return;
65 }
66
67 // Kick off association on the thread the datatype resides on.
68 state_ = ASSOCIATING;
69 if (!StartAssociationAsync()) {
70 StartDoneImpl(ASSOCIATION_FAILED, NOT_RUNNING, FROM_HERE);
71 }
72 }
73
74 bool NonFrontendDataTypeController::StartModels() {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76 DCHECK_EQ(state_, MODEL_STARTING);
77 // By default, no additional services need to be started before we can proceed
78 // with model association, so do nothing.
79 return true;
80 }
81
82 void NonFrontendDataTypeController::StartAssociation() {
83 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
84 DCHECK_EQ(state_, ASSOCIATING);
85 {
86 base::AutoLock lock(abort_association_lock_);
87 if (abort_association_) {
88 abort_association_complete_.Signal();
89 return;
90 }
91 CreateSyncComponents();
92 }
93
94 if (!model_associator_->CryptoReadyIfNecessary()) {
95 StartFailed(NEEDS_CRYPTO, FROM_HERE);
96 return;
97 }
98
99 bool sync_has_nodes = false;
100 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
101 StartFailed(UNRECOVERABLE_ERROR, FROM_HERE);
102 return;
103 }
104
105 base::TimeTicks start_time = base::TimeTicks::Now();
106 bool merge_success = model_associator_->AssociateModels();
107 RecordAssociationTime(base::TimeTicks::Now() - start_time);
108 if (!merge_success) {
109 StartFailed(ASSOCIATION_FAILED, FROM_HERE);
110 return;
111 }
112
113 profile_sync_service_->ActivateDataType(this, change_processor_.get());
114 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, FROM_HERE);
115 }
116
117 void NonFrontendDataTypeController::StartFailed(StartResult result,
118 const tracked_objects::Location& location) {
119 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
120 model_associator_.reset();
121 change_processor_.reset();
122 StartDone(result, NOT_RUNNING, location);
123 }
124
125 void NonFrontendDataTypeController::StartDone(
126 DataTypeController::StartResult result,
127 DataTypeController::State new_state,
128 const tracked_objects::Location& location) {
129 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
130 abort_association_complete_.Signal();
131 base::AutoLock lock(abort_association_lock_);
132 if (!abort_association_) {
133 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
134 NewRunnableMethod(
135 this,
136 &NonFrontendDataTypeController::StartDoneImpl,
137 result,
138 new_state,
139 location));
140 }
141 }
142
143 void NonFrontendDataTypeController::StartDoneImpl(
144 DataTypeController::StartResult result,
145 DataTypeController::State new_state,
146 const tracked_objects::Location& location) {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
148 state_ = new_state;
149 if (state_ != RUNNING) {
150 // Start failed.
151 StopModels();
152 RecordStartFailure(result);
153 }
154
155 // We have to release the callback before we call it, since it's possible
156 // invoking the callback will trigger a call to STOP(), which will get
157 // confused by the non-NULL start_callback_.
158 scoped_ptr<StartCallback> callback(start_callback_.release());
159 callback->Run(result, location);
160 }
161
162 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
163 // distinguishing chrome shutdown from sync shutdown, we should be able to avoid
164 // this (http://crbug.com/55662).
165 void NonFrontendDataTypeController::Stop() {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167 // If Stop() is called while Start() is waiting for association to
168 // complete, we need to abort the association and wait for the DB
169 // thread to finish the StartImpl() task.
170 if (state_ == ASSOCIATING) {
171 state_ = STOPPING;
172 {
173 base::AutoLock lock(abort_association_lock_);
174 abort_association_ = true;
175 if (model_associator_.get())
176 model_associator_->AbortAssociation();
177 }
178 // Wait for the model association to abort.
179 abort_association_complete_.Wait();
180 StartDoneImpl(ABORTED, STOPPING, FROM_HERE);
181 } else if (state_ == MODEL_STARTING) {
182 state_ = STOPPING;
183 // If Stop() is called while Start() is waiting for the models to start,
184 // abort the start. We don't need to continue on since it means we haven't
185 // kicked off the association, and once we call StopModels, we never will.
186 StartDoneImpl(ABORTED, NOT_RUNNING, FROM_HERE);
187 return;
188 } else {
189 state_ = STOPPING;
190
191 StopModels();
192 }
193 DCHECK(!start_callback_.get());
194
195 // Deactivate the change processor on the UI thread. We dont want to listen
196 // for any more changes or process them from server.
197 if (change_processor_ != NULL)
198 profile_sync_service_->DeactivateDataType(this, change_processor_.get());
199
200 if (StopAssociationAsync()) {
201 datatype_stopped_.Wait();
202 } else {
203 // We do DFATAL here because this will eventually lead to a failed CHECK
204 // when the change processor gets destroyed on the wrong thread.
205 LOG(DFATAL) << "Failed to destroy datatype " << name();
206 }
207 state_ = NOT_RUNNING;
208 }
209
210 void NonFrontendDataTypeController::StopModels() {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212 DCHECK(state_ == STOPPING || state_ == NOT_RUNNING);
213 // Do nothing by default.
214 }
215
216 void NonFrontendDataTypeController::StopAssociation() {
217 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
218 if (model_associator_ != NULL)
219 model_associator_->DisassociateModels();
220 change_processor_.reset();
221 model_associator_.reset();
222 datatype_stopped_.Signal();
223 }
224
225 std::string NonFrontendDataTypeController::name() const {
226 // For logging only.
227 return syncable::ModelTypeToString(type());
228 }
229
230 DataTypeController::State NonFrontendDataTypeController::state() const {
231 return state_;
232 }
233
234 void NonFrontendDataTypeController::OnUnrecoverableError(
235 const tracked_objects::Location& from_here,
236 const std::string& message) {
237 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
238 RecordUnrecoverableError(from_here, message);
239 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(this,
240 &NonFrontendDataTypeController::OnUnrecoverableErrorImpl, from_here,
241 message));
242 }
243
244 void NonFrontendDataTypeController::OnUnrecoverableErrorImpl(
245 const tracked_objects::Location& from_here,
246 const std::string& message) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
248 profile_sync_service_->OnUnrecoverableError(from_here, message);
249 }
250
251 ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory()
252 const {
253 return profile_sync_factory_;
254 }
255
256 Profile* NonFrontendDataTypeController::profile() const {
257 return profile_;
258 }
259
260 ProfileSyncService* NonFrontendDataTypeController::profile_sync_service()
261 const {
262 return profile_sync_service_;
263 }
264
265 void NonFrontendDataTypeController::set_state(State state) {
266 state_ = state;
267 }
268
269 void NonFrontendDataTypeController::set_model_associator(
270 AssociatorInterface* associator) {
271 model_associator_.reset(associator);
272 }
273
274 void NonFrontendDataTypeController::set_change_processor(
275 ChangeProcessor* change_processor) {
276 change_processor_.reset(change_processor);
277 }
278
279 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698