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