From f90e1af5767f595eb821bcd5fa5257aedb0281f3 Mon Sep 17 00:00:00 2001 From: "darin%netscape.com" Date: Tue, 4 Sep 2001 23:02:26 +0000 Subject: [PATCH] fixes bug 83526 "http should use fewer connections per server per page" r=bbaetz sr=dougt,blizzard git-svn-id: svn://10.0.0.236/trunk@102220 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/modules/libpref/src/init/all.js | 25 +- .../base/src/nsSocketTransportService.cpp | 14 +- .../protocol/http/src/nsHttpChannel.cpp | 2 +- .../protocol/http/src/nsHttpConnection.cpp | 38 ++- .../protocol/http/src/nsHttpConnection.h | 26 +- .../protocol/http/src/nsHttpHandler.cpp | 238 ++++++++++-------- .../netwerk/protocol/http/src/nsHttpHandler.h | 30 ++- .../protocol/http/src/nsHttpTransaction.cpp | 4 +- .../protocol/http/src/nsHttpTransaction.h | 4 +- 9 files changed, 232 insertions(+), 149 deletions(-) diff --git a/mozilla/modules/libpref/src/init/all.js b/mozilla/modules/libpref/src/init/all.js index bbce51d0694..a45d57c9316 100644 --- a/mozilla/modules/libpref/src/init/all.js +++ b/mozilla/modules/libpref/src/init/all.js @@ -288,11 +288,28 @@ pref("network.http.keep-alive", true); // set it to false in case of problems pref("network.http.proxy.keep-alive", true ); pref("network.http.keep-alive.timeout", 300); -pref("network.http.max-connections", 16); -pref("network.http.max-connections-per-server", 8); -pref("network.http.keep-alive.max-connections", 20); // max connections to be kept alive -pref("network.http.keep-alive.max-connections-per-server", 8); +// limit the absolute number of http connections. +pref("network.http.max-connections", 24); +// limit the absolute number of http connections that can be established per +// host. if a http proxy server is enabled, then the "server" is the proxy +// server. Otherwise, "server" is the http origin server. +pref("network.http.max-connections-per-server", 8); + +// if network.http.keep-alive is true, then a new connection will only be +// attempted if the number of active connections to a host is less then +// network.http.max-persistent-connections-per-server. if a http proxy server +// is enabled, then the "server" is the proxy server. Otherwise, "server" is +// the http origin server. +pref("network.http.max-persistent-connections-per-server", 2); + +// amount of time (in seconds) to suspend pending requests, before spawning a +// new connection, once the limit on the number of persistent connections per +// host has been reached. however, a new connection will not be created if the +// limit on the number of connections per host has also been reached. +pref("network.http.request.max-start-delay", 10); + +// http specific network timeouts (XXX currently unused) pref("network.http.connect.timeout", 30); // in seconds pref("network.http.request.timeout", 120); // in seconds diff --git a/mozilla/netwerk/base/src/nsSocketTransportService.cpp b/mozilla/netwerk/base/src/nsSocketTransportService.cpp index 5e72c2d72af..38b7b0a9936 100644 --- a/mozilla/netwerk/base/src/nsSocketTransportService.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransportService.cpp @@ -31,6 +31,11 @@ #include "nsString.h" #include "nsNetCID.h" +#ifdef DEBUG +// in debug builds this will be valid while the socket transport service is active. +PRThread *NS_SOCKET_THREAD = 0; +#endif + static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID); @@ -356,6 +361,10 @@ nsSocketTransportService::Run(void) PRBool hadThreadEvent = mThreadEvent ? PR_TRUE : PR_FALSE; #endif +#ifdef DEBUG + NS_SOCKET_THREAD = PR_GetCurrentThread(); +#endif + if (mThreadEvent) { // @@ -517,7 +526,10 @@ nsSocketTransportService::Run(void) /* Process any pending operations on the mWorkQ... */ rv = ProcessWorkQ(); } - return NS_OK; +#ifdef DEBUG + NS_SOCKET_THREAD = 0; +#endif + return NS_OK; } diff --git a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp index 12b55420e87..66fa7e73692 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -291,7 +291,7 @@ nsHttpChannel::SetupTransaction() if (NS_FAILED(rv)) return rv; // create the transaction object - mTransaction = new nsHttpTransaction(listenerProxy, this); + mTransaction = new nsHttpTransaction(listenerProxy, this, mCapabilities); if (!mTransaction) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(mTransaction); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp b/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp index f9d3343019f..54757a7b5c5 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnection.cpp @@ -47,9 +47,11 @@ nsHttpConnection::nsHttpConnection() : mTransaction(0) , mConnectionInfo(0) , mLock(nsnull) + , mReadStartTime(0) , mLastActiveTime(0) , mIdleTimeout(0) - , mKeepAlive(0) + , mKeepAlive(1) // assume to keep-alive by default + , mKeepAliveMask(1) , mWriteDone(0) , mReadDone(0) { @@ -72,7 +74,7 @@ nsHttpConnection::~nsHttpConnection() } nsresult -nsHttpConnection::Init(nsHttpConnectionInfo *info) +nsHttpConnection::Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime) { LOG(("nsHttpConnection::Init [this=%x]\n", this)); @@ -86,6 +88,7 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info) mConnectionInfo = info; NS_ADDREF(mConnectionInfo); + mMaxHangTime = maxHangTime; return NS_OK; } @@ -103,6 +106,10 @@ nsHttpConnection::SetTransaction(nsHttpTransaction *transaction) mTransaction = transaction; NS_ADDREF(mTransaction); + // default mKeepAlive according to what will be requested + mKeepAliveMask = mKeepAlive = + mTransaction->Capabilities() & NS_HTTP_ALLOW_KEEPALIVE; + // build a proxy for the progress event sink mProgressSink = 0; if (mTransaction->Callbacks() && mTransaction->ConsumerEventQ()) { @@ -160,6 +167,7 @@ nsHttpConnection::OnHeadersAvailable(nsHttpTransaction *trans, PRBool *reset) else mKeepAlive = PR_TRUE; } + mKeepAliveMask = mKeepAlive; // if this connection is persistent, then the server may send a "Keep-Alive" // header specifying the maximum number of times the connection can be @@ -290,8 +298,8 @@ nsHttpConnection::ProxyStepUp() PRBool nsHttpConnection::CanReuse() { - return mKeepAlive && (NowInSeconds() - mLastActiveTime < mIdleTimeout) - && IsAlive(); + return IsKeepAlive() && (NowInSeconds() - mLastActiveTime < mIdleTimeout) + && IsAlive(); } PRBool @@ -318,7 +326,7 @@ nsHttpConnection::DropTransaction() mProgressSink = 0; // if the transaction was dropped, then we cannot reuse this connection. - mKeepAlive = PR_FALSE; + mKeepAliveMask = mKeepAlive = PR_FALSE; } // called on the socket thread @@ -574,8 +582,10 @@ nsHttpConnection::OnStartRequest(nsIRequest *request, nsISupports *ctxt) mTransaction->SetSecurityInfo(info); } } - else + else { mReadRequest = request; + mReadStartTime = NowInSeconds(); + } return NS_OK; } @@ -630,6 +640,9 @@ nsHttpConnection::OnStopRequest(nsIRequest *request, nsISupports *ctxt, NS_RELEASE(trans); } + // reset the keep-alive mask + mKeepAliveMask = mKeepAlive; + nsHttpHandler::get()->ReclaimConnection(this); } // no point in returning anything else but NS_OK @@ -690,14 +703,23 @@ nsHttpConnection::OnDataAvailable(nsIRequest *request, nsISupports *context, nsIInputStream *inputStream, PRUint32 offset, PRUint32 count) { + LOG(("nsHttpConnection::OnDataAvailable [this=%x]\n", this)); + if (!mTransaction) { - LOG(("nsHttpConnection: no transaction! closing stream\n")); + LOG(("no transaction! closing stream\n")); return NS_BASE_STREAM_CLOSED; } mLastActiveTime = NowInSeconds(); - LOG(("nsHttpConnection::OnDataAvailable [this=%x]\n", this)); + if (mKeepAliveMask && + (mLastActiveTime - mReadStartTime >= PRUint32(mMaxHangTime))) { + LOG(("max hang time exceeded!\n")); + // give the handler a chance to create a new persistent connection to + // this host if we've been busy for too long. + mKeepAliveMask = PR_FALSE; + nsHttpHandler::get()->ProcessTransactionQ(); + } nsresult rv = mTransaction->OnDataReadable(inputStream); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpConnection.h b/mozilla/netwerk/protocol/http/src/nsHttpConnection.h index f6ccec74063..7a4dc3e6b97 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpConnection.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpConnection.h @@ -63,7 +63,12 @@ public: nsHttpConnection(); virtual ~nsHttpConnection(); - nsresult Init(nsHttpConnectionInfo *); + // Initialize the connection: + // info - specifies the connection parameters. + // maxHangTime - limits the amount of time this connection can spend on a + // single transaction before it should no longer be kept + // alive. a value of 0xffff indicates no limit. + nsresult Init(nsHttpConnectionInfo *info, PRUint16 maxHangTime); // SetTransaction causes the given transaction to be processed on this // connection. It fails if there is already an existing transaction. @@ -83,13 +88,11 @@ public: // called to cause the underlying socket to start speaking SSL nsresult ProxyStepUp(); - PRBool CanReuse(); // can this connection be reused? - PRBool IsAlive(); - PRBool IsKeepAlive() { return mKeepAlive; } - PRUint16 IdleTimeout() { return mIdleTimeout; } - - void DontReuse() { mKeepAlive = PR_FALSE; - mIdleTimeout = 0; } + PRBool IsKeepAlive() { return mKeepAliveMask && mKeepAlive; } + PRBool CanReuse(); // can this connection be reused? + void DontReuse() { mKeepAliveMask = PR_FALSE; + mKeepAlive = PR_FALSE; + mIdleTimeout = 0; } void DropTransaction(); void ReportProgress(PRUint32 progress, PRInt32 progressMax); @@ -107,6 +110,8 @@ private: nsresult SetupSSLProxyConnect(); + PRBool IsAlive(); + private: nsCOMPtr mSocketTransport; nsCOMPtr mWriteRequest; @@ -122,10 +127,13 @@ private: PRLock *mLock; + PRUint32 mReadStartTime; // time of OnStartRequest PRUint32 mLastActiveTime; - PRUint16 mIdleTimeout; // value of keep-alive: timeout= + PRUint16 mMaxHangTime; // max download time before dropping keep-alive status + PRUint16 mIdleTimeout; // value of keep-alive: timeout= PRPackedBool mKeepAlive; + PRPackedBool mKeepAliveMask; PRPackedBool mWriteDone; PRPackedBool mReadDone; }; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp index d6a489ff6bf..4ab433b5cf2 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpHandler.cpp @@ -62,6 +62,11 @@ #include #endif +#ifdef DEBUG +// defined by the socket transport service while active +extern PRThread *NS_SOCKET_THREAD; +#endif + static const char NETWORK_PREFS[] = "network."; static const char INTL_ACCEPT_LANGUAGES[] = "intl.accept_languages"; static const char INTL_ACCEPT_CHARSET[] = "intl.charset.default"; @@ -95,9 +100,10 @@ nsHttpHandler::nsHttpHandler() , mProxyCapabilities(NS_HTTP_ALLOW_KEEPALIVE) , mIdleTimeout(10) , mMaxRequestAttempts(10) - , mMaxConnections(16) + , mMaxRequestDelay(10) + , mMaxConnections(24) , mMaxConnectionsPerServer(8) - , mMaxIdleConnectionsPerServer(4) + , mMaxPersistentConnectionsPerServer(2) , mActiveConnections(0) , mIdleConnections(0) , mTransactionQ(0) @@ -378,8 +384,7 @@ nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy, // may be called from any thread nsresult nsHttpHandler::InitiateTransaction(nsHttpTransaction *trans, - nsHttpConnectionInfo *ci, - PRBool failIfBusy) + nsHttpConnectionInfo *ci) { LOG(("nsHttpHandler::InitiateTransaction\n")); @@ -388,19 +393,22 @@ nsHttpHandler::InitiateTransaction(nsHttpTransaction *trans, nsAutoLock lock(mConnectionLock); - return InitiateTransaction_Locked(trans, ci, failIfBusy); + return InitiateTransaction_Locked(trans, ci); } -// may be called from any thread +// called from the socket thread nsresult nsHttpHandler::ReclaimConnection(nsHttpConnection *conn) { NS_ENSURE_ARG_POINTER(conn); +#ifdef DEBUG + NS_PRECONDITION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); +#endif PRBool reusable = conn->CanReuse(); - LOG(("nsHttpHandler::ReclaimConnection [conn=%x keep-alive=%d]\n", - conn, reusable)); + LOG(("nsHttpHandler::ReclaimConnection [conn=%x(%s:%d) keep-alive=%d]\n", + conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port(), reusable)); nsAutoLock lock(mConnectionLock); @@ -408,21 +416,11 @@ nsHttpHandler::ReclaimConnection(nsHttpConnection *conn) mActiveConnections.RemoveElement(conn); if (reusable) { - // verify that we aren't already maxed out on the number of - // keep-alives we can have for this server. - PRUint32 count = CountIdleConnections(conn->ConnectionInfo()); - if (count == PRUint32(mMaxIdleConnectionsPerServer)) { - LOG(("not caching keep-alive connection: " - "would exceed max allowed per server\n")); - NS_RELEASE(conn); - } - else { - LOG(("adding connection to idle list [conn=%x]\n", conn)); - // hold onto this connection in the idle list. we push it - // to the end of the list so as to ensure that we'll visit - // older connections first before getting to this one. - mIdleConnections.AppendElement(conn); - } + LOG(("adding connection to idle list [conn=%x]\n", conn)); + // hold onto this connection in the idle list. we push it + // to the end of the list so as to ensure that we'll visit + // older connections first before getting to this one. + mIdleConnections.AppendElement(conn); } else { LOG(("closing connection: connection can't be reused\n")); @@ -433,7 +431,26 @@ nsHttpHandler::ReclaimConnection(nsHttpConnection *conn) // process the pending transaction queue... if (mTransactionQ.Count() > 0) - ProcessTransactionQ(); + ProcessTransactionQ_Locked(); + + return NS_OK; +} + +// called from the socket thread (see nsHttpConnection::OnDataAvailable) +nsresult +nsHttpHandler::ProcessTransactionQ() +{ + LOG(("nsHttpHandler::ProcessTransactionQ\n")); +#ifdef DEBUG + NS_PRECONDITION(PR_GetCurrentThread() == NS_SOCKET_THREAD, "wrong thread"); +#endif + + nsAutoLock lock(mConnectionLock); + + // conn is no longer keep-alive, so we may be able to initiate + // a pending transaction to the same host. + if (mTransactionQ.Count() > 0) + ProcessTransactionQ_Locked(); return NS_OK; } @@ -632,9 +649,9 @@ nsHttpHandler::UserAgent() // called with the connection lock held void -nsHttpHandler::ProcessTransactionQ() +nsHttpHandler::ProcessTransactionQ_Locked() { - LOG(("nsHttpHandler::ProcessTransactionQ\n")); + LOG(("nsHttpHandler::ProcessTransactionQ_Locked\n")); nsPendingTransaction *pt = nsnull; @@ -644,17 +661,30 @@ nsHttpHandler::ProcessTransactionQ() pt = (nsPendingTransaction *) mTransactionQ[i]; - // try to initiate this transaction... if it fails - // then we'll just skip over this pending transaction - // and try the next. + // skip over a busy pending transaction + if (pt->IsBusy()) + continue; + + // the connection lock is released during InitiateTransaction_Locked, so + // the transaction queue could get modified. mark this pending transaction + // as busy to cause it to be skipped if this function happens to recurse. + pt->SetBusy(PR_TRUE); + + // try to initiate this transaction... if it fails then we'll just skip + // over this pending transaction and try the next. nsresult rv = InitiateTransaction_Locked(pt->Transaction(), pt->ConnectionInfo(), PR_TRUE); + if (NS_SUCCEEDED(rv)) { mTransactionQ.RemoveElementAt(i); delete pt; i--; } + else { + LOG(("InitiateTransaction_Locked failed [rv=%x]\n", rv)); + pt->SetBusy(PR_FALSE); + } } } @@ -671,7 +701,7 @@ nsHttpHandler::EnqueueTransaction(nsHttpTransaction *trans, mTransactionQ.AppendElement(pt); - LOG(("transaction queue contains %u elements\n", mTransactionQ.Count())); + LOG((">> transaction queue contains %u elements\n", mTransactionQ.Count())); return NS_OK; } @@ -682,57 +712,59 @@ nsHttpHandler::InitiateTransaction_Locked(nsHttpTransaction *trans, PRBool failIfBusy) { nsresult rv; + PRUint8 caps = trans->Capabilities(); LOG(("nsHttpHandler::InitiateTransaction_Locked [failIfBusy=%d]\n", failIfBusy)); - if ((mActiveConnections.Count() == PRInt32(mMaxConnections)) || - (CountActiveConnections(ci) == mMaxConnectionsPerServer)) { - LOG(("unable to perform the transaction at this time [trans=%x]\n", trans)); - if (failIfBusy) return NS_ERROR_FAILURE; - return EnqueueTransaction(trans, ci); + if (AtActiveConnectionLimit(ci, caps)) { + LOG((">> unable to perform the transaction at this time [trans=%x]\n", trans)); + return failIfBusy ? NS_ERROR_FAILURE : EnqueueTransaction(trans, ci); } nsHttpConnection *conn = nsnull; - // search the idle connection list - PRInt32 i; - for (i=0; iConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); + LOG((">> comparing against idle connection [conn=%x host=%s:%d]\n", + conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); - // we check if the connection can be reused before even checking if it - // is a "matching" connection. this is how we keep the idle connection - // list fresh. we could alternatively use some sort of timer for this. - if (!conn->CanReuse()) { - LOG(("dropping stale connection: [conn=%x]\n", conn)); - mIdleConnections.RemoveElementAt(i); - i--; - NS_RELEASE(conn); + // we check if the connection can be reused before even checking if it + // is a "matching" connection. this is how we keep the idle connection + // list fresh. we could alternatively use some sort of timer for this. + if (!conn->CanReuse()) { + LOG((" dropping stale connection: [conn=%x]\n", conn)); + mIdleConnections.RemoveElementAt(i); + i--; + NS_RELEASE(conn); + } + else if (conn->ConnectionInfo()->Equals(ci)) { + LOG((" reusing connection [conn=%x]\n", conn)); + mIdleConnections.RemoveElementAt(i); + i--; + break; + } + conn = nsnull; } - else if (conn->ConnectionInfo()->Equals(ci)) { - LOG(("reusing connection [conn=%x]\n", conn)); - mIdleConnections.RemoveElementAt(i); - i--; - break; - } - conn = nsnull; } if (!conn) { - LOG(("creating new connection...\n")); + LOG((">> creating new connection...\n")); NS_NEWXPCOM(conn, nsHttpConnection); if (!conn) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(conn); - rv = conn->Init(ci); + rv = conn->Init(ci, mMaxRequestDelay); if (NS_FAILED(rv)) { NS_RELEASE(conn); return rv; } - } else { + } + else { // Update the connectionInfo (bug 94038) conn->ConnectionInfo()->SetOriginServer(ci->Host(), ci->Port()); } @@ -750,6 +782,7 @@ nsHttpHandler::InitiateTransaction_Locked(nsHttpTransaction *trans, PR_Lock(mConnectionLock); if (NS_FAILED(rv)) { + LOG(("nsHttpConnection::SetTransaction failed [rv=%x]\n", rv)); // the connection may already have been removed from the // active connection list. if (mActiveConnections.RemoveElement(conn)) @@ -783,57 +816,41 @@ nsHttpHandler::RemovePendingTransaction(nsHttpTransaction *trans) return NS_ERROR_NOT_AVAILABLE; } -PRUint8 -nsHttpHandler::CountActiveConnections(nsHttpConnectionInfo *ci) +// we're at the active connection limit if any one of the following conditions is true: +// (1) at max-connections +// (2) keep-alive enabled and at max-persistent-connections-per-host +// (3) keep-alive disabled and at max-connections-per-host +PRBool +nsHttpHandler::AtActiveConnectionLimit(nsHttpConnectionInfo *ci, PRUint8 caps) { - PRUint8 count = 0; - nsHttpConnection *conn = 0; + LOG(("nsHttpHandler::AtActiveConnectionLimit [host=%s:%d caps=%x]\n", + ci->Host(), ci->Port(), caps)); - LOG(("nsHttpHandler::CountActiveConnections [host=%s:%d]\n", - ci->Host(), ci->Port())); + // use >= just to be safe + if (mActiveConnections.Count() >= mMaxConnections) + return PR_TRUE; + nsHttpConnection *conn; + PRUint8 totalCount = 0, persistentCount = 0; PRInt32 i; for (i=0; iConnectionInfo()->Equals(ci)) - count++; - } - - LOG(("found count=%u\n", (PRUintn) count)); - return count; -} - -PRUint8 -nsHttpHandler::CountIdleConnections(nsHttpConnectionInfo *ci) -{ - PRUint8 count = 0; - nsHttpConnection *conn = 0; - - if (!ci) - return 0; - - LOG(("nsHttpHandler::CountIdleConnections [host=%s:%d]\n", - ci->Host(), ci->Port())); - - PRInt32 i; - for (i=0; i> comparing against active connection [conn=%x host=%s:%d]\n", + conn, conn->ConnectionInfo()->Host(), conn->ConnectionInfo()->Port())); if (conn->ConnectionInfo()->Equals(ci)) { - if (conn->CanReuse()) - count++; - else { - mIdleConnections.RemoveElementAt(i); - NS_RELEASE(conn); - i--; - } + totalCount++; + if (conn->IsKeepAlive()) + persistentCount++; } } - LOG(("found count=%u\n", (PRUintn) count)); - return count; + LOG((" total-count=%u, persistent-count=%u\n", + PRUint32(totalCount), PRUint32(persistentCount))); + + // use >= just to be safe + return (totalCount >= mMaxConnectionsPerServer) || + ((caps & NS_HTTP_ALLOW_KEEPALIVE) && + (persistentCount >= mMaxPersistentConnectionsPerServer)); } void @@ -1075,6 +1092,12 @@ nsHttpHandler::PrefsChanged(const char *pref) mMaxRequestAttempts = (PRUint16) CLAMP(val, 1, 0xffff); } + if (bChangedAll || PL_strcmp(pref, "network.http.request.max-start-delay") == 0) { + rv = mPrefs->GetIntPref("network.http.request.max-start-delay", &val); + if (NS_SUCCEEDED(rv)) + mMaxRequestDelay = (PRUint16) CLAMP(val, 0, 0xffff); + } + if (bChangedAll || PL_strcmp(pref, "network.http.max-connections") == 0) { rv = mPrefs->GetIntPref("network.http.max-connections", &val); if (NS_SUCCEEDED(rv)) @@ -1087,18 +1110,10 @@ nsHttpHandler::PrefsChanged(const char *pref) mMaxConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff); } - /* - if (bChangedAll || PL_strcmp(pref, "network.http.keep-alive.max-connections") == 0) { - rv = mPrefs->GetIntPref("network.http.keep-alive.max-connections", &val); + if (bChangedAll || PL_strcmp(pref, "network.http.max-persistent-connections-per-server") == 0) { + rv = mPrefs->GetIntPref("network.http.max-persistent-connections-per-server", &val); if (NS_SUCCEEDED(rv)) - mMaxIdleConnections = (PRUint16) CLAMP(val, 1, 0xffff); - } - */ - - if (bChangedAll || PL_strcmp(pref, "network.http.keep-alive.max-connections-per-server") == 0) { - rv = mPrefs->GetIntPref("network.http.keep-alive.max-connections-per-server", &val); - if (NS_SUCCEEDED(rv)) - mMaxIdleConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff); + mMaxPersistentConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff); } if (bChangedAll || PL_strcmp(pref, "network.http.sendRefererHeader") == 0) { @@ -1787,6 +1802,7 @@ nsPendingTransaction::nsPendingTransaction(nsHttpTransaction *trans, nsHttpConnectionInfo *ci) : mTransaction(trans) , mConnectionInfo(ci) + , mBusy(0) { LOG(("Creating nsPendingTransaction @%x\n", this)); diff --git a/mozilla/netwerk/protocol/http/src/nsHttpHandler.h b/mozilla/netwerk/protocol/http/src/nsHttpHandler.h index 4e4ba191c04..3eff61e643a 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpHandler.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpHandler.h @@ -106,9 +106,7 @@ public: // Called to kick-off a new transaction, by default the transaction // will be put on the pending transaction queue if it cannot be // initiated at this time. Callable from any thread. - nsresult InitiateTransaction(nsHttpTransaction *, - nsHttpConnectionInfo *, - PRBool failIfBusy = PR_FALSE); + nsresult InitiateTransaction(nsHttpTransaction *, nsHttpConnectionInfo *); // Called to cancel a transaction, which may or may not be assigned to // a connection. Callable from any thread. @@ -118,6 +116,10 @@ public: // from any thread. nsresult ReclaimConnection(nsHttpConnection *); + // Called when a connection has been busy with a single transaction for + // longer than mMaxRequestDelay. + nsresult ProcessTransactionQ(); + // // The HTTP handler caches pointers to specific XPCOM services, and // provides the following helper routines for accessing those services: @@ -150,15 +152,19 @@ private: nsHttpTransaction *Transaction() { return mTransaction; } nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; } + PRBool IsBusy() { return mBusy; } + void SetBusy(PRBool value) { mBusy = value; } + private: nsHttpTransaction *mTransaction; nsHttpConnectionInfo *mConnectionInfo; + PRPackedBool mBusy; }; // // Transaction queue helper methods // - void ProcessTransactionQ(); + void ProcessTransactionQ_Locked(); nsresult EnqueueTransaction(nsHttpTransaction *, nsHttpConnectionInfo *); // Called with mConnectionLock held @@ -167,10 +173,7 @@ private: PRBool failIfBusy = PR_FALSE); nsresult RemovePendingTransaction(nsHttpTransaction *); - - PRUint8 CountActiveConnections(nsHttpConnectionInfo *); - PRUint8 CountIdleConnections(nsHttpConnectionInfo *); - + PRBool AtActiveConnectionLimit(nsHttpConnectionInfo *, PRUint8 caps); void DropConnections(nsVoidArray &); // @@ -213,10 +216,11 @@ private: PRUint16 mIdleTimeout; PRUint16 mMaxRequestAttempts; + PRUint16 mMaxRequestDelay; PRUint16 mMaxConnections; PRUint8 mMaxConnectionsPerServer; - PRUint8 mMaxIdleConnectionsPerServer; + PRUint8 mMaxPersistentConnectionsPerServer; nsCString mAccept; nsCString mAcceptLanguages; @@ -230,10 +234,10 @@ private: PRUint32 mSessionStartTime; // connection management - nsVoidArray mActiveConnections; // list of nsHttpConnection objects - nsVoidArray mIdleConnections; // list of nsHttpConnection objects - nsVoidArray mTransactionQ; // list of nsPendingTransaction objects - PRLock *mConnectionLock; // protect connection lists + nsVoidArray mActiveConnections; // list of nsHttpConnection objects + nsVoidArray mIdleConnections; // list of nsHttpConnection objects + nsVoidArray mTransactionQ; // list of nsPendingTransaction objects + PRLock *mConnectionLock; // protect connection lists // useragent components nsXPIDLCString mAppName; diff --git a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp index 27b9091f0be..75358961822 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -38,7 +38,8 @@ //----------------------------------------------------------------------------- nsHttpTransaction::nsHttpTransaction(nsIStreamListener *listener, - nsIInterfaceRequestor *callbacks) + nsIInterfaceRequestor *callbacks, + PRUint8 caps) : mListener(listener) , mCallbacks(callbacks) , mConnection(nsnull) @@ -49,6 +50,7 @@ nsHttpTransaction::nsHttpTransaction(nsIStreamListener *listener, , mTransactionDone(0) , mStatus(NS_OK) , mRestartCount(0) + , mCapabilities(caps) , mHaveStatusLine(PR_FALSE) , mHaveAllHeaders(PR_FALSE) , mFiredOnStart(PR_FALSE) diff --git a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h index 68da1bd8fa0..8f49021e92d 100644 --- a/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h +++ b/mozilla/netwerk/protocol/http/src/nsHttpTransaction.h @@ -52,7 +52,7 @@ public: NS_DECL_NSIINPUTSTREAM // A transaction is constructed from request headers. - nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *); + nsHttpTransaction(nsIStreamListener *, nsIInterfaceRequestor *, PRUint8 caps); virtual ~nsHttpTransaction(); nsrefcnt RefCnt() { return mRefCnt; } @@ -75,6 +75,7 @@ public: nsISupports *SecurityInfo() { return mSecurityInfo; } PRBool IsDone() { return mTransactionDone; } nsresult Status() { return mStatus; } + PRUint8 Capabilities() { return mCapabilities; } // Called to take ownership of the response headers; the transaction // will drop any reference to the response headers after this call. @@ -127,6 +128,7 @@ private: nsresult mStatus; PRUint16 mRestartCount; // the number of times this transaction has been restarted + PRUint8 mCapabilities; PRPackedBool mHaveStatusLine; PRPackedBool mHaveAllHeaders;