Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp

Issue 2676163002: Refactor the forPreload flag to mean speculative preload. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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, 2009, 2010, 2011 Apple Inc. All 5 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
6 rights reserved. 6 rights reserved.
7 Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/ 7 Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
8 8
9 This library is free software; you can redistribute it and/or 9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public 10 modify it under the terms of the GNU Library General Public
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 return ResourceLoadPriorityUnresolved; 150 return ResourceLoadPriorityUnresolved;
151 } 151 }
152 152
153 } // namespace 153 } // namespace
154 154
155 ResourceLoadPriority ResourceFetcher::computeLoadPriority( 155 ResourceLoadPriority ResourceFetcher::computeLoadPriority(
156 Resource::Type type, 156 Resource::Type type,
157 const ResourceRequest& resourceRequest, 157 const ResourceRequest& resourceRequest,
158 ResourcePriority::VisibilityStatus visibility, 158 ResourcePriority::VisibilityStatus visibility,
159 FetchRequest::DeferOption deferOption, 159 FetchRequest::DeferOption deferOption,
160 bool forPreload) { 160 bool speculativePreload) {
161 ResourceLoadPriority priority = typeToPriority(type); 161 ResourceLoadPriority priority = typeToPriority(type);
162 162
163 // Visible resources (images in practice) get a boost to High priority. 163 // Visible resources (images in practice) get a boost to High priority.
164 if (visibility == ResourcePriority::Visible) 164 if (visibility == ResourcePriority::Visible)
165 priority = ResourceLoadPriorityHigh; 165 priority = ResourceLoadPriorityHigh;
166 166
167 // Resources before the first image are considered "early" in the document and 167 // Resources before the first image are considered "early" in the document and
168 // resources after the first image are "late" in the document. Important to 168 // resources after the first image are "late" in the document. Important to
169 // note that this is based on when the preload scanner discovers a resource 169 // note that this is based on when the preload scanner discovers a resource
170 // for the most part so the main parser may not have reached the image element 170 // for the most part so the main parser may not have reached the image element
171 // yet. 171 // yet.
172 if (type == Resource::Image) 172 if (type == Resource::Image)
173 m_imageFetched = true; 173 m_imageFetched = true;
174 174
175 if (FetchRequest::IdleLoad == deferOption) { 175 if (FetchRequest::IdleLoad == deferOption) {
176 priority = ResourceLoadPriorityVeryLow; 176 priority = ResourceLoadPriorityVeryLow;
177 } else if (type == Resource::Script) { 177 } else if (type == Resource::Script) {
178 // Special handling for scripts. 178 // Special handling for scripts.
179 // Default/Parser-Blocking/Preload early in document: High (set in 179 // Default/Parser-Blocking/Preload early in document: High (set in
180 // typeToPriority) 180 // typeToPriority)
181 // Async/Defer: Low Priority (applies to both preload and parser-inserted) 181 // Async/Defer: Low Priority (applies to both preload and parser-inserted)
182 // Preload late in document: Medium 182 // Preload late in document: Medium
183 if (FetchRequest::LazyLoad == deferOption) 183 if (FetchRequest::LazyLoad == deferOption) {
184 priority = ResourceLoadPriorityLow; 184 priority = ResourceLoadPriorityLow;
185 else if (forPreload && m_imageFetched) 185 } else if (speculativePreload && m_imageFetched) {
186 // TODO(yoav): It is not clear why this applies only to preloaded scripts.
186 priority = ResourceLoadPriorityMedium; 187 priority = ResourceLoadPriorityMedium;
188 }
187 } else if (FetchRequest::LazyLoad == deferOption) { 189 } else if (FetchRequest::LazyLoad == deferOption) {
188 priority = ResourceLoadPriorityVeryLow; 190 priority = ResourceLoadPriorityVeryLow;
189 } 191 }
190 192
191 // A manually set priority acts as a floor. This is used to ensure that 193 // A manually set priority acts as a floor. This is used to ensure that
192 // synchronous requests are always given the highest possible priority, as 194 // synchronous requests are always given the highest possible priority, as
193 // well as to ensure that there isn't priority churn if images move in and out 195 // well as to ensure that there isn't priority churn if images move in and out
194 // of the viewport, or is displayed more than once, both in and out of the 196 // of the viewport, or is displayed more than once, both in and out of the
195 // viewport. 197 // viewport.
196 return std::max(context().modifyPriorityForExperiments(priority), 198 return std::max(context().modifyPriorityForExperiments(priority),
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 return resource.get(); 271 return resource.get();
270 } 272 }
271 273
272 bool ResourceFetcher::isControlledByServiceWorker() const { 274 bool ResourceFetcher::isControlledByServiceWorker() const {
273 return context().isControlledByServiceWorker(); 275 return context().isControlledByServiceWorker();
274 } 276 }
275 277
276 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, 278 bool ResourceFetcher::resourceNeedsLoad(Resource* resource,
277 const FetchRequest& request, 279 const FetchRequest& request,
278 RevalidationPolicy policy) { 280 RevalidationPolicy policy) {
279 // Defer a font load until it is actually needed unless this is a preload. 281 // Defer a font load until it is actually needed unless this is a link
280 if (resource->getType() == Resource::Font && !request.forPreload()) 282 // preload.
Charlie Harrison 2017/02/05 18:39:12 I think this should still be for all preloads, not
Yoav Weiss 2017/02/06 09:58:35 I don't know that it's worth-while to pay for an e
Charlie Harrison 2017/02/06 19:54:15 Your call, it isn't a huge deal. Probably the best
283 if (resource->getType() == Resource::Font && !request.isLinkPreload())
281 return false; 284 return false;
282 if (resource->isImage() && shouldDeferImageLoad(resource->url())) 285 if (resource->isImage() && shouldDeferImageLoad(resource->url()))
283 return false; 286 return false;
284 return policy != Use || resource->stillNeedsLoad(); 287 return policy != Use || resource->stillNeedsLoad();
285 } 288 }
286 289
287 // Limit the number of URLs in m_validatedURLs to avoid memory bloat. 290 // Limit the number of URLs in m_validatedURLs to avoid memory bloat.
288 // http://crbug.com/52411 291 // http://crbug.com/52411
289 static const int kMaxValidatedURLsSize = 10000; 292 static const int kMaxValidatedURLsSize = 10000;
290 293
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 } 419 }
417 420
418 void ResourceFetcher::moveCachedNonBlockingResourceToBlocking( 421 void ResourceFetcher::moveCachedNonBlockingResourceToBlocking(
419 Resource* resource, 422 Resource* resource,
420 const FetchRequest& request) { 423 const FetchRequest& request) {
421 // TODO(yoav): Test that non-blocking resources (video/audio/track) continue 424 // TODO(yoav): Test that non-blocking resources (video/audio/track) continue
422 // to not-block even after being preloaded and discovered. 425 // to not-block even after being preloaded and discovered.
423 if (resource && resource->loader() && 426 if (resource && resource->loader() &&
424 resource->isLoadEventBlockingResourceType() && 427 resource->isLoadEventBlockingResourceType() &&
425 m_nonBlockingLoaders.contains(resource->loader()) && 428 m_nonBlockingLoaders.contains(resource->loader()) &&
426 resource->isLinkPreload() && !request.forPreload()) { 429 resource->isLinkPreload() && !request.isLinkPreload()) {
Charlie Harrison 2017/02/05 18:39:12 nit: can we move the isLinkPreload and !isLinkPrel
Yoav Weiss 2017/02/06 09:58:35 Good call
427 m_nonBlockingLoaders.remove(resource->loader()); 430 m_nonBlockingLoaders.remove(resource->loader());
Charlie Harrison 2017/02/05 18:39:12 I am slightly confused what this method does, do y
Yoav Weiss 2017/02/06 09:58:35 renamed the method to a hopefully clearer name, an
428 m_loaders.insert(resource->loader()); 431 m_loaders.insert(resource->loader());
429 } 432 }
430 } 433 }
431 434
432 void ResourceFetcher::updateMemoryCacheStats(Resource* resource, 435 void ResourceFetcher::updateMemoryCacheStats(Resource* resource,
433 RevalidationPolicy policy, 436 RevalidationPolicy policy,
434 const FetchRequest& request, 437 const FetchRequest& request,
435 const ResourceFactory& factory, 438 const ResourceFactory& factory,
436 bool isStaticData) const { 439 bool isStaticData) const {
437 if (isStaticData) 440 if (isStaticData)
438 return; 441 return;
439 442
440 if (request.forPreload()) { 443 if (request.speculativePreload() || request.isLinkPreload()) {
441 DEFINE_RESOURCE_HISTOGRAM("Preload."); 444 DEFINE_RESOURCE_HISTOGRAM("Preload.");
442 } else { 445 } else {
443 DEFINE_RESOURCE_HISTOGRAM(""); 446 DEFINE_RESOURCE_HISTOGRAM("");
444 } 447 }
445 448
446 // Aims to count Resource only referenced from MemoryCache (i.e. what would be 449 // Aims to count Resource only referenced from MemoryCache (i.e. what would be
447 // dead if MemoryCache holds weak references to Resource). Currently we check 450 // dead if MemoryCache holds weak references to Resource). Currently we check
448 // references to Resource from ResourceClient and |m_preloads| only, because 451 // references to Resource from ResourceClient and |m_preloads| only, because
449 // they are major sources of references. 452 // they are major sources of references.
450 if (resource && !resource->isAlive() && 453 if (resource && !resource->isAlive() &&
(...skipping 16 matching lines...) Expand all
467 470
468 context().populateResourceRequest( 471 context().populateResourceRequest(
469 factory.type(), request.clientHintsPreferences(), 472 factory.type(), request.clientHintsPreferences(),
470 request.getResourceWidth(), resourceRequest); 473 request.getResourceWidth(), resourceRequest);
471 474
472 if (!request.url().isValid()) 475 if (!request.url().isValid())
473 return Abort; 476 return Abort;
474 477
475 resourceRequest.setPriority(computeLoadPriority( 478 resourceRequest.setPriority(computeLoadPriority(
476 factory.type(), request.resourceRequest(), ResourcePriority::NotVisible, 479 factory.type(), request.resourceRequest(), ResourcePriority::NotVisible,
477 request.defer(), request.forPreload())); 480 request.defer(), request.speculativePreload()));
478 initializeResourceRequest(resourceRequest, factory.type(), request.defer()); 481 initializeResourceRequest(resourceRequest, factory.type(), request.defer());
479 network_instrumentation::resourcePrioritySet(identifier, 482 network_instrumentation::resourcePrioritySet(identifier,
480 resourceRequest.priority()); 483 resourceRequest.priority());
481 484
482 blockedReason = context().canRequest( 485 blockedReason = context().canRequest(
483 factory.type(), resourceRequest, 486 factory.type(), resourceRequest,
484 MemoryCache::removeFragmentIdentifierIfNeeded(request.url()), 487 MemoryCache::removeFragmentIdentifierIfNeeded(request.url()),
485 request.options(), request.forPreload(), request.getOriginRestriction()); 488 request.options(), request.speculativePreload(),
489 request.getOriginRestriction());
486 if (blockedReason != ResourceRequestBlockedReason::None) { 490 if (blockedReason != ResourceRequestBlockedReason::None) {
487 DCHECK(!substituteData.forceSynchronousLoad()); 491 DCHECK(!substituteData.forceSynchronousLoad());
488 return Block; 492 return Block;
489 } 493 }
490 494
491 context().willStartLoadingResource( 495 context().willStartLoadingResource(
492 identifier, resourceRequest, factory.type(), 496 identifier, resourceRequest, factory.type(),
493 request.options().initiatorInfo.name, request.forPreload()); 497 request.options().initiatorInfo.name, request.speculativePreload());
494 if (!request.url().isValid()) 498 if (!request.url().isValid())
495 return Abort; 499 return Abort;
496 500
497 resourceRequest.setAllowStoredCredentials( 501 resourceRequest.setAllowStoredCredentials(
498 request.options().allowCredentials == AllowStoredCredentials); 502 request.options().allowCredentials == AllowStoredCredentials);
499 return Continue; 503 return Continue;
500 } 504 }
501 505
502 Resource* ResourceFetcher::requestResource( 506 Resource* ResourceFetcher::requestResource(
503 FetchRequest& request, 507 FetchRequest& request,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 initializeRevalidation(resourceRequest, resource); 565 initializeRevalidation(resourceRequest, resource);
562 break; 566 break;
563 case Use: 567 case Use:
564 if (resource->isLinkPreload() && !request.isLinkPreload()) 568 if (resource->isLinkPreload() && !request.isLinkPreload())
565 resource->setLinkPreload(false); 569 resource->setLinkPreload(false);
566 break; 570 break;
567 } 571 }
568 if (!resource) 572 if (!resource)
569 return nullptr; 573 return nullptr;
570 if (resource->getType() != factory.type()) { 574 if (resource->getType() != factory.type()) {
571 DCHECK(request.forPreload()); 575 DCHECK(request.speculativePreload() || request.isLinkPreload());
576 // TODO(yoav): What's the scenario where this can actually happen?
572 return nullptr; 577 return nullptr;
573 } 578 }
574 579
575 if (!resource->isAlive()) 580 if (!resource->isAlive())
576 m_deadStatsRecorder.update(policy); 581 m_deadStatsRecorder.update(policy);
577 582
578 if (policy != Use) 583 if (policy != Use)
579 resource->setIdentifier(identifier); 584 resource->setIdentifier(identifier);
580 585
581 if (!request.forPreload() || policy != Use) { 586 // TODO(yoav): It is not clear why preloads are exempt from this check. Can we
587 // remove the exemption?
588 if (!request.speculativePreload() || policy != Use) {
582 // When issuing another request for a resource that is already in-flight 589 // When issuing another request for a resource that is already in-flight
583 // make sure to not demote the priority of the in-flight request. If the new 590 // make sure to not demote the priority of the in-flight request. If the new
584 // request isn't at the same priority as the in-flight request, only allow 591 // request isn't at the same priority as the in-flight request, only allow
585 // promotions. This can happen when a visible image's priority is increased 592 // promotions. This can happen when a visible image's priority is increased
586 // and then another reference to the image is parsed (which would be at a 593 // and then another reference to the image is parsed (which would be at a
587 // lower priority). 594 // lower priority).
588 if (resourceRequest.priority() > resource->resourceRequest().priority()) 595 if (resourceRequest.priority() > resource->resourceRequest().priority())
589 resource->didChangePriority(resourceRequest.priority(), 0); 596 resource->didChangePriority(resourceRequest.priority(), 0);
597 // TODO(yoav): I'd expect the stated scenario to not go here, as its policy
598 // would be Use.
590 } 599 }
591 600
592 // If only the fragment identifiers differ, it is the same resource. 601 // If only the fragment identifiers differ, it is the same resource.
593 DCHECK(equalIgnoringFragmentIdentifier(resource->url(), request.url())); 602 DCHECK(equalIgnoringFragmentIdentifier(resource->url(), request.url()));
594 requestLoadStarted( 603 requestLoadStarted(
595 identifier, resource, request, 604 identifier, resource, request,
596 policy == Use ? ResourceLoadingFromCache : ResourceLoadingFromNetwork, 605 policy == Use ? ResourceLoadingFromCache : ResourceLoadingFromNetwork,
597 isStaticData); 606 isStaticData);
598 m_documentResources.set( 607 m_documentResources.set(
599 MemoryCache::removeFragmentIdentifierIfNeeded(request.url()), resource); 608 MemoryCache::removeFragmentIdentifierIfNeeded(request.url()), resource);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 const String cacheIdentifier = getCacheIdentifier(); 710 const String cacheIdentifier = getCacheIdentifier();
702 DCHECK(!memoryCache()->resourceForURL(request.resourceRequest().url(), 711 DCHECK(!memoryCache()->resourceForURL(request.resourceRequest().url(),
703 cacheIdentifier)); 712 cacheIdentifier));
704 713
705 RESOURCE_LOADING_DVLOG(1) << "Loading Resource for " 714 RESOURCE_LOADING_DVLOG(1) << "Loading Resource for "
706 << request.resourceRequest().url().elidedString(); 715 << request.resourceRequest().url().elidedString();
707 716
708 Resource* resource = 717 Resource* resource =
709 factory.create(request.resourceRequest(), request.options(), charset); 718 factory.create(request.resourceRequest(), request.options(), charset);
710 resource->setLinkPreload(request.isLinkPreload()); 719 resource->setLinkPreload(request.isLinkPreload());
711 if (request.forPreload()) { 720 if (request.speculativePreload()) {
712 resource->setPreloadDiscoveryTime(request.preloadDiscoveryTime()); 721 resource->setPreloadDiscoveryTime(request.preloadDiscoveryTime());
713 } 722 }
714 resource->setCacheIdentifier(cacheIdentifier); 723 resource->setCacheIdentifier(cacheIdentifier);
715 724
716 // - Don't add main resource to cache to prevent reuse. 725 // - Don't add main resource to cache to prevent reuse.
717 // - Don't add the resource if its body will not be stored. 726 // - Don't add the resource if its body will not be stored.
718 if (factory.type() != Resource::MainResource && 727 if (factory.type() != Resource::MainResource &&
719 request.options().dataBufferingPolicy != DoNotBufferData) { 728 request.options().dataBufferingPolicy != DoNotBufferData) {
720 memoryCache()->add(resource); 729 memoryCache()->add(resource);
721 } 730 }
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 if (existingResource->mustRefetchDueToIntegrityMetadata(fetchRequest)) { 813 if (existingResource->mustRefetchDueToIntegrityMetadata(fetchRequest)) {
805 RecordSriResourceIntegrityMismatchEvent(RefetchDueToIntegrityMismatch); 814 RecordSriResourceIntegrityMismatchEvent(RefetchDueToIntegrityMismatch);
806 return Reload; 815 return Reload;
807 } 816 }
808 817
809 // Service Worker's CORS fallback message must not be cached. 818 // Service Worker's CORS fallback message must not be cached.
810 if (existingResource->response().wasFallbackRequiredByServiceWorker()) 819 if (existingResource->response().wasFallbackRequiredByServiceWorker())
811 return Reload; 820 return Reload;
812 821
813 // We already have a preload going for this URL. 822 // We already have a preload going for this URL.
814 if (fetchRequest.forPreload() && existingResource->isPreloaded()) 823 if (fetchRequest.speculativePreload() && existingResource->isPreloaded())
815 return Use; 824 return Use;
816 825
817 // If the same URL has been loaded as a different type, we need to reload. 826 // If the same URL has been loaded as a different type, we need to reload.
818 if (existingResource->getType() != type) { 827 if (existingResource->getType() != type) {
819 // FIXME: If existingResource is a Preload and the new type is LinkPrefetch 828 // FIXME: If existingResource is a Preload and the new type is LinkPrefetch
820 // We really should discard the new prefetch since the preload has more 829 // We really should discard the new prefetch since the preload has more
821 // specific type information! crbug.com/379893 830 // specific type information! crbug.com/379893
822 // fast/dom/HTMLLinkElement/link-and-subresource-test hits this case. 831 // fast/dom/HTMLLinkElement/link-and-subresource-test hits this case.
823 RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::determineRevalidationPolicy " 832 RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::determineRevalidationPolicy "
824 "reloading due to type mismatch."; 833 "reloading due to type mismatch.";
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 visitor->trace(m_context); 1534 visitor->trace(m_context);
1526 visitor->trace(m_archive); 1535 visitor->trace(m_archive);
1527 visitor->trace(m_loaders); 1536 visitor->trace(m_loaders);
1528 visitor->trace(m_nonBlockingLoaders); 1537 visitor->trace(m_nonBlockingLoaders);
1529 visitor->trace(m_documentResources); 1538 visitor->trace(m_documentResources);
1530 visitor->trace(m_preloads); 1539 visitor->trace(m_preloads);
1531 visitor->trace(m_resourceTimingInfoMap); 1540 visitor->trace(m_resourceTimingInfoMap);
1532 } 1541 }
1533 1542
1534 } // namespace blink 1543 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698