| 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 |