From 902927922e8fae2d413e7145b01d5b678d2eee01 Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Sat, 15 Jan 2005 07:01:20 +0000 Subject: [PATCH] fixes bug 142255 "RFE provide a way to prioritize connections" r=bz --- .../http/public/nsIHttpChannelInternal.idl | 9 +- netwerk/protocol/http/src/nsHttpChannel.cpp | 19 +++- netwerk/protocol/http/src/nsHttpChannel.h | 1 + .../protocol/http/src/nsHttpConnectionMgr.cpp | 86 +++++++++++++++---- .../protocol/http/src/nsHttpConnectionMgr.h | 41 +++++---- netwerk/protocol/http/src/nsHttpHandler.h | 11 ++- .../protocol/http/src/nsHttpTransaction.cpp | 3 +- netwerk/protocol/http/src/nsHttpTransaction.h | 6 ++ 8 files changed, 136 insertions(+), 40 deletions(-) diff --git a/netwerk/protocol/http/public/nsIHttpChannelInternal.idl b/netwerk/protocol/http/public/nsIHttpChannelInternal.idl index d9276c528eb1..0911f1ed2497 100644 --- a/netwerk/protocol/http/public/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/public/nsIHttpChannelInternal.idl @@ -45,7 +45,7 @@ interface nsIProxyInfo; * using any feature exposed by this interface, be aware that this interface * will change and you will be broken. You have been warned. */ -[scriptable, uuid(f3764874-ed7e-4873-883c-11d67a4e3638)] +[scriptable, uuid(ae9dce68-c27c-44f1-b41d-462f5e470945)] interface nsIHttpChannelInternal : nsISupports { /** @@ -77,4 +77,11 @@ interface nsIHttpChannelInternal : nsISupports * Get the proxy info in use by the channel. */ readonly attribute nsIProxyInfo proxyInfo; + + /** + * Get or set the relative priority for this HTTP channel. Smaller values + * have higher priority. Negative values are allowed, and the default + * priority is 0. + */ + attribute short priority; }; diff --git a/netwerk/protocol/http/src/nsHttpChannel.cpp b/netwerk/protocol/http/src/nsHttpChannel.cpp index 0517890bf03e..17992b17b81c 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.cpp +++ b/netwerk/protocol/http/src/nsHttpChannel.cpp @@ -96,6 +96,7 @@ nsHttpChannel::nsHttpChannel() , mStatus(NS_OK) , mLogicalOffset(0) , mCaps(0) + , mPriority(0) , mCachedResponseHead(nsnull) , mCacheAccess(0) , mPostID(0) @@ -352,7 +353,7 @@ nsHttpChannel::Connect(PRBool firstTime) rv = SetupTransaction(); if (NS_FAILED(rv)) return rv; - rv = gHttpHandler->InitiateTransaction(mTransaction); + rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority); if (NS_FAILED(rv)) return rv; return mTransactionPump->AsyncRead(this, nsnull); @@ -3639,6 +3640,20 @@ nsHttpChannel::GetProxyInfo(nsIProxyInfo **result) return NS_OK; } +NS_IMETHODIMP +nsHttpChannel::GetPriority(PRInt16 *value) +{ + *value = mPriority; + return NS_OK; +} + +NS_IMETHODIMP +nsHttpChannel::SetPriority(PRInt16 value) +{ + mPriority = value; + return NS_OK; +} + //----------------------------------------------------------------------------- // nsHttpChannel::nsIRequestObserver //----------------------------------------------------------------------------- @@ -4169,7 +4184,7 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn) seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); } - rv = gHttpHandler->InitiateTransaction(mTransaction); + rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority); if (NS_FAILED(rv)) return rv; return mTransactionPump->AsyncRead(this, nsnull); diff --git a/netwerk/protocol/http/src/nsHttpChannel.h b/netwerk/protocol/http/src/nsHttpChannel.h index 44aea119681e..dcacd2a5ac6a 100644 --- a/netwerk/protocol/http/src/nsHttpChannel.h +++ b/netwerk/protocol/http/src/nsHttpChannel.h @@ -221,6 +221,7 @@ private: PRUint32 mStatus; nsUint64 mLogicalOffset; PRUint8 mCaps; + PRInt16 mPriority; nsCString mContentTypeHint; nsCString mContentCharsetHint; diff --git a/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp index ef95a82d588b..f3ef8bf6bd8e 100644 --- a/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/src/nsHttpConnectionMgr.cpp @@ -53,6 +53,25 @@ static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); //----------------------------------------------------------------------------- +static void +InsertTransactionSorted(nsVoidArray &pendingQ, nsHttpTransaction *trans) +{ + // insert into queue with smallest valued number first. search in reverse + // order under the assumption that many of the existing transactions will + // have the same priority (usually 0). + + for (PRInt32 i=pendingQ.Count()-1; i>=0; --i) { + nsHttpTransaction *t = (nsHttpTransaction *) pendingQ[i]; + if (trans->Priority() >= t->Priority()) { + pendingQ.InsertElementAt(trans, i+1); + return; + } + } + pendingQ.InsertElementAt(trans, 0); +} + +//----------------------------------------------------------------------------- + nsHttpConnectionMgr::nsHttpConnectionMgr() : mRef(0) , mMonitor(nsAutoMonitor::NewMonitor("nsHttpConnectionMgr")) @@ -139,7 +158,7 @@ nsHttpConnectionMgr::Shutdown() } nsresult -nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, nsresult status, void *param) +nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, PRInt32 iparam, void *vparam) { nsAutoMonitor mon(mMonitor); @@ -149,7 +168,7 @@ nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, nsresult status, void rv = NS_ERROR_NOT_INITIALIZED; } else { - PLEvent *event = new nsConnEvent(this, handler, status, param); + PLEvent *event = new nsConnEvent(this, handler, iparam, vparam); if (!event) rv = NS_ERROR_OUT_OF_MEMORY; else { @@ -164,12 +183,24 @@ nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, nsresult status, void //----------------------------------------------------------------------------- nsresult -nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans) +nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans, PRInt32 priority) { - LOG(("nsHttpConnectionMgr::AddTransaction [trans=%x]\n", trans)); + LOG(("nsHttpConnectionMgr::AddTransaction [trans=%x %d]\n", trans, priority)); NS_ADDREF(trans); - nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, NS_OK, trans); + nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans); + if (NS_FAILED(rv)) + NS_RELEASE(trans); + return rv; +} + +nsresult +nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans, PRInt32 priority) +{ + LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%x %d]\n", trans, priority)); + + NS_ADDREF(trans); + nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans); if (NS_FAILED(rv)) NS_RELEASE(trans); return rv; @@ -237,7 +268,7 @@ nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn) LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%x]\n", conn)); NS_ADDREF(conn); - nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, NS_OK, conn); + nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn); if (NS_FAILED(rv)) NS_RELEASE(conn); return rv; @@ -247,7 +278,7 @@ nsresult nsHttpConnectionMgr::UpdateParam(nsParamName name, PRUint16 value) { PRUint32 param = (PRUint32(name) << 16) | PRUint32(value); - return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam, NS_OK, (void *) param); + return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam, 0, (void *) param); } nsresult @@ -256,7 +287,7 @@ nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci) LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci->HashKey().get())); NS_ADDREF(ci); - nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, NS_OK, ci); + nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci); if (NS_FAILED(rv)) NS_RELEASE(ci); return rv; @@ -693,7 +724,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) LOG((" adding transaction to pending queue [trans=%x pending-count=%u]\n", trans, ent->mPendingQ.Count()+1)); // put this transaction on the pending queue... - ent->mPendingQ.AppendElement(trans); + InsertTransactionSorted(ent->mPendingQ, trans); NS_ADDREF(trans); rv = NS_OK; } @@ -708,7 +739,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) //----------------------------------------------------------------------------- void -nsHttpConnectionMgr::OnMsgShutdown(nsresult, void *) +nsHttpConnectionMgr::OnMsgShutdown(PRInt32, void *) { LOG(("nsHttpConnectionMgr::OnMsgShutdown\n")); @@ -720,11 +751,12 @@ nsHttpConnectionMgr::OnMsgShutdown(nsresult, void *) } void -nsHttpConnectionMgr::OnMsgNewTransaction(nsresult, void *param) +nsHttpConnectionMgr::OnMsgNewTransaction(PRInt32 priority, void *param) { LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param)); nsHttpTransaction *trans = (nsHttpTransaction *) param; + trans->SetPriority(priority); nsresult rv = ProcessNewTransaction(trans); if (NS_FAILED(rv)) trans->Close(rv); // for whatever its worth @@ -732,7 +764,29 @@ nsHttpConnectionMgr::OnMsgNewTransaction(nsresult, void *param) } void -nsHttpConnectionMgr::OnMsgCancelTransaction(nsresult reason, void *param) +nsHttpConnectionMgr::OnMsgReschedTransaction(PRInt32 priority, void *param) +{ + LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param)); + + nsHttpTransaction *trans = (nsHttpTransaction *) param; + trans->SetPriority(priority); + + nsHttpConnectionInfo *ci = trans->ConnectionInfo(); + nsCStringKey key(ci->HashKey()); + nsConnectionEntry *ent = (nsConnectionEntry *) mCT.Get(&key); + if (ent) { + PRInt32 index = ent->mPendingQ.IndexOf(trans); + if (index >= 0) { + ent->mPendingQ.RemoveElementAt(index); + InsertTransactionSorted(ent->mPendingQ, trans); + } + } + + NS_RELEASE(trans); +} + +void +nsHttpConnectionMgr::OnMsgCancelTransaction(PRInt32 reason, void *param) { LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param)); @@ -763,7 +817,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(nsresult reason, void *param) } void -nsHttpConnectionMgr::OnMsgProcessPendingQ(nsresult, void *param) +nsHttpConnectionMgr::OnMsgProcessPendingQ(PRInt32, void *param) { nsHttpConnectionInfo *ci = (nsHttpConnectionInfo *) param; @@ -782,7 +836,7 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(nsresult, void *param) } void -nsHttpConnectionMgr::OnMsgPruneDeadConnections(nsresult, void *) +nsHttpConnectionMgr::OnMsgPruneDeadConnections(PRInt32, void *) { LOG(("nsHttpConnectionMgr::OnMsgPruneDeadConnections\n")); @@ -791,7 +845,7 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(nsresult, void *) } void -nsHttpConnectionMgr::OnMsgReclaimConnection(nsresult, void *param) +nsHttpConnectionMgr::OnMsgReclaimConnection(PRInt32, void *param) { LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param)); @@ -835,7 +889,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(nsresult, void *param) } void -nsHttpConnectionMgr::OnMsgUpdateParam(nsresult status, void *param) +nsHttpConnectionMgr::OnMsgUpdateParam(PRInt32, void *param) { PRUint16 name = (PRUint32(param) & 0xFFFF0000) >> 16; PRUint16 value = PRUint32(param) & 0x0000FFFF; diff --git a/netwerk/protocol/http/src/nsHttpConnectionMgr.h b/netwerk/protocol/http/src/nsHttpConnectionMgr.h index af2fdc3cc282..2eb12603d01b 100644 --- a/netwerk/protocol/http/src/nsHttpConnectionMgr.h +++ b/netwerk/protocol/http/src/nsHttpConnectionMgr.h @@ -99,7 +99,11 @@ public: } // adds a transaction to the list of managed transactions. - nsresult AddTransaction(nsHttpTransaction *); + nsresult AddTransaction(nsHttpTransaction *, PRInt32 priority); + + // called to reschedule the given transaction. it must already have been + // added to the connection manager via AddTransaction. + nsresult RescheduleTransaction(nsHttpTransaction *, PRInt32 priority); // cancels a transaction w/ the given reason. nsresult CancelTransaction(nsHttpTransaction *, nsresult reason); @@ -213,7 +217,7 @@ private: nsresult ProcessNewTransaction(nsHttpTransaction *); // message handlers have this signature - typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(nsresult, void *); + typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(PRInt32, void *); // nsConnEvent // @@ -227,11 +231,11 @@ private: public: nsConnEvent(nsHttpConnectionMgr *mgr, nsConnEventHandler handler, - nsresult status, - void *param) + PRInt32 iparam, + void *vparam) : mHandler(handler) - , mStatus(status) - , mParam(param) + , mIParam(iparam) + , mVParam(vparam) { NS_ADDREF(mgr); PL_InitEvent(this, mgr, HandleEvent, DestroyEvent); @@ -242,7 +246,7 @@ private: nsHttpConnectionMgr *mgr = (nsHttpConnectionMgr *) event->owner; nsConnEvent *self = (nsConnEvent *) event; nsConnEventHandler handler = self->mHandler; - (mgr->*handler)(self->mStatus, self->mParam); + (mgr->*handler)(self->mIParam, self->mVParam); NS_RELEASE(mgr); return nsnull; } @@ -253,22 +257,23 @@ private: private: nsConnEventHandler mHandler; - nsresult mStatus; - void *mParam; + PRInt32 mIParam; + void *mVParam; }; nsresult PostEvent(nsConnEventHandler handler, - nsresult status = NS_OK, - void *param = nsnull); + PRInt32 iparam = 0, + void *vparam = nsnull); // message handlers - void OnMsgShutdown (nsresult status, void *param); - void OnMsgNewTransaction (nsresult status, void *param); - void OnMsgCancelTransaction (nsresult status, void *param); - void OnMsgProcessPendingQ (nsresult status, void *param); - void OnMsgPruneDeadConnections (nsresult status, void *param); - void OnMsgReclaimConnection (nsresult status, void *param); - void OnMsgUpdateParam (nsresult status, void *param); + void OnMsgShutdown (PRInt32, void *); + void OnMsgNewTransaction (PRInt32, void *); + void OnMsgReschedTransaction (PRInt32, void *); + void OnMsgCancelTransaction (PRInt32, void *); + void OnMsgProcessPendingQ (PRInt32, void *); + void OnMsgPruneDeadConnections (PRInt32, void *); + void OnMsgReclaimConnection (PRInt32, void *); + void OnMsgUpdateParam (PRInt32, void *); // counters PRUint16 mNumActiveConns; diff --git a/netwerk/protocol/http/src/nsHttpHandler.h b/netwerk/protocol/http/src/nsHttpHandler.h index 6bbf6538954a..1a606e07cd7a 100644 --- a/netwerk/protocol/http/src/nsHttpHandler.h +++ b/netwerk/protocol/http/src/nsHttpHandler.h @@ -130,9 +130,16 @@ 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 *trans) + nsresult InitiateTransaction(nsHttpTransaction *trans, PRInt32 priority) { - return mConnMgr->AddTransaction(trans); + return mConnMgr->AddTransaction(trans, priority); + } + + // Called to change the priority of an existing transaction that has + // already been initiated. + nsresult RescheduleTransaction(nsHttpTransaction *trans, PRInt32 priority) + { + return mConnMgr->RescheduleTransaction(trans, priority); } // Called to cancel a transaction, which may or may not be assigned to diff --git a/netwerk/protocol/http/src/nsHttpTransaction.cpp b/netwerk/protocol/http/src/nsHttpTransaction.cpp index 8ad5dd8a7911..e139fb89bc5f 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/src/nsHttpTransaction.cpp @@ -124,6 +124,7 @@ nsHttpTransaction::nsHttpTransaction() , mContentLength(-1) , mContentRead(0) , mChunkedDecoder(nsnull) + , mPriority(0) , mStatus(NS_OK) , mRestartCount(0) , mCaps(0) @@ -565,7 +566,7 @@ nsHttpTransaction::Restart() mSecurityInfo = 0; NS_IF_RELEASE(mConnection); - return gHttpHandler->InitiateTransaction(this); + return gHttpHandler->InitiateTransaction(this, mPriority); } void diff --git a/netwerk/protocol/http/src/nsHttpTransaction.h b/netwerk/protocol/http/src/nsHttpTransaction.h index 801a768e2ed5..7c3289e33eea 100644 --- a/netwerk/protocol/http/src/nsHttpTransaction.h +++ b/netwerk/protocol/http/src/nsHttpTransaction.h @@ -132,6 +132,10 @@ public: void SetSSLConnectFailed() { mSSLConnectFailed = PR_TRUE; } PRBool SSLConnectFailed() { return mSSLConnectFailed; } + // These methods may only be used by the connection manager. + void SetPriority(PRInt32 priority) { mPriority = priority; } + PRInt32 Priority() { return mPriority; } + private: nsresult Restart(); void ParseLine(char *line); @@ -181,6 +185,8 @@ private: nsresult mStatus; + PRInt16 mPriority; + PRUint16 mRestartCount; // the number of times this transaction has been restarted PRUint8 mCaps;