OLD | NEW |
1 /* | 1 /* |
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) | 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) |
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) | 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) |
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) | 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) |
5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 5 Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
6 | 6 |
7 This library is free software; you can redistribute it and/or | 7 This library is free software; you can redistribute it and/or |
8 modify it under the terms of the GNU Library General Public | 8 modify it under the terms of the GNU Library General Public |
9 License as published by the Free Software Foundation; either | 9 License as published by the Free Software Foundation; either |
10 version 2 of the License, or (at your option) any later version. | 10 version 2 of the License, or (at your option) any later version. |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 KURL url = originalURL; | 104 KURL url = originalURL; |
105 url.removeFragmentIdentifier(); | 105 url.removeFragmentIdentifier(); |
106 return url; | 106 return url; |
107 } | 107 } |
108 | 108 |
109 void MemoryCache::add(Resource* resource) | 109 void MemoryCache::add(Resource* resource) |
110 { | 110 { |
111 ASSERT(WTF::isMainThread()); | 111 ASSERT(WTF::isMainThread()); |
112 ASSERT(!m_resources.contains(resource->url())); | 112 ASSERT(!m_resources.contains(resource->url())); |
113 m_resources.set(resource->url(), MemoryCacheEntry::create(resource)); | 113 m_resources.set(resource->url(), MemoryCacheEntry::create(resource)); |
114 resource->setInCache(true); | 114 update(resource, 0, resource->size(), true); |
115 resource->updateForAccess(); | |
116 | 115 |
117 WTF_LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resou
rce->url().string().latin1().data(), resource); | 116 WTF_LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resou
rce->url().string().latin1().data(), resource); |
118 } | 117 } |
119 | 118 |
120 void MemoryCache::replace(Resource* newResource, Resource* oldResource) | 119 void MemoryCache::replace(Resource* newResource, Resource* oldResource) |
121 { | 120 { |
122 evict(oldResource); | 121 evict(oldResource); |
123 ASSERT(!m_resources.contains(newResource->url())); | 122 add(newResource); |
124 m_resources.set(newResource->url(), MemoryCacheEntry::create(newResource)); | |
125 newResource->setInCache(true); | |
126 insertInLRUList(newResource); | |
127 int delta = newResource->size(); | |
128 if (newResource->decodedSize() && newResource->hasClients()) | 123 if (newResource->decodedSize() && newResource->hasClients()) |
129 insertInLiveDecodedResourcesList(newResource); | 124 insertInLiveDecodedResourcesList(newResource); |
130 if (delta) | 125 } |
131 adjustSize(newResource->hasClients(), delta); | 126 |
| 127 bool MemoryCache::contains(Resource* resource) |
| 128 { |
| 129 if (resource->url().isNull()) |
| 130 return false; |
| 131 MemoryCacheEntry* entry = m_resources.get(resource->url()); |
| 132 return entry && entry->m_resource == resource; |
132 } | 133 } |
133 | 134 |
134 Resource* MemoryCache::resourceForURL(const KURL& resourceURL) | 135 Resource* MemoryCache::resourceForURL(const KURL& resourceURL) |
135 { | 136 { |
136 ASSERT(WTF::isMainThread()); | 137 ASSERT(WTF::isMainThread()); |
137 KURL url = removeFragmentIdentifierIfNeeded(resourceURL); | 138 KURL url = removeFragmentIdentifierIfNeeded(resourceURL); |
138 MemoryCacheEntry* entry = m_resources.get(url); | 139 MemoryCacheEntry* entry = m_resources.get(url); |
139 if (!entry) | 140 if (!entry) |
140 return 0; | 141 return 0; |
141 Resource* resource = entry->m_resource.get(); | 142 Resource* resource = entry->m_resource.get(); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 | 236 |
236 bool canShrinkLRULists = true; | 237 bool canShrinkLRULists = true; |
237 for (int i = size - 1; i >= 0; i--) { | 238 for (int i = size - 1; i >= 0; i--) { |
238 // Remove from the tail, since this is the least frequently accessed of
the objects. | 239 // Remove from the tail, since this is the least frequently accessed of
the objects. |
239 MemoryCacheEntry* current = m_allResources[i].m_tail; | 240 MemoryCacheEntry* current = m_allResources[i].m_tail; |
240 | 241 |
241 // First flush all the decoded data in this queue. | 242 // First flush all the decoded data in this queue. |
242 while (current) { | 243 while (current) { |
243 // Protect 'previous' so it can't get deleted during destroyDecodedD
ata(). | 244 // Protect 'previous' so it can't get deleted during destroyDecodedD
ata(). |
244 MemoryCacheEntry* previous = current->m_previousInAllResourcesList; | 245 MemoryCacheEntry* previous = current->m_previousInAllResourcesList; |
245 ASSERT(!previous || previous->m_resource->inCache()); | 246 ASSERT(!previous || contains(previous->m_resource.get())); |
246 if (!current->m_resource->hasClients() && !current->m_resource->isPr
eloaded() && current->m_resource->isLoaded()) { | 247 if (!current->m_resource->hasClients() && !current->m_resource->isPr
eloaded() && current->m_resource->isLoaded()) { |
247 // Destroy our decoded data. This will remove us from | 248 // Destroy our decoded data. This will remove us from |
248 // m_liveDecodedResources, and possibly move us to a different | 249 // m_liveDecodedResources, and possibly move us to a different |
249 // LRU list in m_allResources. | 250 // LRU list in m_allResources. |
250 current->m_resource->prune(); | 251 current->m_resource->prune(); |
251 | 252 |
252 if (targetSize && m_deadSize <= targetSize) | 253 if (targetSize && m_deadSize <= targetSize) |
253 return; | 254 return; |
254 } | 255 } |
255 // Decoded data may reference other resources. Stop iterating if 'pr
evious' somehow got | 256 // Decoded data may reference other resources. Stop iterating if 'pr
evious' somehow got |
256 // kicked out of cache during destroyDecodedData(). | 257 // kicked out of cache during destroyDecodedData(). |
257 if (previous && !previous->m_resource->inCache()) | 258 if (previous && !contains(previous->m_resource.get())) |
258 break; | 259 break; |
259 current = previous; | 260 current = previous; |
260 } | 261 } |
261 | 262 |
262 // Now evict objects from this queue. | 263 // Now evict objects from this queue. |
263 current = m_allResources[i].m_tail; | 264 current = m_allResources[i].m_tail; |
264 while (current) { | 265 while (current) { |
265 MemoryCacheEntry* previous = current->m_previousInAllResourcesList; | 266 MemoryCacheEntry* previous = current->m_previousInAllResourcesList; |
266 ASSERT(!previous || previous->m_resource->inCache()); | 267 ASSERT(!previous || contains(previous->m_resource.get())); |
267 if (!current->m_resource->hasClients() && !current->m_resource->isPr
eloaded() && !current->m_resource->isCacheValidator()) { | 268 if (!current->m_resource->hasClients() && !current->m_resource->isPr
eloaded() && !current->m_resource->isCacheValidator()) { |
268 evict(current->m_resource.get()); | 269 evict(current->m_resource.get()); |
269 if (targetSize && m_deadSize <= targetSize) | 270 if (targetSize && m_deadSize <= targetSize) |
270 return; | 271 return; |
271 } | 272 } |
272 if (previous && !previous->m_resource->inCache()) | 273 if (previous && !contains(previous->m_resource.get())) |
273 break; | 274 break; |
274 current = previous; | 275 current = previous; |
275 } | 276 } |
276 | 277 |
277 // Shrink the vector back down so we don't waste time inspecting | 278 // Shrink the vector back down so we don't waste time inspecting |
278 // empty LRU lists on future prunes. | 279 // empty LRU lists on future prunes. |
279 if (m_allResources[i].m_head) | 280 if (m_allResources[i].m_head) |
280 canShrinkLRULists = false; | 281 canShrinkLRULists = false; |
281 else if (canShrinkLRULists) | 282 else if (canShrinkLRULists) |
282 m_allResources.resize(i); | 283 m_allResources.resize(i); |
(...skipping 10 matching lines...) Expand all Loading... |
293 m_capacity = totalBytes; | 294 m_capacity = totalBytes; |
294 prune(); | 295 prune(); |
295 } | 296 } |
296 | 297 |
297 bool MemoryCache::evict(Resource* resource) | 298 bool MemoryCache::evict(Resource* resource) |
298 { | 299 { |
299 ASSERT(WTF::isMainThread()); | 300 ASSERT(WTF::isMainThread()); |
300 WTF_LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resourc
e, resource->url().string().latin1().data()); | 301 WTF_LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resourc
e, resource->url().string().latin1().data()); |
301 // The resource may have already been removed by someone other than our call
er, | 302 // The resource may have already been removed by someone other than our call
er, |
302 // who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bu
g.cgi?id=12479#c6>. | 303 // who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bu
g.cgi?id=12479#c6>. |
303 if (resource->inCache()) { | 304 if (contains(resource)) { |
304 // Remove from the appropriate LRU list. | 305 update(resource, resource->size(), 0, false); |
305 removeFromLRUList(resource); | |
306 removeFromLiveDecodedResourcesList(resource); | 306 removeFromLiveDecodedResourcesList(resource); |
307 adjustSize(resource->hasClients(), -static_cast<ptrdiff_t>(resource->siz
e())); | |
308 | 307 |
309 // Remove from the resource map. | 308 // Remove from the resource map. |
310 m_resources.remove(resource->url()); | 309 m_resources.remove(resource->url()); |
311 resource->setInCache(false); | |
312 } else { | |
313 ASSERT(!m_resources.get(resource->url()) || m_resources.get(resource->ur
l())->m_resource != resource); | |
314 } | 310 } |
315 | 311 |
316 return resource->deleteIfPossible(); | 312 return resource->deleteIfPossible(); |
317 } | 313 } |
318 | 314 |
319 MemoryCache::LRUList* MemoryCache::lruListFor(MemoryCacheEntry* entry) | 315 MemoryCache::LRUList* MemoryCache::lruListFor(unsigned accessCount, size_t size) |
320 { | 316 { |
321 unsigned accessCount = std::max(entry->m_resource->accessCount(), 1U); | 317 ASSERT(accessCount > 0); |
322 unsigned queueIndex = WTF::fastLog2(entry->m_resource->size() / accessCount)
; | 318 unsigned queueIndex = WTF::fastLog2(size / accessCount); |
323 if (m_allResources.size() <= queueIndex) | 319 if (m_allResources.size() <= queueIndex) |
324 m_allResources.grow(queueIndex + 1); | 320 m_allResources.grow(queueIndex + 1); |
325 return &m_allResources[queueIndex]; | 321 return &m_allResources[queueIndex]; |
326 } | 322 } |
327 | 323 |
328 void MemoryCache::removeFromLRUList(Resource* resource) | 324 void MemoryCache::removeFromLRUList(MemoryCacheEntry* entry, LRUList* list) |
329 { | 325 { |
330 MemoryCacheEntry* entry = m_resources.get(resource->url()); | |
331 ASSERT(entry->m_resource == resource); | |
332 | |
333 LRUList* list = lruListFor(entry); | |
334 MemoryCacheEntry* next = entry->m_nextInAllResourcesList; | |
335 MemoryCacheEntry* previous = entry->m_previousInAllResourcesList; | |
336 if (!next && !previous && list->m_head != entry) | |
337 return; | |
338 | |
339 #if !ASSERT_DISABLED | 326 #if !ASSERT_DISABLED |
340 // Verify that we are in fact in this list. | 327 // Verify that we are in fact in this list. |
341 bool found = false; | 328 bool found = false; |
342 for (MemoryCacheEntry* current = list->m_head; current; current = current->m
_nextInAllResourcesList) { | 329 for (MemoryCacheEntry* current = list->m_head; current; current = current->m
_nextInAllResourcesList) { |
343 if (current == entry) { | 330 if (current == entry) { |
344 found = true; | 331 found = true; |
345 break; | 332 break; |
346 } | 333 } |
347 } | 334 } |
348 ASSERT(found); | 335 ASSERT(found); |
349 #endif | 336 #endif |
350 | 337 |
| 338 MemoryCacheEntry* next = entry->m_nextInAllResourcesList; |
| 339 MemoryCacheEntry* previous = entry->m_previousInAllResourcesList; |
351 entry->m_nextInAllResourcesList = 0; | 340 entry->m_nextInAllResourcesList = 0; |
352 entry->m_previousInAllResourcesList = 0; | 341 entry->m_previousInAllResourcesList = 0; |
353 | 342 |
354 if (next) | 343 if (next) |
355 next->m_previousInAllResourcesList = previous; | 344 next->m_previousInAllResourcesList = previous; |
356 else | 345 else |
357 list->m_tail = previous; | 346 list->m_tail = previous; |
358 | 347 |
359 if (previous) | 348 if (previous) |
360 previous->m_nextInAllResourcesList = next; | 349 previous->m_nextInAllResourcesList = next; |
361 else | 350 else |
362 list->m_head = next; | 351 list->m_head = next; |
363 } | 352 } |
364 | 353 |
365 void MemoryCache::insertInLRUList(Resource* resource) | 354 void MemoryCache::insertInLRUList(MemoryCacheEntry* entry, LRUList* list) |
366 { | 355 { |
367 MemoryCacheEntry* entry = m_resources.get(resource->url()); | |
368 ASSERT(entry->m_resource == resource); | |
369 | |
370 // Make sure we aren't in some list already. | |
371 ASSERT(!entry->m_nextInAllResourcesList && !entry->m_previousInAllResourcesL
ist); | 356 ASSERT(!entry->m_nextInAllResourcesList && !entry->m_previousInAllResourcesL
ist); |
372 ASSERT(resource->inCache()); | |
373 | |
374 LRUList* list = lruListFor(entry); | |
375 | 357 |
376 entry->m_nextInAllResourcesList = list->m_head; | 358 entry->m_nextInAllResourcesList = list->m_head; |
377 if (list->m_head) | |
378 list->m_head->m_previousInAllResourcesList = entry; | |
379 list->m_head = entry; | 359 list->m_head = entry; |
380 | 360 |
381 if (!entry->m_nextInAllResourcesList) | 361 if (entry->m_nextInAllResourcesList) |
| 362 entry->m_nextInAllResourcesList->m_previousInAllResourcesList = entry; |
| 363 else |
382 list->m_tail = entry; | 364 list->m_tail = entry; |
383 | 365 |
384 #if !ASSERT_DISABLED | 366 #if !ASSERT_DISABLED |
385 // Verify that we are in now in the list like we should be. | 367 // Verify that we are in now in the list like we should be. |
386 list = lruListFor(entry); | |
387 bool found = false; | 368 bool found = false; |
388 for (MemoryCacheEntry* current = list->m_head; current; current = current->m
_nextInAllResourcesList) { | 369 for (MemoryCacheEntry* current = list->m_head; current; current = current->m
_nextInAllResourcesList) { |
389 if (current == entry) { | 370 if (current == entry) { |
390 found = true; | 371 found = true; |
391 break; | 372 break; |
392 } | 373 } |
393 } | 374 } |
394 ASSERT(found); | 375 ASSERT(found); |
395 #endif | 376 #endif |
396 } | 377 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 break; | 444 break; |
464 } | 445 } |
465 } | 446 } |
466 ASSERT(found); | 447 ASSERT(found); |
467 #endif | 448 #endif |
468 } | 449 } |
469 | 450 |
470 bool MemoryCache::isInLiveDecodedResourcesList(Resource* resource) | 451 bool MemoryCache::isInLiveDecodedResourcesList(Resource* resource) |
471 { | 452 { |
472 MemoryCacheEntry* entry = m_resources.get(resource->url()); | 453 MemoryCacheEntry* entry = m_resources.get(resource->url()); |
473 ASSERT(entry->m_resource == resource); | 454 ASSERT(entry && entry->m_resource == resource); |
474 return entry ? entry->m_inLiveDecodedResourcesList : false; | 455 return entry->m_inLiveDecodedResourcesList; |
475 } | 456 } |
476 | 457 |
477 void MemoryCache::addToLiveResourcesSize(Resource* resource) | 458 void MemoryCache::addToLiveResourcesSize(Resource* resource) |
478 { | 459 { |
479 ASSERT(m_deadSize >= resource->size()); | 460 ASSERT(m_deadSize >= resource->size()); |
480 m_liveSize += resource->size(); | 461 m_liveSize += resource->size(); |
481 m_deadSize -= resource->size(); | 462 m_deadSize -= resource->size(); |
482 } | 463 } |
483 | 464 |
484 void MemoryCache::removeFromLiveResourcesSize(Resource* resource) | 465 void MemoryCache::removeFromLiveResourcesSize(Resource* resource) |
485 { | 466 { |
486 ASSERT(m_liveSize >= resource->size()); | 467 ASSERT(m_liveSize >= resource->size()); |
487 m_liveSize -= resource->size(); | 468 m_liveSize -= resource->size(); |
488 m_deadSize += resource->size(); | 469 m_deadSize += resource->size(); |
489 } | 470 } |
490 | 471 |
491 void MemoryCache::adjustSize(bool live, ptrdiff_t delta) | 472 void MemoryCache::update(Resource* resource, size_t oldSize, size_t newSize, boo
l wasAccessed) |
492 { | 473 { |
493 if (live) { | 474 ASSERT(contains(resource)); |
| 475 MemoryCacheEntry* entry = m_resources.get(resource->url()); |
| 476 |
| 477 // The object must now be moved to a different queue, since either its size
or its accessCount has been changed, |
| 478 // and both of those are used to determine which LRU queue the resource shou
ld be in. |
| 479 if (oldSize) |
| 480 removeFromLRUList(entry, lruListFor(entry->m_accessCount, oldSize)); |
| 481 if (wasAccessed) |
| 482 entry->m_accessCount++; |
| 483 if (newSize) |
| 484 insertInLRUList(entry, lruListFor(entry->m_accessCount, newSize)); |
| 485 |
| 486 ptrdiff_t delta = newSize - oldSize; |
| 487 if (resource->hasClients()) { |
494 ASSERT(delta >= 0 || m_liveSize >= static_cast<size_t>(-delta) ); | 488 ASSERT(delta >= 0 || m_liveSize >= static_cast<size_t>(-delta) ); |
495 m_liveSize += delta; | 489 m_liveSize += delta; |
496 } else { | 490 } else { |
497 ASSERT(delta >= 0 || m_deadSize >= static_cast<size_t>(-delta) ); | 491 ASSERT(delta >= 0 || m_deadSize >= static_cast<size_t>(-delta) ); |
498 m_deadSize += delta; | 492 m_deadSize += delta; |
499 } | 493 } |
500 } | 494 } |
501 | 495 |
502 void MemoryCache::removeURLFromCache(ExecutionContext* context, const KURL& url) | 496 void MemoryCache::removeURLFromCache(ExecutionContext* context, const KURL& url) |
503 { | 497 { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz
e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur
rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was
Purged()); | 673 printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSiz
e() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, cur
rent->accessCount(), current->hasClients(), current->isPurgeable(), current->was
Purged()); |
680 | 674 |
681 current = prev; | 675 current = prev; |
682 } | 676 } |
683 } | 677 } |
684 } | 678 } |
685 | 679 |
686 #endif // MEMORY_CACHE_STATS | 680 #endif // MEMORY_CACHE_STATS |
687 | 681 |
688 } // namespace WebCore | 682 } // namespace WebCore |
OLD | NEW |