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