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

Side by Side Diff: chrome/browser/sync/glue/typed_url_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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h" 5 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
6 6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 7 #include "base/metrics/histogram.h"
9 #include "base/task.h" 8 #include "base/task.h"
10 #include "base/time.h"
11 #include "chrome/browser/history/history.h" 9 #include "chrome/browser/history/history.h"
12 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/sync/glue/typed_url_change_processor.h"
14 #include "chrome/browser/sync/glue/typed_url_model_associator.h"
15 #include "chrome/browser/sync/profile_sync_factory.h" 11 #include "chrome/browser/sync/profile_sync_factory.h"
16 #include "chrome/browser/sync/profile_sync_service.h" 12 #include "chrome/browser/sync/profile_sync_service.h"
17 #include "content/browser/browser_thread.h" 13 #include "content/browser/browser_thread.h"
18 #include "content/common/notification_service.h" 14 #include "content/common/notification_service.h"
19 15
20 namespace browser_sync { 16 namespace browser_sync {
21 17
22 class ControlTask : public HistoryDBTask { 18 class ControlTask : public HistoryDBTask {
23 public: 19 public:
24 ControlTask(TypedUrlDataTypeController* controller, bool start) 20 ControlTask(TypedUrlDataTypeController* controller, bool start)
25 : controller_(controller), start_(start) {} 21 : controller_(controller), start_(start) {}
26 22
27 virtual bool RunOnDBThread(history::HistoryBackend* backend, 23 virtual bool RunOnDBThread(history::HistoryBackend* backend,
28 history::HistoryDatabase* db) { 24 history::HistoryDatabase* db) {
29 if (start_) { 25 controller_->RunOnHistoryThread(start_, backend);
30 controller_->StartImpl(backend);
31 } else {
32 controller_->StopImpl();
33 }
34 26
35 // Release the reference to the controller. This ensures that 27 // Release the reference to the controller. This ensures that
36 // the controller isn't held past its lifetime in unit tests. 28 // the controller isn't held past its lifetime in unit tests.
37 controller_ = NULL; 29 controller_ = NULL;
38 return true; 30 return true;
39 } 31 }
40 32
41 virtual void DoneRunOnMainThread() {} 33 virtual void DoneRunOnMainThread() {}
42 34
43 protected: 35 protected:
44 scoped_refptr<TypedUrlDataTypeController> controller_; 36 scoped_refptr<TypedUrlDataTypeController> controller_;
45 bool start_; 37 bool start_;
46 }; 38 };
47 39
48 TypedUrlDataTypeController::TypedUrlDataTypeController( 40 TypedUrlDataTypeController::TypedUrlDataTypeController(
49 ProfileSyncFactory* profile_sync_factory, 41 ProfileSyncFactory* profile_sync_factory,
50 Profile* profile, 42 Profile* profile)
51 ProfileSyncService* sync_service) 43 : NonFrontendDataTypeController(profile_sync_factory,
52 : profile_sync_factory_(profile_sync_factory), 44 profile),
53 profile_(profile), 45 backend_(NULL) {
54 sync_service_(sync_service),
55 state_(NOT_RUNNING),
56 abort_association_(false),
57 abort_association_complete_(false, false),
58 datatype_stopped_(false, false) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60 DCHECK(profile_sync_factory);
61 DCHECK(profile);
62 DCHECK(sync_service);
63 } 46 }
64 47
65 TypedUrlDataTypeController::~TypedUrlDataTypeController() { 48 TypedUrlDataTypeController::~TypedUrlDataTypeController() {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67 } 49 }
68 50
69 void TypedUrlDataTypeController::Start(StartCallback* start_callback) { 51 void TypedUrlDataTypeController::RunOnHistoryThread(bool start,
70 VLOG(1) << "Starting typed_url data controller."; 52 history::HistoryBackend* backend) {
53 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
54 // The only variable we can access here is backend_, since it is always
55 // read from the DB thread. Touching anything else could lead to memory
56 // corruption.
57 backend_ = backend;
58 if (start) {
59 StartAssociation();
60 } else {
61 StopAssociation();
62 }
63 backend_ = NULL;
64 }
65
66 bool TypedUrlDataTypeController::StartModels() {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
72 DCHECK(start_callback); 68 DCHECK_EQ(state(), MODEL_STARTING);
73 if (state_ != NOT_RUNNING || start_callback_.get()) { 69 HistoryService* history = profile()->GetHistoryServiceWithoutCreating();
74 start_callback->Run(BUSY, FROM_HERE);
75 delete start_callback;
76 return;
77 }
78
79 start_callback_.reset(start_callback);
80 abort_association_ = false;
81
82 HistoryService* history = profile_->GetHistoryServiceWithoutCreating();
83 if (history) { 70 if (history) {
84 set_state(ASSOCIATING);
85 history_service_ = history; 71 history_service_ = history;
86 history_service_->ScheduleDBTask(new ControlTask(this, true), this); 72 return true;
87 } else { 73 } else {
88 set_state(MODEL_STARTING);
89 notification_registrar_.Add(this, NotificationType::HISTORY_LOADED, 74 notification_registrar_.Add(this, NotificationType::HISTORY_LOADED,
90 NotificationService::AllSources()); 75 NotificationService::AllSources());
76 return false;
91 } 77 }
92 } 78 }
93 79
80 bool TypedUrlDataTypeController::StartAssociationAsync() {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82 DCHECK_EQ(state(), ASSOCIATING);
83 DCHECK(history_service_.get());
84 history_service_->ScheduleDBTask(new ControlTask(this, true), this);
85 return true;
86 }
87
88 void TypedUrlDataTypeController::CreateSyncComponents() {
89 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
90 DCHECK_EQ(state(), ASSOCIATING);
91 DCHECK(backend_);
92 ProfileSyncFactory::SyncComponents sync_components =
93 profile_sync_factory()->CreateTypedUrlSyncComponents(
94 profile_sync_service(),
95 backend_,
96 this);
97 set_model_associator(sync_components.model_associator);
98 set_change_processor(sync_components.change_processor);
99 }
100
94 void TypedUrlDataTypeController::Observe(NotificationType type, 101 void TypedUrlDataTypeController::Observe(NotificationType type,
95 const NotificationSource& source, 102 const NotificationSource& source,
96 const NotificationDetails& details) { 103 const NotificationDetails& details) {
97 VLOG(1) << "History loaded observed."; 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105 DCHECK_EQ(state(), MODEL_STARTING);
98 notification_registrar_.Remove(this, 106 notification_registrar_.Remove(this,
99 NotificationType::HISTORY_LOADED, 107 NotificationType::HISTORY_LOADED,
100 NotificationService::AllSources()); 108 NotificationService::AllSources());
101 109 history_service_ = profile()->GetHistoryServiceWithoutCreating();
102 history_service_ = profile_->GetHistoryServiceWithoutCreating();
103 DCHECK(history_service_.get()); 110 DCHECK(history_service_.get());
104 history_service_->ScheduleDBTask(new ControlTask(this, true), this); 111 set_state(ASSOCIATING);
112 StopAssociationAsync();
105 } 113 }
106 114
107 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of 115 void TypedUrlDataTypeController::StopModels() {
108 // distinguishing chrome shutdown from sync shutdown, we should be able to avoid
109 // this (http://crbug.com/55662). Further, all this functionality should be
110 // abstracted to a higher layer, where we could ensure all datatypes are doing
111 // the same thing (http://crbug.com/76232).
112 void TypedUrlDataTypeController::Stop() {
113 VLOG(1) << "Stopping typed_url data type controller.";
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117 DCHECK(state() == STOPPING || state() == NOT_RUNNING);
118 notification_registrar_.RemoveAll();
119 }
115 120
116 // If Stop() is called while Start() is waiting for association to 121 bool TypedUrlDataTypeController::StopAssociationAsync() {
117 // complete, we need to abort the association and wait for the DB 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118 // thread to finish the StartImpl() task. 123 DCHECK_EQ(state(), STOPPING);
119 if (state_ == ASSOCIATING) {
120 {
121 base::AutoLock lock(abort_association_lock_);
122 abort_association_ = true;
123 if (model_associator_.get())
124 model_associator_->AbortAssociation();
125 }
126 // Wait for the model association to abort.
127 abort_association_complete_.Wait();
128 StartDoneImpl(ABORTED, STOPPING);
129 }
130
131 // If Stop() is called while Start() is waiting for the history service to
132 // load, abort the start.
133 if (state_ == MODEL_STARTING)
134 StartDoneImpl(ABORTED, STOPPING);
135
136 DCHECK(!start_callback_.get());
137
138 if (change_processor_ != NULL)
139 sync_service_->DeactivateDataType(this, change_processor_.get());
140
141 set_state(NOT_RUNNING);
142 DCHECK(history_service_.get()); 124 DCHECK(history_service_.get());
143 history_service_->ScheduleDBTask(new ControlTask(this, false), this); 125 history_service_->ScheduleDBTask(new ControlTask(this, false), this);
144 datatype_stopped_.Wait();
145 }
146
147 bool TypedUrlDataTypeController::enabled() {
148 return true; 126 return true;
149 } 127 }
150 128
151 syncable::ModelType TypedUrlDataTypeController::type() const { 129 syncable::ModelType TypedUrlDataTypeController::type() const {
152 return syncable::TYPED_URLS; 130 return syncable::TYPED_URLS;
153 } 131 }
154 132
155 browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() 133 browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group()
156 const { 134 const {
157 return browser_sync::GROUP_HISTORY; 135 return browser_sync::GROUP_HISTORY;
158 } 136 }
159 137
160 std::string TypedUrlDataTypeController::name() const { 138 void TypedUrlDataTypeController::RecordUnrecoverableError(
161 // For logging only. 139 const tracked_objects::Location& from_here,
162 return "typed_url"; 140 const std::string& message) {
141 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
142 UMA_HISTOGRAM_COUNTS("Sync.TypedUrlRunFailures", 1);
163 } 143 }
164 144
165 DataTypeController::State TypedUrlDataTypeController::state() const { 145 void TypedUrlDataTypeController::RecordAssociationTime(base::TimeDelta time) {
166 return state_; 146 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
147 UMA_HISTOGRAM_TIMES("Sync.TypedUrlAssociationTime", time);
167 } 148 }
168 149
169 void TypedUrlDataTypeController::StartImpl(history::HistoryBackend* backend) { 150 void TypedUrlDataTypeController::RecordStartFailure(StartResult result) {
170 VLOG(1) << "TypedUrl data type controller StartImpl called."; 151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
171 // No additional services need to be started before we can proceed 152 UMA_HISTOGRAM_ENUMERATION("Sync.TypedUrlStartFailures",
172 // with model association. 153 result,
173 { 154 MAX_START_RESULT);
174 base::AutoLock lock(abort_association_lock_);
175 if (abort_association_) {
176 abort_association_complete_.Signal();
177 return;
178 }
179 ProfileSyncFactory::SyncComponents sync_components =
180 profile_sync_factory_->CreateTypedUrlSyncComponents(
181 sync_service_,
182 backend,
183 this);
184 model_associator_.reset(sync_components.model_associator);
185 change_processor_.reset(sync_components.change_processor);
186 }
187
188 if (!model_associator_->CryptoReadyIfNecessary()) {
189 StartFailed(NEEDS_CRYPTO);
190 return;
191 }
192
193 bool sync_has_nodes = false;
194 if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
195 StartFailed(UNRECOVERABLE_ERROR);
196 return;
197 }
198
199 base::TimeTicks start_time = base::TimeTicks::Now();
200 bool merge_success = model_associator_->AssociateModels();
201 UMA_HISTOGRAM_TIMES("Sync.TypedUrlAssociationTime",
202 base::TimeTicks::Now() - start_time);
203 if (!merge_success) {
204 StartFailed(ASSOCIATION_FAILED);
205 return;
206 }
207
208 sync_service_->ActivateDataType(this, change_processor_.get());
209 StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING);
210 } 155 }
211
212 void TypedUrlDataTypeController::StartDone(
213 DataTypeController::StartResult result,
214 DataTypeController::State new_state) {
215 VLOG(1) << "TypedUrl data type controller StartDone called.";
216
217 abort_association_complete_.Signal();
218 base::AutoLock lock(abort_association_lock_);
219 if (!abort_association_) {
220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
221 NewRunnableMethod(
222 this,
223 &TypedUrlDataTypeController::StartDoneImpl,
224 result,
225 new_state));
226 }
227 }
228
229 void TypedUrlDataTypeController::StartDoneImpl(
230 DataTypeController::StartResult result,
231 DataTypeController::State new_state) {
232 VLOG(1) << "TypedUrl data type controller StartDoneImpl called.";
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
234 set_state(new_state);
235 start_callback_->Run(result, FROM_HERE);
236 start_callback_.reset();
237
238 if (result == UNRECOVERABLE_ERROR || result == ASSOCIATION_FAILED) {
239 UMA_HISTOGRAM_ENUMERATION("Sync.TypedUrlStartFailures",
240 result,
241 MAX_START_RESULT);
242 }
243 }
244
245 void TypedUrlDataTypeController::StopImpl() {
246 VLOG(1) << "TypedUrl data type controller StopImpl called.";
247
248 if (model_associator_ != NULL)
249 model_associator_->DisassociateModels();
250
251 change_processor_.reset();
252 model_associator_.reset();
253
254 datatype_stopped_.Signal();
255 }
256
257 void TypedUrlDataTypeController::StartFailed(StartResult result) {
258 change_processor_.reset();
259 model_associator_.reset();
260 StartDone(result, NOT_RUNNING);
261 }
262
263 void TypedUrlDataTypeController::OnUnrecoverableError(
264 const tracked_objects::Location& from_here,
265 const std::string& message) {
266 BrowserThread::PostTask(
267 BrowserThread::UI, FROM_HERE,
268 NewRunnableMethod(this,
269 &TypedUrlDataTypeController::OnUnrecoverableErrorImpl,
270 from_here, message));
271 }
272
273 void TypedUrlDataTypeController::OnUnrecoverableErrorImpl(
274 const tracked_objects::Location& from_here,
275 const std::string& message) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
277 UMA_HISTOGRAM_COUNTS("Sync.TypedUrlRunFailures", 1);
278 sync_service_->OnUnrecoverableError(from_here, message);
279 }
280
281 } // namespace browser_sync 156 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/typed_url_data_type_controller.h ('k') | chrome/browser/sync/profile_sync_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698