Bug 1273882 - Don't prefetch on origin predictions. r=mayhemer draft
authorNicholas Hurley <hurley@todesschaf.org>
Wed, 08 Jun 2016 14:13:39 -0700
changeset 376835 c6be1c7119c15c00dd185be5b264c2b452453993
parent 376275 ec20b463c04f57a4bfca1edb987fcb9e9707c364
child 523271 6d75905f15b8c27f44ea1001a8cb19e6a84370c1
push id20704
push userbmo:hurley@todesschaf.org
push dateWed, 08 Jun 2016 22:19:26 +0000
reviewersmayhemer
bugs1273882
milestone50.0a1
Bug 1273882 - Don't prefetch on origin predictions. r=mayhemer MozReview-Commit-ID: 13QQarCBaRr
netwerk/base/Predictor.cpp
netwerk/base/Predictor.h
netwerk/test/unit/test_predictor.js
--- a/netwerk/base/Predictor.cpp
+++ b/netwerk/base/Predictor.cpp
@@ -137,16 +137,18 @@ static const char PREDICTOR_MAX_RESOURCE
 static const uint32_t PREDICTOR_MAX_RESOURCES_DEFAULT = 100;
 
 // This is selected in concert with max-resources-per-entry to keep memory usage
 // low-ish. The default of the combo of the two is ~50k
 static const char PREDICTOR_MAX_URI_LENGTH_PREF[] =
   "network.predictor.max-uri-length";
 static const uint32_t PREDICTOR_MAX_URI_LENGTH_DEFAULT = 500;
 
+static const char PREDICTOR_DOING_TESTS_PREF[] = "network.predictor.doing-tests";
+
 static const char PREDICTOR_CLEANED_UP_PREF[] = "network.predictor.cleaned-up";
 
 // All these time values are in sec
 static const uint32_t ONE_DAY = 86400U;
 static const uint32_t ONE_WEEK = 7U * ONE_DAY;
 static const uint32_t ONE_MONTH = 30U * ONE_DAY;
 static const uint32_t ONE_YEAR = 365U * ONE_DAY;
 
@@ -350,16 +352,17 @@ Predictor::Predictor()
   ,mPrefetchMinConfidence(PREFETCH_MIN_DEFAULT)
   ,mPreconnectMinConfidence(PRECONNECT_MIN_DEFAULT)
   ,mPreresolveMinConfidence(PRERESOLVE_MIN_DEFAULT)
   ,mRedirectLikelyConfidence(REDIRECT_LIKELY_DEFAULT)
   ,mPrefetchForceValidFor(PREFETCH_FORCE_VALID_DEFAULT)
   ,mMaxResourcesPerEntry(PREDICTOR_MAX_RESOURCES_DEFAULT)
   ,mStartupCount(1)
   ,mMaxURILength(PREDICTOR_MAX_URI_LENGTH_DEFAULT)
+  ,mDoingTests(false)
 {
   MOZ_ASSERT(!sSelf, "multiple Predictor instances!");
   sSelf = this;
 }
 
 Predictor::~Predictor()
 {
   if (mInitialized)
@@ -450,16 +453,18 @@ Predictor::InstallObserver()
                               PREDICTOR_MAX_RESOURCES_PREF,
                               PREDICTOR_MAX_RESOURCES_DEFAULT);
 
   Preferences::AddBoolVarCache(&mCleanedUp, PREDICTOR_CLEANED_UP_PREF, false);
 
   Preferences::AddUintVarCache(&mMaxURILength, PREDICTOR_MAX_URI_LENGTH_PREF,
                                PREDICTOR_MAX_URI_LENGTH_DEFAULT);
 
+  Preferences::AddBoolVarCache(&mDoingTests, PREDICTOR_DOING_TESTS_PREF, false);
+
   if (!mCleanedUp) {
     mCleanupTimer = do_CreateInstance("@mozilla.org/timer;1");
     mCleanupTimer->Init(this, 60 * 1000, nsITimer::TYPE_ONE_SHOT);
   }
 
   return rv;
 }
 
@@ -976,20 +981,20 @@ Predictor::PredictInternal(PredictorPred
   if (isNew) {
     // nothing else we can do here
     PREDICTOR_LOG(("    new entry"));
     return rv;
   }
 
   switch (reason) {
     case nsINetworkPredictor::PREDICT_LOAD:
-      rv = PredictForPageload(entry, targetURI, stackCount, verifier);
+      rv = PredictForPageload(entry, targetURI, stackCount, fullUri, verifier);
       break;
     case nsINetworkPredictor::PREDICT_STARTUP:
-      rv = PredictForStartup(entry, verifier);
+      rv = PredictForStartup(entry, fullUri, verifier);
       break;
     default:
       PREDICTOR_LOG(("    invalid reason"));
       MOZ_ASSERT(false, "Got unexpected value for prediction reason");
   }
 
   return rv;
 }
