Home | History | Annotate | Download | only in quota
      1 // Copyright 2013 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_QUOTA_QUOTA_MANAGER_H_
      6 #define WEBKIT_BROWSER_QUOTA_QUOTA_MANAGER_H_
      7 
      8 #include <deque>
      9 #include <list>
     10 #include <map>
     11 #include <set>
     12 #include <string>
     13 #include <utility>
     14 #include <vector>
     15 
     16 #include "base/basictypes.h"
     17 #include "base/callback.h"
     18 #include "base/files/file_path.h"
     19 #include "base/memory/ref_counted.h"
     20 #include "base/memory/scoped_ptr.h"
     21 #include "base/memory/weak_ptr.h"
     22 #include "base/sequenced_task_runner_helpers.h"
     23 #include "webkit/browser/quota/quota_callbacks.h"
     24 #include "webkit/browser/quota/quota_client.h"
     25 #include "webkit/browser/quota/quota_database.h"
     26 #include "webkit/browser/quota/quota_task.h"
     27 #include "webkit/browser/quota/special_storage_policy.h"
     28 #include "webkit/browser/webkit_storage_browser_export.h"
     29 
     30 namespace base {
     31 class FilePath;
     32 class SequencedTaskRunner;
     33 class SingleThreadTaskRunner;
     34 }
     35 
     36 namespace quota_internals {
     37 class QuotaInternalsProxy;
     38 }
     39 
     40 namespace quota {
     41 
     42 class MockQuotaManager;
     43 class QuotaDatabase;
     44 class QuotaManagerProxy;
     45 class QuotaTemporaryStorageEvictor;
     46 class UsageTracker;
     47 
     48 struct QuotaManagerDeleter;
     49 
     50 struct WEBKIT_STORAGE_BROWSER_EXPORT UsageAndQuota {
     51   int64 usage;
     52   int64 global_limited_usage;
     53   int64 quota;
     54   int64 available_disk_space;
     55 
     56   UsageAndQuota();
     57   UsageAndQuota(int64 usage,
     58                 int64 global_limited_usage,
     59                 int64 quota,
     60                 int64 available_disk_space);
     61 };
     62 
     63 // An interface called by QuotaTemporaryStorageEvictor.
     64 class WEBKIT_STORAGE_BROWSER_EXPORT QuotaEvictionHandler {
     65  public:
     66   typedef base::Callback<void(const GURL&)> GetLRUOriginCallback;
     67   typedef StatusCallback EvictOriginDataCallback;
     68   typedef base::Callback<void(QuotaStatusCode status,
     69                               const UsageAndQuota& usage_and_quota)>
     70       UsageAndQuotaCallback;
     71 
     72   // Returns the least recently used origin.  It might return empty
     73   // GURL when there are no evictable origins.
     74   virtual void GetLRUOrigin(
     75       StorageType type,
     76       const GetLRUOriginCallback& callback) = 0;
     77 
     78   virtual void EvictOriginData(
     79       const GURL& origin,
     80       StorageType type,
     81       const EvictOriginDataCallback& callback) = 0;
     82 
     83   virtual void GetUsageAndQuotaForEviction(
     84       const UsageAndQuotaCallback& callback) = 0;
     85 
     86  protected:
     87   virtual ~QuotaEvictionHandler() {}
     88 };
     89 
     90 struct UsageInfo {
     91   UsageInfo(const std::string& host, StorageType type, int64 usage)
     92       : host(host),
     93         type(type),
     94         usage(usage) {}
     95   std::string host;
     96   StorageType type;
     97   int64 usage;
     98 };
     99 
    100 // The quota manager class.  This class is instantiated per profile and
    101 // held by the profile.  With the exception of the constructor and the
    102 // proxy() method, all methods should only be called on the IO thread.
    103 class WEBKIT_STORAGE_BROWSER_EXPORT QuotaManager
    104     : public QuotaTaskObserver,
    105       public QuotaEvictionHandler,
    106       public base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter> {
    107  public:
    108   typedef base::Callback<void(QuotaStatusCode,
    109                               int64 /* usage */,
    110                               int64 /* quota */)>
    111       GetUsageAndQuotaCallback;
    112 
    113   static const int64 kIncognitoDefaultQuotaLimit;
    114   static const int64 kNoLimit;
    115 
    116   QuotaManager(bool is_incognito,
    117                const base::FilePath& profile_path,
    118                base::SingleThreadTaskRunner* io_thread,
    119                base::SequencedTaskRunner* db_thread,
    120                SpecialStoragePolicy* special_storage_policy);
    121 
    122   // Returns a proxy object that can be used on any thread.
    123   QuotaManagerProxy* proxy() { return proxy_.get(); }
    124 
    125   // Called by clients or webapps. Returns usage per host.
    126   void GetUsageInfo(const GetUsageInfoCallback& callback);
    127 
    128   // Called by Web Apps.
    129   // This method is declared as virtual to allow test code to override it.
    130   virtual void GetUsageAndQuotaForWebApps(
    131       const GURL& origin,
    132       StorageType type,
    133       const GetUsageAndQuotaCallback& callback);
    134 
    135   // Called by StorageClients.
    136   // This method is declared as virtual to allow test code to override it.
    137   //
    138   // For UnlimitedStorage origins, this version skips usage and quota handling
    139   // to avoid extra query cost.
    140   // Do not call this method for apps/user-facing code.
    141   virtual void GetUsageAndQuota(
    142       const GURL& origin,
    143       StorageType type,
    144       const GetUsageAndQuotaCallback& callback);
    145 
    146   // Called by clients via proxy.
    147   // Client storage should call this method when storage is accessed.
    148   // Used to maintain LRU ordering.
    149   void NotifyStorageAccessed(QuotaClient::ID client_id,
    150                              const GURL& origin,
    151                              StorageType type);
    152 
    153   // Called by clients via proxy.
    154   // Client storage must call this method whenever they have made any
    155   // modifications that change the amount of data stored in their storage.
    156   void NotifyStorageModified(QuotaClient::ID client_id,
    157                              const GURL& origin,
    158                              StorageType type,
    159                              int64 delta);
    160 
    161   // Used to avoid evicting origins with open pages.
    162   // A call to NotifyOriginInUse must be balanced by a later call
    163   // to NotifyOriginNoLongerInUse.
    164   void NotifyOriginInUse(const GURL& origin);
    165   void NotifyOriginNoLongerInUse(const GURL& origin);
    166   bool IsOriginInUse(const GURL& origin) const {
    167     return origins_in_use_.find(origin) != origins_in_use_.end();
    168   }
    169 
    170   void SetUsageCacheEnabled(QuotaClient::ID client_id,
    171                             const GURL& origin,
    172                             StorageType type,
    173                             bool enabled);
    174 
    175   // DeleteOriginData and DeleteHostData (surprisingly enough) delete data of a
    176   // particular StorageType associated with either a specific origin or set of
    177   // origins. Each method additionally requires a |quota_client_mask| which
    178   // specifies the types of QuotaClients to delete from the origin. This is
    179   // specified by the caller as a bitmask built from QuotaClient::IDs. Setting
    180   // the mask to QuotaClient::kAllClientsMask will remove all clients from the
    181   // origin, regardless of type.
    182   virtual void DeleteOriginData(const GURL& origin,
    183                                 StorageType type,
    184                                 int quota_client_mask,
    185                                 const StatusCallback& callback);
    186   void DeleteHostData(const std::string& host,
    187                       StorageType type,
    188                       int quota_client_mask,
    189                       const StatusCallback& callback);
    190 
    191   // Called by UI and internal modules.
    192   void GetAvailableSpace(const AvailableSpaceCallback& callback);
    193   void GetTemporaryGlobalQuota(const QuotaCallback& callback);
    194 
    195   // Ok to call with NULL callback.
    196   void SetTemporaryGlobalOverrideQuota(int64 new_quota,
    197                                        const QuotaCallback& callback);
    198 
    199   void GetPersistentHostQuota(const std::string& host,
    200                               const QuotaCallback& callback);
    201   void SetPersistentHostQuota(const std::string& host,
    202                               int64 new_quota,
    203                               const QuotaCallback& callback);
    204   void GetGlobalUsage(StorageType type, const GlobalUsageCallback& callback);
    205   void GetHostUsage(const std::string& host, StorageType type,
    206                     const UsageCallback& callback);
    207 
    208   void GetStatistics(std::map<std::string, std::string>* statistics);
    209 
    210   bool IsStorageUnlimited(const GURL& origin, StorageType type) const;
    211 
    212   bool CanQueryDiskSize(const GURL& origin) const {
    213     return special_storage_policy_.get() &&
    214            special_storage_policy_->CanQueryDiskSize(origin);
    215   }
    216 
    217   virtual void GetOriginsModifiedSince(StorageType type,
    218                                        base::Time modified_since,
    219                                        const GetOriginsCallback& callback);
    220 
    221   bool ResetUsageTracker(StorageType type);
    222 
    223   // Determines the portion of the temp pool that can be
    224   // utilized by a single host (ie. 5 for 20%).
    225   static const int kPerHostTemporaryPortion;
    226 
    227   static const char kDatabaseName[];
    228 
    229   static const int64 kMinimumPreserveForSystem;
    230 
    231   static const int kThresholdOfErrorsToBeBlacklisted;
    232 
    233   static const int kEvictionIntervalInMilliSeconds;
    234 
    235   // This is kept non-const so that test code can change the value.
    236   // TODO(kinuko): Make this a real const value and add a proper way to set
    237   // the quota for syncable storage. (http://crbug.com/155488)
    238   static int64 kSyncableStorageDefaultHostQuota;
    239 
    240  protected:
    241   virtual ~QuotaManager();
    242 
    243  private:
    244   friend class base::DeleteHelper<QuotaManager>;
    245   friend class base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter>;
    246   friend class MockQuotaManager;
    247   friend class MockStorageClient;
    248   friend class quota_internals::QuotaInternalsProxy;
    249   friend class QuotaManagerProxy;
    250   friend class QuotaManagerTest;
    251   friend class QuotaTemporaryStorageEvictor;
    252   friend struct QuotaManagerDeleter;
    253 
    254   class GetUsageInfoTask;
    255 
    256   class OriginDataDeleter;
    257   class HostDataDeleter;
    258 
    259   class GetModifiedSinceHelper;
    260   class DumpQuotaTableHelper;
    261   class DumpOriginInfoTableHelper;
    262 
    263   typedef QuotaDatabase::QuotaTableEntry QuotaTableEntry;
    264   typedef QuotaDatabase::OriginInfoTableEntry OriginInfoTableEntry;
    265   typedef std::vector<QuotaTableEntry> QuotaTableEntries;
    266   typedef std::vector<OriginInfoTableEntry> OriginInfoTableEntries;
    267 
    268   // Function pointer type used to store the function which returns the
    269   // available disk space for the disk containing the given FilePath.
    270   typedef int64 (*GetAvailableDiskSpaceFn)(const base::FilePath&);
    271 
    272   typedef base::Callback<void(const QuotaTableEntries&)>
    273       DumpQuotaTableCallback;
    274   typedef base::Callback<void(const OriginInfoTableEntries&)>
    275       DumpOriginInfoTableCallback;
    276 
    277   struct EvictionContext {
    278     EvictionContext();
    279     virtual ~EvictionContext();
    280     GURL evicted_origin;
    281     StorageType evicted_type;
    282 
    283     EvictOriginDataCallback evict_origin_data_callback;
    284   };
    285 
    286   typedef QuotaEvictionHandler::UsageAndQuotaCallback
    287       UsageAndQuotaDispatcherCallback;
    288 
    289   // This initialization method is lazily called on the IO thread
    290   // when the first quota manager API is called.
    291   // Initialize must be called after all quota clients are added to the
    292   // manager by RegisterStorage.
    293   void LazyInitialize();
    294 
    295   // Called by clients via proxy.
    296   // Registers a quota client to the manager.
    297   // The client must remain valid until OnQuotaManagerDestored is called.
    298   void RegisterClient(QuotaClient* client);
    299 
    300   UsageTracker* GetUsageTracker(StorageType type) const;
    301 
    302   // Extract cached origins list from the usage tracker.
    303   // (Might return empty list if no origin is tracked by the tracker.)
    304   void GetCachedOrigins(StorageType type, std::set<GURL>* origins);
    305 
    306   // These internal methods are separately defined mainly for testing.
    307   void NotifyStorageAccessedInternal(
    308       QuotaClient::ID client_id,
    309       const GURL& origin,
    310       StorageType type,
    311       base::Time accessed_time);
    312   void NotifyStorageModifiedInternal(
    313       QuotaClient::ID client_id,
    314       const GURL& origin,
    315       StorageType type,
    316       int64 delta,
    317       base::Time modified_time);
    318 
    319   void DumpQuotaTable(const DumpQuotaTableCallback& callback);
    320   void DumpOriginInfoTable(const DumpOriginInfoTableCallback& callback);
    321 
    322   // Methods for eviction logic.
    323   void StartEviction();
    324   void DeleteOriginFromDatabase(const GURL& origin, StorageType type);
    325 
    326   void DidOriginDataEvicted(QuotaStatusCode status);
    327 
    328   void ReportHistogram();
    329   void DidGetTemporaryGlobalUsageForHistogram(int64 usage,
    330                                               int64 unlimited_usage);
    331   void DidGetPersistentGlobalUsageForHistogram(int64 usage,
    332                                                int64 unlimited_usage);
    333 
    334   // QuotaEvictionHandler.
    335   virtual void GetLRUOrigin(
    336       StorageType type,
    337       const GetLRUOriginCallback& callback) OVERRIDE;
    338   virtual void EvictOriginData(
    339       const GURL& origin,
    340       StorageType type,
    341       const EvictOriginDataCallback& callback) OVERRIDE;
    342   virtual void GetUsageAndQuotaForEviction(
    343       const UsageAndQuotaCallback& callback) OVERRIDE;
    344 
    345   void DidSetTemporaryGlobalOverrideQuota(const QuotaCallback& callback,
    346                                           const int64* new_quota,
    347                                           bool success);
    348   void DidGetPersistentHostQuota(const std::string& host,
    349                                  const int64* quota,
    350                                  bool success);
    351   void DidSetPersistentHostQuota(const std::string& host,
    352                                  const QuotaCallback& callback,
    353                                  const int64* new_quota,
    354                                  bool success);
    355   void DidInitialize(int64* temporary_quota_override,
    356                      int64* desired_available_space,
    357                      bool success);
    358   void DidGetLRUOrigin(const GURL* origin,
    359                        bool success);
    360   void DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status,
    361                                          int64 quota_unused);
    362   void DidInitializeTemporaryOriginsInfo(bool success);
    363   void DidGetAvailableSpace(int64 space);
    364   void DidDatabaseWork(bool success);
    365 
    366   void DeleteOnCorrectThread() const;
    367 
    368   void PostTaskAndReplyWithResultForDBThread(
    369       const tracked_objects::Location& from_here,
    370       const base::Callback<bool(QuotaDatabase*)>& task,
    371       const base::Callback<void(bool)>& reply);
    372 
    373   const bool is_incognito_;
    374   const base::FilePath profile_path_;
    375 
    376   scoped_refptr<QuotaManagerProxy> proxy_;
    377   bool db_disabled_;
    378   bool eviction_disabled_;
    379   scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
    380   scoped_refptr<base::SequencedTaskRunner> db_thread_;
    381   mutable scoped_ptr<QuotaDatabase> database_;
    382 
    383   GetLRUOriginCallback lru_origin_callback_;
    384   std::set<GURL> access_notified_origins_;
    385 
    386   QuotaClientList clients_;
    387 
    388   scoped_ptr<UsageTracker> temporary_usage_tracker_;
    389   scoped_ptr<UsageTracker> persistent_usage_tracker_;
    390   scoped_ptr<UsageTracker> syncable_usage_tracker_;
    391   // TODO(michaeln): Need a way to clear the cache, drop and
    392   // reinstantiate the trackers when they're not handling requests.
    393 
    394   scoped_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_;
    395   EvictionContext eviction_context_;
    396 
    397   ClosureQueue db_initialization_callbacks_;
    398   AvailableSpaceCallbackQueue available_space_callbacks_;
    399   GlobalQuotaCallbackQueue temporary_global_quota_callbacks_;
    400   HostQuotaCallbackMap persistent_host_quota_callbacks_;
    401 
    402   bool temporary_quota_initialized_;
    403   int64 temporary_quota_override_;
    404 
    405   int64 desired_available_space_;
    406 
    407   // Map from origin to count.
    408   std::map<GURL, int> origins_in_use_;
    409   // Map from origin to error count.
    410   std::map<GURL, int> origins_in_error_;
    411 
    412   scoped_refptr<SpecialStoragePolicy> special_storage_policy_;
    413 
    414   base::WeakPtrFactory<QuotaManager> weak_factory_;
    415   base::RepeatingTimer<QuotaManager> histogram_timer_;
    416 
    417   // Pointer to the function used to get the available disk space. This is
    418   // overwritten by QuotaManagerTest in order to attain a deterministic reported
    419   // value. The default value points to base::SysInfo::AmountOfFreeDiskSpace.
    420   GetAvailableDiskSpaceFn get_disk_space_fn_;
    421 
    422   DISALLOW_COPY_AND_ASSIGN(QuotaManager);
    423 };
    424 
    425 struct QuotaManagerDeleter {
    426   static void Destruct(const QuotaManager* manager) {
    427     manager->DeleteOnCorrectThread();
    428   }
    429 };
    430 
    431 // The proxy may be called and finally released on any thread.
    432 class WEBKIT_STORAGE_BROWSER_EXPORT QuotaManagerProxy
    433     : public base::RefCountedThreadSafe<QuotaManagerProxy> {
    434  public:
    435   virtual void RegisterClient(QuotaClient* client);
    436   virtual void NotifyStorageAccessed(QuotaClient::ID client_id,
    437                                      const GURL& origin,
    438                                      StorageType type);
    439   virtual void NotifyStorageModified(QuotaClient::ID client_id,
    440                                      const GURL& origin,
    441                                      StorageType type,
    442                                      int64 delta);
    443   virtual void NotifyOriginInUse(const GURL& origin);
    444   virtual void NotifyOriginNoLongerInUse(const GURL& origin);
    445 
    446   virtual void SetUsageCacheEnabled(QuotaClient::ID client_id,
    447                                     const GURL& origin,
    448                                     StorageType type,
    449                                     bool enabled);
    450 
    451   // This method may only be called on the IO thread.
    452   // It may return NULL if the manager has already been deleted.
    453   QuotaManager* quota_manager() const;
    454 
    455  protected:
    456   friend class QuotaManager;
    457   friend class base::RefCountedThreadSafe<QuotaManagerProxy>;
    458 
    459   QuotaManagerProxy(QuotaManager* manager,
    460                     base::SingleThreadTaskRunner* io_thread);
    461   virtual ~QuotaManagerProxy();
    462 
    463   QuotaManager* manager_;  // only accessed on the io thread
    464   scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
    465 
    466   DISALLOW_COPY_AND_ASSIGN(QuotaManagerProxy);
    467 };
    468 
    469 }  // namespace quota
    470 
    471 #endif  // WEBKIT_BROWSER_QUOTA_QUOTA_MANAGER_H_
    472