Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/appcache/mock_appcache_storage.h" | 5 #include "webkit/appcache/mock_appcache_storage.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/message_loop.h" | |
| 8 #include "base/ref_counted.h" | 9 #include "base/ref_counted.h" |
| 10 #include "base/stl_util-inl.h" | |
| 9 #include "webkit/appcache/appcache.h" | 11 #include "webkit/appcache/appcache.h" |
| 10 #include "webkit/appcache/appcache_entry.h" | 12 #include "webkit/appcache/appcache_entry.h" |
| 11 #include "webkit/appcache/appcache_group.h" | 13 #include "webkit/appcache/appcache_group.h" |
| 12 #include "webkit/appcache/appcache_response.h" | 14 #include "webkit/appcache/appcache_response.h" |
| 13 | 15 |
| 16 // This is a quick and easy 'mock' implementation of the storage interface | |
| 17 // that doesn't put anything to disk. | |
| 18 // | |
| 19 // We simply add an extra reference to objects when they're put in storage, | |
| 20 // and remove the extra reference when they are removed from storage. | |
| 21 // Responses are never really removed from the in-memory disk cache. | |
| 22 // Delegate callbacks are made asyncly to appropiately mimic what will | |
| 23 // happen with a real disk-backed storage impl that involves IO on a | |
| 24 // background thread. | |
| 25 | |
| 14 namespace appcache { | 26 namespace appcache { |
| 15 | 27 |
| 16 MockAppCacheStorage::MockAppCacheStorage(AppCacheService* service) | 28 MockAppCacheStorage::MockAppCacheStorage(AppCacheService* service) |
| 17 : AppCacheStorage(service) { | 29 : AppCacheStorage(service), |
| 30 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | |
| 18 last_cache_id_ = 0; | 31 last_cache_id_ = 0; |
| 19 last_entry_id_ = 0; | 32 last_entry_id_ = 0; |
| 20 last_group_id_ = 0; | 33 last_group_id_ = 0; |
| 21 last_response_id_ = 0; | 34 last_response_id_ = 0; |
| 22 } | 35 } |
| 23 | 36 |
| 37 MockAppCacheStorage::~MockAppCacheStorage() { | |
| 38 STLDeleteElements(&pending_tasks_); | |
| 39 } | |
| 40 | |
| 24 void MockAppCacheStorage::LoadCache(int64 id, Delegate* delegate) { | 41 void MockAppCacheStorage::LoadCache(int64 id, Delegate* delegate) { |
| 42 DCHECK(delegate); | |
| 25 AppCache* cache = working_set_.GetCache(id); | 43 AppCache* cache = working_set_.GetCache(id); |
| 26 if (cache->HasOneRef()) { | 44 if (ShouldCacheLoadAppearAsync(cache)) { |
| 27 // TODO(michaeln): make the load look async | 45 ScheduleTask(method_factory_.NewRunnableMethod( |
| 46 &MockAppCacheStorage::ProcessLoadCache, | |
| 47 id, GetOrCreateDelegateReference(delegate))); | |
| 48 return; | |
| 28 } | 49 } |
| 29 delegate->OnCacheLoaded(cache, id); | 50 ProcessLoadCache(id, GetOrCreateDelegateReference(delegate)); |
| 30 } | 51 } |
| 31 | 52 |
| 32 void MockAppCacheStorage::LoadOrCreateGroup( | 53 void MockAppCacheStorage::LoadOrCreateGroup( |
| 33 const GURL& manifest_url, Delegate* delegate) { | 54 const GURL& manifest_url, Delegate* delegate) { |
| 34 scoped_refptr<AppCacheGroup> group = working_set_.GetGroup(manifest_url); | 55 DCHECK(delegate); |
| 35 if (!group.get()) { | 56 AppCacheGroup* group = working_set_.GetGroup(manifest_url); |
| 36 group = new AppCacheGroup(service_, manifest_url); | 57 if (ShouldGroupLoadAppearAsync(group)) { |
| 37 DCHECK(working_set_.GetGroup(manifest_url)); | 58 ScheduleTask(method_factory_.NewRunnableMethod( |
| 59 &MockAppCacheStorage::ProcessLoadOrCreateGroup, | |
| 60 manifest_url, GetOrCreateDelegateReference(delegate))); | |
| 61 return; | |
| 38 } | 62 } |
| 39 // TODO(michaeln): make the load look async if all of the groups | 63 ProcessLoadOrCreateGroup( |
| 40 // caches only have one ref | 64 manifest_url, GetOrCreateDelegateReference(delegate)); |
| 41 delegate->OnGroupLoaded(group.get(), manifest_url); | |
| 42 } | 65 } |
| 43 | 66 |
| 44 void MockAppCacheStorage::StoreGroupAndNewestCache( | 67 void MockAppCacheStorage::StoreGroupAndNewestCache( |
| 45 AppCacheGroup* group, Delegate* delegate) { | 68 AppCacheGroup* group, Delegate* delegate) { |
| 69 DCHECK(group && delegate); | |
| 46 DCHECK(group->newest_complete_cache()); | 70 DCHECK(group->newest_complete_cache()); |
| 47 | 71 |
| 48 // TODO(michaeln): write me | 72 // Always make this operation look async. |
| 49 // 'store' the group + newest | 73 ScheduleTask(method_factory_.NewRunnableMethod( |
| 50 // 'unstore' the old caches | 74 &MockAppCacheStorage::ProcessStoreGroupAndNewestCache, |
| 51 // figure out which responses can be doomed and doom them | 75 group, group->newest_complete_cache(), |
| 52 // OldRepsonses - NewestResponse == ToBeDoomed | 76 GetOrCreateDelegateReference(delegate))); |
| 53 | |
| 54 // TODO(michaeln): Make this appear async | |
| 55 //AddStoredGroup(group); | |
| 56 //AddStoredCache(group->newest_complete_cache()); | |
| 57 // | |
| 58 //foreach(group->old_caches()) | |
| 59 // RemoveStoredCache(old_cache); | |
| 60 //std::set<int64> doomed_responses_ = responses from old caches | |
| 61 //std::set<int64> needed_responses_ = responses from newest cache | |
| 62 //foreach(needed_responses_) | |
| 63 // doomed_responses_.remove(needed_response_); | |
| 64 //DoomResponses(group->manifest_url(), doomed_responses_); | |
| 65 | |
| 66 delegate->OnGroupAndNewestCacheStored(group, false); | |
| 67 } | 77 } |
| 68 | 78 |
| 69 void MockAppCacheStorage::FindResponseForMainRequest( | 79 void MockAppCacheStorage::FindResponseForMainRequest( |
| 70 const GURL& url, Delegate* delegate) { | 80 const GURL& url, Delegate* delegate) { |
| 71 // TODO(michaeln): write me | 81 DCHECK(delegate); |
| 72 // | 82 |
| 73 //foreach(stored_group) { | 83 // Always make this operation look async. |
| 74 // if (group->manifest_url()->origin() != url.GetOrigin()) | 84 ScheduleTask(method_factory_.NewRunnableMethod( |
| 75 // continue; | 85 &MockAppCacheStorage::ProcessFindResponseForMainRequest, |
| 76 // | 86 url, GetOrCreateDelegateReference(delegate))); |
| 77 // look for an entry | |
| 78 // look for a fallback namespace | |
| 79 // look for a online namespace | |
| 80 //} | |
| 81 delegate->OnMainResponseFound( | |
| 82 url, kNoResponseId, false, kNoCacheId, GURL::EmptyGURL()); | |
| 83 } | 87 } |
| 84 | 88 |
| 85 void MockAppCacheStorage::MarkEntryAsForeign( | 89 void MockAppCacheStorage::MarkEntryAsForeign( |
| 86 const GURL& entry_url, int64 cache_id) { | 90 const GURL& entry_url, int64 cache_id) { |
| 87 // Update the working set. | |
| 88 AppCache* cache = working_set_.GetCache(cache_id); | 91 AppCache* cache = working_set_.GetCache(cache_id); |
| 89 if (cache) { | 92 if (cache) { |
| 90 AppCacheEntry* entry = cache->GetEntry(entry_url); | 93 AppCacheEntry* entry = cache->GetEntry(entry_url); |
| 91 DCHECK(entry); | 94 DCHECK(entry); |
| 92 if (entry) | 95 if (entry) |
| 93 entry->add_types(AppCacheEntry::FOREIGN); | 96 entry->add_types(AppCacheEntry::FOREIGN); |
| 94 } | 97 } |
| 95 // TODO(michaeln): in real storage update in storage, and if this cache is | 98 // TODO(michaeln): in real storage update in storage, and if this cache is |
| 96 // being loaded be sure to update the memory cache upon load completion. | 99 // being loaded be sure to update the memory cache upon load completion. |
| 97 } | 100 } |
| 98 | 101 |
| 99 void MockAppCacheStorage::MarkGroupAsObsolete( | 102 void MockAppCacheStorage::MakeGroupObsolete( |
| 100 AppCacheGroup* group, Delegate* delegate) { | 103 AppCacheGroup* group, Delegate* delegate) { |
| 101 // TODO(michaeln): write me | 104 DCHECK(group && delegate); |
| 102 // remove from working_set | 105 |
| 103 // remove from storage | 106 // Always make this method look async. |
| 104 // doom things | 107 ScheduleTask(method_factory_.NewRunnableMethod( |
| 105 // group->set_obsolete(true); | 108 &MockAppCacheStorage::ProcessMakeGroupObsolete, |
| 106 // TODO(michaeln): Make this appear async | 109 group, GetOrCreateDelegateReference(delegate))); |
| 107 } | 110 } |
| 108 | 111 |
| 109 AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader( | 112 AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader( |
| 110 const GURL& origin, int64 response_id) { | 113 const GURL& origin, int64 response_id) { |
| 111 return new AppCacheResponseReader(response_id, disk_cache()); | 114 return new AppCacheResponseReader(response_id, disk_cache()); |
| 112 } | 115 } |
| 113 | 116 |
| 114 AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter( | 117 AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter( |
| 115 const GURL& manifest_url) { | 118 const GURL& manifest_url) { |
| 116 return new AppCacheResponseWriter(NewResponseId(), disk_cache()); | 119 return new AppCacheResponseWriter(NewResponseId(), disk_cache()); |
| 117 } | 120 } |
| 118 | 121 |
| 119 void MockAppCacheStorage::DoomResponses( | 122 void MockAppCacheStorage::DoomResponses( |
| 120 const GURL& manifest_url, const std::vector<int64>& response_ids) { | 123 const GURL& manifest_url, const std::vector<int64>& response_ids) { |
| 121 // We don't bother with deleting responses from mock storage. | 124 // We don't bother with actually removing responses from the disk-cache, |
| 125 // just keep track of which ids have been doomed. | |
| 126 std::vector<int64>::const_iterator it = response_ids.begin(); | |
| 127 while (it != response_ids.end()) { | |
| 128 doomed_response_ids_.insert(*it); | |
| 129 ++it; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void MockAppCacheStorage::ProcessLoadCache( | |
| 134 int64 id, scoped_refptr<DelegateReference> delegate_ref) { | |
| 135 AppCache* cache = working_set_.GetCache(id); | |
| 136 if (delegate_ref->delegate) | |
| 137 delegate_ref->delegate->OnCacheLoaded(cache, id); | |
| 138 } | |
| 139 | |
| 140 void MockAppCacheStorage::ProcessLoadOrCreateGroup( | |
| 141 const GURL& manifest_url, scoped_refptr<DelegateReference> delegate_ref) { | |
| 142 scoped_refptr<AppCacheGroup> group = working_set_.GetGroup(manifest_url); | |
| 143 | |
| 144 // Newly created groups are not put in the stored_groups collection | |
| 145 // until StoreGroupAndNewestCache is called. | |
| 146 if (!group) | |
| 147 group = new AppCacheGroup(service_, manifest_url); | |
| 148 | |
| 149 if (delegate_ref->delegate) | |
| 150 delegate_ref->delegate->OnGroupLoaded(group, manifest_url); | |
| 151 } | |
| 152 | |
| 153 void MockAppCacheStorage::ProcessStoreGroupAndNewestCache( | |
| 154 scoped_refptr<AppCacheGroup> group, | |
| 155 scoped_refptr<AppCache> newest_cache, | |
| 156 scoped_refptr<DelegateReference> delegate_ref) { | |
| 157 DCHECK(group->newest_complete_cache() == newest_cache.get()); | |
| 158 | |
| 159 AddStoredGroup(group); | |
| 160 AddStoredCache(group->newest_complete_cache()); | |
| 161 | |
| 162 // Copy the collection prior to removal, on final release | |
| 163 // of a cache the group's collection will change. | |
| 164 AppCacheGroup::Caches copy = group->old_caches(); | |
| 165 RemoveStoredCaches(copy); | |
| 166 | |
| 167 if (delegate_ref->delegate) | |
| 168 delegate_ref->delegate->OnGroupAndNewestCacheStored(group, true); | |
| 169 | |
| 170 // We don't bother with removing responses from 'mock' storage | |
| 171 // TODO(michaeln): for 'real' storage... | |
| 172 // std::set<int64> doomed_responses_ = responses from old caches | |
| 173 // std::set<int64> needed_responses_ = responses from newest cache | |
| 174 // foreach(needed_responses_) | |
| 175 // doomed_responses_.remove(needed_response_); | |
| 176 // DoomResponses(group->manifest_url(), doomed_responses_); | |
| 177 } | |
| 178 | |
| 179 void MockAppCacheStorage::ProcessFindResponseForMainRequest( | |
| 180 const GURL& url, scoped_refptr<DelegateReference> delegate_ref) { | |
| 181 // TODO(michaeln): write me when doing AppCacheRequestHandler | |
| 182 // foreach(stored_group) { | |
| 183 // if (group->manifest_url()->origin() != url.GetOrigin()) | |
| 184 // continue; | |
| 185 // look for an entry | |
| 186 // look for a fallback namespace | |
| 187 // look for a online namespace | |
| 188 // } | |
| 189 if (delegate_ref->delegate) { | |
| 190 delegate_ref->delegate->OnMainResponseFound( | |
| 191 url, AppCacheEntry(), kNoCacheId, GURL()); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 void MockAppCacheStorage::ProcessMakeGroupObsolete( | |
| 196 scoped_refptr<AppCacheGroup> group, | |
| 197 scoped_refptr<DelegateReference> delegate_ref) { | |
| 198 RemoveStoredGroup(group); | |
| 199 if (group->newest_complete_cache()) | |
| 200 RemoveStoredCache(group->newest_complete_cache()); | |
| 201 | |
| 202 // Copy the collection prior to removal, on final release | |
| 203 // of a cache the group's collection will change. | |
| 204 AppCacheGroup::Caches copy = group->old_caches(); | |
| 205 RemoveStoredCaches(copy); | |
| 206 | |
| 207 group->set_obsolete(true); | |
| 208 | |
| 209 if (delegate_ref->delegate) | |
| 210 delegate_ref->delegate->OnGroupMadeObsolete(group, true); | |
| 211 } | |
| 212 | |
| 213 void MockAppCacheStorage::ScheduleTask(Task* task) { | |
| 214 pending_tasks_.push_back(task); | |
| 215 MessageLoop::current()->PostTask(FROM_HERE, | |
| 216 method_factory_.NewRunnableMethod( | |
| 217 &MockAppCacheStorage::RunOnePendingTask)); | |
| 218 } | |
| 219 | |
| 220 void MockAppCacheStorage::RunOnePendingTask() { | |
| 221 DCHECK(!pending_tasks_.empty()); | |
| 222 Task* task = pending_tasks_.front(); | |
| 223 pending_tasks_.pop_front(); | |
| 224 task->Run(); | |
| 225 delete task; | |
| 122 } | 226 } |
| 123 | 227 |
| 124 void MockAppCacheStorage::AddStoredCache(AppCache* cache) { | 228 void MockAppCacheStorage::AddStoredCache(AppCache* cache) { |
| 125 // cache->set_is_stored(true); | |
| 126 int64 cache_id = cache->cache_id(); | 229 int64 cache_id = cache->cache_id(); |
| 127 if (stored_caches_.find(cache_id) == stored_caches_.end()) | 230 if (stored_caches_.find(cache_id) == stored_caches_.end()) |
| 128 stored_caches_.insert(StoredCacheMap::value_type(cache_id, cache)); | 231 stored_caches_.insert(StoredCacheMap::value_type(cache_id, cache)); |
| 129 } | 232 } |
| 130 | 233 |
| 131 void MockAppCacheStorage::RemoveStoredCache(AppCache* cache) { | 234 void MockAppCacheStorage::RemoveStoredCache(AppCache* cache) { |
| 132 // cache->set_is_stored(false); | 235 // Do not remove from the working set, active caches are still usable |
| 236 // and may be looked up by id until they fall out of use. | |
| 133 stored_caches_.erase(cache->cache_id()); | 237 stored_caches_.erase(cache->cache_id()); |
| 134 } | 238 } |
| 135 | 239 |
| 240 void MockAppCacheStorage::RemoveStoredCaches( | |
| 241 const AppCacheGroup::Caches& caches) { | |
| 242 AppCacheGroup::Caches::const_iterator it = caches.begin(); | |
| 243 while (it != caches.end()) { | |
| 244 RemoveStoredCache(*it); | |
| 245 ++it; | |
| 246 } | |
| 247 } | |
| 248 | |
| 136 void MockAppCacheStorage::AddStoredGroup(AppCacheGroup* group) { | 249 void MockAppCacheStorage::AddStoredGroup(AppCacheGroup* group) { |
| 137 // group->set_is_stored(true); | |
| 138 const GURL& url = group->manifest_url(); | 250 const GURL& url = group->manifest_url(); |
| 139 if (stored_groups_.find(url) == stored_groups_.end()) | 251 if (stored_groups_.find(url) == stored_groups_.end()) |
| 140 stored_groups_.insert(StoredGroupMap::value_type(url, group)); | 252 stored_groups_.insert(StoredGroupMap::value_type(url, group)); |
| 141 } | 253 } |
| 142 | 254 |
| 143 void MockAppCacheStorage::RemoveStoredGroup(AppCacheGroup* group) { | 255 void MockAppCacheStorage::RemoveStoredGroup(AppCacheGroup* group) { |
| 144 // group->set_is_stored(false); | 256 // Also remove from the working set, caches for an 'obsolete' group |
| 257 // may linger in use, but the group itself cannot be looked up by | |
| 258 // 'manifest_url' in the working set any longer. | |
| 259 working_set()->RemoveGroup(group); | |
| 145 stored_groups_.erase(group->manifest_url()); | 260 stored_groups_.erase(group->manifest_url()); |
| 146 } | 261 } |
| 147 | 262 |
| 263 bool MockAppCacheStorage::ShouldGroupLoadAppearAsync( | |
| 264 const AppCacheGroup* group) { | |
| 265 // We'll have to query the database to see if a group for the | |
| 266 // manifest_url exists on disk. So return true for async. | |
| 267 if (!group) | |
| 268 return true; | |
| 269 | |
| 270 // Groups without a newest cache can't have been put to disk yet, so | |
| 271 // we can synchronously return a reference we have in the working set. | |
| 272 if (!group->newest_complete_cache()) | |
| 273 return false; | |
| 274 | |
| 275 // The LoadGroup interface implies also loading the newest cache, so | |
| 276 // if loading the newest cache should appear async, so to must this | |
|
michaeln
2009/10/24 00:36:06
changed locally to... "so too must the"
| |
| 277 // loading of this group. | |
| 278 if (ShouldCacheLoadAppearAsync(group->newest_complete_cache())) | |
| 279 return true; | |
| 280 | |
| 281 | |
| 282 // If any of the old caches are "in use", then the group must also | |
| 283 // be memory resident and not require async loading. | |
| 284 const AppCacheGroup::Caches& old_caches = group->old_caches(); | |
| 285 AppCacheGroup::Caches::const_iterator it = old_caches.begin(); | |
| 286 while (it != old_caches.end()) { | |
| 287 // "in use" caches don't require async loading | |
| 288 if (!ShouldCacheLoadAppearAsync(*it)) | |
| 289 return false; | |
| 290 ++it; | |
| 291 } | |
| 292 | |
| 293 return true; | |
| 294 } | |
| 295 | |
| 296 bool MockAppCacheStorage::ShouldCacheLoadAppearAsync(const AppCache* cache) { | |
| 297 if (!cache) | |
| 298 return true; | |
| 299 | |
| 300 // If the 'stored' ref is the only ref, real storage will have to load from | |
| 301 // the database. | |
| 302 return IsCacheStored(cache) && cache->HasOneRef(); | |
| 303 } | |
| 304 | |
| 148 } // namespace appcache | 305 } // namespace appcache |
| OLD | NEW |