@@ -1022,17 +1027,17 @@ Predictor::PredictForLink(nsIURI *target
     verifier->OnPredictPreconnect(targetURI);
   }
 }
 
 // This is the driver for prediction based on a new pageload.
 static const uint8_t MAX_PAGELOAD_DEPTH = 10;
 bool
 Predictor::PredictForPageload(nsICacheEntry *entry, nsIURI *targetURI,
-                              uint8_t stackCount,
+                              uint8_t stackCount, bool fullUri,
                               nsINetworkPredictorVerifier *verifier)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   PREDICTOR_LOG(("Predictor::PredictForPageload"));
 
   if (stackCount > MAX_PAGELOAD_DEPTH) {
     PREDICTOR_LOG(("    exceeded recursion depth!"));
@@ -1068,33 +1073,33 @@ Predictor::PredictForPageload(nsICacheEn
                          nsICacheStorage::OPEN_SECRETLY |
                          nsICacheStorage::OPEN_PRIORITY |
                          nsICacheStorage::CHECK_MULTITHREADED;
     mCacheDiskStorage->AsyncOpenURI(redirectURI, EmptyCString(), openFlags,
                                     redirectAction);
     return RunPredictions(nullptr, verifier);
   }
 
-  CalculatePredictions(entry, targetURI, lastLoad, loadCount, globalDegradation);
+  CalculatePredictions(entry, targetURI, lastLoad, loadCount, globalDegradation, fullUri);
 
   return RunPredictions(targetURI, verifier);
 }
 
 // This is the driver for predicting at browser startup time based on pages that
 // have previously been loaded close to startup.
 bool
-Predictor::PredictForStartup(nsICacheEntry *entry,
+Predictor::PredictForStartup(nsICacheEntry *entry, bool fullUri,
                              nsINetworkPredictorVerifier *verifier)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   PREDICTOR_LOG(("Predictor::PredictForStartup"));
   int32_t globalDegradation = CalculateGlobalDegradation(mLastStartupTime);
   CalculatePredictions(entry, nullptr, mLastStartupTime, mStartupCount,
-                       globalDegradation);
+                       globalDegradation, fullUri);
   return RunPredictions(nullptr, verifier);
 }
 
 // This calculates how much to degrade our confidence in our data based on
 // the last time this top-level resource was loaded. This "global degradation"
 // applies to *all* subresources we have associated with the top-level
 // resource. This will be in addition to any reduction in confidence we have
 // associated with a particular subresource.
@@ -1237,17 +1242,17 @@ Predictor::SanitizePrefs()
   } else if (mPrefetchRollingLoadCount > kMaxPrefetchRollingLoadCount) {
     mPrefetchRollingLoadCount = kMaxPrefetchRollingLoadCount;
   }
 }
 
 void
 Predictor::CalculatePredictions(nsICacheEntry *entry, nsIURI *referrer,
                                 uint32_t lastLoad, uint32_t loadCount,
-                                int32_t globalDegradation)
+                                int32_t globalDegradation, bool fullUri)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   SanitizePrefs();
 
   // Since the visitor gets called under a cache lock, all we do there is get
   // copies of the keys/values we care about, and then do the real work here
   entry->VisitMetaData(this);
