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

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: Fix autofill 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 ProfileSyncService* sync_service)
52 : profile_sync_factory_(profile_sync_factory), 44 : NonFrontendDataTypeController(profile_sync_factory,
53 profile_(profile), 45 profile,
54 sync_service_(sync_service), 46 sync_service),
55 state_(NOT_RUNNING), 47 backend_(NULL) {
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 } 48 }
64 49
65 TypedUrlDataTypeController::~TypedUrlDataTypeController() { 50 TypedUrlDataTypeController::~TypedUrlDataTypeController() {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67 } 51 }
68 52
69 void TypedUrlDataTypeController::Start(StartCallback* start_callback) { 53 void TypedUrlDataTypeController::RunOnHistoryThread(bool start,
70 VLOG(1) << "Starting typed_url data controller."; 54 history::HistoryBackend* backend) {
55 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
56 // The only variable we can access here is backend_, since it is always
57 // read from the DB thread. Touching anything else could lead to memory
58 // corruption.
59 backend_ = backend;
60 if (start) {
61 Associate();
62 } else {
63 Destroy();
64 }
65 backend_ = NULL;
66 }
67
68 bool TypedUrlDataTypeController::StartModels() {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
72 DCHECK(start_callback); 70 DCHECK_EQ(state_, MODEL_STARTING);
73 if (state_ != NOT_RUNNING || start_callback_.get()) {
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(); 71 HistoryService* history = profile_->GetHistoryServiceWithoutCreating();
83 if (history) { 72 if (history) {
84 set_state(ASSOCIATING);
85 history_service_ = history; 73 history_service_ = history;
86 history_service_->ScheduleDBTask(new ControlTask(this, true), this); 74 return true;
87 } else { 75 } else {
88 set_state(MODEL_STARTING);
89 notification_registrar_.Add(this, NotificationType::HISTORY_LOADED, 76 notification_registrar_.Add(this, NotificationType::HISTORY_LOADED,
90 NotificationService::AllSources()); 77 NotificationService::AllSources());
78 return false;
91 } 79 }
92 } 80 }
93 81
82 bool TypedUrlDataTypeController::KickOffAssociation() {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 DCHECK_EQ(state_, ASSOCIATING);
85 DCHECK(history_service_.get());
86 history_service_->ScheduleDBTask(new ControlTask(this, true), this);
87 return true;
88 }
89
90 void TypedUrlDataTypeController::CreateSyncComponents() {
91 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
92 DCHECK_EQ(state_, ASSOCIATING);
93 DCHECK(backend_);
94 ProfileSyncFactory::SyncComponents sync_components =
95 profile_sync_factory_->CreateTypedUrlSyncComponents(
96 sync_service_,
97 backend_,
98 this);
99 model_associator_.reset(sync_components.model_associator);
100 change_processor_.reset(sync_components.change_processor);
101 }
102
94 void TypedUrlDataTypeController::Observe(NotificationType type, 103 void TypedUrlDataTypeController::Observe(NotificationType type,
95 const NotificationSource& source, 104 const NotificationSource& source,
96 const NotificationDetails& details) { 105 const NotificationDetails& details) {
97 VLOG(1) << "History loaded observed."; 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107 DCHECK_EQ(state_, MODEL_STARTING);
98 notification_registrar_.Remove(this, 108 notification_registrar_.Remove(this,
99 NotificationType::HISTORY_LOADED, 109 NotificationType::HISTORY_LOADED,
100 NotificationService::AllSources()); 110 NotificationService::AllSources());
101
102 history_service_ = profile_->GetHistoryServiceWithoutCreating(); 111 history_service_ = profile_->GetHistoryServiceWithoutCreating();
103 DCHECK(history_service_.get()); 112 DCHECK(history_service_.get());
104 history_service_->ScheduleDBTask(new ControlTask(this, true), this); 113 state_ = ASSOCIATING;
114 KickOffAssociation();
105 } 115 }
106 116
107 // TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of 117 void TypedUrlDataTypeController::CleanUpState() {
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)); 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 DCHECK(state_ == STOPPING || state_ == NOT_RUNNING);
120 notification_registrar_.RemoveAll();
121 }
115 122
116 // If Stop() is called while Start() is waiting for association to 123 bool TypedUrlDataTypeController::KickOffDestroy() {
117 // complete, we need to abort the association and wait for the DB 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118 // thread to finish the StartImpl() task. 125 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()); 126 DCHECK(history_service_.get());
143 history_service_->ScheduleDBTask(new ControlTask(this, false), this); 127 history_service_->ScheduleDBTask(new ControlTask(this, false), this);
144 datatype_stopped_.Wait();
145 }
146
147 bool TypedUrlDataTypeController::enabled() {
148 return true; 128 return true;
149 } 129 }
150 130
151 syncable::ModelType TypedUrlDataTypeController::type() const { 131 syncable::ModelType TypedUrlDataTypeController::type() const {
152 return syncable::TYPED_URLS; 132 return syncable::TYPED_URLS;
153 } 133 }
154 134
155 browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() 135 browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group()
156 const { 136 const {
157 return browser_sync::GROUP_HISTORY; 137 return browser_sync::GROUP_HISTORY;
158 } 138 }
159 139
160 std::string TypedUrlDataTypeController::name() const { 140 void TypedUrlDataTypeController::RecordUnrecoverableError(
161 // For logging only. 141 const tracked_objects::Location& from_here,
162 return "typed_url"; 142 const std::string& message) {
143 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
144 UMA_HISTOGRAM_COUNTS("Sync.TypedUrlRunFailures", 1);
163 } 145 }
164 146
165 DataTypeController::State TypedUrlDataTypeController::state() const { 147 void TypedUrlDataTypeController::RecordAssociationTime(base::TimeDelta time) {
166 return state_; 148 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
149 UMA_HISTOGRAM_TIMES("Sync.TypedUrlAssociationTime", time);
167 } 150 }
168 151
169 void TypedUrlDataTypeController::StartImpl(history::HistoryBackend* backend) { 152 void TypedUrlDataTypeController::RecordStartFailure(StartResult result) {
170 VLOG(1) << "TypedUrl data type controller StartImpl called."; 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
171 // No additional services need to be started before we can proceed 154 UMA_HISTOGRAM_ENUMERATION("Sync.TypedUrlStartFailures",
172 // with model association. 155 result,
173 { 156 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 } 157 }
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 158 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698