bug 1094522 - claim conns with null transactions instead of starting new ones r=hurley
authorPatrick McManus <mcmanus@ducksong.com>
Tue, 27 Jan 2015 21:55:38 -0500
changeset 226377 050e9b432799
parent 226376 b6d3a8960d38
child 226378 c665e2057216
push id28194
push userkwierso@gmail.com
push date2015-01-29 02:10 +0000
treeherdermozilla-central@ea54e6623f59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershurley
bugs1094522
milestone38.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 1094522 - claim conns with null transactions instead of starting new ones r=hurley
netwerk/protocol/http/NullHttpTransaction.cpp
netwerk/protocol/http/NullHttpTransaction.h
netwerk/protocol/http/TunnelUtils.cpp
netwerk/protocol/http/TunnelUtils.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
--- a/netwerk/protocol/http/NullHttpTransaction.cpp
+++ b/netwerk/protocol/http/NullHttpTransaction.cpp
@@ -92,16 +92,17 @@ NS_IMPL_ISUPPORTS(NullHttpTransaction, N
 NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo *ci,
                                          nsIInterfaceRequestor *callbacks,
                                          uint32_t caps)
   : mStatus(NS_OK)
   , mCaps(caps | NS_HTTP_ALLOW_KEEPALIVE)
   , mCapsToClear(0)
   , mRequestHead(nullptr)
   , mIsDone(false)
+  , mClaimed(false)
   , mCallbacks(callbacks)
   , mConnectionInfo(ci)
 {
   nsresult rv;
   mActivityDistributor = do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID,
                                        &rv);
   if (NS_FAILED(rv)) {
     return;
@@ -121,16 +122,26 @@ NullHttpTransaction::NullHttpTransaction
 }
 
 NullHttpTransaction::~NullHttpTransaction()
 {
   mCallbacks = nullptr;
   delete mRequestHead;
 }
 
+bool
+NullHttpTransaction::Claim()
+{
+  if (mClaimed) {
+    return false;
+  }
+  mClaimed = true;
+  return true;
+}
+
 void
 NullHttpTransaction::SetConnection(nsAHttpConnection *conn)
 {
   mConnection = conn;
 }
 
 nsAHttpConnection *
 NullHttpTransaction::Connection()
--- a/netwerk/protocol/http/NullHttpTransaction.h
+++ b/netwerk/protocol/http/NullHttpTransaction.h
@@ -33,18 +33,21 @@ public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NULLHTTPTRANSACTION_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSAHTTPTRANSACTION
 
   NullHttpTransaction(nsHttpConnectionInfo *ci,
                       nsIInterfaceRequestor *callbacks,
                       uint32_t caps);
 
+  bool Claim();
+
   // Overload of nsAHttpTransaction methods
   bool IsNullTransaction() MOZ_OVERRIDE MOZ_FINAL { return true; }
+  NullHttpTransaction *QueryNullTransaction() MOZ_OVERRIDE MOZ_FINAL { return this; }
   bool ResponseTimeoutEnabled() const MOZ_OVERRIDE MOZ_FINAL {return true; }
   PRIntervalTime ResponseTimeout() MOZ_OVERRIDE MOZ_FINAL
   {
     return PR_SecondsToInterval(15);
   }
 
 protected:
   virtual ~NullHttpTransaction();
@@ -57,16 +60,17 @@ private:
   // mCapsToClear holds flags that should be cleared in mCaps, e.g. unset
   // NS_HTTP_REFRESH_DNS when DNS refresh request has completed to avoid
   // redundant requests on the network. To deal with raciness, only unsetting
   // bitfields should be allowed: 'lost races' will thus err on the
   // conservative side, e.g. by going ahead with a 2nd DNS refresh.
   uint32_t mCapsToClear;
   nsHttpRequestHead *mRequestHead;
   bool mIsDone;
+  bool mClaimed;
 
 protected:
   nsRefPtr<nsAHttpConnection> mConnection;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
   nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
 };
 
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -745,16 +745,25 @@ bool
 TLSFilterTransaction::IsNullTransaction()
 {
   if (!mTransaction) {
     return false;
   }
   return mTransaction->IsNullTransaction();
 }
 
+NullHttpTransaction *
+TLSFilterTransaction::QueryNullTransaction()
+{
+  if (!mTransaction) {
+    return nullptr;
+  }
+  return mTransaction->QueryNullTransaction();
+}
+
 nsHttpTransaction *
 TLSFilterTransaction::QueryHttpTransaction()
 {
   if (!mTransaction) {
     return nullptr;
   }
   return mTransaction->QueryHttpTransaction();
 }
