Home | History | Annotate | Download | only in appcache
      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_APPCACHE_APPCACHE_STORAGE_H_
      6 #define WEBKIT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
      7 
      8 #include <map>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "net/base/completion_callback.h"
     17 #include "webkit/browser/appcache/appcache_working_set.h"
     18 #include "webkit/browser/webkit_storage_browser_export.h"
     19 
     20 class GURL;
     21 
     22 namespace appcache {
     23 
     24 class AppCache;
     25 class AppCacheEntry;
     26 class AppCacheGroup;
     27 class AppCacheResponseReader;
     28 class AppCacheResponseWriter;
     29 class AppCacheService;
     30 struct AppCacheInfoCollection;
     31 struct HttpResponseInfoIOBuffer;
     32 
     33 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheStorage {
     34  public:
     35   typedef std::map<GURL, int64> UsageMap;
     36 
     37   class WEBKIT_STORAGE_BROWSER_EXPORT Delegate {
     38    public:
     39     // If retrieval fails, 'collection' will be NULL.
     40     virtual void OnAllInfo(AppCacheInfoCollection* collection) {}
     41 
     42     // If a load fails the 'cache' will be NULL.
     43     virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) {}
     44 
     45     // If a load fails the 'group' will be NULL.
     46     virtual void OnGroupLoaded(
     47         AppCacheGroup* group, const GURL& manifest_url) {}
     48 
     49     // If successfully stored 'success' will be true.
     50     virtual void OnGroupAndNewestCacheStored(
     51         AppCacheGroup* group, AppCache* newest_cache, bool success,
     52         bool would_exceed_quota) {}
     53 
     54     // If the operation fails, success will be false.
     55     virtual void OnGroupMadeObsolete(AppCacheGroup* group, bool success) {}
     56 
     57     // If a load fails the 'response_info' will be NULL.
     58     virtual void OnResponseInfoLoaded(
     59         AppCacheResponseInfo* response_info, int64 response_id) {}
     60 
     61     // If no response is found, entry.response_id() and
     62     // fallback_entry.response_id() will be kNoResponseId.
     63     // If the response is the entry for an intercept or fallback
     64     // namespace, the url of the namespece entry is returned.
     65     // If a response is found, the cache id and manifest url of the
     66     // containing cache and group are also returned.
     67     virtual void OnMainResponseFound(
     68         const GURL& url, const AppCacheEntry& entry,
     69         const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
     70         int64 cache_id, int64 group_id, const GURL& mainfest_url) {}
     71 
     72    protected:
     73     virtual ~Delegate() {}
     74   };
     75 
     76   explicit AppCacheStorage(AppCacheService* service);
     77   virtual ~AppCacheStorage();
     78 
     79   // Schedules a task to retrieve basic info about all groups and caches
     80   // stored in the system. Upon completion the delegate will be called
     81   // with the results.
     82   virtual void GetAllInfo(Delegate* delegate) = 0;
     83 
     84   // Schedules a cache to be loaded from storage. Upon load completion
     85   // the delegate will be called back. If the cache already resides in
     86   // memory, the delegate will be called back immediately without returning
     87   // to the message loop. If the load fails, the delegate will be called
     88   // back with a NULL cache pointer.
     89   virtual void LoadCache(int64 id, Delegate* delegate) = 0;
     90 
     91   // Schedules a group and its newest cache, if any, to be loaded from storage.
     92   // Upon load completion the delegate will be called back. If the group
     93   // and newest cache already reside in memory, the delegate will be called
     94   // back immediately without returning to the message loop. If the load fails,
     95   // the delegate will be called back with a NULL group pointer.
     96   virtual void LoadOrCreateGroup(
     97       const GURL& manifest_url, Delegate* delegate) = 0;
     98 
     99   // Schedules response info to be loaded from storage.
    100   // Upon load completion the delegate will be called back. If the data
    101   // already resides in memory, the delegate will be called back
    102   // immediately without returning to the message loop. If the load fails,
    103   // the delegate will be called back with a NULL pointer.
    104   virtual void LoadResponseInfo(
    105       const GURL& manifest_url, int64 group_id, int64 response_id,
    106       Delegate* delegate);
    107 
    108   // Schedules a group and its newest complete cache to be initially stored or
    109   // incrementally updated with new changes. Upon completion the delegate
    110   // will be called back. A group without a newest cache cannot be stored.
    111   // It's a programming error to call this method without a newest cache. A
    112   // side effect of storing a new newest cache is the removal of the group's
    113   // old caches and responses from persistent storage (although they may still
    114   // linger in the in-memory working set until no longer needed). The new
    115   // cache will be added as the group's newest complete cache only if storage
    116   // succeeds.
    117   virtual void StoreGroupAndNewestCache(
    118       AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) = 0;
    119 
    120   // Schedules a query to identify a response for a main request. Upon
    121   // completion the delegate will be called back.
    122   virtual void FindResponseForMainRequest(
    123       const GURL& url,
    124       const GURL& preferred_manifest_url,
    125       Delegate* delegate) = 0;
    126 
    127   // Performs an immediate lookup of the in-memory cache to
    128   // identify a response for a sub resource request.
    129   virtual void FindResponseForSubRequest(
    130       AppCache* cache, const GURL& url,
    131       AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
    132       bool* found_network_namespace) = 0;
    133 
    134   // Immediately updates in-memory storage, if the cache is in memory,
    135   // and schedules a task to update persistent storage. If the cache is
    136   // already scheduled to be loaded, upon loading completion the entry
    137   // will be marked. There is no delegate completion callback.
    138   virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) = 0;
    139 
    140   // Schedules a task to update persistent storage and doom the group and all
    141   // related caches and responses for deletion. Upon completion the in-memory
    142   // instance is marked as obsolete and the delegate callback is called.
    143   virtual void MakeGroupObsolete(
    144       AppCacheGroup* group, Delegate* delegate) = 0;
    145 
    146   // Cancels all pending callbacks for the delegate. The delegate callbacks
    147   // will not be invoked after, however any scheduled operations will still
    148   // take place. The callbacks for subsequently scheduled operations are
    149   // unaffected.
    150   void CancelDelegateCallbacks(Delegate* delegate) {
    151     DelegateReference* delegate_reference = GetDelegateReference(delegate);
    152     if (delegate_reference)
    153       delegate_reference->CancelReference();
    154   }
    155 
    156   // Creates a reader to read a response from storage.
    157   virtual AppCacheResponseReader* CreateResponseReader(
    158       const GURL& manifest_url, int64 group_id, int64 response_id) = 0;
    159 
    160   // Creates a writer to write a new response to storage. This call
    161   // establishes a new response id.
    162   virtual AppCacheResponseWriter* CreateResponseWriter(
    163       const GURL& manifest_url, int64 group_id) = 0;
    164 
    165   // Schedules the lazy deletion of responses and saves the ids
    166   // persistently such that the responses will be deleted upon restart
    167   // if they aren't deleted prior to shutdown.
    168   virtual void DoomResponses(
    169       const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
    170 
    171   // Schedules the lazy deletion of responses without persistently saving
    172   // the response ids.
    173   virtual void DeleteResponses(
    174       const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
    175 
    176   virtual void PurgeMemory() = 0;
    177 
    178   // Generates unique storage ids for different object types.
    179   int64 NewCacheId() {
    180     return ++last_cache_id_;
    181   }
    182   int64 NewGroupId() {
    183     return ++last_group_id_;
    184   }
    185 
    186   // The working set of object instances currently in memory.
    187   AppCacheWorkingSet* working_set() { return &working_set_; }
    188 
    189   // A map of origins to usage.
    190   const UsageMap* usage_map() { return &usage_map_; }
    191 
    192   // Simple ptr back to the service object that owns us.
    193   AppCacheService* service() { return service_; }
    194 
    195  protected:
    196   friend class AppCacheQuotaClientTest;
    197   friend class AppCacheResponseTest;
    198   friend class AppCacheStorageTest;
    199 
    200   // Helper to call a collection of delegates.
    201   #define FOR_EACH_DELEGATE(delegates, func_and_args)                \
    202     do {                                                             \
    203       for (DelegateReferenceVector::iterator it = delegates.begin(); \
    204            it != delegates.end(); ++it) {                            \
    205         if (it->get()->delegate)                                     \
    206           it->get()->delegate->func_and_args;                        \
    207       }                                                              \
    208     } while (0)
    209 
    210   // Helper used to manage multiple references to a 'delegate' and to
    211   // allow all pending callbacks to that delegate to be easily cancelled.
    212   struct DelegateReference : public base::RefCounted<DelegateReference> {
    213     Delegate* delegate;
    214     AppCacheStorage* storage;
    215 
    216     DelegateReference(Delegate* delegate, AppCacheStorage* storage);
    217 
    218     void CancelReference() {
    219       storage->delegate_references_.erase(delegate);
    220       storage = NULL;
    221       delegate = NULL;
    222     }
    223 
    224    private:
    225     friend class base::RefCounted<DelegateReference>;
    226 
    227     virtual ~DelegateReference();
    228   };
    229   typedef std::map<Delegate*, DelegateReference*> DelegateReferenceMap;
    230   typedef std::vector<scoped_refptr<DelegateReference> >
    231       DelegateReferenceVector;
    232 
    233   // Helper used to manage an async LoadResponseInfo calls on behalf of
    234   // multiple callers.
    235   class ResponseInfoLoadTask {
    236    public:
    237     ResponseInfoLoadTask(const GURL& manifest_url, int64 group_id,
    238                          int64 response_id, AppCacheStorage* storage);
    239     ~ResponseInfoLoadTask();
    240 
    241     int64 response_id() const { return response_id_; }
    242     const GURL& manifest_url() const { return manifest_url_; }
    243     int64 group_id() const { return group_id_; }
    244 
    245     void AddDelegate(DelegateReference* delegate_reference) {
    246       delegates_.push_back(delegate_reference);
    247     }
    248 
    249     void StartIfNeeded();
    250 
    251    private:
    252     void OnReadComplete(int result);
    253 
    254     AppCacheStorage* storage_;
    255     GURL manifest_url_;
    256     int64 group_id_;
    257     int64 response_id_;
    258     scoped_ptr<AppCacheResponseReader> reader_;
    259     DelegateReferenceVector delegates_;
    260     scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
    261   };
    262 
    263   typedef std::map<int64, ResponseInfoLoadTask*> PendingResponseInfoLoads;
    264 
    265   DelegateReference* GetDelegateReference(Delegate* delegate) {
    266     DelegateReferenceMap::iterator iter =
    267         delegate_references_.find(delegate);
    268     if (iter != delegate_references_.end())
    269       return iter->second;
    270     return NULL;
    271   }
    272 
    273   DelegateReference* GetOrCreateDelegateReference(Delegate* delegate) {
    274     DelegateReference* reference = GetDelegateReference(delegate);
    275     if (reference)
    276       return reference;
    277     return new DelegateReference(delegate, this);
    278   }
    279 
    280   ResponseInfoLoadTask* GetOrCreateResponseInfoLoadTask(
    281       const GURL& manifest_url, int64 group_id, int64 response_id) {
    282     PendingResponseInfoLoads::iterator iter =
    283         pending_info_loads_.find(response_id);
    284     if (iter != pending_info_loads_.end())
    285       return iter->second;
    286     return new ResponseInfoLoadTask(manifest_url, group_id, response_id, this);
    287   }
    288 
    289   // Should only be called when creating a new response writer.
    290   int64 NewResponseId() {
    291     return ++last_response_id_;
    292   }
    293 
    294   // Helpers to query and notify the QuotaManager.
    295   void UpdateUsageMapAndNotify(const GURL& origin, int64 new_usage);
    296   void ClearUsageMapAndNotify();
    297   void NotifyStorageAccessed(const GURL& origin);
    298 
    299   // The last storage id used for different object types.
    300   int64 last_cache_id_;
    301   int64 last_group_id_;
    302   int64 last_response_id_;
    303 
    304   UsageMap usage_map_;  // maps origin to usage
    305   AppCacheWorkingSet working_set_;
    306   AppCacheService* service_;
    307   DelegateReferenceMap delegate_references_;
    308   PendingResponseInfoLoads pending_info_loads_;
    309 
    310   // The set of last ids must be retrieved from storage prior to being used.
    311   static const int64 kUnitializedId;
    312 
    313   FRIEND_TEST_ALL_PREFIXES(AppCacheStorageTest, DelegateReferences);
    314   FRIEND_TEST_ALL_PREFIXES(AppCacheStorageTest, UsageMap);
    315 
    316   DISALLOW_COPY_AND_ASSIGN(AppCacheStorage);
    317 };
    318 
    319 }  // namespace appcache
    320 
    321 #endif  // WEBKIT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
    322