bug 709976 dns async early renewal r=bz
authorPatrick McManus <mcmanus@ducksong.com>
Fri, 16 Dec 2011 21:24:12 -0500
changeset 84481 a61e49ccdf6ba726a1e1fce4881b7ae8bae6e274
parent 84480 7121c07c3e7fe15ab69e9e74e21b028837a88212
child 84482 9786d30f60b32fe7352f7e68a7cff78424cff4d6
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs709976
milestone11.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 709976 dns async early renewal r=bz
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/dns/nsHostResolver.h
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -59,16 +59,17 @@
 #include "nsIOService.h"
 
 #include "mozilla/FunctionTimer.h"
 
 using namespace mozilla;
 
 static const char kPrefDnsCacheEntries[]    = "network.dnsCacheEntries";
 static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
+static const char kPrefDnsCacheGrace[]      = "network.dnsCacheExpirationGracePeriod";
 static const char kPrefEnableIDN[]          = "network.enableIDN";
 static const char kPrefIPv4OnlyDomains[]    = "network.dns.ipv4OnlyDomains";
 static const char kPrefDisableIPv6[]        = "network.dns.disableIPv6";
 static const char kPrefDisablePrefetch[]    = "network.dns.disablePrefetch";
 
 //-----------------------------------------------------------------------------
 
 class nsDNSRecord : public nsIDNSRecord
@@ -374,32 +375,35 @@ NS_IMETHODIMP
 nsDNSService::Init()
 {
     NS_TIME_FUNCTION;
 
     NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
 
     // prefs
     PRUint32 maxCacheEntries  = 400;
-    PRUint32 maxCacheLifetime = 3; // minutes
+    PRUint32 maxCacheLifetime = 2; // minutes
+    PRUint32 lifetimeGracePeriod = 1;
     bool     enableIDN        = true;
     bool     disableIPv6      = false;
     bool     disablePrefetch  = false;
     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
     
     nsAdoptingCString ipv4OnlyDomains;
 
     // read prefs
     nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
         PRInt32 val;
         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val)))
             maxCacheEntries = (PRUint32) val;
         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val)))
             maxCacheLifetime = val / 60; // convert from seconds to minutes
+        if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheGrace, &val)))
+            lifetimeGracePeriod = val / 60; // convert from seconds to minutes
 
         // ASSUMPTION: pref branch does not modify out params on failure
         prefs->GetBoolPref(kPrefEnableIDN, &enableIDN);
         prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6);
         prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains));
         prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch);
 
         // If a manual proxy is in use, disable prefetch implicitly