@@ -1265,19 +1270,25 @@ Predictor::CalculatePredictions(nsICache
     if (!ParseMetaDataEntry(key, value, getter_AddRefs(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);
-    UpdateRollingLoadCount(entry, flags, key, hitCount, lastHit);
+    if (fullUri) {
+      UpdateRollingLoadCount(entry, flags, key, hitCount, lastHit);
+    }
     PREDICTOR_LOG(("CalculatePredictions key=%s value=%s confidence=%d", key, value, confidence));
-    if (!referrer) {
+    if (!fullUri) {
+      // Not full URI - don't prefetch! No sense in it!
+      PREDICTOR_LOG(("    forcing non-cacheability - not full URI"));
+      flags &= ~FLAG_PREFETCHABLE;
+    } else if (!referrer) {
       // No referrer means we can't prefetch, so pretend it's non-cacheable,
       // no matter what.
       PREDICTOR_LOG(("    forcing non-cacheability - no referrer"));
       flags &= ~FLAG_PREFETCHABLE;
     } else {
       uint32_t expectedRollingLoadCount = (1 << mPrefetchRollingLoadCount) - 1;
       expectedRollingLoadCount <<= kRollingLoadOffset;
       if ((flags & expectedRollingLoadCount) != expectedRollingLoadCount) {
@@ -1640,17 +1651,17 @@ Predictor::LearnInternal(PredictorLearnR
   switch (reason) {
     case nsINetworkPredictor::LEARN_LOAD_TOPLEVEL:
       // This case only exists to be used during tests - code outside the
       // predictor tests should NEVER call Learn with LEARN_LOAD_TOPLEVEL.
       // The predictor xpcshell test needs this branch, however, because we
       // have no real page loads in xpcshell, and this is how we fake it up
       // so that all the work that normally happens behind the scenes in a
       // page load can be done for testing purposes.
-      if (fullUri) {
+      if (fullUri && mDoingTests) {
         PREDICTOR_LOG(("    WARNING - updating rolling load count. "
                        "If you see this outside tests, you did it wrong"));
         SanitizePrefs();
 
         // Since the visitor gets called under a cache lock, all we do there is get
         // copies of the keys/values we care about, and then do the real work here
         entry->VisitMetaData(this);
         nsTArray<nsCString> keysToOperateOn, valuesToOperateOn;
--- a/netwerk/base/Predictor.h
+++ b/netwerk/base/Predictor.h
@@ -260,22 +260,24 @@ private:
                       nsINetworkPredictorVerifier *verifier);
 
   // Used when predicting because a page is being loaded (which may include
   // being the target of a redirect). All arguments are the same as for
   // PredictInternal. Returns true if any predictions were queued up.
   bool PredictForPageload(nsICacheEntry *entry,
                           nsIURI *targetURI,
                           uint8_t stackCount,
+                          bool fullUri,
                           nsINetworkPredictorVerifier *verifier);
 
   // Used when predicting pages that will be used near browser startup. All
   // arguments are the same as for PredictInternal. Returns true if any
   // predictions were queued up.
   bool PredictForStartup(nsICacheEntry *entry,
+                         bool fullUri,
                          nsINetworkPredictorVerifier *verifier);
 
   // Utilities related to prediction
 
   // Used to update our rolling load count (how many of the last n loads was a
   // partular resource loaded on?)
   //   * entry - cache entry of page we're loading
   //   * flags - value that contains our rolling count as the top 20 bits (but
@@ -311,19 +313,20 @@ private:
   // Used to calculate all confidence values for all resources associated with a
   // page.
   //   * entry - the cache entry with all necessary information about this page
   //   * referrer - the URI that we are loading (may be null)
   //   * lastLoad - timestamp of the last time this page was loaded
   //   * loadCount - number of times this page has been loaded
   //   * gloablDegradation - value calculated by CalculateGlobalDegradation for
   //                         this page
+  //   * 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);
+                            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);
 
   // Used to kick off a prefetch from RunPredictions if necessary
@@ -461,15 +464,17 @@ private:
   nsCOMPtr<nsIDNSService> mDnsService;
 
   RefPtr<DNSListener> mDNSListener;
 
   nsTArray<nsCOMPtr<nsIURI>> mPrefetches;
   nsTArray<nsCOMPtr<nsIURI>> mPreconnects;
   nsTArray<nsCOMPtr<nsIURI>> mPreresolves;
 
+  bool mDoingTests;
+
   static Predictor *sSelf;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_Predictor_h
--- a/netwerk/test/unit/test_predictor.js
+++ b/netwerk/test/unit/test_predictor.js
@@ -563,30 +563,32 @@ function unregisterObserver() {
 function run_test_real() {
   tests.forEach(add_test);
   do_get_profile();
 
   Services.prefs.setBoolPref("network.predictor.enabled", true);
   Services.prefs.setBoolPref("network.predictor.cleaned-up", true);
   Services.prefs.setBoolPref("browser.cache.use_new_backend_temp", true);
   Services.prefs.setIntPref("browser.cache.use_new_backend", 1);
+  Services.prefs.setBoolPref("network.predictor.doing-tests", true);
 
   predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
 
   registerObserver();
 
   do_register_cleanup(() => {
     Services.prefs.clearUserPref("network.predictor.preconnect-min-confidence");
     Services.prefs.clearUserPref("network.predictor.enabled");
     Services.prefs.clearUserPref("network.predictor.cleaned-up");
     Services.prefs.clearUserPref("browser.cache.use_new_backend_temp");
     Services.prefs.clearUserPref("browser.cache.use_new_backend");
     Services.prefs.clearUserPref("network.predictor.preresolve-min-confidence");
     Services.prefs.clearUserPref("network.predictor.enable-prefetch");
     Services.prefs.clearUserPref("network.predictor.prefetch-rolling-load-count");
+    Services.prefs.clearUserPref("network.predictor.doing-tests");
   });
 
   run_next_test();
 }
 
 function run_test() {
   // This indirection is necessary to make e10s tests work as expected
   running_single_process = true;