diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5cdb1c6d0e2f..b0e01b2a253a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1835,6 +1835,7 @@ pref("network.http.rcwn.cache_queue_priority_threshold", 2); // is smaller than this size. pref("network.http.rcwn.small_resource_size_kb", 256); +pref("network.http.rcwn.min_wait_before_racing_ms", 0); pref("network.http.rcwn.max_wait_before_racing_ms", 500); // The ratio of the transaction count for the focused window and the count of diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f430769d643d..35a0783ae4c7 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -128,6 +128,7 @@ static bool sRCWNEnabled = false; static uint32_t sRCWNQueueSizeNormal = 50; static uint32_t sRCWNQueueSizePriority = 10; static uint32_t sRCWNSmallResourceSizeKB = 256; +static uint32_t sRCWNMinWaitMs = 0; static uint32_t sRCWNMaxWaitMs = 500; // True if the local cache should be bypassed when processing a request. @@ -625,7 +626,7 @@ nsHttpChannel::ConnectOnTailUnblock() Unused << ReadFromCache(true); } - return TriggerNetwork(0); + return TriggerNetwork(); } nsresult @@ -4513,7 +4514,7 @@ nsHttpChannel::OnCacheEntryAvailableInternal(nsICacheEntry *entry, Unused << ReadFromCache(true); } - return TriggerNetwork(0); + return TriggerNetwork(); } nsresult @@ -6134,6 +6135,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context) Preferences::AddUintVarCache(&sRCWNQueueSizeNormal, "network.http.rcwn.cache_queue_normal_threshold"); Preferences::AddUintVarCache(&sRCWNQueueSizePriority, "network.http.rcwn.cache_queue_priority_threshold"); Preferences::AddUintVarCache(&sRCWNSmallResourceSizeKB, "network.http.rcwn.small_resource_size_kb"); + Preferences::AddUintVarCache(&sRCWNMinWaitMs, "network.http.rcwn.min_wait_before_racing_ms"); Preferences::AddUintVarCache(&sRCWNMaxWaitMs, "network.http.rcwn.max_wait_before_racing_ms"); } @@ -9302,7 +9304,43 @@ nsHttpChannel::Test_triggerDelayedOpenCacheEntry() } nsresult -nsHttpChannel::TriggerNetwork(int32_t aTimeout) +nsHttpChannel::TriggerNetworkWithDelay(uint32_t aDelay) +{ + MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread"); + + LOG(("nsHttpChannel::TriggerNetworkWithDelay [this=%p, delay=%u]\n", + this, aDelay)); + + if (mCanceled) { + LOG((" channel was canceled.\n")); + return mStatus; + } + + // If a network request has already gone out, there is no point in + // doing this again. + if (mNetworkTriggered) { + LOG((" network already triggered. Returning.\n")); + return NS_OK; + } + + if (!aDelay) { + // We cannot call TriggerNetwork() directly here, because it would + // cause performance regression in tp6 tests, see bug 1398847. + return NS_DispatchToMainThread( + NewRunnableMethod("net::nsHttpChannel::TriggerNetworkWithDelay", + this, &nsHttpChannel::TriggerNetwork), + NS_DISPATCH_NORMAL); + } + + if (!mNetworkTriggerTimer) { + mNetworkTriggerTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + } + mNetworkTriggerTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_ONE_SHOT); + return NS_OK; +} + +nsresult +nsHttpChannel::TriggerNetwork() { MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread"); @@ -9320,36 +9358,29 @@ nsHttpChannel::TriggerNetwork(int32_t aTimeout) return NS_OK; } - if (!aTimeout) { - mNetworkTriggered = true; - if (mNetworkTriggerTimer) { - mNetworkTriggerTimer->Cancel(); - mNetworkTriggerTimer = nullptr; - } - - // If we are waiting for a proxy request, that means we can't trigger - // the next step just yet. We need for mConnectionInfo to be non-null - // before we call TryHSTSPriming. OnProxyAvailable will trigger - // BeginConnect, and Connect will call TryHSTSPriming even if it's - // for the cache callbacks. - if (mProxyRequest) { - LOG((" proxy request in progress. Delaying network trigger.\n")); - mWaitingForProxy = true; - return NS_OK; - } - - if (mCacheAsyncOpenCalled && !mOnCacheAvailableCalled) { - mRaceCacheWithNetwork = true; - } - - LOG((" triggering network\n")); - return TryHSTSPriming(); + mNetworkTriggered = true; + if (mNetworkTriggerTimer) { + mNetworkTriggerTimer->Cancel(); + mNetworkTriggerTimer = nullptr; } - LOG((" setting timer to trigger network: %d ms\n", aTimeout)); - mNetworkTriggerTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - mNetworkTriggerTimer->InitWithCallback(this, aTimeout, nsITimer::TYPE_ONE_SHOT); - return NS_OK; + // If we are waiting for a proxy request, that means we can't trigger + // the next step just yet. We need for mConnectionInfo to be non-null + // before we call TryHSTSPriming. OnProxyAvailable will trigger + // BeginConnect, and Connect will call TryHSTSPriming even if it's + // for the cache callbacks. + if (mProxyRequest) { + LOG((" proxy request in progress. Delaying network trigger.\n")); + mWaitingForProxy = true; + return NS_OK; + } + + if (mCacheAsyncOpenCalled && !mOnCacheAvailableCalled) { + mRaceCacheWithNetwork = true; + } + + LOG((" triggering network\n")); + return TryHSTSPriming(); } nsresult @@ -9380,23 +9411,22 @@ nsHttpChannel::MaybeRaceCacheWithNetwork() // We use microseconds in CachePerfStats but we need milliseconds // for TriggerNetwork. mRaceDelay /= 1000; - if (mRaceDelay > sRCWNMaxWaitMs) { - mRaceDelay = sRCWNMaxWaitMs; - } } - MOZ_ASSERT(sRCWNEnabled, "The pref must be truned on."); + mRaceDelay = clamped(mRaceDelay, sRCWNMinWaitMs, sRCWNMaxWaitMs); + + MOZ_ASSERT(sRCWNEnabled, "The pref must be turned on."); LOG(("nsHttpChannel::MaybeRaceCacheWithNetwork [this=%p, delay=%u]\n", this, mRaceDelay)); - return TriggerNetwork(mRaceDelay); + return TriggerNetworkWithDelay(mRaceDelay); } NS_IMETHODIMP nsHttpChannel::Test_triggerNetwork(int32_t aTimeout) { MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread"); - return TriggerNetwork(aTimeout); + return TriggerNetworkWithDelay(aTimeout); } NS_IMETHODIMP @@ -9406,7 +9436,7 @@ nsHttpChannel::Notify(nsITimer *aTimer) if (aTimer == mCacheOpenTimer) { return Test_triggerDelayedOpenCacheEntry(); } else if (aTimer == mNetworkTriggerTimer) { - return TriggerNetwork(0); + return TriggerNetwork(); } else { MOZ_CRASH("Unknown timer"); } diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 2059044a0ca8..ab2d28dc42ae 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -722,7 +722,8 @@ private: // with the cache fetch, and proceeds to do so. nsresult MaybeRaceCacheWithNetwork(); - nsresult TriggerNetwork(int32_t aTimeout); + nsresult TriggerNetworkWithDelay(uint32_t aDelay); + nsresult TriggerNetwork(); void CancelNetworkRequest(nsresult aStatus); // Timer used to delay the network request, or to trigger the network // request if retrieving the cache entry takes too long.