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

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
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 {
28 29
29 class HistogramUniquifier { 30 class HistogramUniquifier {
30 public: 31 public:
31 static const char* name() { return "Sqlite.DatabaseTracker.Error"; } 32 static const char* name() { return "Sqlite.DatabaseTracker.Error"; }
32 }; 33 };
33 34
34 sql::ErrorDelegate* GetErrorHandlerForTrackerDb() { 35 sql::ErrorDelegate* GetErrorHandlerForTrackerDb() {
35 return new sql::DiagnosticErrorDelegate<HistogramUniquifier>(); 36 return new sql::DiagnosticErrorDelegate<HistogramUniquifier>();
36 } 37 }
37 38
39 void ClearLocalState(webkit_database::DatabaseTracker* tracker) {
michaeln 2011/07/01 03:02:34 What guarantees are there that the tracker has not
jochen (gone - plz use gerrit) 2011/07/06 09:24:53 Done.
40 std::vector<string16> origin_identifiers;
41 tracker->GetAllOriginIdentifiers(&origin_identifiers);
42
43 for (std::vector<string16>::iterator origin = origin_identifiers.begin();
44 origin != origin_identifiers.end(); ++origin) {
45 if (tracker->special_storage_policy() &&
46 tracker->special_storage_policy()->IsStorageProtected(
47 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin))) {
48 continue;
49 }
50 webkit_database::OriginInfo origin_info;
51 std::vector<string16> databases;
52 tracker->GetOriginInfo(*origin, &origin_info);
53 origin_info.GetAllDatabaseNames(&databases);
54
55 for (std::vector<string16>::iterator database = databases.begin();
56 database != databases.end(); ++database) {
57 base::PlatformFile file_handle = base::CreatePlatformFile(
58 tracker->GetFullDBFilePath(*origin, *database),
59 base::PLATFORM_FILE_OPEN_ALWAYS |
60 base::PLATFORM_FILE_SHARE_DELETE |
61 base::PLATFORM_FILE_DELETE_ON_CLOSE |
62 base::PLATFORM_FILE_READ,
63 NULL, NULL);
64 base::ClosePlatformFile(file_handle);
65 }
66 tracker->DeleteOrigin(*origin, true);
67 }
68 }
69
38 } // anon namespace 70 } // anon namespace
39 71
40 namespace webkit_database { 72 namespace webkit_database {
41 73
42 const FilePath::CharType kDatabaseDirectoryName[] = 74 const FilePath::CharType kDatabaseDirectoryName[] =
43 FILE_PATH_LITERAL("databases"); 75 FILE_PATH_LITERAL("databases");
44 const FilePath::CharType kIncognitoDatabaseDirectoryName[] = 76 const FilePath::CharType kIncognitoDatabaseDirectoryName[] =
45 FILE_PATH_LITERAL("databases-incognito"); 77 FILE_PATH_LITERAL("databases-incognito");
46 const FilePath::CharType kTrackerDatabaseFileName[] = 78 const FilePath::CharType kTrackerDatabaseFileName[] =
47 FILE_PATH_LITERAL("Databases.db"); 79 FILE_PATH_LITERAL("Databases.db");
48 static const int kCurrentVersion = 2; 80 static const int kCurrentVersion = 2;
49 static const int kCompatibleVersion = 1; 81 static const int kCompatibleVersion = 1;
50 static const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; 82
83 const FilePath::CharType kTemporaryDirectoryPrefix[] =
84 FILE_PATH_LITERAL("DeleteMe");
85 const FilePath::CharType kTemporaryDirectoryPattern[] =
86 FILE_PATH_LITERAL("DeleteMe*");
51 87
52 OriginInfo::OriginInfo() 88 OriginInfo::OriginInfo()
53 : total_size_(0) {} 89 : total_size_(0) {}
54 90
55 OriginInfo::OriginInfo(const OriginInfo& origin_info) 91 OriginInfo::OriginInfo(const OriginInfo& origin_info)
56 : origin_(origin_info.origin_), 92 : origin_(origin_info.origin_),
57 total_size_(origin_info.total_size_), 93 total_size_(origin_info.total_size_),
58 database_info_(origin_info.database_info_) {} 94 database_info_(origin_info.database_info_) {}
59 95
60 OriginInfo::~OriginInfo() {} 96 OriginInfo::~OriginInfo() {}
(...skipping 19 matching lines...) Expand all
80 return it->second.second; 116 return it->second.second;
81 return string16(); 117 return string16();
82 } 118 }
83 119
84 OriginInfo::OriginInfo(const string16& origin, int64 total_size) 120 OriginInfo::OriginInfo(const string16& origin, int64 total_size)
85 : origin_(origin), total_size_(total_size) {} 121 : origin_(origin), total_size_(total_size) {}
86 122
87 DatabaseTracker::DatabaseTracker( 123 DatabaseTracker::DatabaseTracker(
88 const FilePath& profile_path, 124 const FilePath& profile_path,
89 bool is_incognito, 125 bool is_incognito,
126 bool clear_local_state_on_exit,
90 quota::SpecialStoragePolicy* special_storage_policy, 127 quota::SpecialStoragePolicy* special_storage_policy,
91 quota::QuotaManagerProxy* quota_manager_proxy, 128 quota::QuotaManagerProxy* quota_manager_proxy,
92 base::MessageLoopProxy* db_tracker_thread) 129 base::MessageLoopProxy* db_tracker_thread)
93 : is_initialized_(false), 130 : is_initialized_(false),
94 is_incognito_(is_incognito), 131 is_incognito_(is_incognito),
132 clear_local_state_on_exit_(clear_local_state_on_exit),
95 shutting_down_(false), 133 shutting_down_(false),
96 profile_path_(profile_path), 134 profile_path_(profile_path),
97 db_dir_(is_incognito_ ? 135 db_dir_(is_incognito_ ?
98 profile_path_.Append(kIncognitoDatabaseDirectoryName) : 136 profile_path_.Append(kIncognitoDatabaseDirectoryName) :
99 profile_path_.Append(kDatabaseDirectoryName)), 137 profile_path_.Append(kDatabaseDirectoryName)),
100 db_(new sql::Connection()), 138 db_(new sql::Connection()),
101 databases_table_(NULL), 139 databases_table_(NULL),
102 meta_table_(NULL), 140 meta_table_(NULL),
103 special_storage_policy_(special_storage_policy), 141 special_storage_policy_(special_storage_policy),
104 quota_manager_proxy_(quota_manager_proxy), 142 quota_manager_proxy_(quota_manager_proxy),
143 db_tracker_thread_(db_tracker_thread),
105 incognito_origin_directories_generator_(0) { 144 incognito_origin_directories_generator_(0) {
106 if (quota_manager_proxy) { 145 if (quota_manager_proxy) {
107 quota_manager_proxy->RegisterClient( 146 quota_manager_proxy->RegisterClient(
108 new DatabaseQuotaClient(db_tracker_thread, this)); 147 new DatabaseQuotaClient(db_tracker_thread, this));
109 } 148 }
110 } 149 }
111 150
112 DatabaseTracker::~DatabaseTracker() { 151 DatabaseTracker::~DatabaseTracker() {
113 DCHECK(dbs_to_be_deleted_.empty()); 152 DCHECK(dbs_to_be_deleted_.empty());
114 DCHECK(deletion_callbacks_.empty()); 153 DCHECK(deletion_callbacks_.empty());
115 } 154 }
116 155
117 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, 156 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier,
118 const string16& database_name, 157 const string16& database_name,
119 const string16& database_description, 158 const string16& database_description,
120 int64 estimated_size, 159 int64 estimated_size,
121 int64* database_size) { 160 int64* database_size) {
122 if (!LazyInit()) { 161 if (shutting_down_ || !LazyInit()) {
123 *database_size = 0; 162 *database_size = 0;
124 return; 163 return;
125 } 164 }
126 165
127 if (quota_manager_proxy_) 166 if (quota_manager_proxy_)
128 quota_manager_proxy_->NotifyStorageAccessed( 167 quota_manager_proxy_->NotifyStorageAccessed(
129 quota::QuotaClient::kDatabase, 168 quota::QuotaClient::kDatabase,
130 DatabaseUtil::GetOriginFromIdentifier(origin_identifier), 169 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
131 quota::kStorageTypeTemporary); 170 quota::kStorageTypeTemporary);
132 171
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 -db_file_size); 395 -db_file_size);
357 396
358 // Clean up the main database and invalidate the cached record. 397 // Clean up the main database and invalidate the cached record.
359 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); 398 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
360 origins_info_map_.erase(origin_identifier); 399 origins_info_map_.erase(origin_identifier);
361 400
362 std::vector<DatabaseDetails> details; 401 std::vector<DatabaseDetails> details;
363 if (databases_table_->GetAllDatabaseDetailsForOrigin( 402 if (databases_table_->GetAllDatabaseDetailsForOrigin(
364 origin_identifier, &details) && details.empty()) { 403 origin_identifier, &details) && details.empty()) {
365 // Try to delete the origin in case this was the last database. 404 // Try to delete the origin in case this was the last database.
366 DeleteOrigin(origin_identifier); 405 DeleteOrigin(origin_identifier, false);
367 } 406 }
368 return true; 407 return true;
369 } 408 }
370 409
371 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { 410 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier,
411 bool force) {
372 if (!LazyInit()) 412 if (!LazyInit())
373 return false; 413 return false;
374 414
375 // Check if any database in this origin is opened by any renderer. 415 // Check if any database in this origin is opened by any renderer.
376 if (database_connections_.IsOriginUsed(origin_identifier)) 416 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
377 return false; 417 return false;
378 418
379 int64 deleted_size = 0; 419 int64 deleted_size = 0;
380 if (quota_manager_proxy_) { 420 if (quota_manager_proxy_) {
381 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); 421 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
382 if (origin_info) 422 if (origin_info)
383 deleted_size = origin_info->TotalSize(); 423 deleted_size = origin_info->TotalSize();
384 } 424 }
385 425
386 // We need to invalidate the cached record whether file_util::Delete() 426 // 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 427 // succeeds or not, because even if it fails, it might still delete some
388 // DB files on the hard drive. 428 // DB files on the hard drive.
389 origins_info_map_.erase(origin_identifier); 429 origins_info_map_.erase(origin_identifier);
390 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( 430 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack(
391 UTF16ToWide(origin_identifier))); 431 UTF16ToWide(origin_identifier)));
392 if (!file_util::Delete(origin_dir, true)) 432 if (!file_util::Delete(origin_dir, true)) {
393 return false; 433 if (!force)
434 return false;
435
436 // Rename the directory as its name leaks the origin's name.
437 FilePath new_origin_dir;
438 file_util::CreateTemporaryDirInDir(db_dir_,
439 kTemporaryDirectoryPrefix,
440 &new_origin_dir);
441 FilePath temp_dir = db_dir_.Append(FILE_PATH_LITERAL("0"));
442 file_util::Move(origin_dir, temp_dir);
443 }
394 444
395 databases_table_->DeleteOrigin(origin_identifier); 445 databases_table_->DeleteOrigin(origin_identifier);
396 446
397 if (quota_manager_proxy_ && deleted_size) { 447 if (quota_manager_proxy_ && deleted_size) {
398 quota_manager_proxy_->NotifyStorageModified( 448 quota_manager_proxy_->NotifyStorageModified(
399 quota::QuotaClient::kDatabase, 449 quota::QuotaClient::kDatabase,
400 DatabaseUtil::GetOriginFromIdentifier(origin_identifier), 450 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
401 quota::kStorageTypeTemporary, 451 quota::kStorageTypeTemporary,
402 -deleted_size); 452 -deleted_size);
403 } 453 }
(...skipping 11 matching lines...) Expand all
415 std::set<string16>& databases = it->second; 465 std::set<string16>& databases = it->second;
416 return (databases.find(database_name) != databases.end()); 466 return (databases.find(database_name) != databases.end());
417 } 467 }
418 468
419 bool DatabaseTracker::LazyInit() { 469 bool DatabaseTracker::LazyInit() {
420 if (!is_initialized_ && !shutting_down_) { 470 if (!is_initialized_ && !shutting_down_) {
421 DCHECK(!db_->is_open()); 471 DCHECK(!db_->is_open());
422 DCHECK(!databases_table_.get()); 472 DCHECK(!databases_table_.get());
423 DCHECK(!meta_table_.get()); 473 DCHECK(!meta_table_.get());
424 474
475 // If there are left-over directoryfrom failed deletion attempts, clean
michaeln 2011/07/01 03:02:34 s/b directories from
jochen (gone - plz use gerrit) 2011/07/06 09:24:53 Done.
476 // them up.
477 if (file_util::DirectoryExists(db_dir_)) {
478 file_util::FileEnumerator directories(
479 db_dir_,
480 false,
481 file_util::FileEnumerator::DIRECTORIES,
482 kTemporaryDirectoryPattern);
483 for (FilePath directory = directories.Next(); !directory.empty();
484 directory = directories.Next()) {
485 file_util::Delete(directory, true);
486 }
487 }
488
425 // If the tracker database exists, but it's corrupt or doesn't 489 // If the tracker database exists, but it's corrupt or doesn't
426 // have a meta table, delete the database directory. 490 // have a meta table, delete the database directory.
427 const FilePath kTrackerDatabaseFullPath = 491 const FilePath kTrackerDatabaseFullPath =
428 db_dir_.Append(FilePath(kTrackerDatabaseFileName)); 492 db_dir_.Append(FilePath(kTrackerDatabaseFileName));
429 if (file_util::DirectoryExists(db_dir_) && 493 if (file_util::DirectoryExists(db_dir_) &&
430 file_util::PathExists(kTrackerDatabaseFullPath) && 494 file_util::PathExists(kTrackerDatabaseFullPath) &&
431 (!db_->Open(kTrackerDatabaseFullPath) || 495 (!db_->Open(kTrackerDatabaseFullPath) ||
432 !sql::MetaTable::DoesTableExist(db_.get()))) { 496 !sql::MetaTable::DoesTableExist(db_.get()))) {
433 db_->Close(); 497 db_->Close();
434 if (!file_util::Delete(db_dir_, true)) 498 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(); 804 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
741 it != incognito_file_handles_.end(); it++) 805 it != incognito_file_handles_.end(); it++)
742 base::ClosePlatformFile(it->second); 806 base::ClosePlatformFile(it->second);
743 807
744 FilePath incognito_db_dir = 808 FilePath incognito_db_dir =
745 profile_path_.Append(kIncognitoDatabaseDirectoryName); 809 profile_path_.Append(kIncognitoDatabaseDirectoryName);
746 if (file_util::DirectoryExists(incognito_db_dir)) 810 if (file_util::DirectoryExists(incognito_db_dir))
747 file_util::Delete(incognito_db_dir, true); 811 file_util::Delete(incognito_db_dir, true);
748 } 812 }
749 813
750 // static 814 void DatabaseTracker::Shutdown() {
751 void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { 815 if (shutting_down_ || is_incognito_) {
752 // TODO(michaeln): use SpecialStoragePolicy instead of kExtensionOriginPrefix 816 NOTREACHED();
753 FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); 817 return;
754 FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); 818 }
755 if (file_util::DirectoryExists(db_dir) && 819 if (clear_local_state_on_exit_ && LazyInit()) {
michaeln 2011/07/01 03:02:34 We shouldn't call LazyInit() on the UI thread. It'
jochen (gone - plz use gerrit) 2011/07/06 09:24:53 Done.
756 file_util::PathExists(db_tracker)) { 820 shutting_down_ = true;
757 scoped_ptr<sql::Connection> db_(new sql::Connection); 821
758 if (!db_->Open(db_tracker) || 822 if (!db_tracker_thread_.get()) {
759 !db_->DoesTableExist("Databases")) { 823 NOTREACHED();
760 db_->Close();
761 file_util::Delete(db_dir, true);
762 return; 824 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 } 825 }
775 } 826 scoped_refptr<DatabaseTracker> tracker(this);
776 file_util::FileEnumerator file_enumerator(db_dir, false, 827 db_tracker_thread_->PostTask(FROM_HERE,
777 file_util::FileEnumerator::DIRECTORIES); 828 NewRunnableFunction(ClearLocalState, tracker));
778 for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
779 file_path = file_enumerator.Next()) {
780 if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) {
781 std::string basename = file_path.BaseName().MaybeAsASCII();
782 if (!basename.empty() &&
783 !StartsWithASCII(basename, kExtensionOriginIdentifierPrefix, true)) {
784 file_util::Delete(file_path, true);
785 }
786 }
787 } 829 }
788 } 830 }
789 831
832 void DatabaseTracker::SetClearLocalStateOnExit(bool clear_local_state_on_exit) {
michaeln 2011/07/01 03:02:34 It'd be safer to test and set these data members e
jochen (gone - plz use gerrit) 2011/07/06 09:24:53 Done.
833 if (shutting_down_) {
834 NOTREACHED();
835 return;
836 }
837 clear_local_state_on_exit_ = clear_local_state_on_exit;
838 }
839
790 } // namespace webkit_database 840 } // namespace webkit_database
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698