summaryrefslogtreecommitdiffstats
path: root/webkit/appcache/mock_appcache_storage.cc
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-24 21:42:25 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-24 21:42:25 +0000
commit550890ec7f1cf968abc4544b170e97a67f919902 (patch)
tree632dec32bed5266837a2668a9225d303303e3160 /webkit/appcache/mock_appcache_storage.cc
parented249ab7916d438b0bdb650a796aaf709f6ae1ae (diff)
downloadchromium_src-550890ec7f1cf968abc4544b170e97a67f919902.zip
chromium_src-550890ec7f1cf968abc4544b170e97a67f919902.tar.gz
chromium_src-550890ec7f1cf968abc4544b170e97a67f919902.tar.bz2
MockAppCacheStorage implemention
This is a quick and easy 'mock' implementation of the storage interface that doesn't put anything to disk. We simply add an extra reference to objects when they're put in storage, and remove the extra reference when they are removed from storage. Responses are never really removed from the in-memory disk cache. Delegate callbacks are made asyncly to appropiately mimic what will happen with a real disk-backed storage impl that involves IO on a background thread. This is for use in unit tests and to initially bring up the appcache related layout tests. TEST=mock_appcache_storage_unittest.cc BUG=none Review URL: http://codereview.chromium.org/300043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30017 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache/mock_appcache_storage.cc')
-rw-r--r--webkit/appcache/mock_appcache_storage.cc267
1 files changed, 212 insertions, 55 deletions
diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc
index 3144179..3c626ec 100644
--- a/webkit/appcache/mock_appcache_storage.cc
+++ b/webkit/appcache/mock_appcache_storage.cc
@@ -5,86 +5,89 @@
#include "webkit/appcache/mock_appcache_storage.h"
#include "base/logging.h"
+#include "base/message_loop.h"
#include "base/ref_counted.h"
+#include "base/stl_util-inl.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_entry.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_response.h"
+// This is a quick and easy 'mock' implementation of the storage interface
+// that doesn't put anything to disk.
+//
+// We simply add an extra reference to objects when they're put in storage,
+// and remove the extra reference when they are removed from storage.
+// Responses are never really removed from the in-memory disk cache.
+// Delegate callbacks are made asyncly to appropiately mimic what will
+// happen with a real disk-backed storage impl that involves IO on a
+// background thread.
+
namespace appcache {
MockAppCacheStorage::MockAppCacheStorage(AppCacheService* service)
- : AppCacheStorage(service) {
+ : AppCacheStorage(service),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
last_cache_id_ = 0;
last_entry_id_ = 0;
last_group_id_ = 0;
last_response_id_ = 0;
}
+MockAppCacheStorage::~MockAppCacheStorage() {
+ STLDeleteElements(&pending_tasks_);
+}
+
void MockAppCacheStorage::LoadCache(int64 id, Delegate* delegate) {
+ DCHECK(delegate);
AppCache* cache = working_set_.GetCache(id);
- if (cache->HasOneRef()) {
- // TODO(michaeln): make the load look async
+ if (ShouldCacheLoadAppearAsync(cache)) {
+ ScheduleTask(method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::ProcessLoadCache,
+ id, GetOrCreateDelegateReference(delegate)));
+ return;
}
- delegate->OnCacheLoaded(cache, id);
+ ProcessLoadCache(id, GetOrCreateDelegateReference(delegate));
}
void MockAppCacheStorage::LoadOrCreateGroup(
const GURL& manifest_url, Delegate* delegate) {
- scoped_refptr<AppCacheGroup> group = working_set_.GetGroup(manifest_url);
- if (!group.get()) {
- group = new AppCacheGroup(service_, manifest_url);
- DCHECK(working_set_.GetGroup(manifest_url));
+ DCHECK(delegate);
+ AppCacheGroup* group = working_set_.GetGroup(manifest_url);
+ if (ShouldGroupLoadAppearAsync(group)) {
+ ScheduleTask(method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::ProcessLoadOrCreateGroup,
+ manifest_url, GetOrCreateDelegateReference(delegate)));
+ return;
}
- // TODO(michaeln): make the load look async if all of the groups
- // caches only have one ref
- delegate->OnGroupLoaded(group.get(), manifest_url);
+ ProcessLoadOrCreateGroup(
+ manifest_url, GetOrCreateDelegateReference(delegate));
}
void MockAppCacheStorage::StoreGroupAndNewestCache(
AppCacheGroup* group, Delegate* delegate) {
+ DCHECK(group && delegate);
DCHECK(group->newest_complete_cache());
- // TODO(michaeln): write me
- // 'store' the group + newest
- // 'unstore' the old caches
- // figure out which responses can be doomed and doom them
- // OldRepsonses - NewestResponse == ToBeDoomed
-
- // TODO(michaeln): Make this appear async
- //AddStoredGroup(group);
- //AddStoredCache(group->newest_complete_cache());
- //
- //foreach(group->old_caches())
- // RemoveStoredCache(old_cache);
- //std::set<int64> doomed_responses_ = responses from old caches
- //std::set<int64> needed_responses_ = responses from newest cache
- //foreach(needed_responses_)
- // doomed_responses_.remove(needed_response_);
- //DoomResponses(group->manifest_url(), doomed_responses_);
-
- delegate->OnGroupAndNewestCacheStored(group, false);
+ // Always make this operation look async.
+ ScheduleTask(method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::ProcessStoreGroupAndNewestCache,
+ group, group->newest_complete_cache(),
+ GetOrCreateDelegateReference(delegate)));
}
void MockAppCacheStorage::FindResponseForMainRequest(
const GURL& url, Delegate* delegate) {
- // TODO(michaeln): write me
- //
- //foreach(stored_group) {
- // if (group->manifest_url()->origin() != url.GetOrigin())
- // continue;
- //
- // look for an entry
- // look for a fallback namespace
- // look for a online namespace
- //}
- delegate->OnMainResponseFound(
- url, kNoResponseId, false, kNoCacheId, GURL::EmptyGURL());
+ DCHECK(delegate);
+
+ // Always make this operation look async.
+ ScheduleTask(method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::ProcessFindResponseForMainRequest,
+ url, GetOrCreateDelegateReference(delegate)));
}
void MockAppCacheStorage::MarkEntryAsForeign(
const GURL& entry_url, int64 cache_id) {
- // Update the working set.
AppCache* cache = working_set_.GetCache(cache_id);
if (cache) {
AppCacheEntry* entry = cache->GetEntry(entry_url);
@@ -96,14 +99,14 @@ void MockAppCacheStorage::MarkEntryAsForeign(
// being loaded be sure to update the memory cache upon load completion.
}
-void MockAppCacheStorage::MarkGroupAsObsolete(
+void MockAppCacheStorage::MakeGroupObsolete(
AppCacheGroup* group, Delegate* delegate) {
- // TODO(michaeln): write me
- // remove from working_set
- // remove from storage
- // doom things
- // group->set_obsolete(true);
- // TODO(michaeln): Make this appear async
+ DCHECK(group && delegate);
+
+ // Always make this method look async.
+ ScheduleTask(method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::ProcessMakeGroupObsolete,
+ group, GetOrCreateDelegateReference(delegate)));
}
AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader(
@@ -118,31 +121,185 @@ AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter(
void MockAppCacheStorage::DoomResponses(
const GURL& manifest_url, const std::vector<int64>& response_ids) {
- // We don't bother with deleting responses from mock storage.
+ // We don't bother with actually removing responses from the disk-cache,
+ // just keep track of which ids have been doomed.
+ std::vector<int64>::const_iterator it = response_ids.begin();
+ while (it != response_ids.end()) {
+ doomed_response_ids_.insert(*it);
+ ++it;
+ }
+}
+
+void MockAppCacheStorage::ProcessLoadCache(
+ int64 id, scoped_refptr<DelegateReference> delegate_ref) {
+ AppCache* cache = working_set_.GetCache(id);
+ if (delegate_ref->delegate)
+ delegate_ref->delegate->OnCacheLoaded(cache, id);
+}
+
+void MockAppCacheStorage::ProcessLoadOrCreateGroup(
+ const GURL& manifest_url, scoped_refptr<DelegateReference> delegate_ref) {
+ scoped_refptr<AppCacheGroup> group = working_set_.GetGroup(manifest_url);
+
+ // Newly created groups are not put in the stored_groups collection
+ // until StoreGroupAndNewestCache is called.
+ if (!group)
+ group = new AppCacheGroup(service_, manifest_url);
+
+ if (delegate_ref->delegate)
+ delegate_ref->delegate->OnGroupLoaded(group, manifest_url);
+}
+
+void MockAppCacheStorage::ProcessStoreGroupAndNewestCache(
+ scoped_refptr<AppCacheGroup> group,
+ scoped_refptr<AppCache> newest_cache,
+ scoped_refptr<DelegateReference> delegate_ref) {
+ DCHECK(group->newest_complete_cache() == newest_cache.get());
+
+ AddStoredGroup(group);
+ AddStoredCache(group->newest_complete_cache());
+
+ // Copy the collection prior to removal, on final release
+ // of a cache the group's collection will change.
+ AppCacheGroup::Caches copy = group->old_caches();
+ RemoveStoredCaches(copy);
+
+ if (delegate_ref->delegate)
+ delegate_ref->delegate->OnGroupAndNewestCacheStored(group, true);
+
+ // We don't bother with removing responses from 'mock' storage
+ // TODO(michaeln): for 'real' storage...
+ // std::set<int64> doomed_responses_ = responses from old caches
+ // std::set<int64> needed_responses_ = responses from newest cache
+ // foreach(needed_responses_)
+ // doomed_responses_.remove(needed_response_);
+ // DoomResponses(group->manifest_url(), doomed_responses_);
+}
+
+void MockAppCacheStorage::ProcessFindResponseForMainRequest(
+ const GURL& url, scoped_refptr<DelegateReference> delegate_ref) {
+ // TODO(michaeln): write me when doing AppCacheRequestHandler
+ // foreach(stored_group) {
+ // if (group->manifest_url()->origin() != url.GetOrigin())
+ // continue;
+ // look for an entry
+ // look for a fallback namespace
+ // look for a online namespace
+ // }
+ if (delegate_ref->delegate) {
+ delegate_ref->delegate->OnMainResponseFound(
+ url, AppCacheEntry(), kNoCacheId, GURL());
+ }
+}
+
+void MockAppCacheStorage::ProcessMakeGroupObsolete(
+ scoped_refptr<AppCacheGroup> group,
+ scoped_refptr<DelegateReference> delegate_ref) {
+ RemoveStoredGroup(group);
+ if (group->newest_complete_cache())
+ RemoveStoredCache(group->newest_complete_cache());
+
+ // Copy the collection prior to removal, on final release
+ // of a cache the group's collection will change.
+ AppCacheGroup::Caches copy = group->old_caches();
+ RemoveStoredCaches(copy);
+
+ group->set_obsolete(true);
+
+ if (delegate_ref->delegate)
+ delegate_ref->delegate->OnGroupMadeObsolete(group, true);
+}
+
+void MockAppCacheStorage::ScheduleTask(Task* task) {
+ pending_tasks_.push_back(task);
+ MessageLoop::current()->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &MockAppCacheStorage::RunOnePendingTask));
+}
+
+void MockAppCacheStorage::RunOnePendingTask() {
+ DCHECK(!pending_tasks_.empty());
+ Task* task = pending_tasks_.front();
+ pending_tasks_.pop_front();
+ task->Run();
+ delete task;
}
void MockAppCacheStorage::AddStoredCache(AppCache* cache) {
-// cache->set_is_stored(true);
int64 cache_id = cache->cache_id();
if (stored_caches_.find(cache_id) == stored_caches_.end())
stored_caches_.insert(StoredCacheMap::value_type(cache_id, cache));
}
void MockAppCacheStorage::RemoveStoredCache(AppCache* cache) {
-// cache->set_is_stored(false);
+ // Do not remove from the working set, active caches are still usable
+ // and may be looked up by id until they fall out of use.
stored_caches_.erase(cache->cache_id());
}
+void MockAppCacheStorage::RemoveStoredCaches(
+ const AppCacheGroup::Caches& caches) {
+ AppCacheGroup::Caches::const_iterator it = caches.begin();
+ while (it != caches.end()) {
+ RemoveStoredCache(*it);
+ ++it;
+ }
+}
+
void MockAppCacheStorage::AddStoredGroup(AppCacheGroup* group) {
-// group->set_is_stored(true);
const GURL& url = group->manifest_url();
if (stored_groups_.find(url) == stored_groups_.end())
stored_groups_.insert(StoredGroupMap::value_type(url, group));
}
void MockAppCacheStorage::RemoveStoredGroup(AppCacheGroup* group) {
-// group->set_is_stored(false);
+ // Also remove from the working set, caches for an 'obsolete' group
+ // may linger in use, but the group itself cannot be looked up by
+ // 'manifest_url' in the working set any longer.
+ working_set()->RemoveGroup(group);
stored_groups_.erase(group->manifest_url());
}
+bool MockAppCacheStorage::ShouldGroupLoadAppearAsync(
+ const AppCacheGroup* group) {
+ // We'll have to query the database to see if a group for the
+ // manifest_url exists on disk. So return true for async.
+ if (!group)
+ return true;
+
+ // Groups without a newest cache can't have been put to disk yet, so
+ // we can synchronously return a reference we have in the working set.
+ if (!group->newest_complete_cache())
+ return false;
+
+ // The LoadGroup interface implies also loading the newest cache, so
+ // if loading the newest cache should appear async, so too must the
+ // loading of this group.
+ if (ShouldCacheLoadAppearAsync(group->newest_complete_cache()))
+ return true;
+
+
+ // If any of the old caches are "in use", then the group must also
+ // be memory resident and not require async loading.
+ const AppCacheGroup::Caches& old_caches = group->old_caches();
+ AppCacheGroup::Caches::const_iterator it = old_caches.begin();
+ while (it != old_caches.end()) {
+ // "in use" caches don't require async loading
+ if (!ShouldCacheLoadAppearAsync(*it))
+ return false;
+ ++it;
+ }
+
+ return true;
+}
+
+bool MockAppCacheStorage::ShouldCacheLoadAppearAsync(const AppCache* cache) {
+ if (!cache)
+ return true;
+
+ // If the 'stored' ref is the only ref, real storage will have to load from
+ // the database.
+ return IsCacheStored(cache) && cache->HasOneRef();
+}
+
} // namespace appcache