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.
5 #ifndef WEBKIT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
6 #define WEBKIT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
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"
23 FORWARD_DECLARE_TEST(AppCacheStorageTest
, DelegateReferences
);
24 FORWARD_DECLARE_TEST(AppCacheStorageTest
, UsageMap
);
25 class AppCacheQuotaClientTest
;
26 class AppCacheResponseTest
;
27 class AppCacheStorageTest
;
35 class AppCacheResponseReader
;
36 class AppCacheResponseWriter
;
37 class AppCacheServiceImpl
;
38 struct AppCacheInfoCollection
;
39 struct HttpResponseInfoIOBuffer
;
41 class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheStorage
{
43 typedef std::map
<GURL
, int64
> UsageMap
;
45 class WEBKIT_STORAGE_BROWSER_EXPORT Delegate
{
47 // If retrieval fails, 'collection' will be NULL.
48 virtual void OnAllInfo(AppCacheInfoCollection
* collection
) {}
50 // If a load fails the 'cache' will be NULL.
51 virtual void OnCacheLoaded(AppCache
* cache
, int64 cache_id
) {}
53 // If a load fails the 'group' will be NULL.
54 virtual void OnGroupLoaded(
55 AppCacheGroup
* group
, const GURL
& manifest_url
) {}
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
) {}
62 // If the operation fails, success will be false.
63 virtual void OnGroupMadeObsolete(AppCacheGroup
* group
,
67 // If a load fails the 'response_info' will be NULL.
68 virtual void OnResponseInfoLoaded(
69 AppCacheResponseInfo
* response_info
, int64 response_id
) {}
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
) {}
83 virtual ~Delegate() {}
86 explicit AppCacheStorage(AppCacheServiceImpl
* service
);
87 virtual ~AppCacheStorage();
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
92 virtual void GetAllInfo(Delegate
* delegate
) = 0;
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;
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;
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
,
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
127 virtual void StoreGroupAndNewestCache(
128 AppCacheGroup
* group
, AppCache
* newest_cache
, Delegate
* delegate
) = 0;
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(
134 const GURL
& preferred_manifest_url
,
135 Delegate
* delegate
) = 0;
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;
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;
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
,
155 int response_code
) = 0;
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
161 void CancelDelegateCallbacks(Delegate
* delegate
) {
162 DelegateReference
* delegate_reference
= GetDelegateReference(delegate
);
163 if (delegate_reference
)
164 delegate_reference
->CancelReference();
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;
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;
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;
182 // Schedules the lazy deletion of responses without persistently saving
184 virtual void DeleteResponses(
185 const GURL
& manifest_url
, const std::vector
<int64
>& response_ids
) = 0;
187 // Generates unique storage ids for different object types.
189 return ++last_cache_id_
;
192 return ++last_group_id_
;
195 // The working set of object instances currently in memory.
196 AppCacheWorkingSet
* working_set() { return &working_set_
; }
198 // A map of origins to usage.
199 const UsageMap
* usage_map() { return &usage_map_
; }
201 // Simple ptr back to the service object that owns us.
202 AppCacheServiceImpl
* service() { return service_
; }
205 friend class content::AppCacheQuotaClientTest
;
206 friend class content::AppCacheResponseTest
;
207 friend class content::AppCacheStorageTest
;
209 // Helper to call a collection of delegates.
210 #define FOR_EACH_DELEGATE(delegates, func_and_args) \
212 for (DelegateReferenceVector::iterator it = delegates.begin(); \
213 it != delegates.end(); ++it) { \
214 if (it->get()->delegate) \
215 it->get()->delegate->func_and_args; \
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
> {
223 AppCacheStorage
* storage
;
225 DelegateReference(Delegate
* delegate
, AppCacheStorage
* storage
);
227 void CancelReference() {
228 storage
->delegate_references_
.erase(delegate
);
234 friend class base::RefCounted
<DelegateReference
>;
236 virtual ~DelegateReference();
238 typedef std::map
<Delegate
*, DelegateReference
*> DelegateReferenceMap
;
239 typedef std::vector
<scoped_refptr
<DelegateReference
> >
240 DelegateReferenceVector
;
242 // Helper used to manage an async LoadResponseInfo calls on behalf of
244 class ResponseInfoLoadTask
{
246 ResponseInfoLoadTask(const GURL
& manifest_url
, int64 group_id
,
247 int64 response_id
, AppCacheStorage
* storage
);
248 ~ResponseInfoLoadTask();
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_
; }
254 void AddDelegate(DelegateReference
* delegate_reference
) {
255 delegates_
.push_back(delegate_reference
);
258 void StartIfNeeded();
261 void OnReadComplete(int result
);
263 AppCacheStorage
* storage_
;
267 scoped_ptr
<AppCacheResponseReader
> reader_
;
268 DelegateReferenceVector delegates_
;
269 scoped_refptr
<HttpResponseInfoIOBuffer
> info_buffer_
;
272 typedef std::map
<int64
, ResponseInfoLoadTask
*> PendingResponseInfoLoads
;
274 DelegateReference
* GetDelegateReference(Delegate
* delegate
) {
275 DelegateReferenceMap::iterator iter
=
276 delegate_references_
.find(delegate
);
277 if (iter
!= delegate_references_
.end())
282 DelegateReference
* GetOrCreateDelegateReference(Delegate
* delegate
) {
283 DelegateReference
* reference
= GetDelegateReference(delegate
);
286 return new DelegateReference(delegate
, this);
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())
295 return new ResponseInfoLoadTask(manifest_url
, group_id
, response_id
, this);
298 // Should only be called when creating a new response writer.
299 int64
NewResponseId() {
300 return ++last_response_id_
;
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
);
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_
;
313 UsageMap usage_map_
; // maps origin to usage
314 AppCacheWorkingSet working_set_
;
315 AppCacheServiceImpl
* service_
;
316 DelegateReferenceMap delegate_references_
;
317 PendingResponseInfoLoads pending_info_loads_
;
319 // The set of last ids must be retrieved from storage prior to being used.
320 static const int64 kUnitializedId
;
322 FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest
, DelegateReferences
);
323 FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest
, UsageMap
);
325 DISALLOW_COPY_AND_ASSIGN(AppCacheStorage
);
328 } // namespace appcache
330 #endif // WEBKIT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_