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