Bug 1358038 - "Add "Race Cache With Network" status to netmonitor" r=Honza
authorMichal Novotny <michal.novotny>
Mon, 15 Apr 2019 05:52:00 +0300
changeset 470280 f1455cdc78edbbc11dda951ef0944e3cd387fb12
parent 470279 17f5cadc3b29caeb321b4a14f49c8f06596dd64f
child 470281 c06f27cbfe40d9f05272813d63680b8e73b1e370
push id35892
push userrgurzau@mozilla.com
push dateSat, 20 Apr 2019 09:55:32 +0000
treeherdermozilla-central@a092972b53f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1358038
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1358038 - "Add "Race Cache With Network" status to netmonitor" r=Honza
netwerk/base/nsICacheInfoChannel.idl
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/InterceptedHttpChannel.cpp
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/test/unit/test_race_cache_with_network.js
--- a/netwerk/base/nsICacheInfoChannel.idl
+++ b/netwerk/base/nsICacheInfoChannel.idl
@@ -51,16 +51,25 @@ interface nsICacheInfoChannel : nsISuppo
   /**
    * TRUE if this channel's data is being loaded from the cache.  This value
    * is undefined before the channel fires its OnStartRequest notification
    * and after the channel fires its OnStopRequest notification.
    */
   boolean isFromCache();
 
   /**
+   * Returns true if the channel raced the cache and network requests.
+   * In order to determine if the response is coming from the cache or the
+   * network, the consumer can check isFromCache().
+   * The method can only be called after the channel fires its OnStartRequest
+   * notification.
+   */
+  boolean isRacing();
+
+  /**
    * The unique ID of the corresponding nsICacheEntry from which the response is
    * retrieved. By comparing the returned value, we can judge whether the data
    * of two distinct nsICacheInfoChannels is from the same nsICacheEntry. This
    * scenario could be useful when verifying whether the alternative data from
    * one nsICacheInfochannel matches the main data from another one.
    *
    * Note: NS_ERROR_NOT_AVAILABLE is thrown when a nsICacheInfoChannel has no
    * valid corresponding nsICacheEntry.
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -169,16 +169,17 @@ HttpChannelChild::HttpChannelChild()
       mCacheFetchCount(0),
       mCacheExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME),
       mDeletingChannelSent(false),
       mIPCOpen(false),
       mUnknownDecoderInvolved(false),
       mDivertingToParent(false),
       mFlushedForDiversion(false),
       mIsFromCache(false),
+      mIsRacing(false),
       mCacheNeedToReportBytesReadInitialized(false),
       mNeedToReportBytesRead(true),
       mCacheEntryAvailable(false),
       mAltDataCacheEntryAvailable(false),
       mSendResumeAt(false),
       mKeptAlive(false),
       mIPCActorDeleted(false),
       mSuspendSent(false),
@@ -394,31 +395,33 @@ void HttpChannelChild::AssociateApplicat
 
 class StartRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
  public:
   StartRequestEvent(
       HttpChannelChild* aChild, const nsresult& aChannelStatus,
       const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead,
       const nsHttpHeaderArray& aRequestHeaders,
       const ParentLoadInfoForwarderArgs& loadInfoForwarder,
-      const bool& aIsFromCache, const bool& aCacheEntryAvailable,
-      const uint64_t& aCacheEntryId, const int32_t& aCacheFetchCount,
-      const uint32_t& aCacheExpirationTime, const nsCString& aCachedCharset,
+      const bool& aIsFromCache, const bool& aIsRacing,
+      const bool& aCacheEntryAvailable, const uint64_t& aCacheEntryId,
+      const int32_t& aCacheFetchCount, const uint32_t& aCacheExpirationTime,
+      const nsCString& aCachedCharset,
       const nsCString& aSecurityInfoSerialization, const NetAddr& aSelfAddr,
       const NetAddr& aPeerAddr, const uint32_t& aCacheKey,
       const nsCString& altDataType, const int64_t& altDataLen,
       const bool& deliveringAltData, const bool& aApplyConversion,
       const ResourceTimingStruct& aTiming)
       : NeckoTargetChannelEvent<HttpChannelChild>(aChild),
         mChannelStatus(aChannelStatus),
         mResponseHead(aResponseHead),
         mRequestHeaders(aRequestHeaders),
         mUseResponseHead(aUseResponseHead),
         mApplyConversion(aApplyConversion),
         mIsFromCache(aIsFromCache),
+        mIsRacing(aIsRacing),
         mCacheEntryAvailable(aCacheEntryAvailable),
         mCacheEntryId(aCacheEntryId),
         mCacheFetchCount(aCacheFetchCount),
         mCacheExpirationTime(aCacheExpirationTime),
         mCachedCharset(aCachedCharset),
         mSecurityInfoSerialization(aSecurityInfoSerialization),
         mSelfAddr(aSelfAddr),
         mPeerAddr(aPeerAddr),
@@ -428,30 +431,31 @@ class StartRequestEvent : public NeckoTa
         mDeliveringAltData(deliveringAltData),
         mLoadInfoForwarder(loadInfoForwarder),
         mTiming(aTiming) {}
 
   void Run() override {
     LOG(("StartRequestEvent [this=%p]\n", mChild));
     mChild->OnStartRequest(
         mChannelStatus, mResponseHead, mUseResponseHead, mRequestHeaders,
-        mLoadInfoForwarder, mIsFromCache, mCacheEntryAvailable, mCacheEntryId,
-        mCacheFetchCount, mCacheExpirationTime, mCachedCharset,
+        mLoadInfoForwarder, mIsFromCache, mIsRacing, mCacheEntryAvailable,
+        mCacheEntryId, mCacheFetchCount, mCacheExpirationTime, mCachedCharset,
         mSecurityInfoSerialization, mSelfAddr, mPeerAddr, mCacheKey,
         mAltDataType, mAltDataLen, mDeliveringAltData, mApplyConversion,
         mTiming);
   }
 
  private:
   nsresult mChannelStatus;
   nsHttpResponseHead mResponseHead;
   nsHttpHeaderArray mRequestHeaders;
   bool mUseResponseHead;
   bool mApplyConversion;
   bool mIsFromCache;
+  bool mIsRacing;
   bool mCacheEntryAvailable;
   uint64_t mCacheEntryId;
   int32_t mCacheFetchCount;
   uint32_t mCacheExpirationTime;
   nsCString mCachedCharset;
   nsCString mSecurityInfoSerialization;
   NetAddr mSelfAddr;
   NetAddr mPeerAddr;
@@ -462,41 +466,42 @@ class StartRequestEvent : public NeckoTa
   ParentLoadInfoForwarderArgs mLoadInfoForwarder;
   ResourceTimingStruct mTiming;
 };
 
 mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequest(
     const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
     const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
-    const bool& isFromCache, const bool& cacheEntryAvailable,
-    const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
-    const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
-    const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
-    const NetAddr& peerAddr, const int16_t& redirectCount,
-    const uint32_t& cacheKey, const nsCString& altDataType,
-    const int64_t& altDataLen, const bool& deliveringAltData,
-    const bool& aApplyConversion, const ResourceTimingStruct& aTiming) {
+    const bool& isFromCache, const bool& isRacing,
+    const bool& cacheEntryAvailable, const uint64_t& cacheEntryId,
+    const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime,
+    const nsCString& cachedCharset, const nsCString& securityInfoSerialization,
+    const NetAddr& selfAddr, const NetAddr& peerAddr,
+    const int16_t& redirectCount, const uint32_t& cacheKey,
+    const nsCString& altDataType, const int64_t& altDataLen,
+    const bool& deliveringAltData, const bool& aApplyConversion,
+    const ResourceTimingStruct& aTiming) {
   AUTO_PROFILER_LABEL("HttpChannelChild::RecvOnStartRequest", NETWORK);
   LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this));
   // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   // stage, as they are set in the listener's OnStartRequest.
   MOZ_RELEASE_ASSERT(
       !mFlushedForDiversion,
       "mFlushedForDiversion should be unset before OnStartRequest!");
   MOZ_RELEASE_ASSERT(
       !mDivertingToParent,
       "mDivertingToParent should be unset before OnStartRequest!");
 
   mRedirectCount = redirectCount;
 
   mEventQ->RunOrEnqueue(new StartRequestEvent(
       this, channelStatus, responseHead, useResponseHead, requestHeaders,
-      loadInfoForwarder, isFromCache, cacheEntryAvailable, cacheEntryId,
-      cacheFetchCount, cacheExpirationTime, cachedCharset,
+      loadInfoForwarder, isFromCache, isRacing, cacheEntryAvailable,
+      cacheEntryId, cacheFetchCount, cacheExpirationTime, cachedCharset,
       securityInfoSerialization, selfAddr, peerAddr, cacheKey, altDataType,
       altDataLen, deliveringAltData, aApplyConversion, aTiming));
 
   {
     // Child's mEventQ is to control the execution order of the IPC messages
     // from both main thread IPDL and PBackground IPDL.
     // To guarantee the ordering, PBackground IPC messages that are sent after
     // OnStartRequest will be throttled until OnStartRequest hits the Child's
@@ -515,21 +520,21 @@ mozilla::ipc::IPCResult HttpChannelChild
 
   return IPC_OK();
 }
 
 void HttpChannelChild::OnStartRequest(
     const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
     const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
-    const bool& isFromCache, const bool& cacheEntryAvailable,
-    const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
-    const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
-    const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
-    const NetAddr& peerAddr, const uint32_t& cacheKey,
+    const bool& isFromCache, const bool& isRacing,
+    const bool& cacheEntryAvailable, const uint64_t& cacheEntryId,
+    const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime,
+    const nsCString& cachedCharset, const nsCString& securityInfoSerialization,
+    const NetAddr& selfAddr, const NetAddr& peerAddr, const uint32_t& cacheKey,
     const nsCString& altDataType, const int64_t& altDataLen,
     const bool& deliveringAltData, const bool& aApplyConversion,
     const ResourceTimingStruct& aTiming) {
   LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this));
 
   // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   // stage, as they are set in the listener's OnStartRequest.
   MOZ_RELEASE_ASSERT(
@@ -564,16 +569,17 @@ void HttpChannelChild::OnStartRequest(
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
                           "Deserializing security info should not fail");
     Unused << rv;  // So we don't get an unused error in release builds.
   }
 
   ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo);
 
   mIsFromCache = isFromCache;
+  mIsRacing = isRacing;
   mCacheEntryAvailable = cacheEntryAvailable;
   mCacheEntryId = cacheEntryId;
   mCacheFetchCount = cacheFetchCount;
   mCacheExpirationTime = cacheExpirationTime;
   mCachedCharset = cachedCharset;
   mSelfAddr = selfAddr;
   mPeerAddr = peerAddr;
 
@@ -2996,16 +3002,25 @@ HttpChannelChild::GetCacheEntryId(uint64
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   *aCacheEntryId = mCacheEntryId;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpChannelChild::IsRacing(bool* aIsRacing) {
+  if (!mAfterOnStartRequestBegun) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  *aIsRacing = mIsRacing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpChannelChild::GetCacheKey(uint32_t* cacheKey) {
   MOZ_ASSERT(NS_IsMainThread());
   if (mSynthesizedCacheInfo) {
     return mSynthesizedCacheInfo->GetCacheKey(cacheKey);
   }
 
   *cacheKey = mCacheKey;
   return NS_OK;
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -133,19 +133,20 @@ class HttpChannelChild final : public PH
 
   nsresult CrossProcessRedirectFinished(nsresult aStatus);
 
  protected:
   mozilla::ipc::IPCResult RecvOnStartRequest(
       const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
       const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
       const ParentLoadInfoForwarderArgs& loadInfoForwarder,
-      const bool& isFromCache, const bool& cacheEntryAvailable,
-      const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
-      const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
+      const bool& isFromCache, const bool& isRacing,
+      const bool& cacheEntryAvailable, const uint64_t& cacheEntryId,
+      const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime,
+      const nsCString& cachedCharset,
       const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
       const NetAddr& peerAddr, const int16_t& redirectCount,
       const uint32_t& cacheKey, const nsCString& altDataType,
       const int64_t& altDataLen, const bool& deliveringAltData,
       const bool& aApplyConversion,
       const ResourceTimingStruct& aTiming) override;
   mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override;
   mozilla::ipc::IPCResult RecvRedirect1Begin(
@@ -397,16 +398,17 @@ class HttpChannelChild final : public PH
 
   // Once set, OnData and possibly OnStop will be diverted to the parent.
   Atomic<bool, ReleaseAcquire> mDivertingToParent;
   // Once set, no OnStart/OnData/OnStop callbacks should be received from the
   // parent channel, nor dequeued from the ChannelEventQueue.
   Atomic<bool, ReleaseAcquire> mFlushedForDiversion;
 
   Atomic<bool, SequentiallyConsistent> mIsFromCache;
+  Atomic<bool, SequentiallyConsistent> mIsRacing;
   // Set if we get the result and cache |mNeedToReportBytesRead|
   Atomic<bool, SequentiallyConsistent> mCacheNeedToReportBytesReadInitialized;
   // True if we need to tell the parent the size of unreported received data
   Atomic<bool, SequentiallyConsistent> mNeedToReportBytesRead;
 
   uint8_t mCacheEntryAvailable : 1;
   uint8_t mAltDataCacheEntryAvailable : 1;
 
@@ -458,19 +460,20 @@ class HttpChannelChild final : public PH
   bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
 
   void AssociateApplicationCache(const nsCString& groupID,
                                  const nsCString& clientID);
   void OnStartRequest(
       const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
       const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
       const ParentLoadInfoForwarderArgs& loadInfoForwarder,
-      const bool& isFromCache, const bool& cacheEntryAvailable,
-      const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
-      const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
+      const bool& isFromCache, const bool& isRacing,
+      const bool& cacheEntryAvailable, const uint64_t& cacheEntryId,
+      const int32_t& cacheFetchCount, const uint32_t& cacheExpirationTime,
+      const nsCString& cachedCharset,
       const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
       const NetAddr& peerAddr, const uint32_t& cacheKey,
       const nsCString& altDataType, const int64_t& altDataLen,
       const bool& deliveringAltData, const bool& aApplyConversion,
       const ResourceTimingStruct& aTiming);
   void MaybeDivertOnData(const nsCString& data, const uint64_t& offset,
                          const uint32_t& count);
   void OnTransportAndData(const nsresult& channelStatus, const nsresult& status,
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1359,25 +1359,27 @@ HttpChannelParent::OnStartRequest(nsIReq
     MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed");
     DebugOnly<nsresult> rv =
         static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpDocumentForChild(
             chan);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   bool isFromCache = false;
+  bool isRacing = false;
   uint64_t cacheEntryId = 0;
   int32_t fetchCount = 0;
   uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
   nsCString cachedCharset;
 
   RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(chan);
 
   if (httpChannelImpl) {
     httpChannelImpl->IsFromCache(&isFromCache);
+    httpChannelImpl->IsRacing(&isRacing);
     httpChannelImpl->GetCacheEntryId(&cacheEntryId);
     httpChannelImpl->GetCacheTokenFetchCount(&fetchCount);
     httpChannelImpl->GetCacheTokenExpirationTime(&expirationTime);
     httpChannelImpl->GetCacheTokenCachedCharset(cachedCharset);
   }
 
   bool loadedFromApplicationCache = false;
 
@@ -1468,21 +1470,21 @@ HttpChannelParent::OnStartRequest(nsIReq
   ResourceTimingStruct timing;
   GetTimingAttributes(mChannel, timing);
 
   rv = NS_OK;
   if (mIPCClosed ||
       !SendOnStartRequest(
           channelStatus, *responseHead, useResponseHead,
           cleanedUpRequest ? cleanedUpRequestHeaders : requestHead->Headers(),
-          loadInfoForwarderArg, isFromCache, mCacheEntry ? true : false,
-          cacheEntryId, fetchCount, expirationTime, cachedCharset,
-          secInfoSerialization, chan->GetSelfAddr(), chan->GetPeerAddr(),
-          redirectCount, cacheKey, altDataType, altDataLen, deliveringAltData,
-          applyConversion, timing)) {
+          loadInfoForwarderArg, isFromCache, isRacing,
+          mCacheEntry ? true : false, cacheEntryId, fetchCount, expirationTime,
+          cachedCharset, secInfoSerialization, chan->GetSelfAddr(),
+          chan->GetPeerAddr(), redirectCount, cacheKey, altDataType, altDataLen,
+          deliveringAltData, applyConversion, timing)) {
     rv = NS_ERROR_UNEXPECTED;
   }
   requestHead->Exit();
 
   // OnStartRequest is sent to content process successfully.
   // Notify PHttpBackgroundChannelChild that all following IPC mesasges
   // should be run after OnStartRequest is handled.
   if (NS_SUCCEEDED(rv)) {
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -1171,16 +1171,25 @@ InterceptedHttpChannel::IsFromCache(bool
   if (mSynthesizedCacheInfo) {
     return mSynthesizedCacheInfo->IsFromCache(value);
   }
   *value = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+InterceptedHttpChannel::IsRacing(bool* value) {
+  if (mSynthesizedCacheInfo) {
+    return mSynthesizedCacheInfo->IsRacing(value);
+  }
+  *value = false;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 InterceptedHttpChannel::GetCacheEntryId(uint64_t* aCacheEntryId) {
   if (mSynthesizedCacheInfo) {
     return mSynthesizedCacheInfo->GetCacheEntryId(aCacheEntryId);
   }
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -107,16 +107,17 @@ parent:
 
 child:
   async OnStartRequest(nsresult            channelStatus,
                        nsHttpResponseHead  responseHead,
                        bool                useResponseHead,
                        nsHttpHeaderArray   requestHeaders,
                        ParentLoadInfoForwarderArgs loadInfoForwarder,
                        bool                isFromCache,
+                       bool                isRacing,
                        bool                cacheEntryAvailable,
                        uint64_t            cacheEntryId,
                        int32_t             cacheFetchCount,
                        uint32_t            cacheExpirationTime,
                        nsCString           cachedCharset,
                        nsCString           securityInfoSerialization,
                        NetAddr             selfAddr,
                        NetAddr             peerAddr,
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -8658,16 +8658,25 @@ nsHttpChannel::GetAltDataInputStream(con
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsICachingChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
+nsHttpChannel::IsRacing(bool *aIsRacing) {
+  if (!mAfterOnStartRequestBegun) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  *aIsRacing = mRaceCacheWithNetwork;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsHttpChannel::GetCacheToken(nsISupports **token) {
   NS_ENSURE_ARG_POINTER(token);
   if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
   return CallQueryInterface(mCacheEntry, token);
 }
 
 NS_IMETHODIMP
 nsHttpChannel::SetCacheToken(nsISupports *token) {
--- a/netwerk/test/unit/test_race_cache_with_network.js
+++ b/netwerk/test/unit/test_race_cache_with_network.js
@@ -53,16 +53,17 @@ function cached_handler(metadata, respon
   g200Counter++;
 }
 
 let gResponseCounter = 0;
 let gIsFromCache = 0;
 function checkContent(request, buffer, context, isFromCache)
 {
   Assert.equal(buffer, gResponseBody);
+  info("isRacing: " + request.QueryInterface(Ci.nsICacheInfoChannel).isRacing() + "\n");
   gResponseCounter++;
   if (isFromCache) {
     gIsFromCache++;
   }
   executeSoon(() => { testGenerator.next(); });
 }
 
 function run_test() {