Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: webkit/database/database_tracker.cc

Issue 7234014: Move code to clear web databases on shutdown to the database tracker (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/database/database_tracker.h ('k') | webkit/database/database_tracker_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "app/sql/connection.h" 10 #include "app/sql/connection.h"
11 #include "app/sql/diagnostic_error_delegate.h" 11 #include "app/sql/diagnostic_error_delegate.h"
12 #include "app/sql/meta_table.h" 12 #include "app/sql/meta_table.h"
13 #include "app/sql/statement.h" 13 #include "app/sql/statement.h"
14 #include "app/sql/transaction.h" 14 #include "app/sql/transaction.h"
15 #include "base/basictypes.h" 15 #include "base/basictypes.h"
16 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/message_loop_proxy.h" 17 #include "base/message_loop_proxy.h"
18 #include "base/platform_file.h"
18 #include "base/string_number_conversions.h" 19 #include "base/string_number_conversions.h"
19 #include "base/utf_string_conversions.h" 20 #include "base/utf_string_conversions.h"
20 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
21 #include "webkit/database/database_quota_client.h" 22 #include "webkit/database/database_quota_client.h"
22 #include "webkit/database/database_util.h" 23 #include "webkit/database/database_util.h"
23 #include "webkit/database/databases_table.h" 24 #include "webkit/database/databases_table.h"
24 #include "webkit/quota/quota_manager.h" 25 #include "webkit/quota/quota_manager.h"
25 #include "webkit/quota/special_storage_policy.h" 26 #include "webkit/quota/special_storage_policy.h"
26 27
27 namespace { 28 namespace {
(...skipping 12 matching lines...) Expand all
40 namespace webkit_database { 41 namespace webkit_database {
41 42
42 const FilePath::CharType kDatabaseDirectoryName[] = 43 const FilePath::CharType kDatabaseDirectoryName[] =
43 FILE_PATH_LITERAL("databases"); 44 FILE_PATH_LITERAL("databases");
44 const FilePath::CharType kIncognitoDatabaseDirectoryName[] = 45 const FilePath::CharType kIncognitoDatabaseDirectoryName[] =
45 FILE_PATH_LITERAL("databases-incognito"); 46 FILE_PATH_LITERAL("databases-incognito");
46 const FilePath::CharType kTrackerDatabaseFileName[] = 47 const FilePath::CharType kTrackerDatabaseFileName[] =
47 FILE_PATH_LITERAL("Databases.db"); 48 FILE_PATH_LITERAL("Databases.db");
48 static const int kCurrentVersion = 2; 49 static const int kCurrentVersion = 2;
49 static const int kCompatibleVersion = 1; 50 static const int kCompatibleVersion = 1;
50 static const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; 51
52 const FilePath::CharType kTemporaryDirectoryPrefix[] =
53 FILE_PATH_LITERAL("DeleteMe");
54 const FilePath::CharType kTemporaryDirectoryPattern[] =
55 FILE_PATH_LITERAL("DeleteMe*");
51 56
52 OriginInfo::OriginInfo() 57 OriginInfo::OriginInfo()
53 : total_size_(0) {} 58 : total_size_(0) {}
54 59
55 OriginInfo::OriginInfo(const OriginInfo& origin_info) 60 OriginInfo::OriginInfo(const OriginInfo& origin_info)
56 : origin_(origin_info.origin_), 61 : origin_(origin_info.origin_),
57 total_size_(origin_info.total_size_), 62 total_size_(origin_info.total_size_),
58 database_info_(origin_info.database_info_) {} 63 database_info_(origin_info.database_info_) {}
59 64
60 OriginInfo::~OriginInfo() {} 65 OriginInfo::~OriginInfo() {}
(...skipping 19 matching lines...) Expand all
80 return it->second.second; 85 return it->second.second;
81 return string16(); 86 return string16();
82 } 87 }
83 88
84 OriginInfo::OriginInfo(const string16& origin, int64 total_size) 89 OriginInfo::OriginInfo(const string16& origin, int64 total_size)
85 : origin_(origin), total_size_(total_size) {} 90 : origin_(origin), total_size_(total_size) {}
86 91
87 DatabaseTracker::DatabaseTracker( 92 DatabaseTracker::DatabaseTracker(
88 const FilePath& profile_path, 93 const FilePath& profile_path,
89 bool is_incognito, 94 bool is_incognito,
95 bool clear_local_state_on_exit,
90 quota::SpecialStoragePolicy* special_storage_policy, 96 quota::SpecialStoragePolicy* special_storage_policy,
91 quota::QuotaManagerProxy* quota_manager_proxy, 97 quota::QuotaManagerProxy* quota_manager_proxy,
92 base::MessageLoopProxy* db_tracker_thread) 98 base::MessageLoopProxy* db_tracker_thread)
93 : is_initialized_(false), 99 : is_initialized_(false),
94 is_incognito_(is_incognito), 100 is_incognito_(is_incognito),
101 clear_local_state_on_exit_(clear_local_state_on_exit),
95 shutting_down_(false), 102 shutting_down_(false),
96 profile_path_(profile_path), 103 profile_path_(profile_path),
97 db_dir_(is_incognito_ ? 104 db_dir_(is_incognito_ ?
98 profile_path_.Append(kIncognitoDatabaseDirectoryName) : 105 profile_path_.Append(kIncognitoDatabaseDirectoryName) :
99 profile_path_.Append(kDatabaseDirectoryName)), 106 profile_path_.Append(kDatabaseDirectoryName)),
100 db_(new sql::Connection()), 107 db_(new sql::Connection()),
101 databases_table_(NULL), 108 databases_table_(NULL),
102 meta_table_(NULL), 109 meta_table_(NULL),
103 special_storage_policy_(special_storage_policy), 110 special_storage_policy_(special_storage_policy),
104 quota_manager_proxy_(quota_manager_proxy), 111 quota_manager_proxy_(quota_manager_proxy),
112 db_tracker_thread_(db_tracker_thread),
105 incognito_origin_directories_generator_(0) { 113 incognito_origin_directories_generator_(0) {
106 if (quota_manager_proxy) { 114 if (quota_manager_proxy) {
107 quota_manager_proxy->RegisterClient( 115 quota_manager_proxy->RegisterClient(
108 new DatabaseQuotaClient(db_tracker_thread, this)); 116 new DatabaseQuotaClient(db_tracker_thread, this));
109 } 117 }
110 } 118 }
111 119
112 DatabaseTracker::~DatabaseTracker() { 120 DatabaseTracker::~DatabaseTracker() {
113 DCHECK(dbs_to_be_deleted_.empty()); 121 DCHECK(dbs_to_be_deleted_.empty());
114 DCHECK(deletion_callbacks_.empty()); 122 DCHECK(deletion_callbacks_.empty());
115 } 123 }
116 124
117 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, 125 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier,
118 const string16& database_name, 126 const string16& database_name,
119 const string16& database_description, 127 const string16& database_description,
120 int64 estimated_size, 128 int64 estimated_size,
121 int64* database_size) { 129 int64* database_size) {
122 if (!LazyInit()) { 130 if (shutting_down_ || !LazyInit()) {
123 *database_size = 0; 131 *database_size = 0;
124 return; 132 return;
125 } 133 }
126 134
127 if (quota_manager_proxy_) 135 if (quota_manager_proxy_)
128 quota_manager_proxy_->NotifyStorageAccessed( 136 quota_manager_proxy_->NotifyStorageAccessed(
129 quota::QuotaClient::kDatabase, 137 quota::QuotaClient::kDatabase,
130 DatabaseUtil::GetOriginFromIdentifier(origin_identifier), 138 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
131 quota::kStorageTypeTemporary); 139 quota::kStorageTypeTemporary);
132 140
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 -db_file_size); 364 -db_file_size);
357 365
358 // Clean up the main database and invalidate the cached record. 366 // Clean up the main database and invalidate the cached record.
359 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); 367 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
360 origins_info_map_.erase(origin_identifier); 368 origins_info_map_.erase(origin_identifier);
361 369
362 std::vector<DatabaseDetails> details; 370 std::vector<DatabaseDetails> details;
363 if (databases_table_->GetAllDatabaseDetailsForOrigin( 371 if (databases_table_->GetAllDatabaseDetailsForOrigin(
364 origin_identifier, &details) && details.empty()) { 372 origin_identifier, &details) && details.empty()) {
365 // Try to delete the origin in case this was the last database. 373 // Try to delete the origin in case this was the last database.
366 DeleteOrigin(origin_identifier); 374 DeleteOrigin(origin_identifier, false);
367 } 375 }
368 return true; 376 return true;
369 } 377 }
370 378
371 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { 379 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier,
380 bool force) {
372 if (!LazyInit()) 381 if (!LazyInit())
373 return false; 382 return false;
374 383
375 // Check if any database in this origin is opened by any renderer. 384 // Check if any database in this origin is opened by any renderer.
376 if (database_connections_.IsOriginUsed(origin_identifier)) 385 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
377 return false; 386 return false;
378 387
379 int64 deleted_size = 0; 388 int64 deleted_size = 0;
380 if (quota_manager_proxy_) { 389 if (quota_manager_proxy_) {
381 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); 390 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
382 if (origin_info) 391 if (origin_info)
383 deleted_size = origin_info->TotalSize(); 392 deleted_size = origin_info->TotalSize();
384 } 393 }
385 394
386 // We need to invalidate the cached record whether file_util::Delete()
387 // succeeds or not, because even if it fails, it might still delete some
388 // DB files on the hard drive.
389 origins_info_map_.erase(origin_identifier); 395 origins_info_map_.erase(origin_identifier);
390 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( 396 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack(
391 UTF16ToWide(origin_identifier))); 397 UTF16ToWide(origin_identifier)));
392 if (!file_util::Delete(origin_dir, true)) 398
393 return false; 399 // Create a temporary directory to move possibly still existing databases to,
400 // as we can't delete the origin directory on windows if it contains opened
401 // files.
402 FilePath new_origin_dir;
403 file_util::CreateTemporaryDirInDir(db_dir_,
404 kTemporaryDirectoryPrefix,
405 &new_origin_dir);
406 file_util::FileEnumerator databases(
407 origin_dir,
408 false,
409 file_util::FileEnumerator::FILES);
410 for (FilePath database = databases.Next(); !database.empty();
411 database = databases.Next()) {
412 FilePath new_file = new_origin_dir.Append(database.BaseName());
413 file_util::Move(database, new_file);
414 }
415 file_util::Delete(origin_dir, true);
416 file_util::Delete(new_origin_dir, true); // might fail on windows.
394 417
395 databases_table_->DeleteOrigin(origin_identifier); 418 databases_table_->DeleteOrigin(origin_identifier);
396 419
397 if (quota_manager_proxy_ && deleted_size) { 420 if (quota_manager_proxy_ && deleted_size) {
398 quota_manager_proxy_->NotifyStorageModified( 421 quota_manager_proxy_->NotifyStorageModified(
399 quota::QuotaClient::kDatabase, 422 quota::QuotaClient::kDatabase,
400 DatabaseUtil::GetOriginFromIdentifier(origin_identifier), 423 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
401 quota::kStorageTypeTemporary, 424 quota::kStorageTypeTemporary,
402 -deleted_size); 425 -deleted_size);
403 } 426 }
(...skipping 11 matching lines...) Expand all
415 std::set<string16>& databases = it->second; 438 std::set<string16>& databases = it->second;
416 return (databases.find(database_name) != databases.end()); 439 return (databases.find(database_name) != databases.end());
417 } 440 }
418 441
419 bool DatabaseTracker::LazyInit() { 442 bool DatabaseTracker::LazyInit() {
420 if (!is_initialized_ && !shutting_down_) { 443 if (!is_initialized_ && !shutting_down_) {
421 DCHECK(!db_->is_open()); 444 DCHECK(!db_->is_open());
422 DCHECK(!databases_table_.get()); 445 DCHECK(!databases_table_.get());
423 DCHECK(!meta_table_.get()); 446 DCHECK(!meta_table_.get());
424 447
448 // If there are left-over directories from failed deletion attempts, clean
449 // them up.
450 if (file_util::DirectoryExists(db_dir_)) {
451 file_util::FileEnumerator directories(
452 db_dir_,
453 false,
454 file_util::FileEnumerator::DIRECTORIES,
455 kTemporaryDirectoryPattern);
456 for (FilePath directory = directories.Next(); !directory.empty();
457 directory = directories.Next()) {
458 file_util::Delete(directory, true);
459 }
460 }
461
425 // If the tracker database exists, but it's corrupt or doesn't 462 // If the tracker database exists, but it's corrupt or doesn't
426 // have a meta table, delete the database directory. 463 // have a meta table, delete the database directory.
427 const FilePath kTrackerDatabaseFullPath = 464 const FilePath kTrackerDatabaseFullPath =
428 db_dir_.Append(FilePath(kTrackerDatabaseFileName)); 465 db_dir_.Append(FilePath(kTrackerDatabaseFileName));
429 if (file_util::DirectoryExists(db_dir_) && 466 if (file_util::DirectoryExists(db_dir_) &&
430 file_util::PathExists(kTrackerDatabaseFullPath) && 467 file_util::PathExists(kTrackerDatabaseFullPath) &&
431 (!db_->Open(kTrackerDatabaseFullPath) || 468 (!db_->Open(kTrackerDatabaseFullPath) ||
432 !sql::MetaTable::DoesTableExist(db_.get()))) { 469 !sql::MetaTable::DoesTableExist(db_.get()))) {
433 db_->Close(); 470 db_->Close();
434 if (!file_util::Delete(db_dir_, true)) 471 if (!file_util::Delete(db_dir_, true))
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 for (FileHandlesMap::iterator it = incognito_file_handles_.begin(); 777 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
741 it != incognito_file_handles_.end(); it++) 778 it != incognito_file_handles_.end(); it++)
742 base::ClosePlatformFile(it->second); 779 base::ClosePlatformFile(it->second);
743 780
744 FilePath incognito_db_dir = 781 FilePath incognito_db_dir =
745 profile_path_.Append(kIncognitoDatabaseDirectoryName); 782 profile_path_.Append(kIncognitoDatabaseDirectoryName);
746 if (file_util::DirectoryExists(incognito_db_dir)) 783 if (file_util::DirectoryExists(incognito_db_dir))
747 file_util::Delete(incognito_db_dir, true); 784 file_util::Delete(incognito_db_dir, true);
748 } 785 }
749 786
750 // static 787 void DatabaseTracker::ClearLocalState() {
751 void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { 788 shutting_down_ = true;
752 // TODO(michaeln): use SpecialStoragePolicy instead of kExtensionOriginPrefix 789
753 FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); 790 std::vector<string16> origin_identifiers;
754 FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); 791 GetAllOriginIdentifiers(&origin_identifiers);
755 if (file_util::DirectoryExists(db_dir) && 792
756 file_util::PathExists(db_tracker)) { 793 for (std::vector<string16>::iterator origin = origin_identifiers.begin();
757 scoped_ptr<sql::Connection> db_(new sql::Connection); 794 origin != origin_identifiers.end(); ++origin) {
758 if (!db_->Open(db_tracker) || 795 if (special_storage_policy_.get() &&
759 !db_->DoesTableExist("Databases")) { 796 special_storage_policy_->IsStorageProtected(
760 db_->Close(); 797 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin))) {
761 file_util::Delete(db_dir, true); 798 continue;
762 return;
763 } else {
764 sql::Statement delete_statement(db_->GetCachedStatement(
765 SQL_FROM_HERE, "DELETE FROM Databases WHERE origin NOT LIKE ?"));
766 std::string filter(kExtensionOriginIdentifierPrefix);
767 filter += "%";
768 delete_statement.BindString(0, filter);
769 if (!delete_statement.Run()) {
770 db_->Close();
771 file_util::Delete(db_dir, true);
772 return;
773 }
774 } 799 }
775 } 800 webkit_database::OriginInfo origin_info;
776 file_util::FileEnumerator file_enumerator(db_dir, false, 801 std::vector<string16> databases;
777 file_util::FileEnumerator::DIRECTORIES); 802 GetOriginInfo(*origin, &origin_info);
778 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); 803 origin_info.GetAllDatabaseNames(&databases);
779 file_path = file_enumerator.Next()) { 804
780 if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) { 805 for (std::vector<string16>::iterator database = databases.begin();
781 std::string basename = file_path.BaseName().MaybeAsASCII(); 806 database != databases.end(); ++database) {
782 if (!basename.empty() && 807 base::PlatformFile file_handle = base::CreatePlatformFile(
783 !StartsWithASCII(basename, kExtensionOriginIdentifierPrefix, true)) { 808 GetFullDBFilePath(*origin, *database),
784 file_util::Delete(file_path, true); 809 base::PLATFORM_FILE_OPEN_ALWAYS |
785 } 810 base::PLATFORM_FILE_SHARE_DELETE |
811 base::PLATFORM_FILE_DELETE_ON_CLOSE |
812 base::PLATFORM_FILE_READ,
813 NULL, NULL);
814 base::ClosePlatformFile(file_handle);
786 } 815 }
816 DeleteOrigin(*origin, true);
787 } 817 }
788 } 818 }
789 819
820
821 void DatabaseTracker::Shutdown() {
822 DCHECK(db_tracker_thread_.get());
823 DCHECK(db_tracker_thread_->BelongsToCurrentThread());
824 if (shutting_down_) {
825 NOTREACHED();
826 return;
827 }
828 if (is_incognito_)
829 DeleteIncognitoDBDirectory();
830 else if (clear_local_state_on_exit_ && LazyInit())
831 ClearLocalState();
832 }
833
834 void DatabaseTracker::SetClearLocalStateOnExit(bool clear_local_state_on_exit) {
835 DCHECK(db_tracker_thread_.get());
836 if (!db_tracker_thread_->BelongsToCurrentThread()) {
837 db_tracker_thread_->PostTask(FROM_HERE,
838 NewRunnableMethod(this,
839 &DatabaseTracker::SetClearLocalStateOnExit,
840 clear_local_state_on_exit));
841 return;
842 }
843 if (shutting_down_) {
844 NOTREACHED();
845 return;
846 }
847 clear_local_state_on_exit_ = clear_local_state_on_exit;
848 }
849
790 } // namespace webkit_database 850 } // namespace webkit_database
OLDNEW
« no previous file with comments | « webkit/database/database_tracker.h ('k') | webkit/database/database_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698