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 #ifndef WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
      6 #define WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <utility>
     11 
     12 #include "base/files/file_path.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/observer_list.h"
     17 #include "base/platform_file.h"
     18 #include "base/strings/string16.h"
     19 #include "base/strings/string_util.h"
     20 #include "base/time/time.h"
     21 #include "net/base/completion_callback.h"
     22 #include "webkit/browser/webkit_storage_browser_export.h"
     23 #include "webkit/common/database/database_connections.h"
     24 
     25 namespace base {
     26 class MessageLoopProxy;
     27 }
     28 
     29 namespace sql {
     30 class Connection;
     31 class MetaTable;
     32 }
     33 
     34 namespace quota {
     35 class QuotaManagerProxy;
     36 class SpecialStoragePolicy;
     37 }
     38 
     39 namespace webkit_database {
     40 
     41 WEBKIT_STORAGE_BROWSER_EXPORT extern const base::FilePath::CharType
     42     kDatabaseDirectoryName[];
     43 WEBKIT_STORAGE_BROWSER_EXPORT extern const base::FilePath::CharType
     44     kTrackerDatabaseFileName[];
     45 
     46 class DatabasesTable;
     47 
     48 // This class is used to store information about all databases in an origin.
     49 class WEBKIT_STORAGE_BROWSER_EXPORT OriginInfo {
     50  public:
     51   OriginInfo();
     52   OriginInfo(const OriginInfo& origin_info);
     53   ~OriginInfo();
     54 
     55   const std::string& GetOriginIdentifier() const { return origin_identifier_; }
     56   int64 TotalSize() const { return total_size_; }
     57   void GetAllDatabaseNames(std::vector<base::string16>* databases) const;
     58   int64 GetDatabaseSize(const base::string16& database_name) const;
     59   base::string16 GetDatabaseDescription(
     60       const base::string16& database_name) const;
     61 
     62  protected:
     63   typedef std::map<base::string16, std::pair<int64, base::string16> >
     64       DatabaseInfoMap;
     65 
     66   OriginInfo(const std::string& origin_identifier, int64 total_size);
     67 
     68   std::string origin_identifier_;
     69   int64 total_size_;
     70   DatabaseInfoMap database_info_;
     71 };
     72 
     73 // This class manages the main database and keeps track of open databases.
     74 //
     75 // The data in this class is not thread-safe, so all methods of this class
     76 // should be called on the same thread. The only exceptions are the ctor(),
     77 // the dtor() and the database_directory() and quota_manager_proxy() getters.
     78 //
     79 // Furthermore, some methods of this class have to read/write data from/to
     80 // the disk. Therefore, in a multi-threaded application, all methods of this
     81 // class should be called on the thread dedicated to file operations (file
     82 // thread in the browser process, for example), if such a thread exists.
     83 class WEBKIT_STORAGE_BROWSER_EXPORT DatabaseTracker
     84     : public base::RefCountedThreadSafe<DatabaseTracker> {
     85  public:
     86   class Observer {
     87    public:
     88     virtual void OnDatabaseSizeChanged(const std::string& origin_identifier,
     89                                        const base::string16& database_name,
     90                                        int64 database_size) = 0;
     91     virtual void OnDatabaseScheduledForDeletion(
     92         const std::string& origin_identifier,
     93         const base::string16& database_name) = 0;
     94 
     95    protected:
     96     virtual ~Observer() {}
     97   };
     98 
     99   DatabaseTracker(const base::FilePath& profile_path,
    100                   bool is_incognito,
    101                   quota::SpecialStoragePolicy* special_storage_policy,
    102                   quota::QuotaManagerProxy* quota_manager_proxy,
    103                   base::MessageLoopProxy* db_tracker_thread);
    104 
    105   void DatabaseOpened(const std::string& origin_identifier,
    106                       const base::string16& database_name,
    107                       const base::string16& database_details,
    108                       int64 estimated_size,
    109                       int64* database_size);
    110   void DatabaseModified(const std::string& origin_identifier,
    111                         const base::string16& database_name);
    112   void DatabaseClosed(const std::string& origin_identifier,
    113                       const base::string16& database_name);
    114   void HandleSqliteError(const std::string& origin_identifier,
    115                          const base::string16& database_name,
    116                          int error);
    117 
    118   void CloseDatabases(const DatabaseConnections& connections);
    119 
    120   void AddObserver(Observer* observer);
    121   void RemoveObserver(Observer* observer);
    122 
    123   void CloseTrackerDatabaseAndClearCaches();
    124 
    125   const base::FilePath& DatabaseDirectory() const { return db_dir_; }
    126   base::FilePath GetFullDBFilePath(const std::string& origin_identifier,
    127                                    const base::string16& database_name);
    128 
    129   // virtual for unit-testing only
    130   virtual bool GetOriginInfo(const std::string& origin_id, OriginInfo* info);
    131   virtual bool GetAllOriginIdentifiers(std::vector<std::string>* origin_ids);
    132   virtual bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info);
    133 
    134   // Safe to call on any thread.
    135   quota::QuotaManagerProxy* quota_manager_proxy() const {
    136     return quota_manager_proxy_.get();
    137   }
    138 
    139   bool IsDatabaseScheduledForDeletion(const std::string& origin_identifier,
    140                                       const base::string16& database_name);
    141 
    142   // Deletes a single database. Returns net::OK on success, net::FAILED on
    143   // failure, or net::ERR_IO_PENDING and |callback| is invoked upon completion,
    144   // if non-NULL.
    145   int DeleteDatabase(const std::string& origin_identifier,
    146                      const base::string16& database_name,
    147                      const net::CompletionCallback& callback);
    148 
    149   // Delete any databases that have been touched since the cutoff date that's
    150   // supplied, omitting any that match IDs within |protected_origins|.
    151   // Returns net::OK on success, net::FAILED if not all databases could be
    152   // deleted, and net::ERR_IO_PENDING and |callback| is invoked upon completion,
    153   // if non-NULL. Protected origins, according the the SpecialStoragePolicy,
    154   // are not deleted by this method.
    155   int DeleteDataModifiedSince(const base::Time& cutoff,
    156                               const net::CompletionCallback& callback);
    157 
    158   // Delete all databases that belong to the given origin. Returns net::OK on
    159   // success, net::FAILED if not all databases could be deleted, and
    160   // net::ERR_IO_PENDING and |callback| is invoked upon completion, if non-NULL.
    161   // virtual for unit testing only
    162   virtual int DeleteDataForOrigin(const std::string& origin_identifier,
    163                                   const net::CompletionCallback& callback);
    164 
    165   bool IsIncognitoProfile() const { return is_incognito_; }
    166 
    167   void GetIncognitoFileHandle(const base::string16& vfs_file_path,
    168                               base::PlatformFile* file_handle) const;
    169   void SaveIncognitoFileHandle(const base::string16& vfs_file_path,
    170                                const base::PlatformFile& file_handle);
    171   bool CloseIncognitoFileHandle(const base::string16& vfs_file_path);
    172   bool HasSavedIncognitoFileHandle(const base::string16& vfs_file_path) const;
    173 
    174   // Shutdown the database tracker, deleting database files if the tracker is
    175   // used for an incognito profile.
    176   void Shutdown();
    177   // Disables the exit-time deletion of session-only data.
    178   void SetForceKeepSessionState();
    179 
    180  private:
    181   friend class base::RefCountedThreadSafe<DatabaseTracker>;
    182   friend class MockDatabaseTracker;  // for testing
    183 
    184   typedef std::map<std::string, std::set<base::string16> > DatabaseSet;
    185   typedef std::vector<std::pair<net::CompletionCallback, DatabaseSet> >
    186       PendingDeletionCallbacks;
    187   typedef std::map<base::string16, base::PlatformFile> FileHandlesMap;
    188   typedef std::map<std::string, base::string16> OriginDirectoriesMap;
    189 
    190   class CachedOriginInfo : public OriginInfo {
    191    public:
    192     CachedOriginInfo() : OriginInfo(std::string(), 0) {}
    193     void SetOriginIdentifier(const std::string& origin_identifier) {
    194       origin_identifier_ = origin_identifier;
    195     }
    196     void SetDatabaseSize(const base::string16& database_name, int64 new_size) {
    197       int64 old_size = 0;
    198       if (database_info_.find(database_name) != database_info_.end())
    199         old_size = database_info_[database_name].first;
    200       database_info_[database_name].first = new_size;
    201       if (new_size != old_size)
    202         total_size_ += new_size - old_size;
    203     }
    204     void SetDatabaseDescription(const base::string16& database_name,
    205                                 const base::string16& description) {
    206       database_info_[database_name].second = description;
    207     }
    208   };
    209 
    210   // virtual for unit-testing only.
    211   virtual ~DatabaseTracker();
    212 
    213   // Deletes the directory that stores all DBs in incognito mode, if it exists.
    214   void DeleteIncognitoDBDirectory();
    215 
    216   // Deletes session-only databases. Blocks databases from being created/opened.
    217   void ClearSessionOnlyOrigins();
    218 
    219   bool DeleteClosedDatabase(const std::string& origin_identifier,
    220                             const base::string16& database_name);
    221 
    222   // Delete all files belonging to the given origin given that no database
    223   // connections within this origin are open, or if |force| is true, delete
    224   // the meta data and rename the associated directory.
    225   bool DeleteOrigin(const std::string& origin_identifier, bool force);
    226   void DeleteDatabaseIfNeeded(const std::string& origin_identifier,
    227                               const base::string16& database_name);
    228 
    229   bool LazyInit();
    230   bool UpgradeToCurrentVersion();
    231   void InsertOrUpdateDatabaseDetails(const std::string& origin_identifier,
    232                                      const base::string16& database_name,
    233                                      const base::string16& database_details,
    234                                      int64 estimated_size);
    235 
    236   void ClearAllCachedOriginInfo();
    237   CachedOriginInfo* MaybeGetCachedOriginInfo(
    238       const std::string& origin_identifier,
    239       bool create_if_needed);
    240   CachedOriginInfo* GetCachedOriginInfo(
    241       const std::string& origin_identifier) {
    242     return MaybeGetCachedOriginInfo(origin_identifier, true);
    243   }
    244 
    245   int64 GetDBFileSize(const std::string& origin_identifier,
    246                       const base::string16& database_name);
    247   int64 SeedOpenDatabaseInfo(const std::string& origin_identifier,
    248                              const base::string16& database_name,
    249                              const base::string16& description);
    250   int64 UpdateOpenDatabaseInfoAndNotify(const std::string& origin_identifier,
    251                                         const base::string16& database_name,
    252                                         const base::string16* opt_description);
    253   int64 UpdateOpenDatabaseSizeAndNotify(const std::string& origin_identifier,
    254                                         const base::string16& database_name) {
    255     return UpdateOpenDatabaseInfoAndNotify(
    256         origin_identifier, database_name, NULL);
    257   }
    258 
    259 
    260   void ScheduleDatabaseForDeletion(const std::string& origin_identifier,
    261                                    const base::string16& database_name);
    262   // Schedule a set of open databases for deletion. If non-null, callback is
    263   // invoked upon completion.
    264   void ScheduleDatabasesForDeletion(const DatabaseSet& databases,
    265                                     const net::CompletionCallback& callback);
    266 
    267   // Returns the directory where all DB files for the given origin are stored.
    268   base::string16 GetOriginDirectory(const std::string& origin_identifier);
    269 
    270   bool is_initialized_;
    271   const bool is_incognito_;
    272   bool force_keep_session_state_;
    273   bool shutting_down_;
    274   const base::FilePath profile_path_;
    275   const base::FilePath db_dir_;
    276   scoped_ptr<sql::Connection> db_;
    277   scoped_ptr<DatabasesTable> databases_table_;
    278   scoped_ptr<sql::MetaTable> meta_table_;
    279   ObserverList<Observer, true> observers_;
    280   std::map<std::string, CachedOriginInfo> origins_info_map_;
    281   DatabaseConnections database_connections_;
    282 
    283   // The set of databases that should be deleted but are still opened
    284   DatabaseSet dbs_to_be_deleted_;
    285   PendingDeletionCallbacks deletion_callbacks_;
    286 
    287   // Apps and Extensions can have special rights.
    288   scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
    289 
    290   scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
    291 
    292   // The database tracker thread we're supposed to run file IO on.
    293   scoped_refptr<base::MessageLoopProxy> db_tracker_thread_;
    294 
    295   // When in incognito mode, store a DELETE_ON_CLOSE handle to each
    296   // main DB and journal file that was accessed. When the incognito profile
    297   // goes away (or when the browser crashes), all these handles will be
    298   // closed, and the files will be deleted.
    299   FileHandlesMap incognito_file_handles_;
    300 
    301   // In a non-incognito profile, all DBs in an origin are stored in a directory
    302   // named after the origin. In an incognito profile though, we do not want the
    303   // directory structure to reveal the origins visited by the user (in case the
    304   // browser process crashes and those directories are not deleted). So we use
    305   // this map to assign directory names that do not reveal this information.
    306   OriginDirectoriesMap incognito_origin_directories_;
    307   int incognito_origin_directories_generator_;
    308 
    309   FRIEND_TEST_ALL_PREFIXES(DatabaseTracker, TestHelper);
    310 };
    311 
    312 }  // namespace webkit_database
    313 
    314 #endif  // WEBKIT_BROWSER_DATABASE_DATABASE_TRACKER_H_
    315