summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-08 08:00:50 +0000
committerjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-08 08:00:50 +0000
commit800ad566b10caee04ca18c7eb1796b21c1766c37 (patch)
tree276a35a8565d9bb981bb4ec656db26be3e8bce14
parente6487b915297e168448ea29d81421a3f72a26c10 (diff)
downloadchromium_src-800ad566b10caee04ca18c7eb1796b21c1766c37.zip
chromium_src-800ad566b10caee04ca18c7eb1796b21c1766c37.tar.gz
chromium_src-800ad566b10caee04ca18c7eb1796b21c1766c37.tar.bz2
Move code to clear web databases on shutdown to the database tracker
BUG=86928 TEST=test_shell_tests Review URL: http://codereview.chromium.org/7234014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91817 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_process_impl.cc40
-rw-r--r--chrome/browser/browser_process_impl.h3
-rw-r--r--chrome/browser/profiles/profile.cc7
-rw-r--r--chrome/browser/profiles/profile_impl.cc15
-rw-r--r--chrome/test/testing_profile.cc3
-rw-r--r--webkit/database/database_quota_client_unittest.cc2
-rw-r--r--webkit/database/database_tracker.cc150
-rw-r--r--webkit/database/database_tracker.h30
-rw-r--r--webkit/database/database_tracker_unittest.cc113
-rw-r--r--webkit/database/vfs_backend.cc4
-rw-r--r--webkit/support/simple_database_system.cc3
11 files changed, 264 insertions, 106 deletions
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 02ff81d..f99f38b 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -80,7 +80,6 @@
#include "net/url_request/url_request_context_getter.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/l10n/l10n_util.h"
-#include "webkit/database/database_tracker.h"
#include "webkit/plugins/npapi/plugin_list.h"
#if defined(OS_WIN)
@@ -149,12 +148,6 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
}
BrowserProcessImpl::~BrowserProcessImpl() {
- FilePath profile_path;
- bool clear_local_state_on_exit;
-
- // Store the profile path for clearing local state data on exit.
- clear_local_state_on_exit = ShouldClearLocalState(&profile_path);
-
#if defined(OS_CHROMEOS)
if (web_socket_proxy_thread_.get())
chromeos::WebSocketProxyController::Shutdown();
@@ -267,19 +260,9 @@ BrowserProcessImpl::~BrowserProcessImpl() {
// Now OK to destroy NotificationService.
main_notification_service_.reset();
- // Prior to clearing local state, we want to complete tasks pending
- // on the db thread too.
- db_thread_.reset();
-
// Stop the watchdog thread after stopping other threads.
watchdog_thread_.reset();
- // At this point, no render process exist and the file, io, db, and
- // webkit threads in this process have all terminated, so it's safe
- // to access local state data such as cookies, database, or local storage.
- if (clear_local_state_on_exit)
- ClearLocalState(profile_path);
-
g_browser_process = NULL;
}
@@ -673,29 +656,6 @@ MHTMLGenerationManager* BrowserProcessImpl::mhtml_generation_manager() {
return mhtml_generation_manager_.get();
}
-void BrowserProcessImpl::ClearLocalState(const FilePath& profile_path) {
- webkit_database::DatabaseTracker::ClearLocalState(profile_path);
-}
-
-bool BrowserProcessImpl::ShouldClearLocalState(FilePath* profile_path) {
- FilePath user_data_dir;
- Profile* profile;
-
- // Check for the existence of a profile manager. When quitting early,
- // e.g. because another chrome instance is running, or when invoked with
- // options such as --uninstall or --try-chrome-again=0, the profile manager
- // does not exist yet.
- if (!profile_manager_.get())
- return false;
-
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- profile = profile_manager_->GetDefaultProfile(user_data_dir);
- if (!profile)
- return false;
- *profile_path = profile->GetPath();
- return profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit);
-}
-
void BrowserProcessImpl::CreateResourceDispatcherHost() {
DCHECK(!created_resource_dispatcher_host_ &&
resource_dispatcher_host_.get() == NULL);
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 002e557..db003fd 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -123,9 +123,6 @@ class BrowserProcessImpl : public BrowserProcess,
virtual MHTMLGenerationManager* mhtml_generation_manager();
private:
- void ClearLocalState(const FilePath& profile_path);
- bool ShouldClearLocalState(FilePath* profile_path);
-
void CreateResourceDispatcherHost();
void CreateMetricsService();
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 4193284..b5f9a32 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -265,12 +265,13 @@ class OffTheRecordProfileImpl : public Profile,
profile_->GetRuntimeId(), GetRuntimeId()));
// Clean up all DB files/directories
- if (db_tracker_)
+ if (db_tracker_) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
db_tracker_.get(),
- &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory));
+ &webkit_database::DatabaseTracker::Shutdown));
+ }
BrowserList::RemoveObserver(this);
@@ -741,7 +742,7 @@ class OffTheRecordProfileImpl : public Profile,
GetExtensionSpecialStoragePolicy(),
quota_manager_->proxy());
db_tracker_ = new webkit_database::DatabaseTracker(
- GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(),
+ GetPath(), IsOffTheRecord(), false, GetExtensionSpecialStoragePolicy(),
quota_manager_->proxy(),
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
webkit_context_ = new WebKitContext(
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index b297ba1..4054c08 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -602,6 +602,14 @@ ProfileImpl::~ProfileImpl() {
NewRunnableFunction(&BrowsingDataRemover::ClearGearsData, path_));
}
+ if (db_tracker_) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ db_tracker_.get(),
+ &webkit_database::DatabaseTracker::Shutdown));
+ }
+
// DownloadManager is lazily created, so check before accessing it.
if (download_manager_.get()) {
// The download manager queries the history system and should be shut down
@@ -1309,7 +1317,8 @@ void ProfileImpl::CreateQuotaManagerAndClients() {
GetExtensionSpecialStoragePolicy(),
quota_manager_->proxy());
db_tracker_ = new webkit_database::DatabaseTracker(
- GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(),
+ GetPath(), IsOffTheRecord(), clear_local_state_on_exit_,
+ GetExtensionSpecialStoragePolicy(),
quota_manager_->proxy(),
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
webkit_context_ = new WebKitContext(
@@ -1384,6 +1393,10 @@ void ProfileImpl::Observe(NotificationType type,
appcache_service_->SetClearLocalStateOnExit(
clear_local_state_on_exit_);
}
+ if (db_tracker_) {
+ db_tracker_->SetClearLocalStateOnExit(
+ clear_local_state_on_exit_);
+ }
} else if (*pref_name_in == prefs::kGoogleServicesUsername) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
profile_manager->RegisterProfileName(this);
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 8ba85f0..679cc02 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -397,7 +397,8 @@ ChromeAppCacheService* TestingProfile::GetAppCacheService() {
webkit_database::DatabaseTracker* TestingProfile::GetDatabaseTracker() {
if (!db_tracker_) {
db_tracker_ = new webkit_database::DatabaseTracker(
- GetPath(), false, GetExtensionSpecialStoragePolicy(), NULL, NULL);
+ GetPath(), false, false, GetExtensionSpecialStoragePolicy(),
+ NULL, NULL);
}
return db_tracker_;
}
diff --git a/webkit/database/database_quota_client_unittest.cc b/webkit/database/database_quota_client_unittest.cc
index 6c9f293..9bbae9e 100644
--- a/webkit/database/database_quota_client_unittest.cc
+++ b/webkit/database/database_quota_client_unittest.cc
@@ -26,7 +26,7 @@ static const quota::StorageType kPerm = quota::kStorageTypePersistent;
class MockDatabaseTracker : public DatabaseTracker {
public:
MockDatabaseTracker()
- : DatabaseTracker(FilePath(), false, NULL, NULL, NULL),
+ : DatabaseTracker(FilePath(), false, false, NULL, NULL, NULL),
delete_called_count_(0),
async_delete_(false) {}
diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc
index 7497c38..d01acda 100644
--- a/webkit/database/database_tracker.cc
+++ b/webkit/database/database_tracker.cc
@@ -15,6 +15,7 @@
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/message_loop_proxy.h"
+#include "base/platform_file.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
@@ -47,7 +48,11 @@ const FilePath::CharType kTrackerDatabaseFileName[] =
FILE_PATH_LITERAL("Databases.db");
static const int kCurrentVersion = 2;
static const int kCompatibleVersion = 1;
-static const char* kExtensionOriginIdentifierPrefix = "chrome-extension_";
+
+const FilePath::CharType kTemporaryDirectoryPrefix[] =
+ FILE_PATH_LITERAL("DeleteMe");
+const FilePath::CharType kTemporaryDirectoryPattern[] =
+ FILE_PATH_LITERAL("DeleteMe*");
OriginInfo::OriginInfo()
: total_size_(0) {}
@@ -87,11 +92,13 @@ OriginInfo::OriginInfo(const string16& origin, int64 total_size)
DatabaseTracker::DatabaseTracker(
const FilePath& profile_path,
bool is_incognito,
+ bool clear_local_state_on_exit,
quota::SpecialStoragePolicy* special_storage_policy,
quota::QuotaManagerProxy* quota_manager_proxy,
base::MessageLoopProxy* db_tracker_thread)
: is_initialized_(false),
is_incognito_(is_incognito),
+ clear_local_state_on_exit_(clear_local_state_on_exit),
shutting_down_(false),
profile_path_(profile_path),
db_dir_(is_incognito_ ?
@@ -102,6 +109,7 @@ DatabaseTracker::DatabaseTracker(
meta_table_(NULL),
special_storage_policy_(special_storage_policy),
quota_manager_proxy_(quota_manager_proxy),
+ db_tracker_thread_(db_tracker_thread),
incognito_origin_directories_generator_(0) {
if (quota_manager_proxy) {
quota_manager_proxy->RegisterClient(
@@ -119,7 +127,7 @@ void DatabaseTracker::DatabaseOpened(const string16& origin_identifier,
const string16& database_description,
int64 estimated_size,
int64* database_size) {
- if (!LazyInit()) {
+ if (shutting_down_ || !LazyInit()) {
*database_size = 0;
return;
}
@@ -363,17 +371,18 @@ bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier,
if (databases_table_->GetAllDatabaseDetailsForOrigin(
origin_identifier, &details) && details.empty()) {
// Try to delete the origin in case this was the last database.
- DeleteOrigin(origin_identifier);
+ DeleteOrigin(origin_identifier, false);
}
return true;
}
-bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) {
+bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier,
+ bool force) {
if (!LazyInit())
return false;
// Check if any database in this origin is opened by any renderer.
- if (database_connections_.IsOriginUsed(origin_identifier))
+ if (database_connections_.IsOriginUsed(origin_identifier) && !force)
return false;
int64 deleted_size = 0;
@@ -383,14 +392,28 @@ bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) {
deleted_size = origin_info->TotalSize();
}
- // We need to invalidate the cached record whether file_util::Delete()
- // succeeds or not, because even if it fails, it might still delete some
- // DB files on the hard drive.
origins_info_map_.erase(origin_identifier);
FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack(
UTF16ToWide(origin_identifier)));
- if (!file_util::Delete(origin_dir, true))
- return false;
+
+ // Create a temporary directory to move possibly still existing databases to,
+ // as we can't delete the origin directory on windows if it contains opened
+ // files.
+ FilePath new_origin_dir;
+ file_util::CreateTemporaryDirInDir(db_dir_,
+ kTemporaryDirectoryPrefix,
+ &new_origin_dir);
+ file_util::FileEnumerator databases(
+ origin_dir,
+ false,
+ file_util::FileEnumerator::FILES);
+ for (FilePath database = databases.Next(); !database.empty();
+ database = databases.Next()) {
+ FilePath new_file = new_origin_dir.Append(database.BaseName());
+ file_util::Move(database, new_file);
+ }
+ file_util::Delete(origin_dir, true);
+ file_util::Delete(new_origin_dir, true); // might fail on windows.
databases_table_->DeleteOrigin(origin_identifier);
@@ -422,6 +445,20 @@ bool DatabaseTracker::LazyInit() {
DCHECK(!databases_table_.get());
DCHECK(!meta_table_.get());
+ // If there are left-over directories from failed deletion attempts, clean
+ // them up.
+ if (file_util::DirectoryExists(db_dir_)) {
+ file_util::FileEnumerator directories(
+ db_dir_,
+ false,
+ file_util::FileEnumerator::DIRECTORIES,
+ kTemporaryDirectoryPattern);
+ for (FilePath directory = directories.Next(); !directory.empty();
+ directory = directories.Next()) {
+ file_util::Delete(directory, true);
+ }
+ }
+
// If the tracker database exists, but it's corrupt or doesn't
// have a meta table, delete the database directory.
const FilePath kTrackerDatabaseFullPath =
@@ -747,44 +784,67 @@ void DatabaseTracker::DeleteIncognitoDBDirectory() {
file_util::Delete(incognito_db_dir, true);
}
-// static
-void DatabaseTracker::ClearLocalState(const FilePath& profile_path) {
- // TODO(michaeln): use SpecialStoragePolicy instead of kExtensionOriginPrefix
- FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName));
- FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName));
- if (file_util::DirectoryExists(db_dir) &&
- file_util::PathExists(db_tracker)) {
- scoped_ptr<sql::Connection> db_(new sql::Connection);
- if (!db_->Open(db_tracker) ||
- !db_->DoesTableExist("Databases")) {
- db_->Close();
- file_util::Delete(db_dir, true);
- return;
- } else {
- sql::Statement delete_statement(db_->GetCachedStatement(
- SQL_FROM_HERE, "DELETE FROM Databases WHERE origin NOT LIKE ?"));
- std::string filter(kExtensionOriginIdentifierPrefix);
- filter += "%";
- delete_statement.BindString(0, filter);
- if (!delete_statement.Run()) {
- db_->Close();
- file_util::Delete(db_dir, true);
- return;
- }
+void DatabaseTracker::ClearLocalState() {
+ shutting_down_ = true;
+
+ std::vector<string16> origin_identifiers;
+ GetAllOriginIdentifiers(&origin_identifiers);
+
+ for (std::vector<string16>::iterator origin = origin_identifiers.begin();
+ origin != origin_identifiers.end(); ++origin) {
+ if (special_storage_policy_.get() &&
+ special_storage_policy_->IsStorageProtected(
+ webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin))) {
+ continue;
}
- }
- file_util::FileEnumerator file_enumerator(db_dir, false,
- file_util::FileEnumerator::DIRECTORIES);
- for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
- file_path = file_enumerator.Next()) {
- if (file_path.BaseName() != FilePath(kTrackerDatabaseFileName)) {
- std::string basename = file_path.BaseName().MaybeAsASCII();
- if (!basename.empty() &&
- !StartsWithASCII(basename, kExtensionOriginIdentifierPrefix, true)) {
- file_util::Delete(file_path, true);
- }
+ webkit_database::OriginInfo origin_info;
+ std::vector<string16> databases;
+ GetOriginInfo(*origin, &origin_info);
+ origin_info.GetAllDatabaseNames(&databases);
+
+ for (std::vector<string16>::iterator database = databases.begin();
+ database != databases.end(); ++database) {
+ base::PlatformFile file_handle = base::CreatePlatformFile(
+ GetFullDBFilePath(*origin, *database),
+ base::PLATFORM_FILE_OPEN_ALWAYS |
+ base::PLATFORM_FILE_SHARE_DELETE |
+ base::PLATFORM_FILE_DELETE_ON_CLOSE |
+ base::PLATFORM_FILE_READ,
+ NULL, NULL);
+ base::ClosePlatformFile(file_handle);
}
+ DeleteOrigin(*origin, true);
+ }
+}
+
+
+void DatabaseTracker::Shutdown() {
+ DCHECK(db_tracker_thread_.get());
+ DCHECK(db_tracker_thread_->BelongsToCurrentThread());
+ if (shutting_down_) {
+ NOTREACHED();
+ return;
+ }
+ if (is_incognito_)
+ DeleteIncognitoDBDirectory();
+ else if (clear_local_state_on_exit_ && LazyInit())
+ ClearLocalState();
+}
+
+void DatabaseTracker::SetClearLocalStateOnExit(bool clear_local_state_on_exit) {
+ DCHECK(db_tracker_thread_.get());
+ if (!db_tracker_thread_->BelongsToCurrentThread()) {
+ db_tracker_thread_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &DatabaseTracker::SetClearLocalStateOnExit,
+ clear_local_state_on_exit));
+ return;
+ }
+ if (shutting_down_) {
+ NOTREACHED();
+ return;
}
+ clear_local_state_on_exit_ = clear_local_state_on_exit;
}
} // namespace webkit_database
diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h
index bbc308a..6c6abe0 100644
--- a/webkit/database/database_tracker.h
+++ b/webkit/database/database_tracker.h
@@ -88,7 +88,9 @@ class DatabaseTracker
virtual ~Observer() {}
};
- DatabaseTracker(const FilePath& profile_path, bool is_incognito,
+ DatabaseTracker(const FilePath& profile_path,
+ bool is_incognito,
+ bool clear_local_state_on_exit,
quota::SpecialStoragePolicy* special_storage_policy,
quota::QuotaManagerProxy* quota_manager_proxy,
base::MessageLoopProxy* db_tracker_thread);
@@ -158,10 +160,10 @@ class DatabaseTracker
bool CloseIncognitoFileHandle(const string16& vfs_file_path);
bool HasSavedIncognitoFileHandle(const string16& vfs_file_path) const;
- // Deletes the directory that stores all DBs in incognito mode, if it exists.
- void DeleteIncognitoDBDirectory();
-
- static void ClearLocalState(const FilePath& profile_path);
+ // Shutdown the database tracker, deleting database files if the tracker is
+ // used for an incognito profile or |clear_local_state_on_exit_| is true.
+ void Shutdown();
+ void SetClearLocalStateOnExit(bool clear_local_state_on_exit);
private:
friend class base::RefCountedThreadSafe<DatabaseTracker>;
@@ -193,9 +195,21 @@ class DatabaseTracker
// virtual for unittesting only
virtual ~DatabaseTracker();
+ // Deletes the directory that stores all DBs in incognito mode, if it exists.
+ void DeleteIncognitoDBDirectory();
+
+ // Deletes databases not protected by the special storage policy if
+ // |clear_local_state_on_exit_| is true and blocks databases from being
+ // created/opened.
+ void ClearLocalState();
+
bool DeleteClosedDatabase(const string16& origin_identifier,
const string16& database_name);
- bool DeleteOrigin(const string16& origin_identifier);
+
+ // Delete all files belonging to the given origin given that no database
+ // connections within this origin are open, or if |force| is true, delete
+ // the meta data and rename the associated directory.
+ bool DeleteOrigin(const string16& origin_identifier, bool force);
void DeleteDatabaseIfNeeded(const string16& origin_identifier,
const string16& database_name);
@@ -228,6 +242,7 @@ class DatabaseTracker
bool is_initialized_;
const bool is_incognito_;
+ bool clear_local_state_on_exit_;
bool shutting_down_;
const FilePath profile_path_;
const FilePath db_dir_;
@@ -247,6 +262,9 @@ class DatabaseTracker
scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
+ // The database tracker thread we're supposed to run file IO on.
+ scoped_refptr<base::MessageLoopProxy> db_tracker_thread_;
+
// When in incognito mode, store a DELETE_ON_CLOSE handle to each
// main DB and journal file that was accessed. When the incognito profile
// goes away (or when the browser crashes), all these handles will be
diff --git a/webkit/database/database_tracker_unittest.cc b/webkit/database/database_tracker_unittest.cc
index f10a8ce..c6404b1 100644
--- a/webkit/database/database_tracker_unittest.cc
+++ b/webkit/database/database_tracker_unittest.cc
@@ -5,6 +5,8 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop_proxy.h"
+#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -184,7 +186,7 @@ class DatabaseTracker_TestHelper_Test {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
scoped_refptr<DatabaseTracker> tracker(
- new DatabaseTracker(temp_dir.path(), incognito_mode,
+ new DatabaseTracker(temp_dir.path(), incognito_mode, false,
new TestSpecialStoragePolicy,
NULL, NULL));
@@ -287,7 +289,7 @@ class DatabaseTracker_TestHelper_Test {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
scoped_refptr<DatabaseTracker> tracker(
- new DatabaseTracker(temp_dir.path(), incognito_mode,
+ new DatabaseTracker(temp_dir.path(), incognito_mode, false,
new TestSpecialStoragePolicy,
NULL, NULL));
@@ -407,14 +409,14 @@ class DatabaseTracker_TestHelper_Test {
// Trying to delete an origin with databases in use should fail
tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
&database_size);
- EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1));
+ EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1, false));
origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
EXPECT_TRUE(origin1_info);
EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1));
tracker->DatabaseClosed(kOrigin1, kDB1);
// Delete an origin that doesn't have any database in use
- EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1));
+ EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1, false));
origins_info.clear();
EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
EXPECT_EQ(size_t(1), origins_info.size());
@@ -438,7 +440,7 @@ class DatabaseTracker_TestHelper_Test {
scoped_refptr<TestQuotaManagerProxy> test_quota_proxy(
new TestQuotaManagerProxy);
scoped_refptr<DatabaseTracker> tracker(
- new DatabaseTracker(temp_dir.path(), false /* incognito */,
+ new DatabaseTracker(temp_dir.path(), false /* incognito */, false,
NULL, test_quota_proxy, NULL));
EXPECT_TRUE(test_quota_proxy->registered_client_);
@@ -516,6 +518,102 @@ class DatabaseTracker_TestHelper_Test {
crashed_renderer_connections.RemoveAllConnections();
test_quota_proxy->SimulateQuotaManagerDestroyed();
}
+
+ static void DatabaseTrackerClearLocalStateOnExit() {
+ int64 database_size = 0;
+ const string16 kOrigin1 =
+ DatabaseUtil::GetOriginIdentifier(GURL(kOrigin1Url));
+ const string16 kOrigin2 =
+ DatabaseUtil::GetOriginIdentifier(GURL(kOrigin2Url));
+ const string16 kDB1 = ASCIIToUTF16("db1");
+ const string16 kDB2 = ASCIIToUTF16("db2");
+ const string16 kDB3 = ASCIIToUTF16("db3");
+ const string16 kDescription = ASCIIToUTF16("database_description");
+
+ // Initialize the tracker database.
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath origin1_db_dir;
+ {
+ scoped_refptr<DatabaseTracker> tracker(
+ new DatabaseTracker(
+ temp_dir.path(), false, true,
+ new TestSpecialStoragePolicy,
+ NULL,
+ base::MessageLoopProxy::CreateForCurrentThread()));
+
+ // Open three new databases.
+ tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
+ &database_size);
+ EXPECT_EQ(0, database_size);
+ tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
+ &database_size);
+ EXPECT_EQ(0, database_size);
+ tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
+ &database_size);
+ EXPECT_EQ(0, database_size);
+
+ // Write some data to each file.
+ FilePath db_file;
+ db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
+ EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
+ EXPECT_TRUE(EnsureFileOfSize(db_file, 1));
+
+ db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
+ EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
+ EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
+
+ db_file = tracker->GetFullDBFilePath(kOrigin1, kDB3);
+ EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
+ EXPECT_TRUE(EnsureFileOfSize(db_file, 3));
+
+ // Store the origin database directory as long as it still exists.
+ origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB3).DirName();
+
+ tracker->DatabaseModified(kOrigin1, kDB1);
+ tracker->DatabaseModified(kOrigin2, kDB2);
+ tracker->DatabaseModified(kOrigin1, kDB3);
+
+ // Close all databases but one database.
+ tracker->DatabaseClosed(kOrigin1, kDB1);
+ tracker->DatabaseClosed(kOrigin2, kDB2);
+
+ // Keep an open file handle to the last database.
+ base::PlatformFile file_handle = base::CreatePlatformFile(
+ tracker->GetFullDBFilePath(kOrigin1, kDB3),
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_EXCLUSIVE_READ |
+ base::PLATFORM_FILE_EXCLUSIVE_WRITE |
+ base::PLATFORM_FILE_OPEN_ALWAYS |
+ base::PLATFORM_FILE_SHARE_DELETE,
+ NULL, NULL);
+
+ tracker->Shutdown();
+
+ base::ClosePlatformFile(file_handle);
+ tracker->DatabaseClosed(kOrigin1, kDB3);
+ }
+
+ // At this point, the database tracker should be gone. Create a new one.
+ scoped_refptr<DatabaseTracker> tracker(
+ new DatabaseTracker(temp_dir.path(), false, false,
+ new TestSpecialStoragePolicy,
+ NULL, NULL));
+
+ // Get all data for all origins.
+ std::vector<OriginInfo> origins_info;
+ EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
+ EXPECT_EQ(size_t(1), origins_info.size());
+ EXPECT_EQ(kOrigin2, origins_info[0].GetOrigin());
+ EXPECT_EQ(FilePath(), tracker->GetFullDBFilePath(kOrigin1, kDB1));
+ EXPECT_TRUE(
+ file_util::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
+ EXPECT_EQ(FilePath(), tracker->GetFullDBFilePath(kOrigin1, kDB3));
+
+ // The origin directory should be gone as well.
+ EXPECT_FALSE(file_util::PathExists(origin1_db_dir));
+ }
};
TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
@@ -539,4 +637,9 @@ TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) {
DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
}
+TEST(DatabaseTrackerTest, DatabaseTrackerClearLocalStateOnExit) {
+ // Only works for regular mode.
+ DatabaseTracker_TestHelper_Test::DatabaseTrackerClearLocalStateOnExit();
+}
+
} // namespace webkit_database
diff --git a/webkit/database/vfs_backend.cc b/webkit/database/vfs_backend.cc
index b3879ce..774180e 100644
--- a/webkit/database/vfs_backend.cc
+++ b/webkit/database/vfs_backend.cc
@@ -103,6 +103,10 @@ void VfsBackend::OpenFile(const FilePath& file_path,
base::PLATFORM_FILE_DELETE_ON_CLOSE;
}
+ // This flag will allow us to delete the file later on from the browser
+ // process.
+ flags |= base::PLATFORM_FILE_SHARE_DELETE;
+
// Try to open/create the DB file.
*file_handle =
base::CreatePlatformFile(file_path, flags, NULL, NULL);
diff --git a/webkit/support/simple_database_system.cc b/webkit/support/simple_database_system.cc
index da5f688..73a2452 100644
--- a/webkit/support/simple_database_system.cc
+++ b/webkit/support/simple_database_system.cc
@@ -36,7 +36,8 @@ SimpleDatabaseSystem::SimpleDatabaseSystem()
DCHECK(!instance_);
instance_ = this;
CHECK(temp_dir_.CreateUniqueTempDir());
- db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL, NULL, NULL);
+ db_tracker_ =
+ new DatabaseTracker(temp_dir_.path(), false, false, NULL, NULL, NULL);
db_tracker_->AddObserver(this);
db_thread_.Start();
db_thread_proxy_ = db_thread_.message_loop_proxy();