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
30namespace base {
31class FilePath;
32class SequencedTaskRunner;
33class SingleThreadTaskRunner;
34}
35
36namespace quota_internals {
37class QuotaInternalsProxy;
38}
39
40namespace quota {
41
42class MockQuotaManager;
43class QuotaDatabase;
44class QuotaManagerProxy;
45class QuotaTemporaryStorageEvictor;
46class UsageTracker;
47
48struct QuotaManagerDeleter;
49
50struct 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.
64class 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
90struct 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.
103class 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
425struct 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.
432class 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