Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / storage / browser / database / database_tracker.cc
blob3d579dc039f717687b0c78f0c18b879fbb047365
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 "storage/browser/database/database_tracker.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "net/base/net_errors.h"
17 #include "sql/connection.h"
18 #include "sql/meta_table.h"
19 #include "sql/transaction.h"
20 #include "storage/browser/database/database_quota_client.h"
21 #include "storage/browser/database/database_util.h"
22 #include "storage/browser/database/databases_table.h"
23 #include "storage/browser/quota/quota_manager_proxy.h"
24 #include "storage/browser/quota/special_storage_policy.h"
25 #include "storage/common/database/database_identifier.h"
26 #include "third_party/sqlite/sqlite3.h"
28 namespace storage {
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_identifier_(origin_info.origin_identifier_),
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 std::string& origin_identifier, int64 total_size)
78 : origin_identifier_(origin_identifier), total_size_(total_size) {}
80 DatabaseTracker::DatabaseTracker(
81 const base::FilePath& profile_path,
82 bool is_incognito,
83 storage::SpecialStoragePolicy* special_storage_policy,
84 storage::QuotaManagerProxy* quota_manager_proxy,
85 base::SingleThreadTaskRunner* 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 special_storage_policy_(special_storage_policy),
96 quota_manager_proxy_(quota_manager_proxy),
97 db_tracker_thread_(db_tracker_thread),
98 incognito_origin_directories_generator_(0) {
99 if (quota_manager_proxy) {
100 quota_manager_proxy->RegisterClient(
101 new DatabaseQuotaClient(db_tracker_thread, this));
105 DatabaseTracker::~DatabaseTracker() {
106 DCHECK(dbs_to_be_deleted_.empty());
107 DCHECK(deletion_callbacks_.empty());
110 void DatabaseTracker::DatabaseOpened(const std::string& origin_identifier,
111 const base::string16& database_name,
112 const base::string16& database_description,
113 int64 estimated_size,
114 int64* database_size) {
115 if (shutting_down_ || !LazyInit()) {
116 *database_size = 0;
117 return;
120 if (quota_manager_proxy_.get())
121 quota_manager_proxy_->NotifyStorageAccessed(
122 storage::QuotaClient::kDatabase,
123 storage::GetOriginFromIdentifier(origin_identifier),
124 storage::kStorageTypeTemporary);
126 InsertOrUpdateDatabaseDetails(origin_identifier, database_name,
127 database_description, estimated_size);
128 if (database_connections_.AddConnection(origin_identifier, database_name)) {
129 *database_size = SeedOpenDatabaseInfo(origin_identifier,
130 database_name,
131 database_description);
132 return;
134 *database_size = UpdateOpenDatabaseInfoAndNotify(origin_identifier,
135 database_name,
136 &database_description);
139 void DatabaseTracker::DatabaseModified(const std::string& origin_identifier,
140 const base::string16& database_name) {
141 if (!LazyInit())
142 return;
143 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
146 void DatabaseTracker::DatabaseClosed(const std::string& origin_identifier,
147 const base::string16& database_name) {
148 if (database_connections_.IsEmpty()) {
149 DCHECK(!is_initialized_);
150 return;
153 // We call NotifiyStorageAccessed when a db is opened and also when
154 // closed because we don't call it for read while open.
155 if (quota_manager_proxy_.get())
156 quota_manager_proxy_->NotifyStorageAccessed(
157 storage::QuotaClient::kDatabase,
158 storage::GetOriginFromIdentifier(origin_identifier),
159 storage::kStorageTypeTemporary);
161 UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
162 if (database_connections_.RemoveConnection(origin_identifier, database_name))
163 DeleteDatabaseIfNeeded(origin_identifier, database_name);
166 void DatabaseTracker::HandleSqliteError(
167 const std::string& origin_identifier,
168 const base::string16& database_name,
169 int error) {
170 // We only handle errors that indicate corruption and we
171 // do so with a heavy hand, we delete it. Any renderers/workers
172 // with this database open will receive a message to close it
173 // immediately, once all have closed, the files will be deleted.
174 // In the interim, all attempts to open a new connection to that
175 // database will fail.
176 // Note: the client-side filters out all but these two errors as
177 // a small optimization, see WebDatabaseObserverImpl::HandleSqliteError.
178 if (error == SQLITE_CORRUPT || error == SQLITE_NOTADB) {
179 DeleteDatabase(origin_identifier, database_name,
180 net::CompletionCallback());
184 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
185 if (database_connections_.IsEmpty()) {
186 DCHECK(!is_initialized_ || connections.IsEmpty());
187 return;
190 // When being closed by this route, there's a chance that
191 // the tracker missed some DatabseModified calls. This method is used
192 // when a renderer crashes to cleanup its open resources.
193 // We need to examine what we have in connections for the
194 // size of each open databases and notify any differences between the
195 // actual file sizes now.
196 std::vector<std::pair<std::string, base::string16> > open_dbs;
197 connections.ListConnections(&open_dbs);
198 for (std::vector<std::pair<std::string, base::string16> >::iterator it =
199 open_dbs.begin(); it != open_dbs.end(); ++it)
200 UpdateOpenDatabaseSizeAndNotify(it->first, it->second);
202 std::vector<std::pair<std::string, base::string16> > closed_dbs;
203 database_connections_.RemoveConnections(connections, &closed_dbs);
204 for (std::vector<std::pair<std::string, base::string16> >::iterator it =
205 closed_dbs.begin(); it != closed_dbs.end(); ++it) {
206 DeleteDatabaseIfNeeded(it->first, it->second);
210 void DatabaseTracker::DeleteDatabaseIfNeeded(
211 const std::string& origin_identifier,
212 const base::string16& database_name) {
213 DCHECK(!database_connections_.IsDatabaseOpened(origin_identifier,
214 database_name));
215 if (IsDatabaseScheduledForDeletion(origin_identifier, database_name)) {
216 DeleteClosedDatabase(origin_identifier, database_name);
217 dbs_to_be_deleted_[origin_identifier].erase(database_name);
218 if (dbs_to_be_deleted_[origin_identifier].empty())
219 dbs_to_be_deleted_.erase(origin_identifier);
221 PendingDeletionCallbacks::iterator callback = deletion_callbacks_.begin();
222 while (callback != deletion_callbacks_.end()) {
223 DatabaseSet::iterator found_origin =
224 callback->second.find(origin_identifier);
225 if (found_origin != callback->second.end()) {
226 std::set<base::string16>& databases = found_origin->second;
227 databases.erase(database_name);
228 if (databases.empty()) {
229 callback->second.erase(found_origin);
230 if (callback->second.empty()) {
231 net::CompletionCallback cb = callback->first;
232 cb.Run(net::OK);
233 callback = deletion_callbacks_.erase(callback);
234 continue;
239 ++callback;
244 void DatabaseTracker::AddObserver(Observer* observer) {
245 observers_.AddObserver(observer);
248 void DatabaseTracker::RemoveObserver(Observer* observer) {
249 // When we remove a listener, we do not know which cached information
250 // is still needed and which information can be discarded. So we just
251 // clear all caches and re-populate them as needed.
252 observers_.RemoveObserver(observer);
253 ClearAllCachedOriginInfo();
256 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
257 ClearAllCachedOriginInfo();
259 if (!is_incognito_) {
260 meta_table_.reset(NULL);
261 databases_table_.reset(NULL);
262 db_->Close();
263 is_initialized_ = false;
267 base::string16 DatabaseTracker::GetOriginDirectory(
268 const std::string& origin_identifier) {
269 if (!is_incognito_)
270 return base::UTF8ToUTF16(origin_identifier);
272 OriginDirectoriesMap::const_iterator it =
273 incognito_origin_directories_.find(origin_identifier);
274 if (it != incognito_origin_directories_.end())
275 return it->second;
277 base::string16 origin_directory =
278 base::IntToString16(incognito_origin_directories_generator_++);
279 incognito_origin_directories_[origin_identifier] = origin_directory;
280 return origin_directory;
283 base::FilePath DatabaseTracker::GetFullDBFilePath(
284 const std::string& origin_identifier,
285 const base::string16& database_name) {
286 DCHECK(!origin_identifier.empty());
287 if (!LazyInit())
288 return base::FilePath();
290 int64 id = databases_table_->GetDatabaseID(origin_identifier, database_name);
291 if (id < 0)
292 return base::FilePath();
294 return db_dir_.Append(base::FilePath::FromUTF16Unsafe(
295 GetOriginDirectory(origin_identifier))).AppendASCII(
296 base::Int64ToString(id));
299 bool DatabaseTracker::GetOriginInfo(const std::string& origin_identifier,
300 OriginInfo* info) {
301 DCHECK(info);
302 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier);
303 if (!cached_info)
304 return false;
305 *info = OriginInfo(*cached_info);
306 return true;
309 bool DatabaseTracker::GetAllOriginIdentifiers(
310 std::vector<std::string>* origin_identifiers) {
311 DCHECK(origin_identifiers);
312 DCHECK(origin_identifiers->empty());
313 if (!LazyInit())
314 return false;
315 return databases_table_->GetAllOriginIdentifiers(origin_identifiers);
318 bool DatabaseTracker::GetAllOriginsInfo(
319 std::vector<OriginInfo>* origins_info) {
320 DCHECK(origins_info);
321 DCHECK(origins_info->empty());
323 std::vector<std::string> origins;
324 if (!GetAllOriginIdentifiers(&origins))
325 return false;
327 for (std::vector<std::string>::const_iterator it = origins.begin();
328 it != origins.end(); it++) {
329 CachedOriginInfo* origin_info = GetCachedOriginInfo(*it);
330 if (!origin_info) {
331 // Restore 'origins_info' to its initial state.
332 origins_info->clear();
333 return false;
335 origins_info->push_back(OriginInfo(*origin_info));
338 return true;
341 bool DatabaseTracker::DeleteClosedDatabase(
342 const std::string& origin_identifier,
343 const base::string16& database_name) {
344 if (!LazyInit())
345 return false;
347 // Check if the database is opened by any renderer.
348 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
349 return false;
351 int64 db_file_size = quota_manager_proxy_.get()
352 ? GetDBFileSize(origin_identifier, database_name)
353 : 0;
355 // Try to delete the file on the hard drive.
356 base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
357 if (!sql::Connection::Delete(db_file))
358 return false;
360 if (quota_manager_proxy_.get() && db_file_size)
361 quota_manager_proxy_->NotifyStorageModified(
362 storage::QuotaClient::kDatabase,
363 storage::GetOriginFromIdentifier(origin_identifier),
364 storage::kStorageTypeTemporary,
365 -db_file_size);
367 // Clean up the main database and invalidate the cached record.
368 databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
369 origins_info_map_.erase(origin_identifier);
371 std::vector<DatabaseDetails> details;
372 if (databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
373 origin_identifier, &details) && details.empty()) {
374 // Try to delete the origin in case this was the last database.
375 DeleteOrigin(origin_identifier, false);
377 return true;
380 bool DatabaseTracker::DeleteOrigin(const std::string& origin_identifier,
381 bool force) {
382 if (!LazyInit())
383 return false;
385 // Check if any database in this origin is opened by any renderer.
386 if (database_connections_.IsOriginUsed(origin_identifier) && !force)
387 return false;
389 int64 deleted_size = 0;
390 if (quota_manager_proxy_.get()) {
391 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
392 if (origin_info)
393 deleted_size = origin_info->TotalSize();
396 origins_info_map_.erase(origin_identifier);
397 base::FilePath origin_dir = db_dir_.AppendASCII(origin_identifier);
399 // Create a temporary directory to move possibly still existing databases to,
400 // as we can't delete the origin directory on windows if it contains opened
401 // files.
402 base::FilePath new_origin_dir;
403 base::CreateTemporaryDirInDir(db_dir_,
404 kTemporaryDirectoryPrefix,
405 &new_origin_dir);
406 base::FileEnumerator databases(
407 origin_dir,
408 false,
409 base::FileEnumerator::FILES);
410 for (base::FilePath database = databases.Next(); !database.empty();
411 database = databases.Next()) {
412 base::FilePath new_file = new_origin_dir.Append(database.BaseName());
413 base::Move(database, new_file);
415 base::DeleteFile(origin_dir, true);
416 base::DeleteFile(new_origin_dir, true); // might fail on windows.
418 databases_table_->DeleteOriginIdentifier(origin_identifier);
420 if (quota_manager_proxy_.get() && deleted_size) {
421 quota_manager_proxy_->NotifyStorageModified(
422 storage::QuotaClient::kDatabase,
423 storage::GetOriginFromIdentifier(origin_identifier),
424 storage::kStorageTypeTemporary,
425 -deleted_size);
428 return true;
431 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
432 const std::string& origin_identifier,
433 const base::string16& database_name) {
434 DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
435 if (it == dbs_to_be_deleted_.end())
436 return false;
438 std::set<base::string16>& databases = it->second;
439 return (databases.find(database_name) != databases.end());
442 bool DatabaseTracker::LazyInit() {
443 if (!is_initialized_ && !shutting_down_) {
444 DCHECK(!db_->is_open());
445 DCHECK(!databases_table_.get());
446 DCHECK(!meta_table_.get());
448 // If there are left-over directories from failed deletion attempts, clean
449 // them up.
450 if (base::DirectoryExists(db_dir_)) {
451 base::FileEnumerator directories(
452 db_dir_,
453 false,
454 base::FileEnumerator::DIRECTORIES,
455 kTemporaryDirectoryPattern);
456 for (base::FilePath directory = directories.Next(); !directory.empty();
457 directory = directories.Next()) {
458 base::DeleteFile(directory, true);
462 db_->set_histogram_tag("DatabaseTracker");
464 // If the tracker database exists, but it's corrupt or doesn't
465 // have a meta table, delete the database directory.
466 const base::FilePath kTrackerDatabaseFullPath =
467 db_dir_.Append(base::FilePath(kTrackerDatabaseFileName));
468 if (base::DirectoryExists(db_dir_) &&
469 base::PathExists(kTrackerDatabaseFullPath) &&
470 (!db_->Open(kTrackerDatabaseFullPath) ||
471 !sql::MetaTable::DoesTableExist(db_.get()))) {
472 db_->Close();
473 if (!base::DeleteFile(db_dir_, true))
474 return false;
477 databases_table_.reset(new DatabasesTable(db_.get()));
478 meta_table_.reset(new sql::MetaTable());
480 is_initialized_ =
481 base::CreateDirectory(db_dir_) &&
482 (db_->is_open() ||
483 (is_incognito_ ? db_->OpenInMemory() :
484 db_->Open(kTrackerDatabaseFullPath))) &&
485 UpgradeToCurrentVersion();
486 if (!is_initialized_) {
487 databases_table_.reset(NULL);
488 meta_table_.reset(NULL);
489 db_->Close();
492 return is_initialized_;
495 bool DatabaseTracker::UpgradeToCurrentVersion() {
496 sql::Transaction transaction(db_.get());
497 if (!transaction.Begin() ||
498 !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
499 (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
500 !databases_table_->Init())
501 return false;
503 if (meta_table_->GetVersionNumber() < kCurrentVersion)
504 meta_table_->SetVersionNumber(kCurrentVersion);
506 return transaction.Commit();
509 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
510 const std::string& origin_identifier,
511 const base::string16& database_name,
512 const base::string16& database_description,
513 int64 estimated_size) {
514 DatabaseDetails details;
515 if (!databases_table_->GetDatabaseDetails(
516 origin_identifier, database_name, &details)) {
517 details.origin_identifier = origin_identifier;
518 details.database_name = database_name;
519 details.description = database_description;
520 details.estimated_size = estimated_size;
521 databases_table_->InsertDatabaseDetails(details);
522 } else if ((details.description != database_description) ||
523 (details.estimated_size != estimated_size)) {
524 details.description = database_description;
525 details.estimated_size = estimated_size;
526 databases_table_->UpdateDatabaseDetails(details);
530 void DatabaseTracker::ClearAllCachedOriginInfo() {
531 origins_info_map_.clear();
534 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
535 const std::string& origin_identifier, bool create_if_needed) {
536 if (!LazyInit())
537 return NULL;
539 // Populate the cache with data for this origin if needed.
540 if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
541 if (!create_if_needed)
542 return NULL;
544 std::vector<DatabaseDetails> details;
545 if (!databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
546 origin_identifier, &details)) {
547 return NULL;
550 CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
551 origin_info.SetOriginIdentifier(origin_identifier);
552 for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
553 it != details.end(); it++) {
554 int64 db_file_size;
555 if (database_connections_.IsDatabaseOpened(
556 origin_identifier, it->database_name)) {
557 db_file_size = database_connections_.GetOpenDatabaseSize(
558 origin_identifier, it->database_name);
559 } else {
560 db_file_size = GetDBFileSize(origin_identifier, it->database_name);
562 origin_info.SetDatabaseSize(it->database_name, db_file_size);
563 origin_info.SetDatabaseDescription(it->database_name, it->description);
567 return &origins_info_map_[origin_identifier];
570 int64 DatabaseTracker::GetDBFileSize(const std::string& origin_identifier,
571 const base::string16& database_name) {
572 base::FilePath db_file_name = GetFullDBFilePath(origin_identifier,
573 database_name);
574 int64 db_file_size = 0;
575 if (!base::GetFileSize(db_file_name, &db_file_size))
576 db_file_size = 0;
577 return db_file_size;
580 int64 DatabaseTracker::SeedOpenDatabaseInfo(
581 const std::string& origin_id, const base::string16& name,
582 const base::string16& description) {
583 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
584 int64 size = GetDBFileSize(origin_id, name);
585 database_connections_.SetOpenDatabaseSize(origin_id, name, size);
586 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
587 if (info) {
588 info->SetDatabaseSize(name, size);
589 info->SetDatabaseDescription(name, description);
591 return size;
594 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
595 const std::string& origin_id, const base::string16& name,
596 const base::string16* opt_description) {
597 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
598 int64 new_size = GetDBFileSize(origin_id, name);
599 int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
600 CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
601 if (info && opt_description)
602 info->SetDatabaseDescription(name, *opt_description);
603 if (old_size != new_size) {
604 database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
605 if (info)
606 info->SetDatabaseSize(name, new_size);
607 if (quota_manager_proxy_.get())
608 quota_manager_proxy_->NotifyStorageModified(
609 storage::QuotaClient::kDatabase,
610 storage::GetOriginFromIdentifier(origin_id),
611 storage::kStorageTypeTemporary,
612 new_size - old_size);
613 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
614 origin_id, name, new_size));
616 return new_size;
619 void DatabaseTracker::ScheduleDatabaseForDeletion(
620 const std::string& origin_identifier,
621 const base::string16& database_name) {
622 DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
623 database_name));
624 dbs_to_be_deleted_[origin_identifier].insert(database_name);
625 FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
626 origin_identifier, database_name));
629 void DatabaseTracker::ScheduleDatabasesForDeletion(
630 const DatabaseSet& databases,
631 const net::CompletionCallback& callback) {
632 DCHECK(!databases.empty());
634 if (!callback.is_null())
635 deletion_callbacks_.push_back(std::make_pair(callback, databases));
636 for (DatabaseSet::const_iterator ori = databases.begin();
637 ori != databases.end(); ++ori) {
638 for (std::set<base::string16>::const_iterator db = ori->second.begin();
639 db != ori->second.end(); ++db)
640 ScheduleDatabaseForDeletion(ori->first, *db);
644 int DatabaseTracker::DeleteDatabase(const std::string& origin_identifier,
645 const base::string16& database_name,
646 const net::CompletionCallback& callback) {
647 if (!LazyInit())
648 return net::ERR_FAILED;
650 if (database_connections_.IsDatabaseOpened(origin_identifier,
651 database_name)) {
652 if (!callback.is_null()) {
653 DatabaseSet set;
654 set[origin_identifier].insert(database_name);
655 deletion_callbacks_.push_back(std::make_pair(callback, set));
657 ScheduleDatabaseForDeletion(origin_identifier, database_name);
658 return net::ERR_IO_PENDING;
660 DeleteClosedDatabase(origin_identifier, database_name);
661 return net::OK;
664 int DatabaseTracker::DeleteDataModifiedSince(
665 const base::Time& cutoff,
666 const net::CompletionCallback& callback) {
667 if (!LazyInit())
668 return net::ERR_FAILED;
670 DatabaseSet to_be_deleted;
672 std::vector<std::string> origins_identifiers;
673 if (!databases_table_->GetAllOriginIdentifiers(&origins_identifiers))
674 return net::ERR_FAILED;
675 int rv = net::OK;
676 for (std::vector<std::string>::const_iterator ori =
677 origins_identifiers.begin();
678 ori != origins_identifiers.end(); ++ori) {
679 if (special_storage_policy_.get() &&
680 special_storage_policy_->IsStorageProtected(
681 storage::GetOriginFromIdentifier(*ori))) {
682 continue;
685 std::vector<DatabaseDetails> details;
686 if (!databases_table_->
687 GetAllDatabaseDetailsForOriginIdentifier(*ori, &details))
688 rv = net::ERR_FAILED;
689 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
690 db != details.end(); ++db) {
691 base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
692 base::File::Info file_info;
693 base::GetFileInfo(db_file, &file_info);
694 if (file_info.last_modified < cutoff)
695 continue;
697 // Check if the database is opened by any renderer.
698 if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
699 to_be_deleted[*ori].insert(db->database_name);
700 else
701 DeleteClosedDatabase(*ori, db->database_name);
705 if (rv != net::OK)
706 return rv;
708 if (!to_be_deleted.empty()) {
709 ScheduleDatabasesForDeletion(to_be_deleted, callback);
710 return net::ERR_IO_PENDING;
712 return net::OK;
715 int DatabaseTracker::DeleteDataForOrigin(
716 const std::string& origin, const net::CompletionCallback& callback) {
717 if (!LazyInit())
718 return net::ERR_FAILED;
720 DatabaseSet to_be_deleted;
722 std::vector<DatabaseDetails> details;
723 if (!databases_table_->
724 GetAllDatabaseDetailsForOriginIdentifier(origin, &details))
725 return net::ERR_FAILED;
726 for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
727 db != details.end(); ++db) {
728 // Check if the database is opened by any renderer.
729 if (database_connections_.IsDatabaseOpened(origin, db->database_name))
730 to_be_deleted[origin].insert(db->database_name);
731 else
732 DeleteClosedDatabase(origin, db->database_name);
735 if (!to_be_deleted.empty()) {
736 ScheduleDatabasesForDeletion(to_be_deleted, callback);
737 return net::ERR_IO_PENDING;
739 return net::OK;
742 const base::File* DatabaseTracker::GetIncognitoFile(
743 const base::string16& vfs_file_name) const {
744 DCHECK(is_incognito_);
745 FileHandlesMap::const_iterator it =
746 incognito_file_handles_.find(vfs_file_name);
747 if (it != incognito_file_handles_.end())
748 return it->second;
750 return NULL;
753 const base::File* DatabaseTracker::SaveIncognitoFile(
754 const base::string16& vfs_file_name,
755 base::File file) {
756 DCHECK(is_incognito_);
757 if (!file.IsValid())
758 return NULL;
760 base::File* to_insert = new base::File(file.Pass());
761 std::pair<FileHandlesMap::iterator, bool> rv =
762 incognito_file_handles_.insert(std::make_pair(vfs_file_name, to_insert));
763 DCHECK(rv.second);
764 return rv.first->second;
767 void DatabaseTracker::CloseIncognitoFileHandle(
768 const base::string16& vfs_file_name) {
769 DCHECK(is_incognito_);
770 DCHECK(incognito_file_handles_.find(vfs_file_name) !=
771 incognito_file_handles_.end());
773 FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
774 if (it != incognito_file_handles_.end()) {
775 delete it->second;
776 incognito_file_handles_.erase(it);
780 bool DatabaseTracker::HasSavedIncognitoFileHandle(
781 const base::string16& vfs_file_name) const {
782 return (incognito_file_handles_.find(vfs_file_name) !=
783 incognito_file_handles_.end());
786 void DatabaseTracker::DeleteIncognitoDBDirectory() {
787 is_initialized_ = false;
789 for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
790 it != incognito_file_handles_.end(); it++) {
791 delete it->second;
794 base::FilePath incognito_db_dir =
795 profile_path_.Append(kIncognitoDatabaseDirectoryName);
796 if (base::DirectoryExists(incognito_db_dir))
797 base::DeleteFile(incognito_db_dir, true);
800 void DatabaseTracker::ClearSessionOnlyOrigins() {
801 bool has_session_only_databases =
802 special_storage_policy_.get() &&
803 special_storage_policy_->HasSessionOnlyOrigins();
805 // Clearing only session-only databases, and there are none.
806 if (!has_session_only_databases)
807 return;
809 if (!LazyInit())
810 return;
812 std::vector<std::string> origin_identifiers;
813 GetAllOriginIdentifiers(&origin_identifiers);
815 for (std::vector<std::string>::iterator origin =
816 origin_identifiers.begin();
817 origin != origin_identifiers.end(); ++origin) {
818 GURL origin_url = storage::GetOriginFromIdentifier(*origin);
819 if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
820 continue;
821 if (special_storage_policy_->IsStorageProtected(origin_url))
822 continue;
823 storage::OriginInfo origin_info;
824 std::vector<base::string16> databases;
825 GetOriginInfo(*origin, &origin_info);
826 origin_info.GetAllDatabaseNames(&databases);
828 for (std::vector<base::string16>::iterator database = databases.begin();
829 database != databases.end(); ++database) {
830 base::File file(GetFullDBFilePath(*origin, *database),
831 base::File::FLAG_OPEN_ALWAYS |
832 base::File::FLAG_SHARE_DELETE |
833 base::File::FLAG_DELETE_ON_CLOSE |
834 base::File::FLAG_READ);
836 DeleteOrigin(*origin, true);
841 void DatabaseTracker::Shutdown() {
842 DCHECK(db_tracker_thread_.get());
843 DCHECK(db_tracker_thread_->BelongsToCurrentThread());
844 if (shutting_down_) {
845 NOTREACHED();
846 return;
848 shutting_down_ = true;
849 if (is_incognito_)
850 DeleteIncognitoDBDirectory();
851 else if (!force_keep_session_state_)
852 ClearSessionOnlyOrigins();
853 CloseTrackerDatabaseAndClearCaches();
856 void DatabaseTracker::SetForceKeepSessionState() {
857 DCHECK(db_tracker_thread_.get());
858 if (!db_tracker_thread_->BelongsToCurrentThread()) {
859 db_tracker_thread_->PostTask(
860 FROM_HERE,
861 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
862 return;
864 force_keep_session_state_ = true;
867 } // namespace storage