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

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

Issue 553015: Support for multiple sync ModelSafeWorkers.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 11 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) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "build/build_config.h" 5 #include "build/build_config.h"
6 #include "base/file_util.h" 6 #include "base/file_util.h"
7 #include "base/file_version_info.h" 7 #include "base/file_version_info.h"
8 #include "base/utf_string_conversions.h" 8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/chrome_thread.h" 9 #include "chrome/browser/chrome_thread.h"
10 #include "chrome/browser/sync/glue/change_processor.h" 10 #include "chrome/browser/sync/glue/change_processor.h"
11 #include "chrome/browser/sync/glue/sync_backend_host.h" 11 #include "chrome/browser/sync/glue/sync_backend_host.h"
12 #include "chrome/browser/sync/glue/http_bridge.h" 12 #include "chrome/browser/sync/glue/http_bridge.h"
13 #include "chrome/browser/sync/glue/bookmark_model_worker.h"
14 #include "webkit/glue/webkit_glue.h" 13 #include "webkit/glue/webkit_glue.h"
15 14
16 static const int kSaveChangesIntervalSeconds = 10; 15 static const int kSaveChangesIntervalSeconds = 10;
17 static const char kGaiaServiceId[] = "chromiumsync"; 16 static const char kGaiaServiceId[] = "chromiumsync";
18 static const char kGaiaSourceForChrome[] = "ChromiumBrowser"; 17 static const char kGaiaSourceForChrome[] = "ChromiumBrowser";
19 static const FilePath::CharType kSyncDataFolderName[] = 18 static const FilePath::CharType kSyncDataFolderName[] =
20 FILE_PATH_LITERAL("Sync Data"); 19 FILE_PATH_LITERAL("Sync Data");
21 20
22 typedef GoogleServiceAuthError AuthError; 21 typedef GoogleServiceAuthError AuthError;
23 22
24 namespace browser_sync { 23 namespace browser_sync {
25 24
26 SyncBackendHost::SyncBackendHost(SyncFrontend* frontend, 25 SyncBackendHost::SyncBackendHost(SyncFrontend* frontend,
27 const FilePath& profile_path, 26 const FilePath& profile_path,
28 std::set<ChangeProcessor*> processors) 27 std::set<ChangeProcessor*> processors)
29 : core_thread_("Chrome_SyncCoreThread"), 28 : core_thread_("Chrome_SyncCoreThread"),
30 frontend_loop_(MessageLoop::current()), 29 frontend_loop_(MessageLoop::current()),
31 bookmark_model_worker_(NULL),
32 frontend_(frontend), 30 frontend_(frontend),
33 processors_(processors), 31 processors_(processors),
34 sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)), 32 sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)),
35 last_auth_error_(AuthError::None()) { 33 last_auth_error_(AuthError::None()) {
34
35 // Init our registrar state.
36 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; i++)
37 registrar_.workers[i] = NULL;
38
39 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; i++) {
40 syncable::ModelType t(syncable::ModelTypeFromInt(i));
41 registrar_.routing_info[t] = GROUP_PASSIVE; // Init to syncing 0 types.
42 }
43
36 core_ = new Core(this); 44 core_ = new Core(this);
37 } 45 }
38 46
39 SyncBackendHost::~SyncBackendHost() { 47 SyncBackendHost::~SyncBackendHost() {
40 DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor."; 48 DCHECK(!core_ && !frontend_) << "Must call Shutdown before destructor.";
49
50 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; ++i)
51 DCHECK(registrar_.workers[i] == NULL);
41 } 52 }
42 53
43 void SyncBackendHost::Initialize( 54 void SyncBackendHost::Initialize(
44 const GURL& sync_service_url, 55 const GURL& sync_service_url,
45 URLRequestContextGetter* baseline_context_getter, 56 URLRequestContextGetter* baseline_context_getter,
46 const std::string& lsid) { 57 const std::string& lsid) {
47 if (!core_thread_.Start()) 58 if (!core_thread_.Start())
48 return; 59 return;
49 bookmark_model_worker_ = new BookmarkModelWorker(frontend_loop_); 60
61 // Create a worker for the UI thread and route bookmark changes to it.
62 // TODO(tim): Pull this into a method to reuse. For now we don't even
63 // need to lock because we init before the syncapi exists and we tear down
64 // after the syncapi is destroyed. Make sure to NULL-check workers_ indices
65 // when a new type is synced as the worker may already exist and you just
66 // need to update routing_info_.
67 registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_);
68 registrar_.routing_info[syncable::BOOKMARKS] = GROUP_UI;
50 69
51 core_thread_.message_loop()->PostTask(FROM_HERE, 70 core_thread_.message_loop()->PostTask(FROM_HERE,
52 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize, 71 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
53 sync_service_url, bookmark_model_worker_, true, 72 sync_service_url, true,
54 new HttpBridgeFactory(baseline_context_getter), 73 new HttpBridgeFactory(baseline_context_getter),
55 new HttpBridgeFactory(baseline_context_getter), 74 new HttpBridgeFactory(baseline_context_getter),
56 lsid)); 75 lsid));
57 } 76 }
58 77
59 void SyncBackendHost::Authenticate(const std::string& username, 78 void SyncBackendHost::Authenticate(const std::string& username,
60 const std::string& password, 79 const std::string& password,
61 const std::string& captcha) { 80 const std::string& captcha) {
62 core_thread_.message_loop()->PostTask(FROM_HERE, 81 core_thread_.message_loop()->PostTask(FROM_HERE,
63 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate, 82 NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate,
64 username, password, captcha)); 83 username, password, captcha));
65 } 84 }
66 85
67 void SyncBackendHost::Shutdown(bool sync_disabled) { 86 void SyncBackendHost::Shutdown(bool sync_disabled) {
68 // Thread shutdown should occur in the following order: 87 // Thread shutdown should occur in the following order:
69 // - SyncerThread 88 // - SyncerThread
70 // - CoreThread 89 // - CoreThread
71 // - UI Thread (stops some time after we return from this call). 90 // - UI Thread (stops some time after we return from this call).
72 core_thread_.message_loop()->PostTask(FROM_HERE, 91 core_thread_.message_loop()->PostTask(FROM_HERE,
73 NewRunnableMethod(core_.get(), 92 NewRunnableMethod(core_.get(),
74 &SyncBackendHost::Core::DoShutdown, 93 &SyncBackendHost::Core::DoShutdown,
75 sync_disabled)); 94 sync_disabled));
76 95
77 // Before joining the core_thread_, we wait for the BookmarkModelWorker to 96 // Before joining the core_thread_, we wait for the UIModelWorker to
78 // give us the green light that it is not depending on the frontend_loop_ to 97 // give us the green light that it is not depending on the frontend_loop_ to
79 // process any more tasks. Stop() blocks until this termination condition 98 // process any more tasks. Stop() blocks until this termination condition
80 // is true. 99 // is true.
81 bookmark_model_worker_->Stop(); 100 if (ui_worker())
101 ui_worker()->Stop();
82 102
83 // Stop will return once the thread exits, which will be after DoShutdown 103 // Stop will return once the thread exits, which will be after DoShutdown
84 // runs. DoShutdown needs to run from core_thread_ because the sync backend 104 // runs. DoShutdown needs to run from core_thread_ because the sync backend
85 // requires any thread that opened sqlite handles to relinquish them 105 // requires any thread that opened sqlite handles to relinquish them
86 // personally. We need to join threads, because otherwise the main Chrome 106 // personally. We need to join threads, because otherwise the main Chrome
87 // thread (ui loop) can exit before DoShutdown finishes, at which point 107 // thread (ui loop) can exit before DoShutdown finishes, at which point
88 // virtually anything the sync backend does (or the post-back to 108 // virtually anything the sync backend does (or the post-back to
89 // frontend_loop_ by our Core) will epically fail because the CRT won't be 109 // frontend_loop_ by our Core) will epically fail because the CRT won't be
90 // initialized. For now this only ever happens at sync-enabled-Chrome exit, 110 // initialized. For now this only ever happens at sync-enabled-Chrome exit,
91 // meaning bug 1482548 applies to prolonged "waiting" that may occur in 111 // meaning bug 1482548 applies to prolonged "waiting" that may occur in
92 // DoShutdown. 112 // DoShutdown.
93 core_thread_.Stop(); 113 core_thread_.Stop();
94 114
95 bookmark_model_worker_ = NULL; 115 registrar_.routing_info.clear();
116 delete registrar_.workers[GROUP_UI];
117 registrar_.workers[GROUP_UI] = NULL;
96 frontend_ = NULL; 118 frontend_ = NULL;
97 core_ = NULL; // Releases reference to core_. 119 core_ = NULL; // Releases reference to core_.
98 } 120 }
99 121
100 void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) { 122 void SyncBackendHost::Core::NotifyFrontend(FrontendNotification notification) {
101 if (!host_ || !host_->frontend_) { 123 if (!host_ || !host_->frontend_) {
102 return; // This can happen in testing because the UI loop processes tasks 124 return; // This can happen in testing because the UI loop processes tasks
103 // after an instance of SyncBackendHost was destroyed. In real 125 // after an instance of SyncBackendHost was destroyed. In real
104 // life this doesn't happen. 126 // life this doesn't happen.
105 } 127 }
(...skipping 20 matching lines...) Expand all
126 } 148 }
127 149
128 string16 SyncBackendHost::GetAuthenticatedUsername() const { 150 string16 SyncBackendHost::GetAuthenticatedUsername() const {
129 return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername()); 151 return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername());
130 } 152 }
131 153
132 const GoogleServiceAuthError& SyncBackendHost::GetAuthError() const { 154 const GoogleServiceAuthError& SyncBackendHost::GetAuthError() const {
133 return last_auth_error_; 155 return last_auth_error_;
134 } 156 }
135 157
158 void SyncBackendHost::GetWorkers(std::vector<ModelSafeWorker*>* out) {
159 AutoLock lock(registrar_lock_);
160 out->clear();
161 for (int i = 0; i < MODEL_SAFE_GROUP_COUNT; i++) {
162 if (registrar_.workers[i] == NULL)
163 continue;
164 out->push_back(registrar_.workers[i]);
165 }
166 }
167
168 void SyncBackendHost::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
169 AutoLock lock(registrar_lock_);
170 ModelSafeRoutingInfo copy(registrar_.routing_info);
171 out->swap(copy);
172 }
173
136 SyncBackendHost::Core::Core(SyncBackendHost* backend) 174 SyncBackendHost::Core::Core(SyncBackendHost* backend)
137 : host_(backend), 175 : host_(backend),
138 syncapi_(new sync_api::SyncManager()) { 176 syncapi_(new sync_api::SyncManager()) {
139 } 177 }
140 178
141 // Helper to construct a user agent string (ASCII) suitable for use by 179 // Helper to construct a user agent string (ASCII) suitable for use by
142 // the syncapi for any HTTP communication. This string is used by the sync 180 // the syncapi for any HTTP communication. This string is used by the sync
143 // backend for classifying client types when calculating statistics. 181 // backend for classifying client types when calculating statistics.
144 std::string MakeUserAgentForSyncapi() { 182 std::string MakeUserAgentForSyncapi() {
145 std::string user_agent; 183 std::string user_agent;
(...skipping 14 matching lines...) Expand all
160 198
161 user_agent += WideToASCII(version_info->product_version()); 199 user_agent += WideToASCII(version_info->product_version());
162 user_agent += " (" + WideToASCII(version_info->last_change()) + ")"; 200 user_agent += " (" + WideToASCII(version_info->last_change()) + ")";
163 if (!version_info->is_official_build()) 201 if (!version_info->is_official_build())
164 user_agent += "-devel"; 202 user_agent += "-devel";
165 return user_agent; 203 return user_agent;
166 } 204 }
167 205
168 void SyncBackendHost::Core::DoInitialize( 206 void SyncBackendHost::Core::DoInitialize(
169 const GURL& service_url, 207 const GURL& service_url,
170 BookmarkModelWorker* bookmark_model_worker,
171 bool attempt_last_user_authentication, 208 bool attempt_last_user_authentication,
172 sync_api::HttpPostProviderFactory* http_provider_factory, 209 sync_api::HttpPostProviderFactory* http_provider_factory,
173 sync_api::HttpPostProviderFactory* auth_http_provider_factory, 210 sync_api::HttpPostProviderFactory* auth_http_provider_factory,
174 const std::string& lsid) { 211 const std::string& lsid) {
175 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); 212 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
176 213
177 // Make sure that the directory exists before initializing the backend. 214 // Make sure that the directory exists before initializing the backend.
178 // If it already exists, this will do no harm. 215 // If it already exists, this will do no harm.
179 bool success = file_util::CreateDirectory(host_->sync_data_folder_path()); 216 bool success = file_util::CreateDirectory(host_->sync_data_folder_path());
180 DCHECK(success); 217 DCHECK(success);
181 218
182 syncapi_->SetObserver(this); 219 syncapi_->SetObserver(this);
183 const FilePath& path_str = host_->sync_data_folder_path(); 220 const FilePath& path_str = host_->sync_data_folder_path();
184 success = syncapi_->Init(path_str, 221 success = syncapi_->Init(path_str,
185 (service_url.host() + service_url.path()).c_str(), 222 (service_url.host() + service_url.path()).c_str(),
186 service_url.EffectiveIntPort(), 223 service_url.EffectiveIntPort(),
187 kGaiaServiceId, 224 kGaiaServiceId,
188 kGaiaSourceForChrome, 225 kGaiaSourceForChrome,
189 service_url.SchemeIsSecure(), 226 service_url.SchemeIsSecure(),
190 http_provider_factory, 227 http_provider_factory,
191 auth_http_provider_factory, 228 auth_http_provider_factory,
192 bookmark_model_worker, 229 host_, // ModelSafeWorkerRegistrar.
193 attempt_last_user_authentication, 230 attempt_last_user_authentication,
194 MakeUserAgentForSyncapi().c_str(), 231 MakeUserAgentForSyncapi().c_str(),
195 lsid.c_str()); 232 lsid.c_str());
196 DCHECK(success) << "Syncapi initialization failed!"; 233 DCHECK(success) << "Syncapi initialization failed!";
197 } 234 }
198 235
199 void SyncBackendHost::Core::DoAuthenticate(const std::string& username, 236 void SyncBackendHost::Core::DoAuthenticate(const std::string& username,
200 const std::string& password, 237 const std::string& password,
201 const std::string& captcha) { 238 const std::string& captcha) {
202 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); 239 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
203 syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str()); 240 syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str());
204 } 241 }
205 242
243 UIModelWorker* SyncBackendHost::ui_worker() {
244 ModelSafeWorker* w = registrar_.workers[GROUP_UI];
245 if (w == NULL)
246 return NULL;
247 if (w->GetModelSafeGroup() != GROUP_UI)
248 NOTREACHED();
249 return static_cast<UIModelWorker*>(w);
250 }
251
206 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) { 252 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
207 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop()); 253 DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
208 254
209 save_changes_timer_.Stop(); 255 save_changes_timer_.Stop();
210 syncapi_->Shutdown(); // Stops the SyncerThread. 256 syncapi_->Shutdown(); // Stops the SyncerThread.
211 syncapi_->RemoveObserver(); 257 syncapi_->RemoveObserver();
212 host_->bookmark_model_worker_->OnSyncerShutdownComplete(); 258 host_->ui_worker()->OnSyncerShutdownComplete();
213 259
214 if (sync_disabled && 260 if (sync_disabled &&
215 file_util::DirectoryExists(host_->sync_data_folder_path())) { 261 file_util::DirectoryExists(host_->sync_data_folder_path())) {
216 // Delete the sync data folder to cleanup backend data. 262 // Delete the sync data folder to cleanup backend data.
217 bool success = file_util::Delete(host_->sync_data_folder_path(), true); 263 bool success = file_util::Delete(host_->sync_data_folder_path(), true);
218 DCHECK(success); 264 DCHECK(success);
219 } 265 }
220 266
221 host_ = NULL; 267 host_ = NULL;
222 } 268 }
223 269
224 void SyncBackendHost::Core::OnChangesApplied( 270 void SyncBackendHost::Core::OnChangesApplied(
225 const sync_api::BaseTransaction* trans, 271 const sync_api::BaseTransaction* trans,
226 const sync_api::SyncManager::ChangeRecord* changes, 272 const sync_api::SyncManager::ChangeRecord* changes,
227 int change_count) { 273 int change_count) {
228 if (!host_ || !host_->frontend_) { 274 if (!host_ || !host_->frontend_) {
229 DCHECK(false) << "OnChangesApplied called after Shutdown?"; 275 DCHECK(false) << "OnChangesApplied called after Shutdown?";
230 return; 276 return;
231 } 277 }
232 278
233 // ChangesApplied is the one exception that should come over from the sync 279 // ChangesApplied is the one exception that should come over from the sync
234 // backend already on the service_loop_ thanks to our BookmarkModelWorker. 280 // backend already on the service_loop_ thanks to our UIModelWorker.
235 // SyncFrontend changes exclusively on the UI loop, because it updates 281 // SyncFrontend changes exclusively on the UI loop, because it updates
236 // the bookmark model. As such, we don't need to worry about changes that 282 // the bookmark model. As such, we don't need to worry about changes that
237 // have been made to the bookmark model but not yet applied to the sync 283 // have been made to the bookmark model but not yet applied to the sync
238 // model -- such changes only happen on the UI loop, and there's no 284 // model -- such changes only happen on the UI loop, and there's no
239 // contention. 285 // contention.
240 if (host_->frontend_loop_ != MessageLoop::current()) { 286 if (host_->frontend_loop_ != MessageLoop::current()) {
241 // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters 287 // TODO(ncarter): Bug 1480644. Make this a DCHECK once syncapi filters
242 // out all irrelevant changes. 288 // out all irrelevant changes.
243 DLOG(WARNING) << "Could not update bookmark model from non-UI thread"; 289 DLOG(WARNING) << "Could not update bookmark model from non-UI thread";
244 return; 290 return;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 save_changes_timer_.Start( 340 save_changes_timer_.Start(
295 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), 341 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
296 this, &Core::SaveChanges); 342 this, &Core::SaveChanges);
297 } 343 }
298 344
299 void SyncBackendHost::Core::SaveChanges() { 345 void SyncBackendHost::Core::SaveChanges() {
300 syncapi_->SaveChanges(); 346 syncapi_->SaveChanges();
301 } 347 }
302 348
303 } // namespace browser_sync 349 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/sync_backend_host.h ('k') | chrome/browser/sync/glue/ui_model_worker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698