@@ -408,16 +412,17 @@ nsDNSService::Init()
 
     if (mFirstTime) {
         mFirstTime = false;
 
         // register as prefs observer
         if (prefs) {
             prefs->AddObserver(kPrefDnsCacheEntries, this, false);
             prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
+            prefs->AddObserver(kPrefDnsCacheGrace, this, false);
             prefs->AddObserver(kPrefEnableIDN, this, false);
             prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
             prefs->AddObserver(kPrefDisableIPv6, this, false);
             prefs->AddObserver(kPrefDisablePrefetch, this, false);
 
             // Monitor these to see if there is a change in proxy configuration
             // If a manual proxy is in use, disable prefetch implicitly
             prefs->AddObserver("network.proxy.type", this, false);
@@ -435,16 +440,17 @@ nsDNSService::Init()
     // Don't initialize the resolver if we're in offline mode.
     // Later on, the IO service will reinitialize us when going online.
     if (gIOService->IsOffline() && !gIOService->IsComingOnline())
         return NS_OK;
 
     nsRefPtr<nsHostResolver> res;
     nsresult rv = nsHostResolver::Create(maxCacheEntries,
                                          maxCacheLifetime,
+                                         lifetimeGracePeriod,
                                          getter_AddRefs(res));
     if (NS_SUCCEEDED(rv)) {
         // now, set all of our member variables while holding the lock
         MutexAutoLock lock(mLock);
         mResolver = res;
         mIDN = idn;
         mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership
         mDisableIPv6 = disableIPv6;
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -360,19 +360,21 @@ HostDB_RemoveEntry(PLDHashTable *table,
                    void *arg)
 {
     return PL_DHASH_REMOVE;
 }
 
 //----------------------------------------------------------------------------
 
 nsHostResolver::nsHostResolver(PRUint32 maxCacheEntries,
-                               PRUint32 maxCacheLifetime)
+                               PRUint32 maxCacheLifetime,
+                               PRUint32 lifetimeGracePeriod)
     : mMaxCacheEntries(maxCacheEntries)
     , mMaxCacheLifetime(maxCacheLifetime)
+    , mGracePeriod(lifetimeGracePeriod)
     , mLock("nsHostResolver.mLock")
     , mIdleThreadCV(mLock, "nsHostResolver.mIdleThreadCV")
     , mNumIdleThreads(0)
     , mThreadCount(0)
     , mActiveAnyThreadCount(0)
     , mEvictionQSize(0)
     , mPendingCount(0)
     , mShutdown(true)
@@ -559,26 +561,34 @@ nsHostResolver::ResolveHost(const char  
                                          (PL_DHashTableOperate(&mDB, &key, PL_DHASH_ADD));
 
             // if the record is null, then HostDB_InitEntry failed.
             if (!he || !he->rec)
                 rv = NS_ERROR_OUT_OF_MEMORY;
             // do we have a cached result that we can reuse?
             else if (!(flags & RES_BYPASS_CACHE) &&
                      he->rec->HasResult() &&
-                     NowInMinutes() <= he->rec->expiration) {
+                     NowInMinutes() <= he->rec->expiration + mGracePeriod) {
+                        
                 LOG(("using cached record\n"));
                 // put reference to host record on stack...
                 result = he->rec;
+
+                // For entries that are in the grace period, or all cached
+                // negative entries, use the cache but start a new lookup in
+                // the background
+                if (((NowInMinutes() > he->rec->expiration) ||
+                     he->rec->negative) && !he->rec->resolving) {
+                    LOG(("Using %s cache entry but starting async renewal",
+                         he->rec->negative ? "negative" :"positive"));
+                    IssueLookup(he->rec);
+                }
+                
                 if (he->rec->negative) {
                     status = NS_ERROR_UNKNOWN_HOST;
-                    if (!he->rec->resolving) 
-                        // return the cached failure to the caller, but try and refresh
-                        // the record in the background
-                        IssueLookup(he->rec);
                 }
             }
             // if the host name is an IP address literal and has been parsed,
             // go ahead and use it.
             else if (he->rec->addr) {
                 result = he->rec;
             }
             // try parsing the host name as an IP address literal to short
@@ -606,16 +616,18 @@ nsHostResolver::ResolveHost(const char  
                 // Add callback to the list of pending callbacks.
                 PR_APPEND_LINK(callback, &he->rec->callbacks);
 
                 if (!he->rec->resolving) {
                     he->rec->flags = flags;
                     rv = IssueLookup(he->rec);
                     if (NS_FAILED(rv))
                         PR_REMOVE_AND_INIT_LINK(callback);
+                    else
+                        LOG(("dns lookup blocking pending getaddrinfo query"));
                 }
                 else if (he->rec->onQueue) {
                     // Consider the case where we are on a pending queue of 
                     // lower priority than the request is being made at.
                     // In that case we should upgrade to the higher queue.
 
                     if (IsHighPriority(flags) && !IsHighPriority(he->rec->flags)) {
                         // Move from (low|med) to high.
@@ -925,25 +937,27 @@ nsHostResolver::ThreadFunc(void *arg)
     LOG(("nsHostResolver::ThreadFunc exiting\n"));
 }
 
 //----------------------------------------------------------------------------
 
 nsresult
 nsHostResolver::Create(PRUint32         maxCacheEntries,
                        PRUint32         maxCacheLifetime,
+                       PRUint32         lifetimeGracePeriod,
                        nsHostResolver **result)
 {
 #if defined(PR_LOGGING)
     if (!gHostResolverLog)
         gHostResolverLog = PR_NewLogModule("nsHostResolver");
 #endif
 
     nsHostResolver *res = new nsHostResolver(maxCacheEntries,
-                                             maxCacheLifetime);
+                                             maxCacheLifetime,
+                                             lifetimeGracePeriod);
     if (!res)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(res);
 
     nsresult rv = res->Init();
     if (NS_FAILED(rv))
         NS_RELEASE(res);
 
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -197,16 +197,17 @@ public:
      */
     NS_DECL_REFCOUNTED_THREADSAFE(nsHostResolver)
 
     /**
      * creates an addref'd instance of a nsHostResolver object.
      */
     static nsresult Create(PRUint32         maxCacheEntries,  // zero disables cache
                            PRUint32         maxCacheLifetime, // minutes
+                           PRUint32         lifetimeGracePeriod, // minutes
                            nsHostResolver **resolver);
     
     /**
      * puts the resolver in the shutdown state, which will cause any pending
      * callbacks to be detached.  any future calls to ResolveHost will fail.
      */
     void Shutdown();
 
@@ -245,33 +246,35 @@ public:
         RES_BYPASS_CACHE = 1 << 0,
         RES_CANON_NAME   = 1 << 1,
         RES_PRIORITY_MEDIUM   = 1 << 2,
         RES_PRIORITY_LOW  = 1 << 3,
         RES_SPECULATE     = 1 << 4   
     };
 
 private:
-    nsHostResolver(PRUint32 maxCacheEntries=50, PRUint32 maxCacheLifetime=1);
+    nsHostResolver(PRUint32 maxCacheEntries = 50, PRUint32 maxCacheLifetime = 1,
+                   PRUint32 lifetimeGracePeriod = 0);
    ~nsHostResolver();
 
     nsresult Init();
     nsresult IssueLookup(nsHostRecord *);
     bool     GetHostToLookup(nsHostRecord **m);
     void     OnLookupComplete(nsHostRecord *, nsresult, PRAddrInfo *);
     void     DeQueue(PRCList &aQ, nsHostRecord **aResult);
     void     ClearPendingQueue(PRCList *aPendingQueue);
     nsresult ConditionallyCreateThread(nsHostRecord *rec);
     
     static void  MoveQueue(nsHostRecord *aRec, PRCList &aDestQ);
     
     static void ThreadFunc(void *);
 
     PRUint32      mMaxCacheEntries;
     PRUint32      mMaxCacheLifetime;
+    PRUint32      mGracePeriod;
     Mutex         mLock;
     CondVar       mIdleThreadCV;
     PRUint32      mNumIdleThreads;
     PRUint32      mThreadCount;
     PRUint32      mActiveAnyThreadCount;
     PLDHashTable  mDB;
     PRCList       mHighQ;
     PRCList       mMediumQ;