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  void GetHostUsage(const std::string& host, StorageType type,
208                    QuotaClient::ID client_id,
209                    const UsageCallback& callback);
210
211  bool IsTrackingHostUsage(StorageType type, QuotaClient::ID client_id) const;
212
213  void GetStatistics(std::map<std::string, std::string>* statistics);
214
215  bool IsStorageUnlimited(const GURL& origin, StorageType type) const;
216
217  bool CanQueryDiskSize(const GURL& origin) const {
218    return special_storage_policy_.get() &&
219           special_storage_policy_->CanQueryDiskSize(origin);
220  }
221
222  virtual void GetOriginsModifiedSince(StorageType type,
223                                       base::Time modified_since,
224                                       const GetOriginsCallback& callback);
225
226  bool ResetUsageTracker(StorageType type);
227
228  // Determines the portion of the temp pool that can be
229  // utilized by a single host (ie. 5 for 20%).
230  static const int kPerHostTemporaryPortion;
231
232  static const char kDatabaseName[];
233
234  static const int64 kMinimumPreserveForSystem;
235
236  static const int kThresholdOfErrorsToBeBlacklisted;
237
238  static const int kEvictionIntervalInMilliSeconds;
239
240  // This is kept non-const so that test code can change the value.
241  // TODO(kinuko): Make this a real const value and add a proper way to set
242  // the quota for syncable storage. (http://crbug.com/155488)
243  static int64 kSyncableStorageDefaultHostQuota;
244
245 protected:
246  virtual ~QuotaManager();
247
248 private:
249  friend class base::DeleteHelper<QuotaManager>;
250  friend class base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter>;
251  friend class MockQuotaManager;
252  friend class MockStorageClient;
253  friend class quota_internals::QuotaInternalsProxy;
254  friend class QuotaManagerProxy;
255  friend class QuotaManagerTest;
256  friend class QuotaTemporaryStorageEvictor;
257  friend struct QuotaManagerDeleter;
258
259  class GetUsageInfoTask;
260
261  class OriginDataDeleter;
262  class HostDataDeleter;
263
264  class GetModifiedSinceHelper;
265  class DumpQuotaTableHelper;
266  class DumpOriginInfoTableHelper;
267
268  typedef QuotaDatabase::QuotaTableEntry QuotaTableEntry;
269  typedef QuotaDatabase::OriginInfoTableEntry OriginInfoTableEntry;
270  typedef std::vector<QuotaTableEntry> QuotaTableEntries;
271  typedef std::vector<OriginInfoTableEntry> OriginInfoTableEntries;
272
273  // Function pointer type used to store the function which returns the
274  // available disk space for the disk containing the given FilePath.
275  typedef int64 (*GetAvailableDiskSpaceFn)(const base::FilePath&);
276
277  typedef base::Callback<void(const QuotaTableEntries&)>
278      DumpQuotaTableCallback;
279  typedef base::Callback<void(const OriginInfoTableEntries&)>
280      DumpOriginInfoTableCallback;
281
282  struct EvictionContext {
283    EvictionContext();
284    virtual ~EvictionContext();
285    GURL evicted_origin;
286    StorageType evicted_type;
287
288    EvictOriginDataCallback evict_origin_data_callback;
289  };
290
291  typedef QuotaEvictionHandler::UsageAndQuotaCallback
292      UsageAndQuotaDispatcherCallback;
293
294  // This initialization method is lazily called on the IO thread
295  // when the first quota manager API is called.
296  // Initialize must be called after all quota clients are added to the
297  // manager by RegisterStorage.
298  void LazyInitialize();
299
300  // Called by clients via proxy.
301  // Registers a quota client to the manager.
302  // The client must remain valid until OnQuotaManagerDestored is called.
303  void RegisterClient(QuotaClient* client);
304
305  UsageTracker* GetUsageTracker(StorageType type) const;
306
307  // Extract cached origins list from the usage tracker.
308  // (Might return empty list if no origin is tracked by the tracker.)
309  void GetCachedOrigins(StorageType type, std::set<GURL>* origins);
310
311  // These internal methods are separately defined mainly for testing.
312  void NotifyStorageAccessedInternal(
313      QuotaClient::ID client_id,
314      const GURL& origin,
315      StorageType type,
316      base::Time accessed_time);
317  void NotifyStorageModifiedInternal(
318      QuotaClient::ID client_id,
319      const GURL& origin,
320      StorageType type,
321      int64 delta,
322      base::Time modified_time);
323
324  void DumpQuotaTable(const DumpQuotaTableCallback& callback);
325  void DumpOriginInfoTable(const DumpOriginInfoTableCallback& callback);
326
327  // Methods for eviction logic.
328  void StartEviction();
329  void DeleteOriginFromDatabase(const GURL& origin, StorageType type);
330
331  void DidOriginDataEvicted(QuotaStatusCode status);
332
333  void ReportHistogram();
334  void DidGetTemporaryGlobalUsageForHistogram(int64 usage,
335                                              int64 unlimited_usage);
336  void DidGetPersistentGlobalUsageForHistogram(int64 usage,
337                                               int64 unlimited_usage);
338
339  // QuotaEvictionHandler.
340  virtual void GetLRUOrigin(
341      StorageType type,
342      const GetLRUOriginCallback& callback) OVERRIDE;
343  virtual void EvictOriginData(
344      const GURL& origin,
345      StorageType type,
346      const EvictOriginDataCallback& callback) OVERRIDE;
347  virtual void GetUsageAndQuotaForEviction(
348      const UsageAndQuotaCallback& callback) OVERRIDE;
349
350  void DidSetTemporaryGlobalOverrideQuota(const QuotaCallback& callback,
351                                          const int64* new_quota,
352                                          bool success);
353  void DidGetPersistentHostQuota(const std::string& host,
354                                 const int64* quota,
355                                 bool success);
356  void DidSetPersistentHostQuota(const std::string& host,
357                                 const QuotaCallback& callback,
358                                 const int64* new_quota,
359                                 bool success);
360  void DidInitialize(int64* temporary_quota_override,
361                     int64* desired_available_space,
362                     bool success);
363  void DidGetLRUOrigin(const GURL* origin,
364                       bool success);
365  void DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status,
366                                         int64 quota_unused);
367  void DidInitializeTemporaryOriginsInfo(bool success);
368  void DidGetAvailableSpace(int64 space);
369  void DidDatabaseWork(bool success);
370
371  void DeleteOnCorrectThread() const;
372
373  void PostTaskAndReplyWithResultForDBThread(
374      const tracked_objects::Location& from_here,
375      const base::Callback<bool(QuotaDatabase*)>& task,
376      const base::Callback<void(bool)>& reply);
377
378  const bool is_incognito_;
379  const base::FilePath profile_path_;
380
381  scoped_refptr<QuotaManagerProxy> proxy_;
382  bool db_disabled_;
383  bool eviction_disabled_;
384  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
385  scoped_refptr<base::SequencedTaskRunner> db_thread_;
386  mutable scoped_ptr<QuotaDatabase> database_;
387
388  GetLRUOriginCallback lru_origin_callback_;
389  std::set<GURL> access_notified_origins_;
390
391  QuotaClientList clients_;
392
393  scoped_ptr<UsageTracker> temporary_usage_tracker_;
394  scoped_ptr<UsageTracker> persistent_usage_tracker_;
395  scoped_ptr<UsageTracker> syncable_usage_tracker_;
396  // TODO(michaeln): Need a way to clear the cache, drop and
397  // reinstantiate the trackers when they're not handling requests.
398
399  scoped_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_;
400  EvictionContext eviction_context_;
401
402  ClosureQueue db_initialization_callbacks_;
403  AvailableSpaceCallbackQueue available_space_callbacks_;
404  GlobalQuotaCallbackQueue temporary_global_quota_callbacks_;
405  HostQuotaCallbackMap persistent_host_quota_callbacks_;
406
407  bool temporary_quota_initialized_;
408  int64 temporary_quota_override_;
409
410  int64 desired_available_space_;
411
412  // Map from origin to count.
413  std::map<GURL, int> origins_in_use_;
414  // Map from origin to error count.
415  std::map<GURL, int> origins_in_error_;
416
417  scoped_refptr<SpecialStoragePolicy> special_storage_policy_;
418
419  base::RepeatingTimer<QuotaManager> histogram_timer_;
420
421  // Pointer to the function used to get the available disk space. This is
422  // overwritten by QuotaManagerTest in order to attain a deterministic reported
423  // value. The default value points to base::SysInfo::AmountOfFreeDiskSpace.
424  GetAvailableDiskSpaceFn get_disk_space_fn_;
425
426  base::WeakPtrFactory<QuotaManager> weak_factory_;
427
428  DISALLOW_COPY_AND_ASSIGN(QuotaManager);
429};
430
431struct QuotaManagerDeleter {
432  static void Destruct(const QuotaManager* manager) {
433    manager->DeleteOnCorrectThread();
434  }
435};
436
437// The proxy may be called and finally released on any thread.
438class WEBKIT_STORAGE_BROWSER_EXPORT QuotaManagerProxy
439    : public base::RefCountedThreadSafe<QuotaManagerProxy> {
440 public:
441  typedef QuotaManager::GetUsageAndQuotaCallback
442      GetUsageAndQuotaCallback;
443
444  virtual void RegisterClient(QuotaClient* client);
445  virtual void NotifyStorageAccessed(QuotaClient::ID client_id,
446                                     const GURL& origin,
447                                     StorageType type);
448  virtual void NotifyStorageModified(QuotaClient::ID client_id,
449                                     const GURL& origin,
450                                     StorageType type,
451                                     int64 delta);
452  virtual void NotifyOriginInUse(const GURL& origin);
453  virtual void NotifyOriginNoLongerInUse(const GURL& origin);
454
455  virtual void SetUsageCacheEnabled(QuotaClient::ID client_id,
456                                    const GURL& origin,
457                                    StorageType type,
458                                    bool enabled);
459  virtual void GetUsageAndQuota(
460      base::SequencedTaskRunner* original_task_runner,
461      const GURL& origin,
462      StorageType type,
463      const GetUsageAndQuotaCallback& callback);
464
465  // This method may only be called on the IO thread.
466  // It may return NULL if the manager has already been deleted.
467  QuotaManager* quota_manager() const;
468
469 protected:
470  friend class QuotaManager;
471  friend class base::RefCountedThreadSafe<QuotaManagerProxy>;
472
473  QuotaManagerProxy(QuotaManager* manager,
474                    base::SingleThreadTaskRunner* io_thread);
475  virtual ~QuotaManagerProxy();
476
477  QuotaManager* manager_;  // only accessed on the io thread
478  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
479
480  DISALLOW_COPY_AND_ASSIGN(QuotaManagerProxy);
481};
482
483}  // namespace quota
484
485#endif  // WEBKIT_BROWSER_QUOTA_QUOTA_MANAGER_H_
486