Home | History | Annotate | Download | only in database
      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.
      4 
      5 #include "storage/browser/database/database_tracker.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/files/file.h"
     13 #include "base/files/file_enumerator.h"
     14 #include "base/files/file_util.h"
     15 #include "base/message_loop/message_loop_proxy.h"
     16 #include "base/strings/string_number_conversions.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "net/base/net_errors.h"
     19 #include "sql/connection.h"
     20 #include "sql/meta_table.h"
     21 #include "sql/transaction.h"
     22 #include "storage/browser/database/database_quota_client.h"
     23 #include "storage/browser/database/database_util.h"
     24 #include "storage/browser/database/databases_table.h"
     25 #include "storage/browser/quota/quota_manager_proxy.h"
     26 #include "storage/browser/quota/special_storage_policy.h"
     27 #include "storage/common/database/database_identifier.h"
     28 #include "third_party/sqlite/sqlite3.h"
     29 
     30 namespace storage {
     31 
     32 const base::FilePath::CharType kDatabaseDirectoryName[] =
     33     FILE_PATH_LITERAL("databases");
     34 const base::FilePath::CharType kIncognitoDatabaseDirectoryName[] =
     35     FILE_PATH_LITERAL("databases-incognito");
     36 const base::FilePath::CharType kTrackerDatabaseFileName[] =
     37     FILE_PATH_LITERAL("Databases.db");
     38 static const int kCurrentVersion = 2;
     39 static const int kCompatibleVersion = 1;
     40 
     41 const base::FilePath::CharType kTemporaryDirectoryPrefix[] =
     42     FILE_PATH_LITERAL("DeleteMe");
     43 const base::FilePath::CharType kTemporaryDirectoryPattern[] =
     44     FILE_PATH_LITERAL("DeleteMe*");
     45 
     46 OriginInfo::OriginInfo()
     47     : total_size_(0) {}
     48 
     49 OriginInfo::OriginInfo(const OriginInfo& origin_info)
     50     : origin_identifier_(origin_info.origin_identifier_),
     51       total_size_(origin_info.total_size_),
     52       database_info_(origin_info.database_info_) {}
     53 
     54 OriginInfo::~OriginInfo() {}
     55 
     56 void OriginInfo::GetAllDatabaseNames(
     57     std::vector<base::string16>* databases) const {
     58   for (DatabaseInfoMap::const_iterator it = database_info_.begin();
     59        it != database_info_.end(); it++) {
     60     databases->push_back(it->first);
     61   }
     62 }
     63 
     64 int64 OriginInfo::GetDatabaseSize(const base::string16& database_name) const {
     65   DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
     66   if (it != database_info_.end())
     67     return it->second.first;
     68   return 0;
     69 }
     70 
     71 base::string16 OriginInfo::GetDatabaseDescription(
     72     const base::string16& database_name) const {
     73   DatabaseInfoMap::const_iterator it = database_info_.find(database_name);
     74   if (it != database_info_.end())
     75     return it->second.second;
     76   return base::string16();
     77 }
     78 
     79 OriginInfo::OriginInfo(const std::string& origin_identifier, int64 total_size)
     80     : origin_identifier_(origin_identifier), total_size_(total_size) {}
     81 
     82 DatabaseTracker::DatabaseTracker(
     83     const base::FilePath& profile_path,
     84     bool is_incognito,
     85     storage::SpecialStoragePolicy* special_storage_policy,
     86     storage::QuotaManagerProxy* quota_manager_proxy,
     87     base::MessageLoopProxy* db_tracker_thread)
     88     : is_initialized_(false),
     89       is_incognito_(is_incognito),
     90       force_keep_session_state_(false),
     91       shutting_down_(false),
     92       profile_path_(profile_path),
     93       db_dir_(is_incognito_
     94                   ? profile_path_.Append(kIncognitoDatabaseDirectoryName)
     95                   : profile_path_.Append(kDatabaseDirectoryName)),
     96       db_(new sql::Connection()),
     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));
    104   }
    105 }
    106 
    107 DatabaseTracker::~DatabaseTracker() {
    108   DCHECK(dbs_to_be_deleted_.empty());
    109   DCHECK(deletion_callbacks_.empty());
    110 }
    111 
    112 void DatabaseTracker::DatabaseOpened(const std::string& 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;
    120   }
    121 
    122   if (quota_manager_proxy_.get())
    123     quota_manager_proxy_->NotifyStorageAccessed(
    124         storage::QuotaClient::kDatabase,
    125         storage::GetOriginFromIdentifier(origin_identifier),
    126         storage::kStorageTypeTemporary);
    127 
    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;
    135   }
    136   *database_size  = UpdateOpenDatabaseInfoAndNotify(origin_identifier,
    137                                                     database_name,
    138                                                     &database_description);
    139 }
    140 
    141 void DatabaseTracker::DatabaseModified(const std::string& origin_identifier,
    142                                        const base::string16& database_name) {
    143   if (!LazyInit())
    144     return;
    145   UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
    146 }
    147 
    148 void DatabaseTracker::DatabaseClosed(const std::string& origin_identifier,
    149                                      const base::string16& database_name) {
    150   if (database_connections_.IsEmpty()) {
    151     DCHECK(!is_initialized_);
    152     return;
    153   }
    154 
    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_.get())
    158     quota_manager_proxy_->NotifyStorageAccessed(
    159         storage::QuotaClient::kDatabase,
    160         storage::GetOriginFromIdentifier(origin_identifier),
    161         storage::kStorageTypeTemporary);
    162 
    163   UpdateOpenDatabaseSizeAndNotify(origin_identifier, database_name);
    164   if (database_connections_.RemoveConnection(origin_identifier, database_name))
    165     DeleteDatabaseIfNeeded(origin_identifier, database_name);
    166 }
    167 
    168 void DatabaseTracker::HandleSqliteError(
    169     const std::string& 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());
    183   }
    184 }
    185 
    186 void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) {
    187   if (database_connections_.IsEmpty()) {
    188     DCHECK(!is_initialized_ || connections.IsEmpty());
    189     return;
    190   }
    191 
    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<std::string, base::string16> > open_dbs;
    199   connections.ListConnections(&open_dbs);
    200   for (std::vector<std::pair<std::string, base::string16> >::iterator it =
    201            open_dbs.begin(); it != open_dbs.end(); ++it)
    202     UpdateOpenDatabaseSizeAndNotify(it->first, it->second);
    203 
    204   std::vector<std::pair<std::string, base::string16> > closed_dbs;
    205   database_connections_.RemoveConnections(connections, &closed_dbs);
    206   for (std::vector<std::pair<std::string, base::string16> >::iterator it =
    207            closed_dbs.begin(); it != closed_dbs.end(); ++it) {
    208     DeleteDatabaseIfNeeded(it->first, it->second);
    209   }
    210 }
    211 
    212 void DatabaseTracker::DeleteDatabaseIfNeeded(
    213     const std::string& 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);
    222 
    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;
    237           }
    238         }
    239       }
    240 
    241       ++callback;
    242     }
    243   }
    244 }
    245 
    246 void DatabaseTracker::AddObserver(Observer* observer) {
    247   observers_.AddObserver(observer);
    248 }
    249 
    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();
    256 }
    257 
    258 void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() {
    259   ClearAllCachedOriginInfo();
    260 
    261   if (!is_incognito_) {
    262     meta_table_.reset(NULL);
    263     databases_table_.reset(NULL);
    264     db_->Close();
    265     is_initialized_ = false;
    266   }
    267 }
    268 
    269 base::string16 DatabaseTracker::GetOriginDirectory(
    270     const std::string& origin_identifier) {
    271   if (!is_incognito_)
    272     return base::UTF8ToUTF16(origin_identifier);
    273 
    274   OriginDirectoriesMap::const_iterator it =
    275       incognito_origin_directories_.find(origin_identifier);
    276   if (it != incognito_origin_directories_.end())
    277     return it->second;
    278 
    279   base::string16 origin_directory =
    280       base::IntToString16(incognito_origin_directories_generator_++);
    281   incognito_origin_directories_[origin_identifier] = origin_directory;
    282   return origin_directory;
    283 }
    284 
    285 base::FilePath DatabaseTracker::GetFullDBFilePath(
    286     const std::string& origin_identifier,
    287     const base::string16& database_name) {
    288   DCHECK(!origin_identifier.empty());
    289   if (!LazyInit())
    290     return base::FilePath();
    291 
    292   int64 id = databases_table_->GetDatabaseID(origin_identifier, database_name);
    293   if (id < 0)
    294     return base::FilePath();
    295 
    296   return db_dir_.Append(base::FilePath::FromUTF16Unsafe(
    297       GetOriginDirectory(origin_identifier))).AppendASCII(
    298           base::Int64ToString(id));
    299 }
    300 
    301 bool DatabaseTracker::GetOriginInfo(const std::string& origin_identifier,
    302                                     OriginInfo* info) {
    303   DCHECK(info);
    304   CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier);
    305   if (!cached_info)
    306     return false;
    307   *info = OriginInfo(*cached_info);
    308   return true;
    309 }
    310 
    311 bool DatabaseTracker::GetAllOriginIdentifiers(
    312     std::vector<std::string>* origin_identifiers) {
    313   DCHECK(origin_identifiers);
    314   DCHECK(origin_identifiers->empty());
    315   if (!LazyInit())
    316     return false;
    317   return databases_table_->GetAllOriginIdentifiers(origin_identifiers);
    318 }
    319 
    320 bool DatabaseTracker::GetAllOriginsInfo(
    321     std::vector<OriginInfo>* origins_info) {
    322   DCHECK(origins_info);
    323   DCHECK(origins_info->empty());
    324 
    325   std::vector<std::string> origins;
    326   if (!GetAllOriginIdentifiers(&origins))
    327     return false;
    328 
    329   for (std::vector<std::string>::const_iterator it = origins.begin();
    330        it != origins.end(); it++) {
    331     CachedOriginInfo* origin_info = GetCachedOriginInfo(*it);
    332     if (!origin_info) {
    333       // Restore 'origins_info' to its initial state.
    334       origins_info->clear();
    335       return false;
    336     }
    337     origins_info->push_back(OriginInfo(*origin_info));
    338   }
    339 
    340   return true;
    341 }
    342 
    343 bool DatabaseTracker::DeleteClosedDatabase(
    344     const std::string& origin_identifier,
    345     const base::string16& database_name) {
    346   if (!LazyInit())
    347     return false;
    348 
    349   // Check if the database is opened by any renderer.
    350   if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
    351     return false;
    352 
    353   int64 db_file_size = quota_manager_proxy_.get()
    354                            ? GetDBFileSize(origin_identifier, database_name)
    355                            : 0;
    356 
    357   // Try to delete the file on the hard drive.
    358   base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
    359   if (!sql::Connection::Delete(db_file))
    360     return false;
    361 
    362   if (quota_manager_proxy_.get() && db_file_size)
    363     quota_manager_proxy_->NotifyStorageModified(
    364         storage::QuotaClient::kDatabase,
    365         storage::GetOriginFromIdentifier(origin_identifier),
    366         storage::kStorageTypeTemporary,
    367         -db_file_size);
    368 
    369   // Clean up the main database and invalidate the cached record.
    370   databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
    371   origins_info_map_.erase(origin_identifier);
    372 
    373   std::vector<DatabaseDetails> details;
    374   if (databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
    375           origin_identifier, &details) && details.empty()) {
    376     // Try to delete the origin in case this was the last database.
    377     DeleteOrigin(origin_identifier, false);
    378   }
    379   return true;
    380 }
    381 
    382 bool DatabaseTracker::DeleteOrigin(const std::string& origin_identifier,
    383                                    bool force) {
    384   if (!LazyInit())
    385     return false;
    386 
    387   // Check if any database in this origin is opened by any renderer.
    388   if (database_connections_.IsOriginUsed(origin_identifier) && !force)
    389     return false;
    390 
    391   int64 deleted_size = 0;
    392   if (quota_manager_proxy_.get()) {
    393     CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
    394     if (origin_info)
    395       deleted_size = origin_info->TotalSize();
    396   }
    397 
    398   origins_info_map_.erase(origin_identifier);
    399   base::FilePath origin_dir = db_dir_.AppendASCII(origin_identifier);
    400 
    401   // Create a temporary directory to move possibly still existing databases to,
    402   // as we can't delete the origin directory on windows if it contains opened
    403   // files.
    404   base::FilePath new_origin_dir;
    405   base::CreateTemporaryDirInDir(db_dir_,
    406                                 kTemporaryDirectoryPrefix,
    407                                 &new_origin_dir);
    408   base::FileEnumerator databases(
    409       origin_dir,
    410       false,
    411       base::FileEnumerator::FILES);
    412   for (base::FilePath database = databases.Next(); !database.empty();
    413        database = databases.Next()) {
    414     base::FilePath new_file = new_origin_dir.Append(database.BaseName());
    415     base::Move(database, new_file);
    416   }
    417   base::DeleteFile(origin_dir, true);
    418   base::DeleteFile(new_origin_dir, true); // might fail on windows.
    419 
    420   databases_table_->DeleteOriginIdentifier(origin_identifier);
    421 
    422   if (quota_manager_proxy_.get() && deleted_size) {
    423     quota_manager_proxy_->NotifyStorageModified(
    424         storage::QuotaClient::kDatabase,
    425         storage::GetOriginFromIdentifier(origin_identifier),
    426         storage::kStorageTypeTemporary,
    427         -deleted_size);
    428   }
    429 
    430   return true;
    431 }
    432 
    433 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
    434     const std::string& origin_identifier,
    435     const base::string16& database_name) {
    436   DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
    437   if (it == dbs_to_be_deleted_.end())
    438     return false;
    439 
    440   std::set<base::string16>& databases = it->second;
    441   return (databases.find(database_name) != databases.end());
    442 }
    443 
    444 bool DatabaseTracker::LazyInit() {
    445   if (!is_initialized_ && !shutting_down_) {
    446     DCHECK(!db_->is_open());
    447     DCHECK(!databases_table_.get());
    448     DCHECK(!meta_table_.get());
    449 
    450     // If there are left-over directories from failed deletion attempts, clean
    451     // them up.
    452     if (base::DirectoryExists(db_dir_)) {
    453       base::FileEnumerator directories(
    454           db_dir_,
    455           false,
    456           base::FileEnumerator::DIRECTORIES,
    457           kTemporaryDirectoryPattern);
    458       for (base::FilePath directory = directories.Next(); !directory.empty();
    459            directory = directories.Next()) {
    460         base::DeleteFile(directory, true);
    461       }
    462     }
    463 
    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;
    475     }
    476 
    477     db_->set_histogram_tag("DatabaseTracker");
    478 
    479     databases_table_.reset(new DatabasesTable(db_.get()));
    480     meta_table_.reset(new sql::MetaTable());
    481 
    482     is_initialized_ =
    483         base::CreateDirectory(db_dir_) &&
    484         (db_->is_open() ||
    485          (is_incognito_ ? db_->OpenInMemory() :
    486           db_->Open(kTrackerDatabaseFullPath))) &&
    487         UpgradeToCurrentVersion();
    488     if (!is_initialized_) {
    489       databases_table_.reset(NULL);
    490       meta_table_.reset(NULL);
    491       db_->Close();
    492     }
    493   }
    494   return is_initialized_;
    495 }
    496 
    497 bool DatabaseTracker::UpgradeToCurrentVersion() {
    498   sql::Transaction transaction(db_.get());
    499   if (!transaction.Begin() ||
    500       !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
    501       (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
    502       !databases_table_->Init())
    503     return false;
    504 
    505   if (meta_table_->GetVersionNumber() < kCurrentVersion)
    506     meta_table_->SetVersionNumber(kCurrentVersion);
    507 
    508   return transaction.Commit();
    509 }
    510 
    511 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
    512     const std::string& origin_identifier,
    513     const base::string16& database_name,
    514     const base::string16& database_description,
    515     int64 estimated_size) {
    516   DatabaseDetails details;
    517   if (!databases_table_->GetDatabaseDetails(
    518           origin_identifier, database_name, &details)) {
    519     details.origin_identifier = origin_identifier;
    520     details.database_name = database_name;
    521     details.description = database_description;
    522     details.estimated_size = estimated_size;
    523     databases_table_->InsertDatabaseDetails(details);
    524   } else if ((details.description != database_description) ||
    525              (details.estimated_size != estimated_size)) {
    526     details.description = database_description;
    527     details.estimated_size = estimated_size;
    528     databases_table_->UpdateDatabaseDetails(details);
    529   }
    530 }
    531 
    532 void DatabaseTracker::ClearAllCachedOriginInfo() {
    533   origins_info_map_.clear();
    534 }
    535 
    536 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
    537     const std::string& origin_identifier, bool create_if_needed) {
    538   if (!LazyInit())
    539     return NULL;
    540 
    541   // Populate the cache with data for this origin if needed.
    542   if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
    543     if (!create_if_needed)
    544       return NULL;
    545 
    546     std::vector<DatabaseDetails> details;
    547     if (!databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
    548             origin_identifier, &details)) {
    549       return NULL;
    550     }
    551 
    552     CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
    553     origin_info.SetOriginIdentifier(origin_identifier);
    554     for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
    555          it != details.end(); it++) {
    556       int64 db_file_size;
    557       if (database_connections_.IsDatabaseOpened(
    558               origin_identifier, it->database_name)) {
    559         db_file_size = database_connections_.GetOpenDatabaseSize(
    560             origin_identifier, it->database_name);
    561       } else {
    562         db_file_size = GetDBFileSize(origin_identifier, it->database_name);
    563       }
    564       origin_info.SetDatabaseSize(it->database_name, db_file_size);
    565       origin_info.SetDatabaseDescription(it->database_name, it->description);
    566     }
    567   }
    568 
    569   return &origins_info_map_[origin_identifier];
    570 }
    571 
    572 int64 DatabaseTracker::GetDBFileSize(const std::string& origin_identifier,
    573                                      const base::string16& database_name) {
    574   base::FilePath db_file_name = GetFullDBFilePath(origin_identifier,
    575                                                   database_name);
    576   int64 db_file_size = 0;
    577   if (!base::GetFileSize(db_file_name, &db_file_size))
    578     db_file_size = 0;
    579   return db_file_size;
    580 }
    581 
    582 int64 DatabaseTracker::SeedOpenDatabaseInfo(
    583     const std::string& origin_id, const base::string16& name,
    584     const base::string16& description) {
    585   DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
    586   int64 size = GetDBFileSize(origin_id, name);
    587   database_connections_.SetOpenDatabaseSize(origin_id, name,  size);
    588   CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
    589   if (info) {
    590     info->SetDatabaseSize(name, size);
    591     info->SetDatabaseDescription(name, description);
    592   }
    593   return size;
    594 }
    595 
    596 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
    597     const std::string& origin_id, const base::string16& name,
    598     const base::string16* opt_description) {
    599   DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
    600   int64 new_size = GetDBFileSize(origin_id, name);
    601   int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
    602   CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
    603   if (info && opt_description)
    604     info->SetDatabaseDescription(name, *opt_description);
    605   if (old_size != new_size) {
    606     database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
    607     if (info)
    608       info->SetDatabaseSize(name, new_size);
    609     if (quota_manager_proxy_.get())
    610       quota_manager_proxy_->NotifyStorageModified(
    611           storage::QuotaClient::kDatabase,
    612           storage::GetOriginFromIdentifier(origin_id),
    613           storage::kStorageTypeTemporary,
    614           new_size - old_size);
    615     FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
    616         origin_id, name, new_size));
    617   }
    618   return new_size;
    619 }
    620 
    621 void DatabaseTracker::ScheduleDatabaseForDeletion(
    622     const std::string& origin_identifier,
    623     const base::string16& database_name) {
    624   DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
    625                                                 database_name));
    626   dbs_to_be_deleted_[origin_identifier].insert(database_name);
    627   FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
    628       origin_identifier, database_name));
    629 }
    630 
    631 void DatabaseTracker::ScheduleDatabasesForDeletion(
    632     const DatabaseSet& databases,
    633     const net::CompletionCallback& callback) {
    634   DCHECK(!databases.empty());
    635 
    636   if (!callback.is_null())
    637     deletion_callbacks_.push_back(std::make_pair(callback, databases));
    638   for (DatabaseSet::const_iterator ori = databases.begin();
    639        ori != databases.end(); ++ori) {
    640     for (std::set<base::string16>::const_iterator db = ori->second.begin();
    641          db != ori->second.end(); ++db)
    642       ScheduleDatabaseForDeletion(ori->first, *db);
    643   }
    644 }
    645 
    646 int DatabaseTracker::DeleteDatabase(const std::string& origin_identifier,
    647                                     const base::string16& database_name,
    648                                     const net::CompletionCallback& callback) {
    649   if (!LazyInit())
    650     return net::ERR_FAILED;
    651 
    652   if (database_connections_.IsDatabaseOpened(origin_identifier,
    653                                              database_name)) {
    654     if (!callback.is_null()) {
    655       DatabaseSet set;
    656       set[origin_identifier].insert(database_name);
    657       deletion_callbacks_.push_back(std::make_pair(callback, set));
    658     }
    659     ScheduleDatabaseForDeletion(origin_identifier, database_name);
    660     return net::ERR_IO_PENDING;
    661   }
    662   DeleteClosedDatabase(origin_identifier, database_name);
    663   return net::OK;
    664 }
    665 
    666 int DatabaseTracker::DeleteDataModifiedSince(
    667     const base::Time& cutoff,
    668     const net::CompletionCallback& callback) {
    669   if (!LazyInit())
    670     return net::ERR_FAILED;
    671 
    672   DatabaseSet to_be_deleted;
    673 
    674   std::vector<std::string> origins_identifiers;
    675   if (!databases_table_->GetAllOriginIdentifiers(&origins_identifiers))
    676     return net::ERR_FAILED;
    677   int rv = net::OK;
    678   for (std::vector<std::string>::const_iterator ori =
    679            origins_identifiers.begin();
    680        ori != origins_identifiers.end(); ++ori) {
    681     if (special_storage_policy_.get() &&
    682         special_storage_policy_->IsStorageProtected(
    683             storage::GetOriginFromIdentifier(*ori))) {
    684       continue;
    685     }
    686 
    687     std::vector<DatabaseDetails> details;
    688     if (!databases_table_->
    689             GetAllDatabaseDetailsForOriginIdentifier(*ori, &details))
    690       rv = net::ERR_FAILED;
    691     for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
    692          db != details.end(); ++db) {
    693       base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
    694       base::File::Info file_info;
    695       base::GetFileInfo(db_file, &file_info);
    696       if (file_info.last_modified < cutoff)
    697         continue;
    698 
    699       // Check if the database is opened by any renderer.
    700       if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
    701         to_be_deleted[*ori].insert(db->database_name);
    702       else
    703         DeleteClosedDatabase(*ori, db->database_name);
    704     }
    705   }
    706 
    707   if (rv != net::OK)
    708     return rv;
    709 
    710   if (!to_be_deleted.empty()) {
    711     ScheduleDatabasesForDeletion(to_be_deleted, callback);
    712     return net::ERR_IO_PENDING;
    713   }
    714   return net::OK;
    715 }
    716 
    717 int DatabaseTracker::DeleteDataForOrigin(
    718     const std::string& origin, const net::CompletionCallback& callback) {
    719   if (!LazyInit())
    720     return net::ERR_FAILED;
    721 
    722   DatabaseSet to_be_deleted;
    723 
    724   std::vector<DatabaseDetails> details;
    725   if (!databases_table_->
    726           GetAllDatabaseDetailsForOriginIdentifier(origin, &details))
    727     return net::ERR_FAILED;
    728   for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
    729        db != details.end(); ++db) {
    730     // Check if the database is opened by any renderer.
    731     if (database_connections_.IsDatabaseOpened(origin, db->database_name))
    732       to_be_deleted[origin].insert(db->database_name);
    733     else
    734       DeleteClosedDatabase(origin, db->database_name);
    735   }
    736 
    737   if (!to_be_deleted.empty()) {
    738     ScheduleDatabasesForDeletion(to_be_deleted, callback);
    739     return net::ERR_IO_PENDING;
    740   }
    741   return net::OK;
    742 }
    743 
    744 const base::File* DatabaseTracker::GetIncognitoFile(
    745     const base::string16& vfs_file_name) const {
    746   DCHECK(is_incognito_);
    747   FileHandlesMap::const_iterator it =
    748       incognito_file_handles_.find(vfs_file_name);
    749   if (it != incognito_file_handles_.end())
    750     return it->second;
    751 
    752   return NULL;
    753 }
    754 
    755 const base::File* DatabaseTracker::SaveIncognitoFile(
    756     const base::string16& vfs_file_name,
    757     base::File file) {
    758   DCHECK(is_incognito_);
    759   if (!file.IsValid())
    760     return NULL;
    761 
    762   base::File* to_insert = new base::File(file.Pass());
    763   std::pair<FileHandlesMap::iterator, bool> rv =
    764       incognito_file_handles_.insert(std::make_pair(vfs_file_name, to_insert));
    765   DCHECK(rv.second);
    766   return rv.first->second;
    767 }
    768 
    769 void DatabaseTracker::CloseIncognitoFileHandle(
    770     const base::string16& vfs_file_name) {
    771   DCHECK(is_incognito_);
    772   DCHECK(incognito_file_handles_.find(vfs_file_name) !=
    773          incognito_file_handles_.end());
    774 
    775   FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
    776   if (it != incognito_file_handles_.end()) {
    777     delete it->second;
    778     incognito_file_handles_.erase(it);
    779   }
    780 }
    781 
    782 bool DatabaseTracker::HasSavedIncognitoFileHandle(
    783     const base::string16& vfs_file_name) const {
    784   return (incognito_file_handles_.find(vfs_file_name) !=
    785           incognito_file_handles_.end());
    786 }
    787 
    788 void DatabaseTracker::DeleteIncognitoDBDirectory() {
    789   is_initialized_ = false;
    790 
    791   for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
    792        it != incognito_file_handles_.end(); it++) {
    793     delete it->second;
    794   }
    795 
    796   base::FilePath incognito_db_dir =
    797       profile_path_.Append(kIncognitoDatabaseDirectoryName);
    798   if (base::DirectoryExists(incognito_db_dir))
    799     base::DeleteFile(incognito_db_dir, true);
    800 }
    801 
    802 void DatabaseTracker::ClearSessionOnlyOrigins() {
    803   bool has_session_only_databases =
    804       special_storage_policy_.get() &&
    805       special_storage_policy_->HasSessionOnlyOrigins();
    806 
    807   // Clearing only session-only databases, and there are none.
    808   if (!has_session_only_databases)
    809     return;
    810 
    811   if (!LazyInit())
    812     return;
    813 
    814   std::vector<std::string> origin_identifiers;
    815   GetAllOriginIdentifiers(&origin_identifiers);
    816 
    817   for (std::vector<std::string>::iterator origin =
    818            origin_identifiers.begin();
    819        origin != origin_identifiers.end(); ++origin) {
    820     GURL origin_url = storage::GetOriginFromIdentifier(*origin);
    821     if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
    822       continue;
    823     if (special_storage_policy_->IsStorageProtected(origin_url))
    824       continue;
    825     storage::OriginInfo origin_info;
    826     std::vector<base::string16> databases;
    827     GetOriginInfo(*origin, &origin_info);
    828     origin_info.GetAllDatabaseNames(&databases);
    829 
    830     for (std::vector<base::string16>::iterator database = databases.begin();
    831          database != databases.end(); ++database) {
    832       base::File file(GetFullDBFilePath(*origin, *database),
    833                       base::File::FLAG_OPEN_ALWAYS |
    834                           base::File::FLAG_SHARE_DELETE |
    835                           base::File::FLAG_DELETE_ON_CLOSE |
    836                           base::File::FLAG_READ);
    837     }
    838     DeleteOrigin(*origin, true);
    839   }
    840 }
    841 
    842 
    843 void DatabaseTracker::Shutdown() {
    844   DCHECK(db_tracker_thread_.get());
    845   DCHECK(db_tracker_thread_->BelongsToCurrentThread());
    846   if (shutting_down_) {
    847     NOTREACHED();
    848     return;
    849   }
    850   shutting_down_ = true;
    851   if (is_incognito_)
    852     DeleteIncognitoDBDirectory();
    853   else if (!force_keep_session_state_)
    854     ClearSessionOnlyOrigins();
    855   CloseTrackerDatabaseAndClearCaches();
    856 }
    857 
    858 void DatabaseTracker::SetForceKeepSessionState() {
    859   DCHECK(db_tracker_thread_.get());
    860   if (!db_tracker_thread_->BelongsToCurrentThread()) {
    861     db_tracker_thread_->PostTask(
    862         FROM_HERE,
    863         base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
    864     return;
    865   }
    866   force_keep_session_state_ = true;
    867 }
    868 
    869 }  // namespace storage
    870