--- a/netwerk/protocol/http/TunnelUtils.h
+++ b/netwerk/protocol/http/TunnelUtils.h
@@ -80,16 +80,17 @@ the encrypted text available in mOutputD
 
 **************************************************************************/
 
 struct PRSocketOptionData;
 
 namespace mozilla { namespace net {
 
 class nsHttpRequestHead;
+class NullHttpTransaction;
 class TLSFilterTransaction;
 
 class NudgeTunnelCallback : public nsISupports
 {
 public:
   virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
 };
 
@@ -122,16 +123,17 @@ public:
   void     newIODriver(nsIAsyncInputStream *aSocketIn,
                        nsIAsyncOutputStream *aSocketOut,
                        nsIAsyncInputStream **outSocketIn,
                        nsIAsyncOutputStream **outSocketOut);
 
   // nsAHttpTransaction overloads
   nsHttpPipeline *QueryPipeline() MOZ_OVERRIDE;
   bool IsNullTransaction() MOZ_OVERRIDE;
+  NullHttpTransaction *QueryNullTransaction() MOZ_OVERRIDE;
   nsHttpTransaction *QueryHttpTransaction() MOZ_OVERRIDE;
   SpdyConnectTransaction *QuerySpdyConnectTransaction() MOZ_OVERRIDE;
 
 private:
   nsresult StartTimerCallback();
   void Cleanup();
   int32_t FilterOutput(const char *aBuf, int32_t aAmount);
   int32_t FilterInput(char *aBuf, int32_t aAmount);
--- a/netwerk/protocol/http/nsAHttpTransaction.h
+++ b/netwerk/protocol/http/nsAHttpTransaction.h
@@ -18,16 +18,17 @@ namespace mozilla { namespace net {
 
 class nsAHttpConnection;
 class nsAHttpSegmentReader;
 class nsAHttpSegmentWriter;
 class nsHttpTransaction;
 class nsHttpPipeline;
 class nsHttpRequestHead;
 class nsHttpConnectionInfo;
+class NullHttpTransaction;
 class SpdyConnectTransaction;
 
 //----------------------------------------------------------------------------
 // Abstract base class for a HTTP transaction:
 //
 // A transaction is a "sink" for the response data.  The connection pushes
 // data to the transaction by writing to it.  The transaction supports
 // WriteSegments and may refuse to accept data if its buffers are full (its
@@ -114,29 +115,30 @@ public:
     // Used to inform the connection that it is being used in a pipelined
     // context. That may influence the handling of some errors.
     // The value is the pipeline position (> 1).
     virtual nsresult SetPipelinePosition(int32_t) = 0;
     virtual int32_t  PipelinePosition() = 0;
 
     // Occasionally the abstract interface has to give way to base implementations
     // to respect differences between spdy, pipelines, etc..
-    // These Query* (and IsNUllTransaction()) functions provide a way to do
+    // These Query* (and IsNullTransaction()) functions provide a way to do
     // that without using xpcom or rtti. Any calling code that can't deal with
     // a null response from one of them probably shouldn't be using nsAHttpTransaction
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<nsHttpPipeline *>(this).. i.e. it can be nullptr for
     // non pipeline implementations of nsAHttpTransaction
     virtual nsHttpPipeline *QueryPipeline() { return nullptr; }
 
     // equivalent to !!dynamic_cast<NullHttpTransaction *>(this)
     // A null transaction is expected to return BASE_STREAM_CLOSED on all of
     // its IO functions all the time.
     virtual bool IsNullTransaction() { return false; }
+    virtual NullHttpTransaction *QueryNullTransaction() { return nullptr; }
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<nsHttpTransaction *>(this).. i.e. it can be nullptr for
     // non nsHttpTransaction implementations of nsAHttpTransaction
     virtual nsHttpTransaction *QueryHttpTransaction() { return nullptr; }
 
     // If we used rtti this would be the result of doing
     // dynamic_cast<SpdyConnectTransaction *>(this).. i.e. it can be nullptr for
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1495,16 +1495,28 @@ nsHttpConnectionMgr::MakeNewConnection(n
             }
 
             // return OK because we have essentially opened a new connection
             // by converting a speculative half-open to general use
             return NS_OK;
         }
     }
 
+    uint32_t activeLength = ent->mActiveConns.Length();
+    for (uint32_t i = 0; i < activeLength; i++) {
+        nsAHttpTransaction *activeTrans = ent->mActiveConns[i]->Transaction();
+        NullHttpTransaction *nullTrans = activeTrans ? activeTrans->QueryNullTransaction() : nullptr;
+        if (nullTrans && nullTrans->Claim()) {
+            LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
+                 "Claiming a null transaction for later use\n",
+                 ent->mConnInfo->HashKey().get()));
+            return NS_OK;
+        }
+    }
+
     // If this host is trying to negotiate a SPDY session right now,
     // don't create any new connections until the result of the
     // negotiation is known.
     if (!(trans->Caps() & NS_HTTP_DISALLOW_SPDY) &&
         (trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) &&
         RestrictConnections(ent)) {
         LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
              "Not Available Due to RestrictConnections()\n",