[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / webkit / database / database_tracker.cc
blob2daeef1af92b11bd0e65b88725550988adc63f46
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webkit/database/database_tracker.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/file_util.h"
13 #include "base/message_loop_proxy.h"
14 #include "base/platform_file.h"
15 #include "base/string_number_conversions.h"
16 #include "base/utf_string_conversions.h"
17 #include "net/base/net_errors.h"
18 #include "sql/connection.h"
19 #include "sql/diagnostic_error_delegate.h"
20 #include "sql/meta_table.h"
21 #include "sql/transaction.h"
22 #include "third_party/sqlite/sqlite3.h"
23 #include "webkit/database/database_quota_client.h"
24 #include "webkit/database/database_util.h"
25 #include "webkit/database/databases_table.h"
26 #include "webkit/quota/quota_manager.h"
27 #include "webkit/quota/special_storage_policy.h"
29 namespace {
31 class HistogramUniquifier {
32 public:
33 static const char* name() { return "Sqlite.DatabaseTracker.Error"; }
36 sql::ErrorDelegate* GetErrorHandlerForTrackerDb() {
37 return new sql::DiagnosticErrorDelegate<HistogramUniquifier>();
40 } // anon namespace
42 namespace webkit_database {
44 const FilePath::CharType kDatabaseDirectoryName[] =
45 FILE_PATH_LITERAL("databases");
46 const FilePath::CharType kIncognitoDatabaseDirectoryName[] =
47 FILE_PATH_LITERAL("databases-incognito");
48 const FilePath::CharType kTrackerDatabaseFileName[] =
49 FILE_PATH_LITERAL("Databases.db");
50 static const int kCurrentVersion = 2;
51 static const int kCompatibleVersion = 1;
53 const FilePath::CharType kTemporaryDirectoryPrefix[] =
54 FILE_PATH_LITERAL("DeleteMe");
55 const FilePath::CharType kTemporaryDirectoryPattern[] =
56 FILE_PATH_LITERAL("DeleteMe*");
58 OriginInfo::OriginInfo()
59 : total_size_(0) {}
61 OriginInfo::OriginInfo(const OriginInfo& origin_info)
62 : origin_(origin_info.origin_),
63 total_size_(origin_info.total_size_),
64 database_info_(origin_info.database_info_) {}
66 OriginInfo::~OriginInfo() {}
68 void OriginInfo::GetAllDatabaseNames(std::vector<string16>* databases) const {
69 for (DatabaseInfoMap::const_iterator it = database_info_.begin();
70 it != database_info_.end(); it++) {
71 databases->push_back(it->first);
75 int64 OriginInfo::GetDatabaseSize(const string16& database_name) const {
76 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
77 if (it != database_info_.end())
78 return it->second.first;
79 return 0;
82 string16 OriginInfo::GetDatabaseDescription(
83 const string16& database_name) const {
84 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
85 if (it != database_info_.end())
86 return it->second.second;
87 return string16();
90 OriginInfo::OriginInfo(const string16& origin, int64 total_size)
91 : origin_(origin), total_size_(total_size) {}
93 DatabaseTracker::DatabaseTracker(
94 const FilePath& profile_path,
95 bool is_incognito,
96 quota::SpecialStoragePolicy* special_storage_policy,
97 quota::QuotaManagerProxy* quota_manager_proxy,
98 base::MessageLoopProxy* db_tracker_thread)
99 : is_initialized_(false),
100 is_incognito_(is_incognito),
101 force_keep_session_state_(false),
102 shutting_down_(false),
103 profile_path_(profile_path),
104 db_dir_(is_incognito_ ?
105 profile_path_.Append(kIncognitoDatabaseDirectoryName) :
106 profile_path_.Append(kDatabaseDirectoryName)),
107 db_(new sql::Connection()),
108 databases_table_(NULL),
109 meta_table_(NULL),
110 special_storage_policy_(special_storage_policy),
111 quota_manager_proxy_(quota_manager_proxy),
112 db_tracker_thread_(db_tracker_thread),
113 incognito_origin_directories_generator_(0) {
114 if (quota_manager_proxy) {
115 quota_manager_proxy->RegisterClient(
116 new DatabaseQuotaClient(db_tracker_thread, this));
120 DatabaseTracker::~DatabaseTracker() {
121 DCHECK(dbs_to_be_deleted_.empty());
122 DCHECK(deletion_callbacks_.empty());
125 void DatabaseTracker::DatabaseOpened(const string16& origin_identifier,
126 const string16& database_name,
127 const string16& database_description,
128 int64 estimated_size,
129 int64* database_size) {
130 if (shutting_down_ || !LazyInit()) {
131 *database_size = 0;
132 return;
135 if (quota_manager_proxy_)
136 quota_manager_proxy_->NotifyStorageAccessed(
137 quota::QuotaClient::kDatabase,
138 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
139 quota::kStorageTypeTemporary);
141 InsertOrUpdateDatabaseDetails(origin_identifier, database_name,
142 database_description, estimated_size);
143 if (database_connections_.AddConnection(origin_identifier, database_name)) {
144 *database_size = SeedOpenDatabaseInfo(origin_identifier,
145 database_name,
146 database_description);
147 return;
149 *database_size = UpdateOpenDatabaseInfoAndNotify(origin_identifier,
150 database_name,
151 &database_description);
154 void DatabaseTracker::DatabaseModified(const string16& origin_identifier,
155 const string16& database_name) {
156 if (!LazyInit())
157 return;
158 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
161 void DatabaseTracker::DatabaseClosed(const string16& origin_identifier,
162 const string16& database_name) {
163 if (database_connections_.IsEmpty()) {
164 DCHECK(!is_initialized_);
165 return;
168 // We call NotifiyStorageAccessed when a db is opened and also when
169 // closed because we don't call it for read while open.
170 if (quota_manager_proxy_)
171 quota_manager_proxy_->NotifyStorageAccessed(
172 quota::QuotaClient::kDatabase,
173 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
174 quota::kStorageTypeTemporary);
176 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
177 if (database_connections_.RemoveConnection(origin_identifier, database_name))
178 DeleteDatabaseIfNeeded(origin_identifier, database_name);
181 void DatabaseTracker::HandleSqliteError(
182 const string16& origin_identifier,
183 const string16& database_name,
184 int error) {
185 // We only handle errors that indicate corruption and we
186 // do so with a heavy hand, we delete it. Any renderers/workers
187 // with this database open will receive a message to close it
188 // immediately, once all have closed, the files will be deleted.
189 // In the interim, all attempts to open a new connection to that
190 // database will fail.
191 // Note: the client-side filters out all but these two errors as
192 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
193 if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
194 DeleteDatabase(origin_identifier, database_name,
195 net::CompletionCallback());
199 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
200 if (database_connections_.IsEmpty()) {
201 DCHECK(!is_initialized_ || connections.IsEmpty());
202 return;
205 // When being closed by this route, there's a chance that
206 // the tracker missed some DatabseModified calls. This method is used
207 // when a renderer crashes to cleanup its open resources.
208 // We need to examine what we have in connections for the
209 // size of each open databases and notify any differences between the
210 // actual file sizes now.
211 std::vector<std::pair<string16, string16> > open_dbs;
212 connections.ListConnections(&open_dbs);
213 for (std::vector<std::pair<string16, string16> >::iterator it =
214 open_dbs.begin(); it != open_dbs.end(); ++it)
215 UpdateOpenDatabaseSizeAndNotify(it->first, it->second);
217 std::vector<std::pair<string16, string16> > closed_dbs;
218 database_connections_.RemoveConnections(connections, &closed_dbs);
219 for (std::vector<std::pair<string16, string16> >::iterator it =
220 closed_dbs.begin(); it != closed_dbs.end(); ++it) {
221 DeleteDatabaseIfNeeded(it->first, it->second);
225 void DatabaseTracker::DeleteDatabaseIfNeeded(const string16& origin_identifier,
226 const string16& database_name) {
227 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier,
228 database_name));
229 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) {
230 DeleteClosedDatabase(origin_identifier, database_name);
231 dbs_to_be_deleted_[origin_identifier].erase(database_name);
232 if (dbs_to_be_deleted_[origin_identifier].empty())
233 dbs_to_be_deleted_.erase(origin_identifier);
235 PendingDeletionCallbacks::iterator callback = deletion_callbacks_.begin();
236 while (callback != deletion_callbacks_.end()) {
237 DatabaseSet::iterator found_origin =
238 callback->second.find(origin_identifier);
239 if (found_origin != callback->second.end()) {
240 std::set<string16>& databases = found_origin->second;
241 databases.erase(database_name);
242 if (databases.empty()) {
243 callback->second.erase(found_origin);
244 if (callback->second.empty()) {
245 net::CompletionCallback cb = callback->first;
246 cb.Run(net::OK);
247 callback = deletion_callbacks_.erase(callback);
248 continue;
253 ++callback;
258 void DatabaseTracker::AddObserver(Observer* observer) {
259 observers_.AddObserver(observer);
262 void DatabaseTracker::RemoveObserver(Observer* observer) {
263 // When we remove a listener, we do not know which cached information
264 // is still needed and which information can be discarded. So we just
265 // clear all caches and re-populate them as needed.
266 observers_.RemoveObserver(observer);
267 ClearAllCachedOriginInfo();
270 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
271 ClearAllCachedOriginInfo();
273 if (!is_incognito_) {
274 meta_table_.reset(NULL);
275 databases_table_.reset(NULL);
276 db_->Close();
277 is_initialized_ = false;
281 string16 DatabaseTracker::GetOriginDirectory(
282 const string16& origin_identifier) {
283 if (!is_incognito_)
284 return origin_identifier;
286 OriginDirectoriesMap::const_iterator it =
287 incognito_origin_directories_.find(origin_identifier);
288 if (it != incognito_origin_directories_.end())
289 return it->second;
291 string16 origin_directory =
292 base::IntToString16(incognito_origin_directories_generator_++);
293 incognito_origin_directories_[origin_identifier] = origin_directory;
294 return origin_directory;
297 FilePath DatabaseTracker::GetFullDBFilePath(
298 const string16& origin_identifier,
299 const string16& database_name) {
300 DCHECK(!origin_identifier.empty());
301 if (!LazyInit())
302 return FilePath();
304 int64 id = databases_table_->GetDatabaseID(
305 origin_identifier, database_name);
306 if (id < 0)
307 return FilePath();
309 FilePath file_name = FilePath::FromWStringHack(
310 UTF8ToWide(base::Int64ToString(id)));
311 return db_dir_.Append(FilePath::FromWStringHack(
312 UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name);
315 bool DatabaseTracker::GetOriginInfo(const string16& origin_identifier,
316 OriginInfo* info) {
317 DCHECK(info);
318 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier);
319 if (!cached_info)
320 return false;
321 *info = OriginInfo(*cached_info);
322 return true;
325 bool DatabaseTracker::GetAllOriginIdentifiers(
326 std::vector<string16>* origin_identifiers) {
327 DCHECK(origin_identifiers);
328 DCHECK(origin_identifiers->empty());
329 if (!LazyInit())
330 return false;
331 return databases_table_->GetAllOrigins(origin_identifiers);
334 bool DatabaseTracker::GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) {
335 DCHECK(origins_info);
336 DCHECK(origins_info->empty());
338 std::vector<string16> origins;
339 if (!GetAllOriginIdentifiers(&origins))
340 return false;
342 for (std::vector<string16>::const_iterator it = origins.begin();
343 it != origins.end(); it++) {
344 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it);
345 if (!origin_info) {
346 // Restore 'origins_info' to its initial state.
347 origins_info->clear();
348 return false;
350 origins_info->push_back(OriginInfo(*origin_info));
353 return true;
356 bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier,
357 const string16& database_name) {
358 if (!LazyInit())
359 return false;
361 // Check if the database is opened by any renderer.
362 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
363 return false;
365 int64 db_file_size = quota_manager_proxy_ ?
366 GetDBFileSize(origin_identifier, database_name) : 0;
368 // Try to delete the file on the hard drive.
369 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
370 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false))
371 return false;
373 // Also delete any orphaned journal file.
374 DCHECK(db_file.Extension().empty());
375 file_util::Delete(db_file.InsertBeforeExtensionASCII(
376 DatabaseUtil::kJournalFileSuffix), false);
378 if (quota_manager_proxy_ && db_file_size)
379 quota_manager_proxy_->NotifyStorageModified(
380 quota::QuotaClient::kDatabase,
381 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
382 quota::kStorageTypeTemporary,
383 -db_file_size);
385 // Clean up the main database and invalidate the cached record.
386 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
387 origins_info_map_.erase(origin_identifier);
389 std::vector<DatabaseDetails> details;
390 if (databases_table_->GetAllDatabaseDetailsForOrigin(
391 origin_identifier, &details) && details.empty()) {
392 // Try to delete the origin in case this was the last database.
393 DeleteOrigin(origin_identifier, false);
395 return true;
398 bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier,
399 bool force) {
400 if (!LazyInit())
401 return false;
403 // Check if any database in this origin is opened by any renderer.
404 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
405 return false;
407 int64 deleted_size = 0;
408 if (quota_manager_proxy_) {
409 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
410 if (origin_info)
411 deleted_size = origin_info->TotalSize();
414 origins_info_map_.erase(origin_identifier);
415 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack(
416 UTF16ToWide(origin_identifier)));
418 // Create a temporary directory to move possibly still existing databases to,
419 // as we can't delete the origin directory on windows if it contains opened
420 // files.
421 FilePath new_origin_dir;
422 file_util::CreateTemporaryDirInDir(db_dir_,
423 kTemporaryDirectoryPrefix,
424 &new_origin_dir);
425 file_util::FileEnumerator databases(
426 origin_dir,
427 false,
428 file_util::FileEnumerator::FILES);
429 for (FilePath database = databases.Next(); !database.empty();
430 database = databases.Next()) {
431 FilePath new_file = new_origin_dir.Append(database.BaseName());
432 file_util::Move(database, new_file);
434 file_util::Delete(origin_dir, true);
435 file_util::Delete(new_origin_dir, true); // might fail on windows.
437 databases_table_->DeleteOrigin(origin_identifier);
439 if (quota_manager_proxy_ && deleted_size) {
440 quota_manager_proxy_->NotifyStorageModified(
441 quota::QuotaClient::kDatabase,
442 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
443 quota::kStorageTypeTemporary,
444 -deleted_size);
447 return true;
450 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
451 const string16& origin_identifier,
452 const string16& database_name) {
453 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
454 if (it == dbs_to_be_deleted_.end())
455 return false;
457 std::set<string16>& databases = it->second;
458 return (databases.find(database_name) != databases.end());
461 bool DatabaseTracker::LazyInit() {
462 if (!is_initialized_ && !shutting_down_) {
463 DCHECK(!db_->is_open());
464 DCHECK(!databases_table_.get());
465 DCHECK(!meta_table_.get());
467 // If there are left-over directories from failed deletion attempts, clean
468 // them up.
469 if (file_util::DirectoryExists(db_dir_)) {
470 file_util::FileEnumerator directories(
471 db_dir_,
472 false,
473 file_util::FileEnumerator::DIRECTORIES,
474 kTemporaryDirectoryPattern);
475 for (FilePath directory = directories.Next(); !directory.empty();
476 directory = directories.Next()) {
477 file_util::Delete(directory, true);
481 // If the tracker database exists, but it's corrupt or doesn't
482 // have a meta table, delete the database directory.
483 const FilePath kTrackerDatabaseFullPath =
484 db_dir_.Append(FilePath(kTrackerDatabaseFileName));
485 if (file_util::DirectoryExists(db_dir_) &&
486 file_util::PathExists(kTrackerDatabaseFullPath) &&
487 (!db_->Open(kTrackerDatabaseFullPath) ||
488 !sql::MetaTable::DoesTableExist(db_.get()))) {
489 db_->Close();
490 if (!file_util::Delete(db_dir_, true))
491 return false;
494 db_->set_error_delegate(GetErrorHandlerForTrackerDb());
496 databases_table_.reset(new DatabasesTable(db_.get()));
497 meta_table_.reset(new sql::MetaTable());
499 is_initialized_ =
500 file_util::CreateDirectory(db_dir_) &&
501 (db_->is_open() ||
502 (is_incognito_ ? db_->OpenInMemory() :
503 db_->Open(kTrackerDatabaseFullPath))) &&
504 UpgradeToCurrentVersion();
505 if (!is_initialized_) {
506 databases_table_.reset(NULL);
507 meta_table_.reset(NULL);
508 db_->Close();
511 return is_initialized_;
514 bool DatabaseTracker::UpgradeToCurrentVersion() {
515 sql::Transaction transaction(db_.get());
516 if (!transaction.Begin() ||
517 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
518 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
519 !databases_table_->Init())
520 return false;
522 if (meta_table_->GetVersionNumber() < kCurrentVersion)
523 meta_table_->SetVersionNumber(kCurrentVersion);
525 return transaction.Commit();
528 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
529 const string16& origin_identifier,
530 const string16& database_name,
531 const string16& database_description,
532 int64 estimated_size) {
533 DatabaseDetails details;
534 if (!databases_table_->GetDatabaseDetails(
535 origin_identifier, database_name, &details)) {
536 details.origin_identifier = origin_identifier;
537 details.database_name = database_name;
538 details.description = database_description;
539 details.estimated_size = estimated_size;
540 databases_table_->InsertDatabaseDetails(details);
541 } else if ((details.description != database_description) ||
542 (details.estimated_size != estimated_size)) {
543 details.description = database_description;
544 details.estimated_size = estimated_size;
545 databases_table_->UpdateDatabaseDetails(details);
549 void DatabaseTracker::ClearAllCachedOriginInfo() {
550 origins_info_map_.clear();
553 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
554 const string16& origin_identifier, bool create_if_needed) {
555 if (!LazyInit())
556 return NULL;
558 // Populate the cache with data for this origin if needed.
559 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
560 if (!create_if_needed)
561 return NULL;
563 std::vector<DatabaseDetails> details;
564 if (!databases_table_->GetAllDatabaseDetailsForOrigin(
565 origin_identifier, &details)) {
566 return NULL;
569 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
570 origin_info.SetOrigin(origin_identifier);
571 for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
572 it != details.end(); it++) {
573 int64 db_file_size;
574 if (database_connections_.IsDatabaseOpened(
575 origin_identifier, it->database_name)) {
576 db_file_size = database_connections_.GetOpenDatabaseSize(
577 origin_identifier, it->database_name);
578 } else {
579 db_file_size = GetDBFileSize(origin_identifier, it->database_name);
581 origin_info.SetDatabaseSize(it->database_name, db_file_size);
582 origin_info.SetDatabaseDescription(it->database_name, it->description);
586 return &origins_info_map_[origin_identifier];
589 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier,
590 const string16& database_name) {
591 FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name);
592 int64 db_file_size = 0;
593 if (!file_util::GetFileSize(db_file_name, &db_file_size))
594 db_file_size = 0;
595 return db_file_size;
598 int64 DatabaseTracker::SeedOpenDatabaseInfo(
599 const string16& origin_id, const string16& name,
600 const string16& description) {
601 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
602 int64 size = GetDBFileSize(origin_id, name);
603 database_connections_.SetOpenDatabaseSize(origin_id, name, size);
604 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
605 if (info) {
606 info->SetDatabaseSize(name, size);
607 info->SetDatabaseDescription(name, description);
609 return size;
612 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
613 const string16& origin_id, const string16& name,
614 const string16* opt_description) {
615 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
616 int64 new_size = GetDBFileSize(origin_id, name);
617 int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
618 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
619 if (info && opt_description)
620 info->SetDatabaseDescription(name, *opt_description);
621 if (old_size != new_size) {
622 database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
623 if (info)
624 info->SetDatabaseSize(name, new_size);
625 if (quota_manager_proxy_)
626 quota_manager_proxy_->NotifyStorageModified(
627 quota::QuotaClient::kDatabase,
628 DatabaseUtil::GetOriginFromIdentifier(origin_id),
629 quota::kStorageTypeTemporary,
630 new_size - old_size);
631 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
632 origin_id, name, new_size));
634 return new_size;
637 void DatabaseTracker::ScheduleDatabaseForDeletion(
638 const string16& origin_identifier,
639 const string16& database_name) {
640 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
641 database_name));
642 dbs_to_be_deleted_[origin_identifier].insert(database_name);
643 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
644 origin_identifier, database_name));
647 void DatabaseTracker::ScheduleDatabasesForDeletion(
648 const DatabaseSet& databases,
649 const net::CompletionCallback& callback) {
650 DCHECK(!databases.empty());
652 if (!callback.is_null())
653 deletion_callbacks_.push_back(std::make_pair(callback, databases));
654 for (DatabaseSet::const_iterator ori = databases.begin();
655 ori != databases.end(); ++ori) {
656 for (std::set<string16>::const_iterator db = ori->second.begin();
657 db != ori->second.end(); ++db)
658 ScheduleDatabaseForDeletion(ori->first, *db);
662 int DatabaseTracker::DeleteDatabase(const string16& origin_identifier,
663 const string16& database_name,
664 const net::CompletionCallback& callback) {
665 if (!LazyInit())
666 return net::ERR_FAILED;
668 if (database_connections_.IsDatabaseOpened(origin_identifier,
669 database_name)) {
670 if (!callback.is_null()) {
671 DatabaseSet set;
672 set[origin_identifier].insert(database_name);
673 deletion_callbacks_.push_back(std::make_pair(callback, set));
675 ScheduleDatabaseForDeletion(origin_identifier, database_name);
676 return net::ERR_IO_PENDING;
678 DeleteClosedDatabase(origin_identifier, database_name);
679 return net::OK;
682 int DatabaseTracker::DeleteDataModifiedSince(
683 const base::Time& cutoff,
684 const net::CompletionCallback& callback) {
685 if (!LazyInit())
686 return net::ERR_FAILED;
688 DatabaseSet to_be_deleted;
690 std::vector<string16> origins_identifiers;
691 if (!databases_table_->GetAllOrigins(&origins_identifiers))
692 return net::ERR_FAILED;
693 int rv = net::OK;
694 for (std::vector<string16>::const_iterator ori = origins_identifiers.begin();
695 ori != origins_identifiers.end(); ++ori) {
696 if (special_storage_policy_.get() &&
697 special_storage_policy_->IsStorageProtected(
698 DatabaseUtil::GetOriginFromIdentifier(*ori))) {
699 continue;
702 std::vector<DatabaseDetails> details;
703 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details))
704 rv = net::ERR_FAILED;
705 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
706 db != details.end(); ++db) {
707 FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
708 base::PlatformFileInfo file_info;
709 file_util::GetFileInfo(db_file, &file_info);
710 if (file_info.last_modified < cutoff)
711 continue;
713 // Check if the database is opened by any renderer.
714 if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
715 to_be_deleted[*ori].insert(db->database_name);
716 else
717 DeleteClosedDatabase(*ori, db->database_name);
721 if (rv != net::OK)
722 return rv;
724 if (!to_be_deleted.empty()) {
725 ScheduleDatabasesForDeletion(to_be_deleted, callback);
726 return net::ERR_IO_PENDING;
728 return net::OK;
731 int DatabaseTracker::DeleteDataForOrigin(
732 const string16& origin, const net::CompletionCallback& callback) {
733 if (!LazyInit())
734 return net::ERR_FAILED;
736 DatabaseSet to_be_deleted;
738 std::vector<DatabaseDetails> details;
739 if (!databases_table_->GetAllDatabaseDetailsForOrigin(origin, &details))
740 return net::ERR_FAILED;
741 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
742 db != details.end(); ++db) {
743 // Check if the database is opened by any renderer.
744 if (database_connections_.IsDatabaseOpened(origin, db->database_name))
745 to_be_deleted[origin].insert(db->database_name);
746 else
747 DeleteClosedDatabase(origin, db->database_name);
750 if (!to_be_deleted.empty()) {
751 ScheduleDatabasesForDeletion(to_be_deleted, callback);
752 return net::ERR_IO_PENDING;
754 return net::OK;
757 void DatabaseTracker::GetIncognitoFileHandle(
758 const string16& vfs_file_name, base::PlatformFile* file_handle) const {
759 DCHECK(is_incognito_);
760 FileHandlesMap::const_iterator it =
761 incognito_file_handles_.find(vfs_file_name);
762 if (it != incognito_file_handles_.end())
763 *file_handle = it->second;
764 else
765 *file_handle = base::kInvalidPlatformFileValue;
768 void DatabaseTracker::SaveIncognitoFileHandle(
769 const string16& vfs_file_name, const base::PlatformFile& file_handle) {
770 DCHECK(is_incognito_);
771 DCHECK(incognito_file_handles_.find(vfs_file_name) ==
772 incognito_file_handles_.end());
773 if (file_handle != base::kInvalidPlatformFileValue)
774 incognito_file_handles_[vfs_file_name] = file_handle;
777 bool DatabaseTracker::CloseIncognitoFileHandle(const string16& vfs_file_name) {
778 DCHECK(is_incognito_);
779 DCHECK(incognito_file_handles_.find(vfs_file_name) !=
780 incognito_file_handles_.end());
782 bool handle_closed = false;
783 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
784 if (it != incognito_file_handles_.end()) {
785 handle_closed = base::ClosePlatformFile(it->second);
786 if (handle_closed)
787 incognito_file_handles_.erase(it);
789 return handle_closed;
792 bool DatabaseTracker::HasSavedIncognitoFileHandle(
793 const string16& vfs_file_name) const {
794 return (incognito_file_handles_.find(vfs_file_name) !=
795 incognito_file_handles_.end());
798 void DatabaseTracker::DeleteIncognitoDBDirectory() {
799 shutting_down_ = true;
800 is_initialized_ = false;
802 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
803 it != incognito_file_handles_.end(); it++)
804 base::ClosePlatformFile(it->second);
806 FilePath incognito_db_dir =
807 profile_path_.Append(kIncognitoDatabaseDirectoryName);
808 if (file_util::DirectoryExists(incognito_db_dir))
809 file_util::Delete(incognito_db_dir, true);
812 void DatabaseTracker::ClearSessionOnlyOrigins() {
813 shutting_down_ = true;
815 bool has_session_only_databases =
816 special_storage_policy_.get() &&
817 special_storage_policy_->HasSessionOnlyOrigins();
819 // Clearing only session-only databases, and there are none.
820 if (!has_session_only_databases)
821 return;
823 if (!LazyInit())
824 return;
826 std::vector<string16> origin_identifiers;
827 GetAllOriginIdentifiers(&origin_identifiers);
829 for (std::vector<string16>::iterator origin = origin_identifiers.begin();
830 origin != origin_identifiers.end(); ++origin) {
831 GURL origin_url =
832 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin);
833 if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
834 continue;
835 if (special_storage_policy_->IsStorageProtected(origin_url))
836 continue;
837 webkit_database::OriginInfo origin_info;
838 std::vector<string16> databases;
839 GetOriginInfo(*origin, &origin_info);
840 origin_info.GetAllDatabaseNames(&databases);
842 for (std::vector<string16>::iterator database = databases.begin();
843 database != databases.end(); ++database) {
844 base::PlatformFile file_handle = base::CreatePlatformFile(
845 GetFullDBFilePath(*origin, *database),
846 base::PLATFORM_FILE_OPEN_ALWAYS |
847 base::PLATFORM_FILE_SHARE_DELETE |
848 base::PLATFORM_FILE_DELETE_ON_CLOSE |
849 base::PLATFORM_FILE_READ,
850 NULL, NULL);
851 base::ClosePlatformFile(file_handle);
853 DeleteOrigin(*origin, true);
858 void DatabaseTracker::Shutdown() {
859 DCHECK(db_tracker_thread_.get());
860 DCHECK(db_tracker_thread_->BelongsToCurrentThread());
861 if (shutting_down_) {
862 NOTREACHED();
863 return;
865 if (is_incognito_)
866 DeleteIncognitoDBDirectory();
867 else if (!force_keep_session_state_)
868 ClearSessionOnlyOrigins();
871 void DatabaseTracker::SetForceKeepSessionState() {
872 DCHECK(db_tracker_thread_.get());
873 if (!db_tracker_thread_->BelongsToCurrentThread()) {
874 db_tracker_thread_->PostTask(
875 FROM_HERE,
876 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
877 return;
879 force_keep_session_state_ = true;
882 } // namespace webkit_database