bug 1129571 - h2/spdy coalsescing by full DNS rrset r=hurley

This commit is contained in:
Patrick McManus 2015-01-30 10:55:07 -05:00
parent 811d8614fd
commit c2d290654c
8 changed files with 168 additions and 58 deletions

View File

@ -1988,11 +1988,13 @@ NS_IMPL_ISUPPORTS(nsSocketTransport,
nsISocketTransport,
nsITransport,
nsIDNSListener,
nsIClassInfo)
nsIClassInfo,
nsIInterfaceRequestor)
NS_IMPL_CI_INTERFACE_GETTER(nsSocketTransport,
nsISocketTransport,
nsITransport,
nsIDNSListener)
nsIDNSListener,
nsIInterfaceRequestor)
NS_IMETHODIMP
nsSocketTransport::OpenInputStream(uint32_t flags,
@ -2419,6 +2421,17 @@ nsSocketTransport::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
// nsIInterfaceRequestor
NS_IMETHODIMP
nsSocketTransport::GetInterface(const nsIID &iid, void **result)
{
if (iid.Equals(NS_GET_IID(nsIDNSRecord))) {
return mDNSRecord ?
mDNSRecord->QueryInterface(iid, result) : NS_ERROR_NO_INTERFACE;
}
return this->QueryInterface(iid, result);
}
NS_IMETHODIMP
nsSocketTransport::GetInterfaces(uint32_t *count, nsIID * **array)
{

View File

@ -14,6 +14,7 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIInterfaceRequestor.h"
#include "nsISocketTransport.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
@ -108,6 +109,7 @@ class nsSocketTransport MOZ_FINAL : public nsASocketHandler
, public nsISocketTransport
, public nsIDNSListener
, public nsIClassInfo
, public nsIInterfaceRequestor
{
typedef mozilla::Mutex Mutex;
@ -117,6 +119,7 @@ public:
NS_DECL_NSISOCKETTRANSPORT
NS_DECL_NSIDNSLISTENER
NS_DECL_NSICLASSINFO
NS_DECL_NSIINTERFACEREQUESTOR
nsSocketTransport();

View File

@ -94,6 +94,13 @@ ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
return NS_OK;
}
NS_IMETHODIMP
ChildDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray)
{
aAddressArray = mAddresses;
return NS_OK;
}
// shamelessly copied from nsDNSRecord
NS_IMETHODIMP
ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr **result)

View File

