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