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

Side by Side Diff: components/webdata/common/web_database_service.cc

Issue 14103021: Use Observer to notify of WebDB load instead of callbacks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix WIN builds Created 7 years, 7 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
« no previous file with comments | « components/webdata/common/web_database_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "components/webdata/common/web_database_service.h" 5 #include "components/webdata/common/web_database_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/memory/scoped_vector.h"
10 #include "components/webdata/common/web_data_request_manager.h" 9 #include "components/webdata/common/web_data_request_manager.h"
11 #include "components/webdata/common/web_data_results.h" 10 #include "components/webdata/common/web_data_results.h"
11 #include "components/webdata/common/web_data_service_backend.h"
12 #include "components/webdata/common/web_data_service_consumer.h" 12 #include "components/webdata/common/web_data_service_consumer.h"
13 13
14 using base::Bind; 14 using base::Bind;
15 using base::FilePath; 15 using base::FilePath;
16 using content::BrowserThread; 16 using content::BrowserThread;
17 17
18 18 // Receives messages from the backend on the DB thread, posts them to
19 //////////////////////////////////////////////////////////////////////////////// 19 // WebDatabaseService on the UI thread.
20 // 20 class WebDatabaseService::BackendDelegate :
21 // WebDataServiceBackend implementation. 21 public WebDataServiceBackend::Delegate {
22 //
23 ////////////////////////////////////////////////////////////////////////////////
24
25 // Refcounted to allow asynchronous destruction on the DB thread.
26 class WebDataServiceBackend
27 : public base::RefCountedThreadSafe<WebDataServiceBackend,
28 BrowserThread::DeleteOnDBThread> {
29 public: 22 public:
30 explicit WebDataServiceBackend(const FilePath& path); 23 BackendDelegate(
31 24 const base::WeakPtr<WebDatabaseService>& web_database_service)
32 // Must call only before InitDatabaseWithCallback. 25 : web_database_service_(web_database_service) {
33 void AddTable(scoped_ptr<WebDatabaseTable> table);
34
35 // Initializes the database and notifies caller via callback when complete.
36 // Callback is called synchronously.
37 void InitDatabaseWithCallback(
38 const WebDatabaseService::InitCallback& callback);
39
40 // Opens the database file from the profile path if an init has not yet been
41 // attempted. Separated from the constructor to ease construction/destruction
42 // of this object on one thread but database access on the DB thread. Returns
43 // the status of the database.
44 sql::InitStatus LoadDatabaseIfNecessary();
45
46 // Shuts down database. |should_reinit| tells us whether or not it should be
47 // possible to re-initialize the DB after the shutdown.
48 void ShutdownDatabase(bool should_reinit);
49
50 // Task wrappers to run database tasks.
51 void DBWriteTaskWrapper(
52 const WebDatabaseService::WriteTask& task,
53 scoped_ptr<WebDataRequest> request);
54 void DBReadTaskWrapper(
55 const WebDatabaseService::ReadTask& task,
56 scoped_ptr<WebDataRequest> request);
57
58 const scoped_refptr<WebDataRequestManager>& request_manager() {
59 return request_manager_;
60 } 26 }
61 27
62 WebDatabase* database() { return db_.get(); } 28 virtual void DBLoaded(sql::InitStatus status) OVERRIDE {
63 29 BrowserThread::PostTask(
30 BrowserThread::UI,
31 FROM_HERE,
32 base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
33 web_database_service_,
34 status));
35 }
64 private: 36 private:
65 friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>; 37 const base::WeakPtr<WebDatabaseService> web_database_service_;
66 friend class base::DeleteHelper<WebDataServiceBackend>;
67
68 virtual ~WebDataServiceBackend();
69
70 // Commit the current transaction.
71 void Commit();
72
73 // Path to database file.
74 FilePath db_path_;
75
76 // The tables that participate in managing the database. These are
77 // owned here but other than that this class does nothing with
78 // them. Their initialization is in whatever factory creates
79 // WebDatabaseService, and lookup by type is provided by the
80 // WebDatabase class. The tables need to be owned by this refcounted
81 // object, or they themselves would need to be refcounted. Owning
82 // them here rather than having WebDatabase own them makes for
83 // easier unit testing of WebDatabase.
84 ScopedVector<WebDatabaseTable> tables_;
85
86 scoped_ptr<WebDatabase> db_;
87
88 // Keeps track of all pending requests made to the db.
89 scoped_refptr<WebDataRequestManager> request_manager_;
90
91 // State of database initialization. Used to prevent the executing of tasks
92 // before the db is ready.
93 sql::InitStatus init_status_;
94
95 // True if an attempt has been made to load the database (even if the attempt
96 // fails), used to avoid continually trying to reinit if the db init fails.
97 bool init_complete_;
98
99 DISALLOW_COPY_AND_ASSIGN(WebDataServiceBackend);
100 }; 38 };
101 39
102 WebDataServiceBackend::WebDataServiceBackend(
103 const FilePath& path)
104 : db_path_(path),
105 request_manager_(new WebDataRequestManager()),
106 init_status_(sql::INIT_FAILURE),
107 init_complete_(false) {
108 }
109
110 void WebDataServiceBackend::AddTable(scoped_ptr<WebDatabaseTable> table) {
111 DCHECK(!db_.get());
112 tables_.push_back(table.release());
113 }
114
115 void WebDataServiceBackend::InitDatabaseWithCallback(
116 const WebDatabaseService::InitCallback& callback) {
117 if (!callback.is_null()) {
118 callback.Run(LoadDatabaseIfNecessary());
119 }
120 }
121
122 sql::InitStatus WebDataServiceBackend::LoadDatabaseIfNecessary() {
123 if (init_complete_ || db_path_.empty()) {
124 return init_status_;
125 }
126 init_complete_ = true;
127 db_.reset(new WebDatabase());
128
129 for (ScopedVector<WebDatabaseTable>::iterator it = tables_.begin();
130 it != tables_.end();
131 ++it) {
132 db_->AddTable(*it);
133 }
134
135 init_status_ = db_->Init(db_path_);
136 if (init_status_ != sql::INIT_OK) {
137 LOG(ERROR) << "Cannot initialize the web database: " << init_status_;
138 db_.reset(NULL);
139 return init_status_;
140 }
141
142 db_->BeginTransaction();
143 return init_status_;
144 }
145
146 void WebDataServiceBackend::ShutdownDatabase(bool should_reinit) {
147 if (db_ && init_status_ == sql::INIT_OK)
148 db_->CommitTransaction();
149 db_.reset(NULL);
150 init_complete_ = !should_reinit; // Setting init_complete_ to true will ensure
151 // that the init sequence is not re-run.
152
153 init_status_ = sql::INIT_FAILURE;
154 }
155
156 void WebDataServiceBackend::DBWriteTaskWrapper(
157 const WebDatabaseService::WriteTask& task,
158 scoped_ptr<WebDataRequest> request) {
159 LoadDatabaseIfNecessary();
160 if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) {
161 WebDatabase::State state = task.Run(db_.get());
162 if (state == WebDatabase::COMMIT_NEEDED)
163 Commit();
164 }
165 request_manager_->RequestCompleted(request.Pass());
166 }
167
168 void WebDataServiceBackend::DBReadTaskWrapper(
169 const WebDatabaseService::ReadTask& task,
170 scoped_ptr<WebDataRequest> request) {
171 LoadDatabaseIfNecessary();
172 if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) {
173 request->SetResult(task.Run(db_.get()).Pass());
174 }
175 request_manager_->RequestCompleted(request.Pass());
176 }
177
178 WebDataServiceBackend::~WebDataServiceBackend() {
179 ShutdownDatabase(false);
180 }
181
182 void WebDataServiceBackend::Commit() {
183 if (db_ && init_status_ == sql::INIT_OK) {
184 db_->CommitTransaction();
185 db_->BeginTransaction();
186 } else {
187 NOTREACHED() << "Commit scheduled after Shutdown()";
188 }
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////
192 WebDatabaseService::WebDatabaseService( 40 WebDatabaseService::WebDatabaseService(
193 const base::FilePath& path) 41 const base::FilePath& path)
194 : path_(path) { 42 : path_(path),
43 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
195 // WebDatabaseService should be instantiated on UI thread. 44 // WebDatabaseService should be instantiated on UI thread.
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
197 // WebDatabaseService requires DB thread if instantiated. 46 // WebDatabaseService requires DB thread if instantiated.
198 DCHECK(BrowserThread::IsWellKnownThread(BrowserThread::DB)); 47 DCHECK(BrowserThread::IsWellKnownThread(BrowserThread::DB));
199 } 48 }
200 49
201 WebDatabaseService::~WebDatabaseService() { 50 WebDatabaseService::~WebDatabaseService() {
202 } 51 }
203 52
204 void WebDatabaseService::AddTable(scoped_ptr<WebDatabaseTable> table) { 53 void WebDatabaseService::AddTable(scoped_ptr<WebDatabaseTable> table) {
205 if (!wds_backend_) { 54 if (!wds_backend_) {
206 wds_backend_ = new WebDataServiceBackend(path_); 55 wds_backend_ = new WebDataServiceBackend(
56 path_, new BackendDelegate(weak_ptr_factory_.GetWeakPtr()));
207 } 57 }
208 wds_backend_->AddTable(table.Pass()); 58 wds_backend_->AddTable(table.Pass());
209 } 59 }
210 60
211 void WebDatabaseService::LoadDatabase(const InitCallback& callback) { 61 void WebDatabaseService::LoadDatabase() {
212 DCHECK(wds_backend_); 62 DCHECK(wds_backend_);
213 63
214 BrowserThread::PostTask( 64 BrowserThread::PostTask(
215 BrowserThread::DB, 65 BrowserThread::DB,
216 FROM_HERE, 66 FROM_HERE,
217 Bind(&WebDataServiceBackend::InitDatabaseWithCallback, 67 Bind(&WebDataServiceBackend::InitDatabase, wds_backend_));
218 wds_backend_, callback));
219 } 68 }
220 69
221 void WebDatabaseService::UnloadDatabase() { 70 void WebDatabaseService::UnloadDatabase() {
222 if (!wds_backend_) 71 if (!wds_backend_)
223 return; 72 return;
224 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 73 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
225 Bind(&WebDataServiceBackend::ShutdownDatabase, 74 Bind(&WebDataServiceBackend::ShutdownDatabase,
226 wds_backend_, true)); 75 wds_backend_, true));
227 } 76 }
228 77
229 void WebDatabaseService::ShutdownDatabase() { 78 void WebDatabaseService::ShutdownDatabase() {
230 if (!wds_backend_) 79 if (!wds_backend_)
231 return; 80 return;
81 weak_ptr_factory_.InvalidateWeakPtrs();
232 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 82 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
233 Bind(&WebDataServiceBackend::ShutdownDatabase, 83 Bind(&WebDataServiceBackend::ShutdownDatabase,
234 wds_backend_, false)); 84 wds_backend_, false));
235 } 85 }
236 86
237 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { 87 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
239 if (!wds_backend_) 89 if (!wds_backend_)
240 return NULL; 90 return NULL;
241 return wds_backend_->database(); 91 return wds_backend_->database();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 task, base::Passed(&request))); 128 task, base::Passed(&request)));
279 129
280 return handle; 130 return handle;
281 } 131 }
282 132
283 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { 133 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
284 if (!wds_backend_) 134 if (!wds_backend_)
285 return; 135 return;
286 wds_backend_->request_manager()->CancelRequest(h); 136 wds_backend_->request_manager()->CancelRequest(h);
287 } 137 }
138
139 void WebDatabaseService::AddObserver(WebDatabaseObserver* observer) {
140 observer_list_.AddObserver(observer);
141 }
142
143 void WebDatabaseService::RemoveObserver(WebDatabaseObserver* observer) {
144 observer_list_.RemoveObserver(observer);
145 }
146
147 void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status) {
148 if (status == sql::INIT_OK) {
149 // Notify that the database has been initialized.
150 FOR_EACH_OBSERVER(WebDatabaseObserver,
151 observer_list_,
152 WebDatabaseLoaded());
153 } else {
154 // Notify that the database load failed.
155 FOR_EACH_OBSERVER(WebDatabaseObserver,
156 observer_list_,
157 WebDatabaseLoadFailed(status));
158 }
159 }
OLDNEW
« no previous file with comments | « components/webdata/common/web_database_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698