| 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 |