@ -172,6 +172,46 @@ nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
return NS_OK;
}
NS_IMETHODIMP
nsDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray)
{
if (mDone) {
return NS_ERROR_NOT_AVAILABLE;
}
mHostRecord->addr_info_lock.Lock();
if (mHostRecord->addr_info) {
for (NetAddrElement *iter = mHostRecord->addr_info->mAddresses.getFirst();
iter; iter = iter->getNext()) {
if (mHostRecord->Blacklisted(&iter->mAddress)) {
continue;
}
NetAddr *addr = aAddressArray.AppendElement(NetAddr());
memcpy(addr, &iter->mAddress, sizeof(NetAddr));
if (addr->raw.family == AF_INET) {
addr->inet.port = 0;
} else if (addr->raw.family == AF_INET6) {
addr->inet6.port = 0;
}
}
mHostRecord->addr_info_lock.Unlock();
} else {
mHostRecord->addr_info_lock.Unlock();
if (!mHostRecord->addr) {
return NS_ERROR_NOT_AVAILABLE;
}
NetAddr *addr = aAddressArray.AppendElement(NetAddr());
memcpy(addr, mHostRecord->addr, sizeof(NetAddr));
if (addr->raw.family == AF_INET) {
addr->inet.port = 0;
} else if (addr->raw.family == AF_INET6) {
addr->inet6.port = 0;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr * *result)
{

View File

@ -10,8 +10,10 @@ namespace net {
union NetAddr;
}
}
template<class T> class nsTArray;
%}
native NetAddr(mozilla::net::NetAddr);
[ref] native nsNetAddrTArrayRef(nsTArray<mozilla::net::NetAddr>);
interface nsINetAddr;
/**
@ -22,7 +24,7 @@ interface nsINetAddr;
* like an enumerator, allowing the caller to easily step through the
* list of IP addresses.
*/
[scriptable, uuid(95ced6f3-44b4-4427-a149-c9a1e033d852)]
[scriptable, uuid(f92228ae-c417-4188-a604-0830a95e7eb9)]
interface nsIDNSRecord : nsISupports
{
/**
@ -45,6 +47,15 @@ interface nsIDNSRecord : nsISupports
*/
[noscript] NetAddr getNextAddr(in uint16_t aPort);
/**
* this function copies the value of all working members of the RR
* set into the output array.
*
* @param aAddressArray
* The result set
*/
[noscript] void getAddresses(out nsNetAddrTArrayRef aAddressArray);
/**
* this function returns the value of the next IP address as a
* scriptable address and increments the internal address iterator.

View File

@ -70,10 +70,10 @@ nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key,
ent->mIdleConns.Length());
self->mLogData.AppendPrintf(" Half Opens Length = %u\n",
ent->mHalfOpens.Length());
self->mLogData.AppendPrintf(" Coalescing Key = %s\n",
ent->mCoalescingKey.get());
self->mLogData.AppendPrintf(" Coalescing Keys Length = %u\n",
ent->mCoalescingKeys.Length());
self->mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n",
ent->mUsingSpdy, ent->mTestedSpdy, ent->mSpdyPreferred);
ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash);
self->mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n",
ent->mPipelineState, ent->mPipeliningPenalty);
for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
@ -96,7 +96,10 @@ nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key,
self->mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
ent->mPendingQ[i]->PrintDiagnostics(self->mLogData);
}
for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
self->mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
i, ent->mCoalescingKeys[i].get());
}
return PL_DHASH_NEXT;
}

View File

@ -26,6 +26,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/net/DashboardTypes.h"
#include "NullHttpTransaction.h"
#include "nsIDNSRecord.h"
#include "nsITransport.h"
#include "nsISocketTransportService.h"
#include <algorithm>
@ -569,6 +570,46 @@ nsHttpConnectionMgr::ClearConnectionHistory()
return NS_OK;
}
nsHttpConnectionMgr::nsConnectionEntry *
nsHttpConnectionMgr::LookupPreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent)
{
nsConnectionEntry *preferred = nullptr;
uint32_t len = ent->mCoalescingKeys.Length();
for (uint32_t i = 0; !preferred && (i < len); ++i) {
preferred = mSpdyPreferredHash.Get(ent->mCoalescingKeys[i]);
}
return preferred;
}
void
nsHttpConnectionMgr::StorePreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent)
{
if (ent->mCoalescingKeys.IsEmpty()) {
return;
}
ent->mInPreferredHash = true;
uint32_t len = ent->mCoalescingKeys.Length();
for (uint32_t i = 0; i < len; ++i) {
mSpdyPreferredHash.Put(ent->mCoalescingKeys[i], ent);
}
}
void
nsHttpConnectionMgr::RemovePreferredHash(nsHttpConnectionMgr::nsConnectionEntry *ent)
{
if (!ent->mInPreferredHash || ent->mCoalescingKeys.IsEmpty()) {
return;
}
ent->mInPreferredHash = false;
uint32_t len = ent->mCoalescingKeys.Length();
for (uint32_t i = 0; i < len; ++i) {
mSpdyPreferredHash.Remove(ent->mCoalescingKeys[i]);
}
}
// Given a nsHttpConnectionInfo find the connection entry object that
// contains either the nshttpconnection or nshttptransaction parameter.
// Normally this is done by the hashkey lookup of connectioninfo,
@ -587,13 +628,13 @@ nsHttpConnectionMgr::LookupConnectionEntry(nsHttpConnectionInfo *ci,
// If there is no sign of coalescing (or it is disabled) then just
// return the primary hash lookup
if (!ent || !ent->mUsingSpdy || ent->mCoalescingKey.IsEmpty())
if (!ent || !ent->mUsingSpdy || ent->mCoalescingKeys.IsEmpty())
return ent;
// If there is no preferred coalescing entry for this host (or the
// preferred entry is the one that matched the mCT hash lookup) then
// there is only option
nsConnectionEntry *preferred = mSpdyPreferredHash.Get(ent->mCoalescingKey);
nsConnectionEntry *preferred = LookupPreferredHash(ent);
if (!preferred || (preferred == ent))
return ent;
@ -674,18 +715,15 @@ nsHttpConnectionMgr::ReportSpdyConnection(nsHttpConnection *conn,
// lookup. Filtering on that has to be done at the time of use
// rather than the time of registration (i.e. now).
nsConnectionEntry *joinedConnection;
nsConnectionEntry *preferred =
mSpdyPreferredHash.Get(ent->mCoalescingKey);
nsConnectionEntry *preferred = LookupPreferredHash(ent);
LOG(("ReportSpdyConnection %s %s ent=%p preferred=%p\n",
ent->mConnInfo->Host(), ent->mCoalescingKey.get(),
ent, preferred));
LOG(("ReportSpdyConnection %p,%s prefers %p,%s\n",
ent, ent->mConnInfo->Host(), preferred,
preferred ? preferred->mConnInfo->Host() : ""));
if (!preferred) {
if (!ent->mCoalescingKey.IsEmpty()) {
mSpdyPreferredHash.Put(ent->mCoalescingKey, ent);
ent->mSpdyPreferred = true;
}
// this becomes the preferred entry
StorePreferredHash(ent);
} else if ((preferred != ent) &&
(joinedConnection = GetSpdyPreferredEnt(ent)) &&
(joinedConnection != ent)) {
@ -775,11 +813,11 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
{
if (!gHttpHandler->IsSpdyEnabled() ||
!gHttpHandler->CoalesceSpdy() ||
aOriginalEntry->mCoalescingKey.IsEmpty())
aOriginalEntry->mCoalescingKeys.IsEmpty()) {
return nullptr;
}
nsConnectionEntry *preferred =
mSpdyPreferredHash.Get(aOriginalEntry->mCoalescingKey);
nsConnectionEntry *preferred = LookupPreferredHash(aOriginalEntry);
// if there is no redirection no cert validation is required
if (preferred == aOriginalEntry)
@ -807,8 +845,7 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
if (!activeSpdy) {
// remove the preferred status of this entry if it cannot be
// used for pooling.
preferred->mSpdyPreferred = false;
RemoveSpdyPreferredEnt(preferred->mCoalescingKey);
RemovePreferredHash(preferred);
LOG(("nsHttpConnectionMgr::GetSpdyPreferredConnection "
"preferred host mapping %s to %s removed due to inactivity.\n",
aOriginalEntry->mConnInfo->Host(),
@ -872,15 +909,6 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
return preferred;
}
void
nsHttpConnectionMgr::RemoveSpdyPreferredEnt(nsACString &aHashKey)
{
if (aHashKey.IsEmpty())
return;
mSpdyPreferredHash.Remove(aHashKey);
}
//-----------------------------------------------------------------------------
// enumeration callbacks
@ -2749,8 +2777,7 @@ nsHttpConnectionMgr::OnMsgUpdateParam(int32_t, void *param)
nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
{
MOZ_COUNT_DTOR(nsConnectionEntry);
if (mSpdyPreferred)
gHttpHandler->ConnMgr()->RemoveSpdyPreferredEnt(mCoalescingKey);
gHttpHandler->ConnMgr()->RemovePreferredHash(this);
}
void
@ -3469,32 +3496,36 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
// just completed. We can't do coalescing if using a proxy because the
// ip addresses are not available to the client.
if (status == NS_NET_STATUS_CONNECTED_TO &&
if (status == NS_NET_STATUS_CONNECTING_TO &&
gHttpHandler->IsSpdyEnabled() &&
gHttpHandler->CoalesceSpdy() &&
mEnt && mEnt->mConnInfo && mEnt->mConnInfo->EndToEndSSL() &&
!mEnt->mConnInfo->UsingProxy() &&
mEnt->mCoalescingKey.IsEmpty()) {
mEnt->mCoalescingKeys.IsEmpty()) {
NetAddr addr;
nsresult rv = mSocketTransport->GetPeerAddr(&addr);
if (NS_SUCCEEDED(rv)) {
mEnt->mCoalescingKey.SetCapacity(kIPv6CStrBufSize + 26);
NetAddrToString(&addr, mEnt->mCoalescingKey.BeginWriting(), kIPv6CStrBufSize);
mEnt->mCoalescingKey.SetLength(
strlen(mEnt->mCoalescingKey.BeginReading()));
if (mEnt->mConnInfo->GetAnonymous())
mEnt->mCoalescingKey.AppendLiteral("~A:");
else
mEnt->mCoalescingKey.AppendLiteral("~.:");
mEnt->mCoalescingKey.AppendInt(mEnt->mConnInfo->Port());
LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus "
"STATUS_CONNECTED_TO Established New Coalescing Key for host "
"%s [%s]", mEnt->mConnInfo->Host(),
mEnt->mCoalescingKey.get()));
nsCOMPtr<nsIDNSRecord> dnsRecord(do_GetInterface(mSocketTransport));
nsTArray<NetAddr> addressSet;
nsresult rv = NS_ERROR_NOT_AVAILABLE;
if (dnsRecord) {
rv = dnsRecord->GetAddresses(addressSet);
}
if (NS_SUCCEEDED(rv) && !addressSet.IsEmpty()) {
for (uint32_t i = 0; i < addressSet.Length(); ++i) {
nsCString *newKey = mEnt->mCoalescingKeys.AppendElement(nsCString());
newKey->SetCapacity(kIPv6CStrBufSize + 26);
NetAddrToString(&addressSet[i], newKey->BeginWriting(), kIPv6CStrBufSize);
newKey->SetLength(strlen(newKey->BeginReading()));
if (mEnt->mConnInfo->GetAnonymous()) {
newKey->AppendLiteral("~A:");
} else {
newKey->AppendLiteral("~.:");
}
newKey->AppendInt(mEnt->mConnInfo->Port());
LOG(("nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus "
"STATUS_CONNECTING_TO Established New Coalescing Key # %d for host "
"%s [%s]", i, mEnt->mConnInfo->Host(), newKey->get()));
}
gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt);
}
}
@ -3585,7 +3616,7 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
, mSpdyCWND(0)
, mUsingSpdy(false)
, mTestedSpdy(false)
, mSpdyPreferred(false)
, mInPreferredHash(false)
, mPreferIPv4(false)
, mPreferIPv6(false)
{

View File

@ -364,7 +364,7 @@ private:
// mSpdyPreferred. The mapping is maintained in the connection mananger
// mSpdyPreferred hash.
//
nsCString mCoalescingKey;
nsTArray<nsCString> mCoalescingKeys;
// The value of a recevied SPDY settings type 5 previously received
// for this connection entry and the time it was set.
@ -382,7 +382,7 @@ private:
// minimized so that we can multiplex on a single spdy connection.
bool mTestedSpdy;
bool mSpdyPreferred;
bool mInPreferredHash;
// Flags to remember our happy-eyeballs decision.
// Reset only by Ctrl-F5 reload.
@ -589,7 +589,9 @@ private:
// Manage the preferred spdy connection entry for this address
nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal);
nsConnectionEntry *LookupPreferredHash(nsConnectionEntry *ent);
void StorePreferredHash(nsConnectionEntry *ent);
void RemovePreferredHash(nsConnectionEntry *ent);
nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent);
nsDataHashtable<nsCStringHashKey, nsConnectionEntry *> mSpdyPreferredHash;
nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,