Revert 198312 "Effects Pepper Plugin and MediaStream Glue."
[chromium-blink-merge.git] / webkit / database / database_tracker.cc
blob85fa2624eb93d59dc8f37ce06e9d8e6e0337111b
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/strings/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/meta_table.h"
20 #include "sql/transaction.h"
21 #include "third_party/sqlite/sqlite3.h"
22 #include "webkit/database/database_quota_client.h"
23 #include "webkit/database/database_util.h"
24 #include "webkit/database/databases_table.h"
25 #include "webkit/quota/quota_manager.h"
26 #include "webkit/quota/special_storage_policy.h"
28 namespace webkit_database {
30 const base::FilePath::CharType kDatabaseDirectoryName[] =
31 FILE_PATH_LITERAL("databases");
32 const base::FilePath::CharType kIncognitoDatabaseDirectoryName[] =
33 FILE_PATH_LITERAL("databases-incognito");
34 const base::FilePath::CharType kTrackerDatabaseFileName[] =
35 FILE_PATH_LITERAL("Databases.db");
36 static const int kCurrentVersion = 2;
37 static const int kCompatibleVersion = 1;
39 const base::FilePath::CharType kTemporaryDirectoryPrefix[] =
40 FILE_PATH_LITERAL("DeleteMe");
41 const base::FilePath::CharType kTemporaryDirectoryPattern[] =
42 FILE_PATH_LITERAL("DeleteMe*");
44 OriginInfo::OriginInfo()
45 : total_size_(0) {}
47 OriginInfo::OriginInfo(const OriginInfo& origin_info)
48 : origin_(origin_info.origin_),
49 total_size_(origin_info.total_size_),
50 database_info_(origin_info.database_info_) {}
52 OriginInfo::~OriginInfo() {}
54 void OriginInfo::GetAllDatabaseNames(
55 std::vector<base::string16>* databases) const {
56 for (DatabaseInfoMap::const_iterator it = database_info_.begin();
57 it != database_info_.end(); it++) {
58 databases->push_back(it->first);
62 int64 OriginInfo::GetDatabaseSize(const base::string16& database_name) const {
63 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
64 if (it != database_info_.end())
65 return it->second.first;
66 return 0;
69 base::string16 OriginInfo::GetDatabaseDescription(
70 const base::string16& database_name) const {
71 DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
72 if (it != database_info_.end())
73 return it->second.second;
74 return base::string16();
77 OriginInfo::OriginInfo(const base::string16& origin, int64 total_size)
78 : origin_(origin), total_size_(total_size) {}
80 DatabaseTracker::DatabaseTracker(
81 const base::FilePath& profile_path,
82 bool is_incognito,
83 quota::SpecialStoragePolicy* special_storage_policy,
84 quota::QuotaManagerProxy* quota_manager_proxy,
85 base::MessageLoopProxy* db_tracker_thread)
86 : is_initialized_(false),
87 is_incognito_(is_incognito),
88 force_keep_session_state_(false),
89 shutting_down_(false),
90 profile_path_(profile_path),
91 db_dir_(is_incognito_ ?
92 profile_path_.Append(kIncognitoDatabaseDirectoryName) :
93 profile_path_.Append(kDatabaseDirectoryName)),
94 db_(new sql::Connection()),
95 databases_table_(NULL),
96 meta_table_(NULL),
97 special_storage_policy_(special_storage_policy),
98 quota_manager_proxy_(quota_manager_proxy),
99 db_tracker_thread_(db_tracker_thread),
100 incognito_origin_directories_generator_(0) {
101 if (quota_manager_proxy) {
102 quota_manager_proxy->RegisterClient(
103 new DatabaseQuotaClient(db_tracker_thread, this));
107 DatabaseTracker::~DatabaseTracker() {
108 DCHECK(dbs_to_be_deleted_.empty());
109 DCHECK(deletion_callbacks_.empty());
112 void DatabaseTracker::DatabaseOpened(const base::string16& origin_identifier,
113 const base::string16& database_name,
114 const base::string16& database_description,
115 int64 estimated_size,
116 int64* database_size) {
117 if (shutting_down_ || !LazyInit()) {
118 *database_size = 0;
119 return;
122 if (quota_manager_proxy_)
123 quota_manager_proxy_->NotifyStorageAccessed(
124 quota::QuotaClient::kDatabase,
125 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
126 quota::kStorageTypeTemporary);
128 InsertOrUpdateDatabaseDetails(origin_identifier, database_name,
129 database_description, estimated_size);
130 if (database_connections_.AddConnection(origin_identifier, database_name)) {
131 *database_size = SeedOpenDatabaseInfo(origin_identifier,
132 database_name,
133 database_description);
134 return;
136 *database_size = UpdateOpenDatabaseInfoAndNotify(origin_identifier,
137 database_name,
138 &database_description);
141 void DatabaseTracker::DatabaseModified(const base::string16& origin_identifier,
142 const base::string16& database_name) {
143 if (!LazyInit())
144 return;
145 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
148 void DatabaseTracker::DatabaseClosed(const base::string16& origin_identifier,
149 const base::string16& database_name) {
150 if (database_connections_.IsEmpty()) {
151 DCHECK(!is_initialized_);
152 return;
155 // We call NotifiyStorageAccessed when a db is opened and also when
156 // closed because we don't call it for read while open.
157 if (quota_manager_proxy_)
158 quota_manager_proxy_->NotifyStorageAccessed(
159 quota::QuotaClient::kDatabase,
160 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
161 quota::kStorageTypeTemporary);
163 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
164 if (database_connections_.RemoveConnection(origin_identifier, database_name))
165 DeleteDatabaseIfNeeded(origin_identifier, database_name);
168 void DatabaseTracker::HandleSqliteError(
169 const base::string16& origin_identifier,
170 const base::string16& database_name,
171 int error) {
172 // We only handle errors that indicate corruption and we
173 // do so with a heavy hand, we delete it. Any renderers/workers
174 // with this database open will receive a message to close it
175 // immediately, once all have closed, the files will be deleted.
176 // In the interim, all attempts to open a new connection to that
177 // database will fail.
178 // Note: the client-side filters out all but these two errors as
179 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
180 if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
181 DeleteDatabase(origin_identifier, database_name,
182 net::CompletionCallback());
186 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
187 if (database_connections_.IsEmpty()) {
188 DCHECK(!is_initialized_ || connections.IsEmpty());
189 return;
192 // When being closed by this route, there's a chance that
193 // the tracker missed some DatabseModified calls. This method is used
194 // when a renderer crashes to cleanup its open resources.
195 // We need to examine what we have in connections for the
196 // size of each open databases and notify any differences between the
197 // actual file sizes now.
198 std::vector<std::pair<base::string16, base::string16> > open_dbs;
199 connections.ListConnections(&open_dbs);
200 for (std::vector<std::pair<base::string16, base::string16> >::iterator it =
201 open_dbs.begin(); it != open_dbs.end(); ++it)
202 UpdateOpenDatabaseSizeAndNotify(it->first, it->second);
204 std::vector<std::pair<base::string16, base::string16> > closed_dbs;
205 database_connections_.RemoveConnections(connections, &closed_dbs);
206 for (std::vector<std::pair<base::string16, base::string16> >::iterator it =
207 closed_dbs.begin(); it != closed_dbs.end(); ++it) {
208 DeleteDatabaseIfNeeded(it->first, it->second);
212 void DatabaseTracker::DeleteDatabaseIfNeeded(
213 const base::string16& origin_identifier,
214 const base::string16& database_name) {
215 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier,
216 database_name));
217 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) {
218 DeleteClosedDatabase(origin_identifier, database_name);
219 dbs_to_be_deleted_[origin_identifier].erase(database_name);
220 if (dbs_to_be_deleted_[origin_identifier].empty())
221 dbs_to_be_deleted_.erase(origin_identifier);
223 PendingDeletionCallbacks::iterator callback = deletion_callbacks_.begin();
224 while (callback != deletion_callbacks_.end()) {
225 DatabaseSet::iterator found_origin =
226 callback->second.find(origin_identifier);
227 if (found_origin != callback->second.end()) {
228 std::set<base::string16>& databases = found_origin->second;
229 databases.erase(database_name);
230 if (databases.empty()) {
231 callback->second.erase(found_origin);
232 if (callback->second.empty()) {
233 net::CompletionCallback cb = callback->first;
234 cb.Run(net::OK);
235 callback = deletion_callbacks_.erase(callback);
236 continue;
241 ++callback;
246 void DatabaseTracker::AddObserver(Observer* observer) {
247 observers_.AddObserver(observer);
250 void DatabaseTracker::RemoveObserver(Observer* observer) {
251 // When we remove a listener, we do not know which cached information
252 // is still needed and which information can be discarded. So we just
253 // clear all caches and re-populate them as needed.
254 observers_.RemoveObserver(observer);
255 ClearAllCachedOriginInfo();
258 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
259 ClearAllCachedOriginInfo();
261 if (!is_incognito_) {
262 meta_table_.reset(NULL);
263 databases_table_.reset(NULL);
264 db_->Close();
265 is_initialized_ = false;
269 base::string16 DatabaseTracker::GetOriginDirectory(
270 const base::string16& origin_identifier) {
271 if (!is_incognito_)
272 return origin_identifier;
274 OriginDirectoriesMap::const_iterator it =
275 incognito_origin_directories_.find(origin_identifier);
276 if (it != incognito_origin_directories_.end())
277 return it->second;
279 base::string16 origin_directory =
280 base::IntToString16(incognito_origin_directories_generator_++);
281 incognito_origin_directories_[origin_identifier] = origin_directory;
282 return origin_directory;
285 base::FilePath DatabaseTracker::GetFullDBFilePath(
286 const base::string16& origin_identifier,
287 const base::string16& database_name) {
288 DCHECK(!origin_identifier.empty());
289 if (!LazyInit())
290 return base::FilePath();
292 int64 id = databases_table_->GetDatabaseID(
293 origin_identifier, database_name);
294 if (id < 0)
295 return base::FilePath();
297 base::FilePath file_name = base::FilePath::FromWStringHack(
298 UTF8ToWide(base::Int64ToString(id)));
299 return db_dir_.Append(base::FilePath::FromWStringHack(
300 UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name);
303 bool DatabaseTracker::GetOriginInfo(const base::string16& origin_identifier,
304 OriginInfo* info) {
305 DCHECK(info);
306 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier);
307 if (!cached_info)
308 return false;
309 *info = OriginInfo(*cached_info);
310 return true;
313 bool DatabaseTracker::GetAllOriginIdentifiers(
314 std::vector<base::string16>* origin_identifiers) {
315 DCHECK(origin_identifiers);
316 DCHECK(origin_identifiers->empty());
317 if (!LazyInit())
318 return false;
319 return databases_table_->GetAllOrigins(origin_identifiers);
322 bool DatabaseTracker::GetAllOriginsInfo(
323 std::vector<OriginInfo>* origins_info) {
324 DCHECK(origins_info);
325 DCHECK(origins_info->empty());
327 std::vector<base::string16> origins;
328 if (!GetAllOriginIdentifiers(&origins))
329 return false;
331 for (std::vector<base::string16>::const_iterator it = origins.begin();
332 it != origins.end(); it++) {
333 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it);
334 if (!origin_info) {
335 // Restore 'origins_info' to its initial state.
336 origins_info->clear();
337 return false;
339 origins_info->push_back(OriginInfo(*origin_info));
342 return true;
345 bool DatabaseTracker::DeleteClosedDatabase(
346 const base::string16& origin_identifier,
347 const base::string16& database_name) {
348 if (!LazyInit())
349 return false;
351 // Check if the database is opened by any renderer.
352 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
353 return false;
355 int64 db_file_size = quota_manager_proxy_ ?
356 GetDBFileSize(origin_identifier, database_name) : 0;
358 // Try to delete the file on the hard drive.
359 base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
360 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false))
361 return false;
363 // Also delete any orphaned journal file.
364 DCHECK(db_file.Extension().empty());
365 file_util::Delete(db_file.InsertBeforeExtensionASCII(
366 DatabaseUtil::kJournalFileSuffix), false);
368 if (quota_manager_proxy_ && db_file_size)
369 quota_manager_proxy_->NotifyStorageModified(
370 quota::QuotaClient::kDatabase,
371 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
372 quota::kStorageTypeTemporary,
373 -db_file_size);
375 // Clean up the main database and invalidate the cached record.
376 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
377 origins_info_map_.erase(origin_identifier);
379 std::vector<DatabaseDetails> details;
380 if (databases_table_->GetAllDatabaseDetailsForOrigin(
381 origin_identifier, &details) && details.empty()) {
382 // Try to delete the origin in case this was the last database.
383 DeleteOrigin(origin_identifier, false);
385 return true;
388 bool DatabaseTracker::DeleteOrigin(const base::string16& origin_identifier,
389 bool force) {
390 if (!LazyInit())
391 return false;
393 // Check if any database in this origin is opened by any renderer.
394 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
395 return false;
397 int64 deleted_size = 0;
398 if (quota_manager_proxy_) {
399 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
400 if (origin_info)
401 deleted_size = origin_info->TotalSize();
404 origins_info_map_.erase(origin_identifier);
405 base::FilePath origin_dir = db_dir_.Append(base::FilePath::FromWStringHack(
406 UTF16ToWide(origin_identifier)));
408 // Create a temporary directory to move possibly still existing databases to,
409 // as we can't delete the origin directory on windows if it contains opened
410 // files.
411 base::FilePath new_origin_dir;
412 file_util::CreateTemporaryDirInDir(db_dir_,
413 kTemporaryDirectoryPrefix,
414 &new_origin_dir);
415 file_util::FileEnumerator databases(
416 origin_dir,
417 false,
418 file_util::FileEnumerator::FILES);
419 for (base::FilePath database = databases.Next(); !database.empty();
420 database = databases.Next()) {
421 base::FilePath new_file = new_origin_dir.Append(database.BaseName());
422 file_util::Move(database, new_file);
424 file_util::Delete(origin_dir, true);
425 file_util::Delete(new_origin_dir, true); // might fail on windows.
427 databases_table_->DeleteOrigin(origin_identifier);
429 if (quota_manager_proxy_ && deleted_size) {
430 quota_manager_proxy_->NotifyStorageModified(
431 quota::QuotaClient::kDatabase,
432 DatabaseUtil::GetOriginFromIdentifier(origin_identifier),
433 quota::kStorageTypeTemporary,
434 -deleted_size);
437 return true;
440 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
441 const base::string16& origin_identifier,
442 const base::string16& database_name) {
443 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
444 if (it == dbs_to_be_deleted_.end())
445 return false;
447 std::set<base::string16>& databases = it->second;
448 return (databases.find(database_name) != databases.end());
451 bool DatabaseTracker::LazyInit() {
452 if (!is_initialized_ && !shutting_down_) {
453 DCHECK(!db_->is_open());
454 DCHECK(!databases_table_.get());
455 DCHECK(!meta_table_.get());
457 // If there are left-over directories from failed deletion attempts, clean
458 // them up.
459 if (file_util::DirectoryExists(db_dir_)) {
460 file_util::FileEnumerator directories(
461 db_dir_,
462 false,
463 file_util::FileEnumerator::DIRECTORIES,
464 kTemporaryDirectoryPattern);
465 for (base::FilePath directory = directories.Next(); !directory.empty();
466 directory = directories.Next()) {
467 file_util::Delete(directory, true);
471 // If the tracker database exists, but it's corrupt or doesn't
472 // have a meta table, delete the database directory.
473 const base::FilePath kTrackerDatabaseFullPath =
474 db_dir_.Append(base::FilePath(kTrackerDatabaseFileName));
475 if (file_util::DirectoryExists(db_dir_) &&
476 file_util::PathExists(kTrackerDatabaseFullPath) &&
477 (!db_->Open(kTrackerDatabaseFullPath) ||
478 !sql::MetaTable::DoesTableExist(db_.get()))) {
479 db_->Close();
480 if (!file_util::Delete(db_dir_, true))
481 return false;
484 db_->set_error_histogram_name("Sqlite.DatabaseTracker.Error");
486 databases_table_.reset(new DatabasesTable(db_.get()));
487 meta_table_.reset(new sql::MetaTable());
489 is_initialized_ =
490 file_util::CreateDirectory(db_dir_) &&
491 (db_->is_open() ||
492 (is_incognito_ ? db_->OpenInMemory() :
493 db_->Open(kTrackerDatabaseFullPath))) &&
494 UpgradeToCurrentVersion();
495 if (!is_initialized_) {
496 databases_table_.reset(NULL);
497 meta_table_.reset(NULL);
498 db_->Close();
501 return is_initialized_;
504 bool DatabaseTracker::UpgradeToCurrentVersion() {
505 sql::Transaction transaction(db_.get());
506 if (!transaction.Begin() ||
507 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
508 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
509 !databases_table_->Init())
510 return false;
512 if (meta_table_->GetVersionNumber() < kCurrentVersion)
513 meta_table_->SetVersionNumber(kCurrentVersion);
515 return transaction.Commit();
518 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
519 const base::string16& origin_identifier,
520 const base::string16& database_name,
521 const base::string16& database_description,
522 int64 estimated_size) {
523 DatabaseDetails details;
524 if (!databases_table_->GetDatabaseDetails(
525 origin_identifier, database_name, &details)) {
526 details.origin_identifier = origin_identifier;
527 details.database_name = database_name;
528 details.description = database_description;
529 details.estimated_size = estimated_size;
530 databases_table_->InsertDatabaseDetails(details);
531 } else if ((details.description != database_description) ||
532 (details.estimated_size != estimated_size)) {
533 details.description = database_description;
534 details.estimated_size = estimated_size;
535 databases_table_->UpdateDatabaseDetails(details);
539 void DatabaseTracker::ClearAllCachedOriginInfo() {
540 origins_info_map_.clear();
543 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
544 const base::string16& origin_identifier, bool create_if_needed) {
545 if (!LazyInit())
546 return NULL;
548 // Populate the cache with data for this origin if needed.
549 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
550 if (!create_if_needed)
551 return NULL;
553 std::vector<DatabaseDetails> details;
554 if (!databases_table_->GetAllDatabaseDetailsForOrigin(
555 origin_identifier, &details)) {
556 return NULL;
559 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
560 origin_info.SetOrigin(origin_identifier);
561 for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
562 it != details.end(); it++) {
563 int64 db_file_size;
564 if (database_connections_.IsDatabaseOpened(
565 origin_identifier, it->database_name)) {
566 db_file_size = database_connections_.GetOpenDatabaseSize(
567 origin_identifier, it->database_name);
568 } else {
569 db_file_size = GetDBFileSize(origin_identifier, it->database_name);
571 origin_info.SetDatabaseSize(it->database_name, db_file_size);
572 origin_info.SetDatabaseDescription(it->database_name, it->description);
576 return &origins_info_map_[origin_identifier];
579 int64 DatabaseTracker::GetDBFileSize(const base::string16& origin_identifier,
580 const base::string16& database_name) {
581 base::FilePath db_file_name = GetFullDBFilePath(origin_identifier,
582 database_name);
583 int64 db_file_size = 0;
584 if (!file_util::GetFileSize(db_file_name, &db_file_size))
585 db_file_size = 0;
586 return db_file_size;
589 int64 DatabaseTracker::SeedOpenDatabaseInfo(
590 const base::string16& origin_id, const base::string16& name,
591 const base::string16& description) {
592 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
593 int64 size = GetDBFileSize(origin_id, name);
594 database_connections_.SetOpenDatabaseSize(origin_id, name, size);
595 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
596 if (info) {
597 info->SetDatabaseSize(name, size);
598 info->SetDatabaseDescription(name, description);
600 return size;
603 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
604 const base::string16& origin_id, const base::string16& name,
605 const base::string16* opt_description) {
606 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
607 int64 new_size = GetDBFileSize(origin_id, name);
608 int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
609 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
610 if (info && opt_description)
611 info->SetDatabaseDescription(name, *opt_description);
612 if (old_size != new_size) {
613 database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
614 if (info)
615 info->SetDatabaseSize(name, new_size);
616 if (quota_manager_proxy_)
617 quota_manager_proxy_->NotifyStorageModified(
618 quota::QuotaClient::kDatabase,
619 DatabaseUtil::GetOriginFromIdentifier(origin_id),
620 quota::kStorageTypeTemporary,
621 new_size - old_size);
622 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
623 origin_id, name, new_size));
625 return new_size;
628 void DatabaseTracker::ScheduleDatabaseForDeletion(
629 const base::string16& origin_identifier,
630 const base::string16& database_name) {
631 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
632 database_name));
633 dbs_to_be_deleted_[origin_identifier].insert(database_name);
634 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
635 origin_identifier, database_name));
638 void DatabaseTracker::ScheduleDatabasesForDeletion(
639 const DatabaseSet& databases,
640 const net::CompletionCallback& callback) {
641 DCHECK(!databases.empty());
643 if (!callback.is_null())
644 deletion_callbacks_.push_back(std::make_pair(callback, databases));
645 for (DatabaseSet::const_iterator ori = databases.begin();
646 ori != databases.end(); ++ori) {
647 for (std::set<base::string16>::const_iterator db = ori->second.begin();
648 db != ori->second.end(); ++db)
649 ScheduleDatabaseForDeletion(ori->first, *db);
653 int DatabaseTracker::DeleteDatabase(const base::string16& origin_identifier,
654 const base::string16& database_name,
655 const net::CompletionCallback& callback) {
656 if (!LazyInit())
657 return net::ERR_FAILED;
659 if (database_connections_.IsDatabaseOpened(origin_identifier,
660 database_name)) {
661 if (!callback.is_null()) {
662 DatabaseSet set;
663 set[origin_identifier].insert(database_name);
664 deletion_callbacks_.push_back(std::make_pair(callback, set));
666 ScheduleDatabaseForDeletion(origin_identifier, database_name);
667 return net::ERR_IO_PENDING;
669 DeleteClosedDatabase(origin_identifier, database_name);
670 return net::OK;
673 int DatabaseTracker::DeleteDataModifiedSince(
674 const base::Time& cutoff,
675 const net::CompletionCallback& callback) {
676 if (!LazyInit())
677 return net::ERR_FAILED;
679 DatabaseSet to_be_deleted;
681 std::vector<base::string16> origins_identifiers;
682 if (!databases_table_->GetAllOrigins(&origins_identifiers))
683 return net::ERR_FAILED;
684 int rv = net::OK;
685 for (std::vector<base::string16>::const_iterator ori =
686 origins_identifiers.begin();
687 ori != origins_identifiers.end(); ++ori) {
688 if (special_storage_policy_.get() &&
689 special_storage_policy_->IsStorageProtected(
690 DatabaseUtil::GetOriginFromIdentifier(*ori))) {
691 continue;
694 std::vector<DatabaseDetails> details;
695 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details))
696 rv = net::ERR_FAILED;
697 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
698 db != details.end(); ++db) {
699 base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
700 base::PlatformFileInfo file_info;
701 file_util::GetFileInfo(db_file, &file_info);
702 if (file_info.last_modified < cutoff)
703 continue;
705 // Check if the database is opened by any renderer.
706 if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
707 to_be_deleted[*ori].insert(db->database_name);
708 else
709 DeleteClosedDatabase(*ori, db->database_name);
713 if (rv != net::OK)
714 return rv;
716 if (!to_be_deleted.empty()) {
717 ScheduleDatabasesForDeletion(to_be_deleted, callback);
718 return net::ERR_IO_PENDING;
720 return net::OK;
723 int DatabaseTracker::DeleteDataForOrigin(
724 const base::string16& origin, const net::CompletionCallback& callback) {
725 if (!LazyInit())
726 return net::ERR_FAILED;
728 DatabaseSet to_be_deleted;
730 std::vector<DatabaseDetails> details;
731 if (!databases_table_->GetAllDatabaseDetailsForOrigin(origin, &details))
732 return net::ERR_FAILED;
733 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
734 db != details.end(); ++db) {
735 // Check if the database is opened by any renderer.
736 if (database_connections_.IsDatabaseOpened(origin, db->database_name))
737 to_be_deleted[origin].insert(db->database_name);
738 else
739 DeleteClosedDatabase(origin, db->database_name);
742 if (!to_be_deleted.empty()) {
743 ScheduleDatabasesForDeletion(to_be_deleted, callback);
744 return net::ERR_IO_PENDING;
746 return net::OK;
749 void DatabaseTracker::GetIncognitoFileHandle(
750 const base::string16& vfs_file_name,
751 base::PlatformFile* file_handle) const {
752 DCHECK(is_incognito_);
753 FileHandlesMap::const_iterator it =
754 incognito_file_handles_.find(vfs_file_name);
755 if (it != incognito_file_handles_.end())
756 *file_handle = it->second;
757 else
758 *file_handle = base::kInvalidPlatformFileValue;
761 void DatabaseTracker::SaveIncognitoFileHandle(
762 const base::string16& vfs_file_name,
763 const base::PlatformFile& file_handle) {
764 DCHECK(is_incognito_);
765 DCHECK(incognito_file_handles_.find(vfs_file_name) ==
766 incognito_file_handles_.end());
767 if (file_handle != base::kInvalidPlatformFileValue)
768 incognito_file_handles_[vfs_file_name] = file_handle;
771 bool DatabaseTracker::CloseIncognitoFileHandle(
772 const base::string16& vfs_file_name) {
773 DCHECK(is_incognito_);
774 DCHECK(incognito_file_handles_.find(vfs_file_name) !=
775 incognito_file_handles_.end());
777 bool handle_closed = false;
778 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
779 if (it != incognito_file_handles_.end()) {
780 handle_closed = base::ClosePlatformFile(it->second);
781 if (handle_closed)
782 incognito_file_handles_.erase(it);
784 return handle_closed;
787 bool DatabaseTracker::HasSavedIncognitoFileHandle(
788 const base::string16& vfs_file_name) const {
789 return (incognito_file_handles_.find(vfs_file_name) !=
790 incognito_file_handles_.end());
793 void DatabaseTracker::DeleteIncognitoDBDirectory() {
794 shutting_down_ = true;
795 is_initialized_ = false;
797 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
798 it != incognito_file_handles_.end(); it++)
799 base::ClosePlatformFile(it->second);
801 base::FilePath incognito_db_dir =
802 profile_path_.Append(kIncognitoDatabaseDirectoryName);
803 if (file_util::DirectoryExists(incognito_db_dir))
804 file_util::Delete(incognito_db_dir, true);
807 void DatabaseTracker::ClearSessionOnlyOrigins() {
808 shutting_down_ = true;
810 bool has_session_only_databases =
811 special_storage_policy_.get() &&
812 special_storage_policy_->HasSessionOnlyOrigins();
814 // Clearing only session-only databases, and there are none.
815 if (!has_session_only_databases)
816 return;
818 if (!LazyInit())
819 return;
821 std::vector<base::string16> origin_identifiers;
822 GetAllOriginIdentifiers(&origin_identifiers);
824 for (std::vector<base::string16>::iterator origin =
825 origin_identifiers.begin();
826 origin != origin_identifiers.end(); ++origin) {
827 GURL origin_url =
828 webkit_database::DatabaseUtil::GetOriginFromIdentifier(*origin);
829 if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
830 continue;
831 if (special_storage_policy_->IsStorageProtected(origin_url))
832 continue;
833 webkit_database::OriginInfo origin_info;
834 std::vector<base::string16> databases;
835 GetOriginInfo(*origin, &origin_info);
836 origin_info.GetAllDatabaseNames(&databases);
838 for (std::vector<base::string16>::iterator database = databases.begin();
839 database != databases.end(); ++database) {
840 base::PlatformFile file_handle = base::CreatePlatformFile(
841 GetFullDBFilePath(*origin, *database),
842 base::PLATFORM_FILE_OPEN_ALWAYS |
843 base::PLATFORM_FILE_SHARE_DELETE |
844 base::PLATFORM_FILE_DELETE_ON_CLOSE |
845 base::PLATFORM_FILE_READ,
846 NULL, NULL);
847 base::ClosePlatformFile(file_handle);
849 DeleteOrigin(*origin, true);
854 void DatabaseTracker::Shutdown() {
855 DCHECK(db_tracker_thread_.get());
856 DCHECK(db_tracker_thread_->BelongsToCurrentThread());
857 if (shutting_down_) {
858 NOTREACHED();
859 return;
861 if (is_incognito_)
862 DeleteIncognitoDBDirectory();
863 else if (!force_keep_session_state_)
864 ClearSessionOnlyOrigins();
867 void DatabaseTracker::SetForceKeepSessionState() {
868 DCHECK(db_tracker_thread_.get());
869 if (!db_tracker_thread_->BelongsToCurrentThread()) {
870 db_tracker_thread_->PostTask(
871 FROM_HERE,
872 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
873 return;
875 force_keep_session_state_ = true;
878 } // namespace webkit_database