OLD | NEW |
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 Loading... |
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 } |
OLD | NEW |