Bug 1390274 - only parse URIs in the predictor when absolutely necessary. r?valentin draft
authorNicholas Hurley <hurley@mozilla.com>
Tue, 22 Aug 2017 07:43:41 -0700
changeset 652406 966218acae0f0cfcbfb508dfa51eaa46dc9c264b
parent 650074 a9d372645a32b8d23d44244f351639af9d73b96a
child 728078 cab940f1c293c475a6ba16efab938dbd947ad5cf
push id76044
push userbmo:hurley@mozilla.com
push dateThu, 24 Aug 2017 19:28:36 +0000
reviewersvalentin
bugs1390274
milestone57.0a1
Bug 1390274 - only parse URIs in the predictor when absolutely necessary. r?valentin This moves URI creation from ParseMetaDataEntry into SetupPrediction because ParseMetaDataEntry is called in way more circumstances than we actually need the URI from. Even in those cases where we might use the URI (but it's not guaranteed), we end up using the URI less often than we create one. In case it wasn't clear, SetupPrediction is the only thing called post-ParseMetaDataEntry that would require a parsed URI in the first place. SetupPrediction has the duplicated NS_NewURI calls to avoid creating URIs for those calls to SetupPrediction that are no-ops. MozReview-Commit-ID: HlhVj7p2uuk
netwerk/base/Predictor.cpp
netwerk/base/Predictor.h
--- a/netwerk/base/Predictor.cpp
+++ b/netwerk/base/Predictor.cpp
@@ -1306,19 +1306,19 @@ Predictor::CalculatePredictions(nsICache
   keysToOperateOn.SwapElements(mKeysToOperateOn);
   valuesToOperateOn.SwapElements(mValuesToOperateOn);
 
   MOZ_ASSERT(keysToOperateOn.Length() == valuesToOperateOn.Length());
   for (size_t i = 0; i < keysToOperateOn.Length(); ++i) {
     const char *key = keysToOperateOn[i].BeginReading();
     const char *value = valuesToOperateOn[i].BeginReading();
 
-    nsCOMPtr<nsIURI> uri;
+    nsCString uri;
     uint32_t hitCount, lastHit, flags;
-    if (!ParseMetaDataEntry(key, value, getter_AddRefs(uri), hitCount, lastHit, flags)) {
+    if (!ParseMetaDataEntry(key, value, uri, hitCount, lastHit, flags)) {
       // This failed, get rid of it so we don't waste space
       entry->SetMetaDataElement(key, nullptr);
       continue;
     }
 
     int32_t confidence = CalculateConfidence(hitCount, loadCount, lastHit,
                                              lastLoad, globalDegradation);
     if (fullUri) {
@@ -1346,34 +1346,52 @@ Predictor::CalculatePredictions(nsICache
     PREDICTOR_LOG(("    setting up prediction"));
     SetupPrediction(confidence, flags, uri);
   }
 }
 
 // (Maybe) adds a predictive action to the prediction runner, based on our
 // calculated confidence for the subresource in question.
 void
-Predictor::SetupPrediction(int32_t confidence, uint32_t flags, nsIURI *uri)
+Predictor::SetupPrediction(int32_t confidence, uint32_t flags, const nsCString &uri)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsAutoCString uriStr;
-  uri->GetAsciiSpec(uriStr);
+  nsresult rv = NS_OK;
   PREDICTOR_LOG(("SetupPrediction mEnablePrefetch=%d mPrefetchMinConfidence=%d "
                  "mPreconnectMinConfidence=%d mPreresolveMinConfidence=%d "
                  "flags=%d confidence=%d uri=%s", mEnablePrefetch,
                  mPrefetchMinConfidence, mPreconnectMinConfidence,
-                 mPreresolveMinConfidence, flags, confidence, uriStr.get()));
+                 mPreresolveMinConfidence, flags, confidence, uri.get()));
   if (mEnablePrefetch && (flags & FLAG_PREFETCHABLE) &&
       (mPrefetchRollingLoadCount || (confidence >= mPrefetchMinConfidence))) {
-    mPrefetches.AppendElement(uri);
+    nsCOMPtr<nsIURI> prefetchURI;
+    rv = NS_NewURI(getter_AddRefs(prefetchURI), uri, nullptr, nullptr,
+                   mIOService);
+    if (NS_SUCCEEDED(rv)) {
+      mPrefetches.AppendElement(prefetchURI);
+    }
   } else if (confidence >= mPreconnectMinConfidence) {
-    mPreconnects.AppendElement(uri);
+    nsCOMPtr<nsIURI> preconnectURI;
+    rv = NS_NewURI(getter_AddRefs(preconnectURI), uri, nullptr, nullptr,
+                   mIOService);
+    if (NS_SUCCEEDED(rv)) {
+      mPreconnects.AppendElement(preconnectURI);
+    }
   } else if (confidence >= mPreresolveMinConfidence) {
-    mPreresolves.AppendElement(uri);
+    nsCOMPtr<nsIURI> preresolveURI;
+    rv = NS_NewURI(getter_AddRefs(preresolveURI), uri, nullptr, nullptr,
+                   mIOService);
+    if (NS_SUCCEEDED(rv)) {
+      mPreresolves.AppendElement(preresolveURI);
+    }
+  }
+
+  if (NS_FAILED(rv)) {
+    PREDICTOR_LOG(("    NS_NewURI returned 0x%" PRIx32, static_cast<uint32_t>(rv)));
   }
 }
 
 nsresult
 Predictor::Prefetch(nsIURI *uri, nsIURI *referrer,
                     const OriginAttributes& originAttributes,
                     nsINetworkPredictorVerifier *verifier)
 {
@@ -1749,19 +1767,19 @@ Predictor::LearnInternal(PredictorLearnR
         keysToOperateOn.SwapElements(mKeysToOperateOn);
         valuesToOperateOn.SwapElements(mValuesToOperateOn);
 
         MOZ_ASSERT(keysToOperateOn.Length() == valuesToOperateOn.Length());
         for (size_t i = 0; i < keysToOperateOn.Length(); ++i) {
           const char *key = keysToOperateOn[i].BeginReading();
           const char *value = valuesToOperateOn[i].BeginReading();
 
-          nsCOMPtr<nsIURI> uri;
+          nsCString uri;
           uint32_t hitCount, lastHit, flags;
-          if (!ParseMetaDataEntry(nullptr, value, nullptr, hitCount, lastHit, flags)) {
+          if (!ParseMetaDataEntry(key, value, uri, hitCount, lastHit, flags)) {
             // This failed, get rid of it so we don't waste space
             entry->SetMetaDataElement(key, nullptr);
             continue;
           }
           UpdateRollingLoadCount(entry, flags, key, hitCount, lastHit);
         }
       } else {
         PREDICTOR_LOG(("    nothing to do for toplevel"));
@@ -1791,29 +1809,28 @@ Predictor::SpaceCleaner::OnMetaDataEleme
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!IsURIMetadataElement(key)) {
     // This isn't a bit of metadata we care about
     return NS_OK;
   }
 
+  nsCString uri;
   uint32_t hitCount, lastHit, flags;
-  bool ok = mPredictor->ParseMetaDataEntry(nullptr, value, nullptr,
-                                           hitCount, lastHit, flags);
+  bool ok = mPredictor->ParseMetaDataEntry(key, value, uri, hitCount, lastHit, flags);
 
   if (!ok) {
     // Couldn't parse this one, just get rid of it
     nsCString nsKey;
     nsKey.AssignASCII(key);
     mLongKeysToDelete.AppendElement(nsKey);
     return NS_OK;
   }
 
-  nsCString uri(key + (sizeof(META_DATA_PREFIX) - 1));
   uint32_t uriLength = uri.Length();
   if (uriLength > mPredictor->mMaxURILength) {
     // Default to getting rid of URIs that are too long and were put in before
     // we had our limit on URI length, in order to free up some space.
     nsCString nsKey;
     nsKey.AssignASCII(key);
     mLongKeysToDelete.AppendElement(nsKey);
     return NS_OK;
@@ -1870,18 +1887,19 @@ Predictor::LearnForSubresource(nsICacheE
     return;
   }
 
   nsCString value;
   rv = entry->GetMetaDataElement(key.BeginReading(), getter_Copies(value));
 
   uint32_t hitCount, lastHit, flags;
   bool isNewResource = (NS_FAILED(rv) ||
-                        !ParseMetaDataEntry(nullptr, value.BeginReading(),
-                                            nullptr, hitCount, lastHit, flags));
+                        !ParseMetaDataEntry(key.BeginReading(),
+                                            value.BeginReading(), uri,
+                                            hitCount, lastHit, flags));
 
   int32_t resourceCount = 0;
   if (isNewResource) {
     // This is a new addition
     PREDICTOR_LOG(("    new resource"));
     nsCString s;
     rv = entry->GetMetaDataElement(RESOURCE_META_DATA, getter_Copies(s));
     if (NS_SUCCEEDED(rv)) {
@@ -1963,17 +1981,17 @@ Predictor::LearnForStartup(nsICacheEntry
 
   // These actually do the same set of work, just on different entries, so we
   // can pass through to get the real work done here
   PREDICTOR_LOG(("Predictor::LearnForStartup"));
   LearnForSubresource(entry, targetURI);
 }
 
 bool
-Predictor::ParseMetaDataEntry(const char *key, const char *value, nsIURI **uri,
+Predictor::ParseMetaDataEntry(const char *key, const char *value, nsCString &uri,
                               uint32_t &hitCount, uint32_t &lastHit,
                               uint32_t &flags)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   PREDICTOR_LOG(("Predictor::ParseMetaDataEntry key=%s value=%s",
                  key ? key : "", value));
 
@@ -2013,22 +2031,20 @@ Predictor::ParseMetaDataEntry(const char
   PREDICTOR_LOG(("    lastHit -> %u", lastHit));
 
   value = comma + 1;
   flags = static_cast<uint32_t>(atoi(value));
   PREDICTOR_LOG(("    flags -> %u", flags));
 
   if (key) {
     const char *uriStart = key + (sizeof(META_DATA_PREFIX) - 1);
-    nsresult rv = NS_NewURI(uri, uriStart, nullptr, mIOService);
-    if (NS_FAILED(rv)) {
-      PREDICTOR_LOG(("    NS_NewURI returned 0x%" PRIX32, static_cast<uint32_t>(rv)));
-      return false;
-    }
+    uri.AssignASCII(uriStart);
     PREDICTOR_LOG(("    uri -> %s", uriStart));
+  } else {
+    uri.Truncate();
   }
 
   return true;
 }
 
 NS_IMETHODIMP
 Predictor::Reset()
 {
@@ -2672,17 +2688,24 @@ Predictor::CacheabilityAction::OnCacheEn
   PREDICTOR_LOG(("CacheabilityAction::OnCacheEntryAvailable this=%p", this));
   if (NS_FAILED(result)) {
     // Nothing to do
     PREDICTOR_LOG(("    nothing to do result=%" PRIX32 " isNew=%d",
                    static_cast<uint32_t>(result), isNew));
     return NS_OK;
   }
 
-  nsresult rv = entry->VisitMetaData(this);
+  nsCString strTargetURI;
+  nsresult rv = mTargetURI->GetAsciiSpec(strTargetURI);
+  if (NS_FAILED(rv)) {
+    PREDICTOR_LOG(("    GetAsciiSpec returned %" PRIx32, static_cast<uint32_t>(rv)));
+    return NS_OK;
+  }
+
+  rv = entry->VisitMetaData(this);
   if (NS_FAILED(rv)) {
     PREDICTOR_LOG(("    VisitMetaData returned %" PRIx32, static_cast<uint32_t>(rv)));
     return NS_OK;
   }
 
   nsTArray<nsCString> keysToCheck, valuesToCheck;
   keysToCheck.SwapElements(mKeysToCheck);
   valuesToCheck.SwapElements(mValuesToCheck);
@@ -2692,27 +2715,26 @@ Predictor::CacheabilityAction::OnCacheEn
   if (NS_SUCCEEDED(mTargetURI->GetQuery(query)) && !query.IsEmpty()) {
     hasQueryString = true;
   }
 
   MOZ_ASSERT(keysToCheck.Length() == valuesToCheck.Length());
   for (size_t i = 0; i < keysToCheck.Length(); ++i) {
     const char *key = keysToCheck[i].BeginReading();
     const char *value = valuesToCheck[i].BeginReading();
-    nsCOMPtr<nsIURI> uri;
+    nsCString uri;
     uint32_t hitCount, lastHit, flags;
 
-    if (!mPredictor->ParseMetaDataEntry(key, value, getter_AddRefs(uri),
-                                        hitCount, lastHit, flags)) {
+    if (!mPredictor->ParseMetaDataEntry(key, value, uri, hitCount, lastHit,
+                                        flags)) {
       PREDICTOR_LOG(("    failed to parse key=%s value=%s", key, value));
       continue;
     }
 
-    bool eq = false;
-    if (NS_SUCCEEDED(uri->Equals(mTargetURI, &eq)) && eq) {
+    if (strTargetURI.Equals(uri)) {
       if (mHttpStatus == 200 && mMethod.EqualsLiteral("GET") && !hasQueryString) {
         PREDICTOR_LOG(("    marking %s cacheable", key));
         flags |= FLAG_PREFETCHABLE;
       } else {
         PREDICTOR_LOG(("    marking %s uncacheable", key));
         flags &= ~FLAG_PREFETCHABLE;
       }
       nsCString newValue;
--- a/netwerk/base/Predictor.h
+++ b/netwerk/base/Predictor.h
@@ -325,18 +325,18 @@ private:
   //   * fullUri - whether we're predicting for a full URI or origin-only
   void CalculatePredictions(nsICacheEntry *entry, nsIURI *referrer,
                             uint32_t lastLoad, uint32_t loadCount,
                             int32_t globalDegradation, bool fullUri);
 
   // Used to prepare any necessary prediction for a resource on a page
   //   * confidence - value calculated by CalculateConfidence for this resource
   //   * flags - the flags taken from the resource
-  //   * uri - the URI of the resource
-  void SetupPrediction(int32_t confidence, uint32_t flags, nsIURI *uri);
+  //   * uri - the ascii spec of the URI of the resource
+  void SetupPrediction(int32_t confidence, uint32_t flags, const nsCString &uri);
 
   // Used to kick off a prefetch from RunPredictions if necessary
   //   * uri - the URI to prefetch
   //   * referrer - the URI of the referring page
   //   * originAttributes - the originAttributes of this prefetch
   //   * verifier - used for testing to ensure the expected prefetch happens
   nsresult Prefetch(nsIURI *uri, nsIURI *referrer,
                     const OriginAttributes& originAttributes,
@@ -404,21 +404,21 @@ private:
   // close to browser startup
   //   * entry - the cache entry that stores the startup page list
   //   * targetURI - the URI of a page that was loaded near browser startup
   void LearnForStartup(nsICacheEntry *entry, nsIURI *targetURI);
 
   // Used to parse the data we store in cache metadata
   //   * key - the cache metadata key
   //   * value - the cache metadata value
-  //   * uri - (out) the URI this metadata entry was about
+  //   * uri - (out) the ascii spec of the URI this metadata entry was about
   //   * hitCount - (out) the number of times this URI has been seen
   //   * lastHit - (out) timestamp of the last time this URI was seen
   //   * flags - (out) flags for this metadata entry
-  bool ParseMetaDataEntry(const char *key, const char *value, nsIURI **uri,
+  bool ParseMetaDataEntry(const char *key, const char *value, nsCString &uri,
                           uint32_t &hitCount, uint32_t &lastHit,
                           uint32_t &flags);
 
   // Used to update whether a particular URI was cacheable or not.
   // sourceURI and targetURI are the same as the arguments to Learn
   // and httpStatus is the status code we got while loading targetURI.
   void UpdateCacheabilityInternal(nsIURI *sourceURI, nsIURI *targetURI,
                                   uint32_t httpStatus, const nsCString &method,