OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/webdata/web_database_service.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/location.h" |
| 9 #include "chrome/browser/api/webdata/web_data_results.h" |
| 10 #include "chrome/browser/api/webdata/web_data_service_consumer.h" |
| 11 #include "chrome/browser/webdata/web_data_request_manager.h" |
| 12 #include "chrome/browser/webdata/web_data_service.h" |
| 13 // TODO(caitkp): Remove this autofill dependency. |
| 14 #include "components/autofill/browser/autofill_country.h" |
| 15 |
| 16 using base::Bind; |
| 17 using base::FilePath; |
| 18 using content::BrowserThread; |
| 19 |
| 20 |
| 21 //////////////////////////////////////////////////////////////////////////////// |
| 22 // |
| 23 // WebDataServiceBackend implementation. |
| 24 // |
| 25 //////////////////////////////////////////////////////////////////////////////// |
| 26 |
| 27 // Refcounted to allow asynchronous destruction on the DB thread. |
| 28 class WebDataServiceBackend |
| 29 : public base::RefCountedThreadSafe<WebDataServiceBackend, |
| 30 BrowserThread::DeleteOnDBThread> { |
| 31 public: |
| 32 explicit WebDataServiceBackend(const FilePath& path); |
| 33 |
| 34 // Initializes the database and notifies caller via callback when complete. |
| 35 // Callback is called synchronously. |
| 36 void InitDatabaseWithCallback( |
| 37 const WebDatabaseService::InitCallback& callback); |
| 38 |
| 39 // Opens the database file from the profile path if an init has not yet been |
| 40 // attempted. Separated from the constructor to ease construction/destruction |
| 41 // of this object on one thread but database access on the DB thread. Returns |
| 42 // the status of the database. |
| 43 sql::InitStatus LoadDatabaseIfNecessary(); |
| 44 |
| 45 // Shuts down database. |should_reinit| tells us whether or not it should be |
| 46 // possible to re-initialize the DB after the shutdown. |
| 47 void ShutdownDatabase(bool should_reinit); |
| 48 |
| 49 // Task wrappers to run database tasks. |
| 50 void DBWriteTaskWrapper( |
| 51 const WebDatabaseService::WriteTask& task, |
| 52 scoped_ptr<WebDataRequest> request); |
| 53 void DBReadTaskWrapper( |
| 54 const WebDatabaseService::ReadTask& task, |
| 55 scoped_ptr<WebDataRequest> request); |
| 56 |
| 57 const scoped_refptr<WebDataRequestManager>& request_manager() { |
| 58 return request_manager_; |
| 59 } |
| 60 |
| 61 WebDatabase* database() { return db_.get(); } |
| 62 |
| 63 private: |
| 64 friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>; |
| 65 friend class base::DeleteHelper<WebDataServiceBackend>; |
| 66 |
| 67 virtual ~WebDataServiceBackend(); |
| 68 |
| 69 // Commit the current transaction. |
| 70 void Commit(); |
| 71 |
| 72 // Path to database file. |
| 73 FilePath db_path_; |
| 74 |
| 75 scoped_ptr<WebDatabase> db_; |
| 76 |
| 77 // Keeps track of all pending requests made to the db. |
| 78 scoped_refptr<WebDataRequestManager> request_manager_; |
| 79 |
| 80 // State of database initialization. Used to prevent the executing of tasks |
| 81 // before the db is ready. |
| 82 sql::InitStatus init_status_; |
| 83 |
| 84 // True if an attempt has been made to load the database (even if the attempt |
| 85 // fails), used to avoid continually trying to reinit if the db init fails. |
| 86 bool init_complete_; |
| 87 |
| 88 // The application locale. The locale is needed for some database migrations, |
| 89 // and must be read on the UI thread. It's cached here so that we can pass it |
| 90 // to the migration code on the DB thread. |
| 91 const std::string app_locale_; |
| 92 |
| 93 DISALLOW_COPY_AND_ASSIGN(WebDataServiceBackend); |
| 94 }; |
| 95 |
| 96 WebDataServiceBackend::WebDataServiceBackend(const FilePath& path) |
| 97 : db_path_(path), |
| 98 request_manager_(new WebDataRequestManager()), |
| 99 init_status_(sql::INIT_FAILURE), |
| 100 init_complete_(false), |
| 101 app_locale_(AutofillCountry::ApplicationLocale()) { |
| 102 } |
| 103 |
| 104 void WebDataServiceBackend::InitDatabaseWithCallback( |
| 105 const WebDatabaseService::InitCallback& callback) { |
| 106 if (!callback.is_null()) { |
| 107 callback.Run(LoadDatabaseIfNecessary()); |
| 108 } |
| 109 } |
| 110 |
| 111 sql::InitStatus WebDataServiceBackend::LoadDatabaseIfNecessary() { |
| 112 if (init_complete_ || db_path_.empty()) { |
| 113 return init_status_; |
| 114 } |
| 115 init_complete_ = true; |
| 116 db_.reset(new WebDatabase()); |
| 117 init_status_ = db_->Init(db_path_, app_locale_); |
| 118 if (init_status_ != sql::INIT_OK) { |
| 119 LOG(ERROR) << "Cannot initialize the web database: " << init_status_; |
| 120 db_.reset(NULL); |
| 121 return init_status_; |
| 122 } |
| 123 |
| 124 db_->BeginTransaction(); |
| 125 return init_status_; |
| 126 } |
| 127 |
| 128 void WebDataServiceBackend::ShutdownDatabase(bool should_reinit) { |
| 129 if (db_ && init_status_ == sql::INIT_OK) |
| 130 db_->CommitTransaction(); |
| 131 db_.reset(NULL); |
| 132 init_complete_ = !should_reinit; // Setting init_complete_ to true will ensure |
| 133 // that the init sequence is not re-run. |
| 134 |
| 135 init_status_ = sql::INIT_FAILURE; |
| 136 } |
| 137 |
| 138 void WebDataServiceBackend::DBWriteTaskWrapper( |
| 139 const WebDatabaseService::WriteTask& task, |
| 140 scoped_ptr<WebDataRequest> request) { |
| 141 LoadDatabaseIfNecessary(); |
| 142 if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) { |
| 143 WebDatabase::State state = task.Run(db_.get()); |
| 144 if (state == WebDatabase::COMMIT_NEEDED) |
| 145 Commit(); |
| 146 } |
| 147 request_manager_->RequestCompleted(request.Pass()); |
| 148 } |
| 149 |
| 150 void WebDataServiceBackend::DBReadTaskWrapper( |
| 151 const WebDatabaseService::ReadTask& task, |
| 152 scoped_ptr<WebDataRequest> request) { |
| 153 LoadDatabaseIfNecessary(); |
| 154 if (db_ && init_status_ == sql::INIT_OK && !request->IsCancelled()) { |
| 155 request->SetResult(task.Run(db_.get()).Pass()); |
| 156 } |
| 157 request_manager_->RequestCompleted(request.Pass()); |
| 158 } |
| 159 |
| 160 WebDataServiceBackend::~WebDataServiceBackend() { |
| 161 ShutdownDatabase(false); |
| 162 } |
| 163 |
| 164 void WebDataServiceBackend::Commit() { |
| 165 if (db_ && init_status_ == sql::INIT_OK) { |
| 166 db_->CommitTransaction(); |
| 167 db_->BeginTransaction(); |
| 168 } else { |
| 169 NOTREACHED() << "Commit scheduled after Shutdown()"; |
| 170 } |
| 171 } |
| 172 |
| 173 //////////////////////////////////////////////////////////////////////////////// |
| 174 WebDatabaseService::WebDatabaseService(const base::FilePath& path) |
| 175 : path_(path) { |
| 176 // WebDatabaseService should be instantiated on UI thread. |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 178 // WebDatabaseService requires DB thread if instantiated. |
| 179 DCHECK(BrowserThread::IsWellKnownThread(BrowserThread::DB)); |
| 180 } |
| 181 |
| 182 WebDatabaseService::~WebDatabaseService() { |
| 183 } |
| 184 |
| 185 void WebDatabaseService::LoadDatabase(const InitCallback& callback) { |
| 186 if (!wds_backend_) |
| 187 wds_backend_ = new WebDataServiceBackend(path_); |
| 188 |
| 189 BrowserThread::PostTask( |
| 190 BrowserThread::DB, |
| 191 FROM_HERE, |
| 192 Bind(&WebDataServiceBackend::InitDatabaseWithCallback, |
| 193 wds_backend_, callback)); |
| 194 } |
| 195 |
| 196 void WebDatabaseService::UnloadDatabase() { |
| 197 if (!wds_backend_) |
| 198 return; |
| 199 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| 200 Bind(&WebDataServiceBackend::ShutdownDatabase, |
| 201 wds_backend_, true)); |
| 202 } |
| 203 |
| 204 void WebDatabaseService::ShutdownDatabase() { |
| 205 if (!wds_backend_) |
| 206 return; |
| 207 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| 208 Bind(&WebDataServiceBackend::ShutdownDatabase, |
| 209 wds_backend_, false)); |
| 210 } |
| 211 |
| 212 WebDatabase* WebDatabaseService::GetDatabaseOnDB() const { |
| 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 214 if (!wds_backend_) |
| 215 return NULL; |
| 216 return wds_backend_->database(); |
| 217 } |
| 218 |
| 219 void WebDatabaseService::ScheduleDBTask( |
| 220 const tracked_objects::Location& from_here, |
| 221 const WriteTask& task) { |
| 222 if (!wds_backend_) { |
| 223 NOTREACHED() << "Task scheduled after Shutdown()"; |
| 224 return; |
| 225 } |
| 226 |
| 227 scoped_ptr<WebDataRequest> request( |
| 228 new WebDataRequest(NULL, wds_backend_->request_manager())); |
| 229 |
| 230 BrowserThread::PostTask(BrowserThread::DB, from_here, |
| 231 Bind(&WebDataServiceBackend::DBWriteTaskWrapper, wds_backend_, |
| 232 task, base::Passed(&request))); |
| 233 } |
| 234 |
| 235 WebDataService::Handle WebDatabaseService::ScheduleDBTaskWithResult( |
| 236 const tracked_objects::Location& from_here, |
| 237 const ReadTask& task, |
| 238 WebDataServiceConsumer* consumer) { |
| 239 DCHECK(consumer); |
| 240 WebDataService::Handle handle = 0; |
| 241 |
| 242 if (!wds_backend_) { |
| 243 NOTREACHED() << "Task scheduled after Shutdown()"; |
| 244 return handle; |
| 245 } |
| 246 |
| 247 scoped_ptr<WebDataRequest> request( |
| 248 new WebDataRequest(consumer, wds_backend_->request_manager())); |
| 249 handle = request->GetHandle(); |
| 250 |
| 251 BrowserThread::PostTask(BrowserThread::DB, from_here, |
| 252 Bind(&WebDataServiceBackend::DBReadTaskWrapper, wds_backend_, |
| 253 task, base::Passed(&request))); |
| 254 |
| 255 return handle; |
| 256 } |
| 257 |
| 258 void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) { |
| 259 if (!wds_backend_) |
| 260 return; |
| 261 wds_backend_->request_manager()->CancelRequest(h); |
| 262 } |
OLD | NEW |