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 "webkit/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/file_util.h"
     13 #include "base/files/file_enumerator.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "base/platform_file.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 "third_party/sqlite/sqlite3.h"
     23 #include "webkit/browser/database/database_quota_client.h"
     24 #include "webkit/browser/database/database_util.h"
     25 #include "webkit/browser/database/databases_table.h"
     26 #include "webkit/browser/quota/quota_manager.h"
     27 #include "webkit/browser/quota/special_storage_policy.h"
     28 #include "webkit/common/database/database_identifier.h"
     29 
     30 namespace webkit_database {
     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     quota::SpecialStoragePolicy* special_storage_policy,
     86     quota::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         quota::QuotaClient::kDatabase,
    125         webkit_database::GetOriginFromIdentifier(origin_identifier),
    126         quota::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         quota::QuotaClient::kDatabase,
    160         webkit_database::GetOriginFromIdentifier(origin_identifier),
    161         quota::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(
    293       origin_identifier, database_name);
    294   if (id < 0)
    295     return base::FilePath();
    296 
    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);
    301 }
    302 
    303 bool DatabaseTracker::GetOriginInfo(const std::string& 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;
    311 }
    312 
    313 bool DatabaseTracker::GetAllOriginIdentifiers(
    314     std::vector<std::string>* origin_identifiers) {
    315   DCHECK(origin_identifiers);
    316   DCHECK(origin_identifiers->empty());
    317   if (!LazyInit())
    318     return false;
    319   return databases_table_->GetAllOriginIdentifiers(origin_identifiers);
    320 }
    321 
    322 bool DatabaseTracker::GetAllOriginsInfo(
    323     std::vector<OriginInfo>* origins_info) {
    324   DCHECK(origins_info);
    325   DCHECK(origins_info->empty());
    326 
    327   std::vector<std::string> origins;
    328   if (!GetAllOriginIdentifiers(&origins))
    329     return false;
    330 
    331   for (std::vector<std::string>::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;
    338     }
    339     origins_info->push_back(OriginInfo(*origin_info));
    340   }
    341 
    342   return true;
    343 }
    344 
    345 bool DatabaseTracker::DeleteClosedDatabase(
    346     const std::string& origin_identifier,
    347     const base::string16& database_name) {
    348   if (!LazyInit())
    349     return false;
    350 
    351   // Check if the database is opened by any renderer.
    352   if (database_connections_.IsDatabaseOpened(origin_identifier, database_name))
    353     return false;
    354 
    355   int64 db_file_size = quota_manager_proxy_.get()
    356                            ? GetDBFileSize(origin_identifier, database_name)
    357                            : 0;
    358 
    359   // Try to delete the file on the hard drive.
    360   base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name);
    361   if (!sql::Connection::Delete(db_file))
    362     return false;
    363 
    364   if (quota_manager_proxy_.get() && db_file_size)
    365     quota_manager_proxy_->NotifyStorageModified(
    366         quota::QuotaClient::kDatabase,
    367         webkit_database::GetOriginFromIdentifier(origin_identifier),
    368         quota::kStorageTypeTemporary,
    369         -db_file_size);
    370 
    371   // Clean up the main database and invalidate the cached record.
    372   databases_table_->DeleteDatabaseDetails(origin_identifier, database_name);
    373   origins_info_map_.erase(origin_identifier);
    374 
    375   std::vector<DatabaseDetails> details;
    376   if (databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
    377           origin_identifier, &details) && details.empty()) {
    378     // Try to delete the origin in case this was the last database.
    379     DeleteOrigin(origin_identifier, false);
    380   }
    381   return true;
    382 }
    383 
    384 bool DatabaseTracker::DeleteOrigin(const std::string& origin_identifier,
    385                                    bool force) {
    386   if (!LazyInit())
    387     return false;
    388 
    389   // Check if any database in this origin is opened by any renderer.
    390   if (database_connections_.IsOriginUsed(origin_identifier) && !force)
    391     return false;
    392 
    393   int64 deleted_size = 0;
    394   if (quota_manager_proxy_.get()) {
    395     CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier);
    396     if (origin_info)
    397       deleted_size = origin_info->TotalSize();
    398   }
    399 
    400   origins_info_map_.erase(origin_identifier);
    401   base::FilePath origin_dir = db_dir_.AppendASCII(origin_identifier);
    402 
    403   // Create a temporary directory to move possibly still existing databases to,
    404   // as we can't delete the origin directory on windows if it contains opened
    405   // files.
    406   base::FilePath new_origin_dir;
    407   file_util::CreateTemporaryDirInDir(db_dir_,
    408                                      kTemporaryDirectoryPrefix,
    409                                      &new_origin_dir);
    410   base::FileEnumerator databases(
    411       origin_dir,
    412       false,
    413       base::FileEnumerator::FILES);
    414   for (base::FilePath database = databases.Next(); !database.empty();
    415        database = databases.Next()) {
    416     base::FilePath new_file = new_origin_dir.Append(database.BaseName());
    417     base::Move(database, new_file);
    418   }
    419   base::DeleteFile(origin_dir, true);
    420   base::DeleteFile(new_origin_dir, true); // might fail on windows.
    421 
    422   databases_table_->DeleteOriginIdentifier(origin_identifier);
    423 
    424   if (quota_manager_proxy_.get() && deleted_size) {
    425     quota_manager_proxy_->NotifyStorageModified(
    426         quota::QuotaClient::kDatabase,
    427         webkit_database::GetOriginFromIdentifier(origin_identifier),
    428         quota::kStorageTypeTemporary,
    429         -deleted_size);
    430   }
    431 
    432   return true;
    433 }
    434 
    435 bool DatabaseTracker::IsDatabaseScheduledForDeletion(
    436     const std::string& origin_identifier,
    437     const base::string16& database_name) {
    438   DatabaseSet::iterator it = dbs_to_be_deleted_.find(origin_identifier);
    439   if (it == dbs_to_be_deleted_.end())
    440     return false;
    441 
    442   std::set<base::string16>& databases = it->second;
    443   return (databases.find(database_name) != databases.end());
    444 }
    445 
    446 bool DatabaseTracker::LazyInit() {
    447   if (!is_initialized_ && !shutting_down_) {
    448     DCHECK(!db_->is_open());
    449     DCHECK(!databases_table_.get());
    450     DCHECK(!meta_table_.get());
    451 
    452     // If there are left-over directories from failed deletion attempts, clean
    453     // them up.
    454     if (base::DirectoryExists(db_dir_)) {
    455       base::FileEnumerator directories(
    456           db_dir_,
    457           false,
    458           base::FileEnumerator::DIRECTORIES,
    459           kTemporaryDirectoryPattern);
    460       for (base::FilePath directory = directories.Next(); !directory.empty();
    461            directory = directories.Next()) {
    462         base::DeleteFile(directory, true);
    463       }
    464     }
    465 
    466     // If the tracker database exists, but it's corrupt or doesn't
    467     // have a meta table, delete the database directory.
    468     const base::FilePath kTrackerDatabaseFullPath =
    469         db_dir_.Append(base::FilePath(kTrackerDatabaseFileName));
    470     if (base::DirectoryExists(db_dir_) &&
    471         base::PathExists(kTrackerDatabaseFullPath) &&
    472         (!db_->Open(kTrackerDatabaseFullPath) ||
    473          !sql::MetaTable::DoesTableExist(db_.get()))) {
    474       db_->Close();
    475       if (!base::DeleteFile(db_dir_, true))
    476         return false;
    477     }
    478 
    479     db_->set_histogram_tag("DatabaseTracker");
    480 
    481     databases_table_.reset(new DatabasesTable(db_.get()));
    482     meta_table_.reset(new sql::MetaTable());
    483 
    484     is_initialized_ =
    485         file_util::CreateDirectory(db_dir_) &&
    486         (db_->is_open() ||
    487          (is_incognito_ ? db_->OpenInMemory() :
    488           db_->Open(kTrackerDatabaseFullPath))) &&
    489         UpgradeToCurrentVersion();
    490     if (!is_initialized_) {
    491       databases_table_.reset(NULL);
    492       meta_table_.reset(NULL);
    493       db_->Close();
    494     }
    495   }
    496   return is_initialized_;
    497 }
    498 
    499 bool DatabaseTracker::UpgradeToCurrentVersion() {
    500   sql::Transaction transaction(db_.get());
    501   if (!transaction.Begin() ||
    502       !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
    503       (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
    504       !databases_table_->Init())
    505     return false;
    506 
    507   if (meta_table_->GetVersionNumber() < kCurrentVersion)
    508     meta_table_->SetVersionNumber(kCurrentVersion);
    509 
    510   return transaction.Commit();
    511 }
    512 
    513 void DatabaseTracker::InsertOrUpdateDatabaseDetails(
    514     const std::string& origin_identifier,
    515     const base::string16& database_name,
    516     const base::string16& database_description,
    517     int64 estimated_size) {
    518   DatabaseDetails details;
    519   if (!databases_table_->GetDatabaseDetails(
    520           origin_identifier, database_name, &details)) {
    521     details.origin_identifier = origin_identifier;
    522     details.database_name = database_name;
    523     details.description = database_description;
    524     details.estimated_size = estimated_size;
    525     databases_table_->InsertDatabaseDetails(details);
    526   } else if ((details.description != database_description) ||
    527              (details.estimated_size != estimated_size)) {
    528     details.description = database_description;
    529     details.estimated_size = estimated_size;
    530     databases_table_->UpdateDatabaseDetails(details);
    531   }
    532 }
    533 
    534 void DatabaseTracker::ClearAllCachedOriginInfo() {
    535   origins_info_map_.clear();
    536 }
    537 
    538 DatabaseTracker::CachedOriginInfo* DatabaseTracker::MaybeGetCachedOriginInfo(
    539     const std::string& origin_identifier, bool create_if_needed) {
    540   if (!LazyInit())
    541     return NULL;
    542 
    543   // Populate the cache with data for this origin if needed.
    544   if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) {
    545     if (!create_if_needed)
    546       return NULL;
    547 
    548     std::vector<DatabaseDetails> details;
    549     if (!databases_table_->GetAllDatabaseDetailsForOriginIdentifier(
    550             origin_identifier, &details)) {
    551       return NULL;
    552     }
    553 
    554     CachedOriginInfo& origin_info = origins_info_map_[origin_identifier];
    555     origin_info.SetOriginIdentifier(origin_identifier);
    556     for (std::vector<DatabaseDetails>::const_iterator it = details.begin();
    557          it != details.end(); it++) {
    558       int64 db_file_size;
    559       if (database_connections_.IsDatabaseOpened(
    560               origin_identifier, it->database_name)) {
    561         db_file_size = database_connections_.GetOpenDatabaseSize(
    562             origin_identifier, it->database_name);
    563       } else {
    564         db_file_size = GetDBFileSize(origin_identifier, it->database_name);
    565       }
    566       origin_info.SetDatabaseSize(it->database_name, db_file_size);
    567       origin_info.SetDatabaseDescription(it->database_name, it->description);
    568     }
    569   }
    570 
    571   return &origins_info_map_[origin_identifier];
    572 }
    573 
    574 int64 DatabaseTracker::GetDBFileSize(const std::string& origin_identifier,
    575                                      const base::string16& database_name) {
    576   base::FilePath db_file_name = GetFullDBFilePath(origin_identifier,
    577                                                   database_name);
    578   int64 db_file_size = 0;
    579   if (!file_util::GetFileSize(db_file_name, &db_file_size))
    580     db_file_size = 0;
    581   return db_file_size;
    582 }
    583 
    584 int64 DatabaseTracker::SeedOpenDatabaseInfo(
    585     const std::string& origin_id, const base::string16& name,
    586     const base::string16& description) {
    587   DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
    588   int64 size = GetDBFileSize(origin_id, name);
    589   database_connections_.SetOpenDatabaseSize(origin_id, name,  size);
    590   CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
    591   if (info) {
    592     info->SetDatabaseSize(name, size);
    593     info->SetDatabaseDescription(name, description);
    594   }
    595   return size;
    596 }
    597 
    598 int64 DatabaseTracker::UpdateOpenDatabaseInfoAndNotify(
    599     const std::string& origin_id, const base::string16& name,
    600     const base::string16* opt_description) {
    601   DCHECK(database_connections_.IsDatabaseOpened(origin_id, name));
    602   int64 new_size = GetDBFileSize(origin_id, name);
    603   int64 old_size = database_connections_.GetOpenDatabaseSize(origin_id, name);
    604   CachedOriginInfo* info = MaybeGetCachedOriginInfo(origin_id, false);
    605   if (info && opt_description)
    606     info->SetDatabaseDescription(name, *opt_description);
    607   if (old_size != new_size) {
    608     database_connections_.SetOpenDatabaseSize(origin_id, name, new_size);
    609     if (info)
    610       info->SetDatabaseSize(name, new_size);
    611     if (quota_manager_proxy_.get())
    612       quota_manager_proxy_->NotifyStorageModified(
    613           quota::QuotaClient::kDatabase,
    614           webkit_database::GetOriginFromIdentifier(origin_id),
    615           quota::kStorageTypeTemporary,
    616           new_size - old_size);
    617     FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged(
    618         origin_id, name, new_size));
    619   }
    620   return new_size;
    621 }
    622 
    623 void DatabaseTracker::ScheduleDatabaseForDeletion(
    624     const std::string& origin_identifier,
    625     const base::string16& database_name) {
    626   DCHECK(database_connections_.IsDatabaseOpened(origin_identifier,
    627                                                 database_name));
    628   dbs_to_be_deleted_[origin_identifier].insert(database_name);
    629   FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseScheduledForDeletion(
    630       origin_identifier, database_name));
    631 }
    632 
    633 void DatabaseTracker::ScheduleDatabasesForDeletion(
    634     const DatabaseSet& databases,
    635     const net::CompletionCallback& callback) {
    636   DCHECK(!databases.empty());
    637 
    638   if (!callback.is_null())
    639     deletion_callbacks_.push_back(std::make_pair(callback, databases));
    640   for (DatabaseSet::const_iterator ori = databases.begin();
    641        ori != databases.end(); ++ori) {
    642     for (std::set<base::string16>::const_iterator db = ori->second.begin();
    643          db != ori->second.end(); ++db)
    644       ScheduleDatabaseForDeletion(ori->first, *db);
    645   }
    646 }
    647 
    648 int DatabaseTracker::DeleteDatabase(const std::string& origin_identifier,
    649                                     const base::string16& database_name,
    650                                     const net::CompletionCallback& callback) {
    651   if (!LazyInit())
    652     return net::ERR_FAILED;
    653 
    654   if (database_connections_.IsDatabaseOpened(origin_identifier,
    655                                              database_name)) {
    656     if (!callback.is_null()) {
    657       DatabaseSet set;
    658       set[origin_identifier].insert(database_name);
    659       deletion_callbacks_.push_back(std::make_pair(callback, set));
    660     }
    661     ScheduleDatabaseForDeletion(origin_identifier, database_name);
    662     return net::ERR_IO_PENDING;
    663   }
    664   DeleteClosedDatabase(origin_identifier, database_name);
    665   return net::OK;
    666 }
    667 
    668 int DatabaseTracker::DeleteDataModifiedSince(
    669     const base::Time& cutoff,
    670     const net::CompletionCallback& callback) {
    671   if (!LazyInit())
    672     return net::ERR_FAILED;
    673 
    674   DatabaseSet to_be_deleted;
    675 
    676   std::vector<std::string> origins_identifiers;
    677   if (!databases_table_->GetAllOriginIdentifiers(&origins_identifiers))
    678     return net::ERR_FAILED;
    679   int rv = net::OK;
    680   for (std::vector<std::string>::const_iterator ori =
    681            origins_identifiers.begin();
    682        ori != origins_identifiers.end(); ++ori) {
    683     if (special_storage_policy_.get() &&
    684         special_storage_policy_->IsStorageProtected(
    685             webkit_database::GetOriginFromIdentifier(*ori))) {
    686       continue;
    687     }
    688 
    689     std::vector<DatabaseDetails> details;
    690     if (!databases_table_->
    691             GetAllDatabaseDetailsForOriginIdentifier(*ori, &details))
    692       rv = net::ERR_FAILED;
    693     for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
    694          db != details.end(); ++db) {
    695       base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name);
    696       base::PlatformFileInfo file_info;
    697       file_util::GetFileInfo(db_file, &file_info);
    698       if (file_info.last_modified < cutoff)
    699         continue;
    700 
    701       // Check if the database is opened by any renderer.
    702       if (database_connections_.IsDatabaseOpened(*ori, db->database_name))
    703         to_be_deleted[*ori].insert(db->database_name);
    704       else
    705         DeleteClosedDatabase(*ori, db->database_name);
    706     }
    707   }
    708 
    709   if (rv != net::OK)
    710     return rv;
    711 
    712   if (!to_be_deleted.empty()) {
    713     ScheduleDatabasesForDeletion(to_be_deleted, callback);
    714     return net::ERR_IO_PENDING;
    715   }
    716   return net::OK;
    717 }
    718 
    719 int DatabaseTracker::DeleteDataForOrigin(
    720     const std::string& origin, const net::CompletionCallback& callback) {
    721   if (!LazyInit())
    722     return net::ERR_FAILED;
    723 
    724   DatabaseSet to_be_deleted;
    725 
    726   std::vector<DatabaseDetails> details;
    727   if (!databases_table_->
    728           GetAllDatabaseDetailsForOriginIdentifier(origin, &details))
    729     return net::ERR_FAILED;
    730   for (std::vector<DatabaseDetails>::const_iterator db = details.begin();
    731        db != details.end(); ++db) {
    732     // Check if the database is opened by any renderer.
    733     if (database_connections_.IsDatabaseOpened(origin, db->database_name))
    734       to_be_deleted[origin].insert(db->database_name);
    735     else
    736       DeleteClosedDatabase(origin, db->database_name);
    737   }
    738 
    739   if (!to_be_deleted.empty()) {
    740     ScheduleDatabasesForDeletion(to_be_deleted, callback);
    741     return net::ERR_IO_PENDING;
    742   }
    743   return net::OK;
    744 }
    745 
    746 void DatabaseTracker::GetIncognitoFileHandle(
    747     const base::string16& vfs_file_name,
    748     base::PlatformFile* file_handle) const {
    749   DCHECK(is_incognito_);
    750   FileHandlesMap::const_iterator it =
    751       incognito_file_handles_.find(vfs_file_name);
    752   if (it != incognito_file_handles_.end())
    753     *file_handle = it->second;
    754   else
    755     *file_handle = base::kInvalidPlatformFileValue;
    756 }
    757 
    758 void DatabaseTracker::SaveIncognitoFileHandle(
    759     const base::string16& vfs_file_name,
    760     const base::PlatformFile& file_handle) {
    761   DCHECK(is_incognito_);
    762   DCHECK(incognito_file_handles_.find(vfs_file_name) ==
    763          incognito_file_handles_.end());
    764   if (file_handle != base::kInvalidPlatformFileValue)
    765     incognito_file_handles_[vfs_file_name] = file_handle;
    766 }
    767 
    768 bool DatabaseTracker::CloseIncognitoFileHandle(
    769     const base::string16& vfs_file_name) {
    770   DCHECK(is_incognito_);
    771   DCHECK(incognito_file_handles_.find(vfs_file_name) !=
    772          incognito_file_handles_.end());
    773 
    774   bool handle_closed = false;
    775   FileHandlesMap::iterator it = incognito_file_handles_.find(vfs_file_name);
    776   if (it != incognito_file_handles_.end()) {
    777     handle_closed = base::ClosePlatformFile(it->second);
    778     if (handle_closed)
    779       incognito_file_handles_.erase(it);
    780   }
    781   return handle_closed;
    782 }
    783 
    784 bool DatabaseTracker::HasSavedIncognitoFileHandle(
    785     const base::string16& vfs_file_name) const {
    786   return (incognito_file_handles_.find(vfs_file_name) !=
    787           incognito_file_handles_.end());
    788 }
    789 
    790 void DatabaseTracker::DeleteIncognitoDBDirectory() {
    791   shutting_down_ = true;
    792   is_initialized_ = false;
    793 
    794   for (FileHandlesMap::iterator it = incognito_file_handles_.begin();
    795        it != incognito_file_handles_.end(); it++)
    796     base::ClosePlatformFile(it->second);
    797 
    798   base::FilePath incognito_db_dir =
    799       profile_path_.Append(kIncognitoDatabaseDirectoryName);
    800   if (base::DirectoryExists(incognito_db_dir))
    801     base::DeleteFile(incognito_db_dir, true);
    802 }
    803 
    804 void DatabaseTracker::ClearSessionOnlyOrigins() {
    805   shutting_down_ = true;
    806 
    807   bool has_session_only_databases =
    808       special_storage_policy_.get() &&
    809       special_storage_policy_->HasSessionOnlyOrigins();
    810 
    811   // Clearing only session-only databases, and there are none.
    812   if (!has_session_only_databases)
    813     return;
    814 
    815   if (!LazyInit())
    816     return;
    817 
    818   std::vector<std::string> origin_identifiers;
    819   GetAllOriginIdentifiers(&origin_identifiers);
    820 
    821   for (std::vector<std::string>::iterator origin =
    822            origin_identifiers.begin();
    823        origin != origin_identifiers.end(); ++origin) {
    824     GURL origin_url = webkit_database::GetOriginFromIdentifier(*origin);
    825     if (!special_storage_policy_->IsStorageSessionOnly(origin_url))
    826       continue;
    827     if (special_storage_policy_->IsStorageProtected(origin_url))
    828       continue;
    829     webkit_database::OriginInfo origin_info;
    830     std::vector<base::string16> databases;
    831     GetOriginInfo(*origin, &origin_info);
    832     origin_info.GetAllDatabaseNames(&databases);
    833 
    834     for (std::vector<base::string16>::iterator database = databases.begin();
    835          database != databases.end(); ++database) {
    836       base::PlatformFile file_handle = base::CreatePlatformFile(
    837           GetFullDBFilePath(*origin, *database),
    838           base::PLATFORM_FILE_OPEN_ALWAYS |
    839           base::PLATFORM_FILE_SHARE_DELETE |
    840           base::PLATFORM_FILE_DELETE_ON_CLOSE |
    841           base::PLATFORM_FILE_READ,
    842           NULL, NULL);
    843       base::ClosePlatformFile(file_handle);
    844     }
    845     DeleteOrigin(*origin, true);
    846   }
    847 }
    848 
    849 
    850 void DatabaseTracker::Shutdown() {
    851   DCHECK(db_tracker_thread_.get());
    852   DCHECK(db_tracker_thread_->BelongsToCurrentThread());
    853   if (shutting_down_) {
    854     NOTREACHED();
    855     return;
    856   }
    857   if (is_incognito_)
    858     DeleteIncognitoDBDirectory();
    859   else if (!force_keep_session_state_)
    860     ClearSessionOnlyOrigins();
    861 }
    862 
    863 void DatabaseTracker::SetForceKeepSessionState() {
    864   DCHECK(db_tracker_thread_.get());
    865   if (!db_tracker_thread_->BelongsToCurrentThread()) {
    866     db_tracker_thread_->PostTask(
    867         FROM_HERE,
    868         base::Bind(&DatabaseTracker::SetForceKeepSessionState, this));
    869     return;
    870   }
    871   force_keep_session_state_ = true;
    872 }
    873 
    874 }  // namespace webkit_database
    875