OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "webkit/database/database_tracker.h" | 5 #include "webkit/database/database_tracker.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "app/sql/connection.h" | 9 #include "app/sql/connection.h" |
10 #include "app/sql/meta_table.h" | 10 #include "app/sql/meta_table.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 const int kCompatibleVersion = 1; | 29 const int kCompatibleVersion = 1; |
30 const int64 kDefaultExtensionQuota = 50 * 1024 * 1024; | 30 const int64 kDefaultExtensionQuota = 50 * 1024 * 1024; |
31 const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; | 31 const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; |
32 | 32 |
33 DatabaseTracker::DatabaseTracker(const FilePath& profile_path) | 33 DatabaseTracker::DatabaseTracker(const FilePath& profile_path) |
34 : initialized_(false), | 34 : initialized_(false), |
35 db_dir_(profile_path.Append(FilePath(kDatabaseDirectoryName))), | 35 db_dir_(profile_path.Append(FilePath(kDatabaseDirectoryName))), |
36 db_(new sql::Connection()), | 36 db_(new sql::Connection()), |
37 databases_table_(NULL), | 37 databases_table_(NULL), |
38 meta_table_(NULL), | 38 meta_table_(NULL), |
39 dbs_deleted_callback_(NULL), | |
40 default_quota_(5 * 1024 * 1024) { | 39 default_quota_(5 * 1024 * 1024) { |
41 } | 40 } |
42 | 41 |
43 DatabaseTracker::~DatabaseTracker() { | 42 DatabaseTracker::~DatabaseTracker() { |
44 DCHECK(observers_.size() == 0); | 43 DCHECK(observers_.size() == 0); |
45 DCHECK(dbs_to_be_deleted_.empty()); | 44 DCHECK(dbs_to_be_deleted_.empty()); |
46 DCHECK(!dbs_deleted_callback_); | 45 DCHECK(deletion_callbacks_.empty()); |
47 } | 46 } |
48 | 47 |
49 void DatabaseTracker::SetDefaultQuota(int64 quota) { | 48 void DatabaseTracker::SetDefaultQuota(int64 quota) { |
50 default_quota_ = quota; | 49 default_quota_ = quota; |
51 ClearAllCachedOriginInfo(); | 50 ClearAllCachedOriginInfo(); |
52 } | 51 } |
53 | 52 |
54 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, | 53 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, |
55 const string16& database_name, | 54 const string16& database_name, |
56 const string16& database_description, | 55 const string16& database_description, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 closed_dbs.begin(); it != closed_dbs.end(); ++it) { | 97 closed_dbs.begin(); it != closed_dbs.end(); ++it) { |
99 DeleteDatabaseIfNeeded(it->first, it->second); | 98 DeleteDatabaseIfNeeded(it->first, it->second); |
100 } | 99 } |
101 } | 100 } |
102 | 101 |
103 void DatabaseTracker::DeleteDatabaseIfNeeded(const string16& origin_identifier, | 102 void DatabaseTracker::DeleteDatabaseIfNeeded(const string16& origin_identifier, |
104 const string16& database_name) { | 103 const string16& database_name) { |
105 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier, | 104 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier, |
106 database_name)); | 105 database_name)); |
107 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) { | 106 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) { |
108 DeleteDatabase(origin_identifier, database_name); | 107 DeleteClosedDatabase(origin_identifier, database_name); |
109 dbs_to_be_deleted_[origin_identifier].erase(database_name); | 108 dbs_to_be_deleted_[origin_identifier].erase(database_name); |
110 if (dbs_to_be_deleted_[origin_identifier].empty()) | 109 if (dbs_to_be_deleted_[origin_identifier].empty()) |
111 dbs_to_be_deleted_.erase(origin_identifier); | 110 dbs_to_be_deleted_.erase(origin_identifier); |
112 if (dbs_to_be_deleted_.empty()) { | 111 |
113 DCHECK(dbs_deleted_callback_); | 112 std::vector<net::CompletionCallback*> to_be_deleted; |
114 dbs_deleted_callback_->Run(net::OK); | 113 for (PendingCompletionMap::iterator callback = deletion_callbacks_.begin(); |
115 dbs_deleted_callback_ = NULL; | 114 callback != deletion_callbacks_.end(); ++callback) { |
| 115 DatabaseSet::iterator found_origin = |
| 116 callback->second.find(origin_identifier); |
| 117 if (found_origin != callback->second.end()) { |
| 118 std::set<string16>& databases = found_origin->second; |
| 119 databases.erase(database_name); |
| 120 if (databases.empty()) { |
| 121 callback->second.erase(found_origin); |
| 122 if (callback->second.empty()) { |
| 123 net::CompletionCallback* cb = callback->first; |
| 124 cb->Run(net::OK); |
| 125 to_be_deleted.push_back(cb); |
| 126 } |
| 127 } |
| 128 } |
116 } | 129 } |
| 130 for (std::vector<net::CompletionCallback*>::iterator cb = |
| 131 to_be_deleted.begin(); cb != to_be_deleted.end(); ++cb) |
| 132 deletion_callbacks_.erase(*cb); |
117 } | 133 } |
118 } | 134 } |
119 | 135 |
120 void DatabaseTracker::AddObserver(Observer* observer) { | 136 void DatabaseTracker::AddObserver(Observer* observer) { |
121 observers_.AddObserver(observer); | 137 observers_.AddObserver(observer); |
122 } | 138 } |
123 | 139 |
124 void DatabaseTracker::RemoveObserver(Observer* observer) { | 140 void DatabaseTracker::RemoveObserver(Observer* observer) { |
125 // When we remove a listener, we do not know which cached information | 141 // When we remove a listener, we do not know which cached information |
126 // is still needed and which information can be discarded. So we just | 142 // is still needed and which information can be discarded. So we just |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 } | 194 } |
179 | 195 |
180 void DatabaseTracker::SetOriginQuota(const string16& origin_identifier, | 196 void DatabaseTracker::SetOriginQuota(const string16& origin_identifier, |
181 int64 new_quota) { | 197 int64 new_quota) { |
182 if (quota_table_->SetOriginQuota(origin_identifier, new_quota) && | 198 if (quota_table_->SetOriginQuota(origin_identifier, new_quota) && |
183 (origins_info_map_.find(origin_identifier) != origins_info_map_.end())) { | 199 (origins_info_map_.find(origin_identifier) != origins_info_map_.end())) { |
184 origins_info_map_[origin_identifier].SetQuota(new_quota); | 200 origins_info_map_[origin_identifier].SetQuota(new_quota); |
185 } | 201 } |
186 } | 202 } |
187 | 203 |
188 bool DatabaseTracker::DeleteDatabase(const string16& origin_identifier, | 204 bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier, |
189 const string16& database_name) { | 205 const string16& database_name) { |
190 // Check if the database is opened by any renderer. | 206 // Check if the database is opened by any renderer. |
191 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) | 207 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) |
192 return false; | 208 return false; |
193 | 209 |
194 // Try to delete the file on the hard drive. | 210 // Try to delete the file on the hard drive. |
195 // TODO(jochen): Delete directory if this was the last database. | |
196 // TODO(jochen): Delete journal files associated with this database. | 211 // TODO(jochen): Delete journal files associated with this database. |
197 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); | 212 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); |
198 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) | 213 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) |
199 return false; | 214 return false; |
200 | 215 |
201 // Clean up the main database and invalidate the cached record. | 216 // Clean up the main database and invalidate the cached record. |
202 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); | 217 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); |
203 origins_info_map_.erase(origin_identifier); | 218 origins_info_map_.erase(origin_identifier); |
| 219 |
| 220 // Try to delete the origin in case this was the last database. |
| 221 std::vector<DatabaseDetails> details; |
| 222 if (databases_table_->GetAllDatabaseDetailsForOrigin( |
| 223 origin_identifier, &details) && details.empty()) |
| 224 DeleteOrigin(origin_identifier); |
204 return true; | 225 return true; |
205 } | 226 } |
206 | 227 |
207 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { | 228 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { |
208 // Check if any database in this origin is opened by any renderer. | 229 // Check if any database in this origin is opened by any renderer. |
209 if (database_connections_.IsOriginUsed(origin_identifier)) | 230 if (database_connections_.IsOriginUsed(origin_identifier)) |
210 return false; | 231 return false; |
211 | 232 |
212 // We need to invalidate the cached record whether file_util::Delete() | 233 // We need to invalidate the cached record whether file_util::Delete() |
213 // succeeds or not, because even if it fails, it might still delete some | 234 // succeeds or not, because even if it fails, it might still delete some |
214 // DB files on the hard drive. | 235 // DB files on the hard drive. |
215 origins_info_map_.erase(origin_identifier); | 236 origins_info_map_.erase(origin_identifier); |
216 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( | 237 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( |
217 UTF16ToWide(origin_identifier))); | 238 UTF16ToWide(origin_identifier))); |
218 if (!file_util::Delete(origin_dir, true)) | 239 if (!file_util::Delete(origin_dir, true)) |
219 return false; | 240 return false; |
220 | 241 |
221 databases_table_->DeleteOrigin(origin_identifier); | 242 databases_table_->DeleteOrigin(origin_identifier); |
222 return true; | 243 return true; |
223 } | 244 } |
224 | 245 |
225 bool DatabaseTracker::IsDatabaseScheduledForDeletion( | 246 bool DatabaseTracker::IsDatabaseScheduledForDeletion( |
226 const string16& origin_identifier, | 247 const string16& origin_identifier, |
227 const string16& database_name) { | 248 const string16& database_name) { |
228 std::map<string16, std::set<string16> >::iterator it = | 249 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier); |
229 dbs_to_be_deleted_.find(origin_identifier); | |
230 if (it == dbs_to_be_deleted_.end()) | 250 if (it == dbs_to_be_deleted_.end()) |
231 return false; | 251 return false; |
232 | 252 |
233 std::set<string16>& databases = it->second; | 253 std::set<string16>& databases = it->second; |
234 return (databases.find(database_name) != databases.end()); | 254 return (databases.find(database_name) != databases.end()); |
235 } | 255 } |
236 | 256 |
237 bool DatabaseTracker::LazyInit() { | 257 bool DatabaseTracker::LazyInit() { |
238 if (!initialized_) { | 258 if (!initialized_) { |
239 DCHECK(!db_->is_open()); | 259 DCHECK(!db_->is_open()); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 void DatabaseTracker::ScheduleDatabaseForDeletion( | 401 void DatabaseTracker::ScheduleDatabaseForDeletion( |
382 const string16& origin_identifier, | 402 const string16& origin_identifier, |
383 const string16& database_name) { | 403 const string16& database_name) { |
384 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier, | 404 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier, |
385 database_name)); | 405 database_name)); |
386 dbs_to_be_deleted_[origin_identifier].insert(database_name); | 406 dbs_to_be_deleted_[origin_identifier].insert(database_name); |
387 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion( | 407 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion( |
388 origin_identifier, database_name)); | 408 origin_identifier, database_name)); |
389 } | 409 } |
390 | 410 |
| 411 int DatabaseTracker::DeleteDatabase(const string16& origin_identifier, |
| 412 const string16& database_name, |
| 413 net::CompletionCallback* callback) { |
| 414 if (!LazyInit()) |
| 415 return net::ERR_FAILED; |
| 416 |
| 417 DCHECK(!callback || |
| 418 deletion_callbacks_.find(callback) == deletion_callbacks_.end()); |
| 419 |
| 420 if (database_connections_.IsDatabaseOpened(origin_identifier, |
| 421 database_name)) { |
| 422 if (callback) |
| 423 deletion_callbacks_[callback][origin_identifier].insert(database_name); |
| 424 ScheduleDatabaseForDeletion(origin_identifier, database_name); |
| 425 return net::ERR_IO_PENDING; |
| 426 } |
| 427 DeleteClosedDatabase(origin_identifier, database_name); |
| 428 return net::OK; |
| 429 } |
| 430 |
391 int DatabaseTracker::DeleteDataModifiedSince( | 431 int DatabaseTracker::DeleteDataModifiedSince( |
392 const base::Time& cutoff, | 432 const base::Time& cutoff, |
393 net::CompletionCallback* callback) { | 433 net::CompletionCallback* callback) { |
394 // Check for reentrancy. | 434 if (!LazyInit()) |
395 if (dbs_deleted_callback_ || !LazyInit()) | |
396 return net::ERR_FAILED; | 435 return net::ERR_FAILED; |
397 | 436 |
398 DCHECK(callback); | 437 DCHECK(!callback || |
399 dbs_deleted_callback_ = callback; | 438 deletion_callbacks_.find(callback) == deletion_callbacks_.end()); |
| 439 DatabaseSet to_be_deleted; |
400 | 440 |
401 std::vector<string16> origins; | 441 std::vector<string16> origins; |
402 if (!databases_table_->GetAllOrigins(&origins)) { | 442 if (!databases_table_->GetAllOrigins(&origins)) |
403 dbs_deleted_callback_ = NULL; | |
404 return net::ERR_FAILED; | 443 return net::ERR_FAILED; |
405 } | |
406 int rv = net::OK; | 444 int rv = net::OK; |
407 for (std::vector<string16>::const_iterator ori = origins.begin(); | 445 for (std::vector<string16>::const_iterator ori = origins.begin(); |
408 ori != origins.end(); ++ori) { | 446 ori != origins.end(); ++ori) { |
409 if (StartsWith(*ori, ASCIIToUTF16(kExtensionOriginIdentifierPrefix), true)) | 447 if (StartsWith(*ori, ASCIIToUTF16(kExtensionOriginIdentifierPrefix), true)) |
410 continue; | 448 continue; |
411 std::vector<DatabaseDetails> details; | 449 std::vector<DatabaseDetails> details; |
412 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details)) { | 450 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details)) |
413 rv = net::ERR_FAILED; | 451 rv = net::ERR_FAILED; |
414 continue; | |
415 } | |
416 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); | 452 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); |
417 db != details.end(); ++db) { | 453 db != details.end(); ++db) { |
418 FilePath db_file = GetFullDBFilePath(*ori, db->database_name); | 454 FilePath db_file = GetFullDBFilePath(*ori, db->database_name); |
419 file_util::FileInfo file_info; | 455 file_util::FileInfo file_info; |
420 file_util::GetFileInfo(db_file, &file_info); | 456 file_util::GetFileInfo(db_file, &file_info); |
421 if (file_info.last_modified < cutoff) | 457 if (file_info.last_modified < cutoff) |
422 continue; | 458 continue; |
423 | 459 |
424 // Check if the database is opened by any renderer. | 460 // Check if the database is opened by any renderer. |
425 if (database_connections_.IsDatabaseOpened(*ori, db->database_name)) { | 461 if (database_connections_.IsDatabaseOpened(*ori, db->database_name)) |
426 ScheduleDatabaseForDeletion(*ori, db->database_name); | 462 to_be_deleted[*ori].insert(db->database_name); |
427 rv = net::ERR_IO_PENDING; | 463 else |
428 } else { | 464 DeleteClosedDatabase(*ori, db->database_name); |
429 DeleteDatabase(*ori, db->database_name); | |
430 } | |
431 } | 465 } |
432 } | 466 } |
433 | 467 |
434 if (rv != net::ERR_IO_PENDING) { | 468 if (!to_be_deleted.empty()) { |
435 dbs_to_be_deleted_.clear(); | 469 if (callback) |
436 dbs_deleted_callback_ = NULL; | 470 deletion_callbacks_[callback] = to_be_deleted; |
| 471 for (DatabaseSet::iterator ori = to_be_deleted.begin(); |
| 472 ori != to_be_deleted.end(); ++ori) { |
| 473 for (std::set<string16>::iterator db = ori->second.begin(); |
| 474 db != ori->second.end(); ++db) |
| 475 ScheduleDatabaseForDeletion(ori->first, *db); |
| 476 } |
| 477 rv = net::ERR_IO_PENDING; |
437 } | 478 } |
438 return rv; | 479 return rv; |
439 } | 480 } |
440 | 481 |
441 // static | 482 // static |
442 void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { | 483 void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { |
443 FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); | 484 FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); |
444 FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); | 485 FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); |
445 if (file_util::DirectoryExists(db_dir) && | 486 if (file_util::DirectoryExists(db_dir) && |
446 file_util::PathExists(db_tracker)) { | 487 file_util::PathExists(db_tracker)) { |
(...skipping 22 matching lines...) Expand all Loading... |
469 file_path = file_enumerator.Next()) { | 510 file_path = file_enumerator.Next()) { |
470 if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) { | 511 if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) { |
471 if (!StartsWith(file_path.BaseName().ToWStringHack(), | 512 if (!StartsWith(file_path.BaseName().ToWStringHack(), |
472 ASCIIToWide(kExtensionOriginIdentifierPrefix), true)) | 513 ASCIIToWide(kExtensionOriginIdentifierPrefix), true)) |
473 file_util::Delete(file_path, true); | 514 file_util::Delete(file_path, true); |
474 } | 515 } |
475 } | 516 } |
476 } | 517 } |
477 | 518 |
478 } // namespace webkit_database | 519 } // namespace webkit_database |
OLD | NEW |