Bug 1377208 - Move background h2 stream into background group. r=hurley

This commit is contained in:
Kershaw Chang 2017-08-30 02:19:00 -04:00
parent af8a2b8fbb
commit 567b0d202a
9 changed files with 222 additions and 33 deletions

View File

@ -63,8 +63,9 @@ private:
Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction,
Http2Session *aSession,
Http2Stream *aAssociatedStream,
uint32_t aID)
:Http2Stream(aTransaction, aSession, 0)
uint32_t aID,
uint64_t aCurrentForegroundTabOuterContentWindowId)
:Http2Stream(aTransaction, aSession, 0, aCurrentForegroundTabOuterContentWindowId)
, mConsumerStream(nullptr)
, mAssociatedTransaction(aAssociatedStream->Transaction())
, mBufferedPush(aTransaction)

View File

@ -32,7 +32,8 @@ public:
Http2PushedStream(Http2PushTransactionBuffer *aTransaction,
Http2Session *aSession,
Http2Stream *aAssociatedStream,
uint32_t aID);
uint32_t aID,
uint64_t aCurrentForegroundTabOuterContentWindowId);
virtual ~Http2PushedStream() {}
bool GetPushComplete();

View File

@ -140,6 +140,8 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
mPingThreshold = gHttpHandler->SpdyPingThreshold();
mPreviousPingThreshold = mPingThreshold;
mCurrentForegroundTabOuterContentWindowId =
gHttpHandler->ConnMgr()->CurrentTopLevelOuterContentWindowId();
}
void
@ -418,7 +420,11 @@ Http2Session::AddStream(nsAHttpTransaction *aHttpTransaction,
return true;
}
Http2Stream *stream = new Http2Stream(aHttpTransaction, this, aPriority);
Http2Stream *stream =
new Http2Stream(aHttpTransaction,
this,
aPriority,
mCurrentForegroundTabOuterContentWindowId);
LOG3(("Http2Session::AddStream session=%p stream=%p serial=%" PRIu64 " "
"NextID=0x%X (tentative)", this, stream, mSerial, mNextStreamID));
@ -797,14 +803,9 @@ Http2Session::GeneratePriority(uint32_t aID, uint8_t aPriorityWeight)
LOG3(("Http2Session::GeneratePriority %p %X %X\n",
this, aID, aPriorityWeight));
uint32_t frameSize = kFrameHeaderBytes + 5;
char *packet = EnsureOutputBuffer(frameSize);
mOutputQueueUsed += frameSize;
char *packet = CreatePriorityFrame(aID, 0, aPriorityWeight);
CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, aID);
NetworkEndian::writeUint32(packet + kFrameHeaderBytes, 0);
memcpy(packet + frameSize - 1, &aPriorityWeight, 1);
LogIO(this, nullptr, "Generate Priority", packet, frameSize);
LogIO(this, nullptr, "Generate Priority", packet, kFrameHeaderBytes + 5);
FlushOutputQueue();
}
@ -981,14 +982,38 @@ Http2Session::SendHello()
}
void
Http2Session::CreatePriorityNode(uint32_t streamID, uint32_t dependsOn, uint8_t weight,
const char *label)
Http2Session::SendPriorityFrame(uint32_t streamID,
uint32_t dependsOn,
uint8_t weight)
{
char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG3(("Http2Session::SendPriorityFrame %p Frame 0x%X depends on 0x%X "
"weight %d\n", this, streamID, dependsOn, weight));
char *packet = CreatePriorityFrame(streamID, dependsOn, weight);
LogIO(this, nullptr, "SendPriorityFrame", packet, kFrameHeaderBytes + 5);
FlushOutputQueue();
}
char *
Http2Session::CreatePriorityFrame(uint32_t streamID,
uint32_t dependsOn,
uint8_t weight)
{
char *packet = EnsureOutputBuffer(kFrameHeaderBytes + 5);
CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, streamID);
mOutputQueueUsed += kFrameHeaderBytes + 5;
NetworkEndian::writeUint32(packet + kFrameHeaderBytes, dependsOn); // depends on
packet[kFrameHeaderBytes + 4] = weight; // weight
return packet;
}
void
Http2Session::CreatePriorityNode(uint32_t streamID, uint32_t dependsOn, uint8_t weight,
const char *label)
{
char *packet = CreatePriorityFrame(streamID, dependsOn, weight);
LOG3(("Http2Session %p generate Priority Frame 0x%X depends on 0x%X "
"weight %d for %s class\n", this, streamID, dependsOn, weight, label));
@ -1755,7 +1780,11 @@ Http2Session::RecvPushPromise(Http2Session *self)
new Http2PushTransactionBuffer();
transactionBuffer->SetConnection(self);
Http2PushedStream *pushedStream =
new Http2PushedStream(transactionBuffer, self, associatedStream, promisedID);
new Http2PushedStream(transactionBuffer,
self,
associatedStream,
promisedID,
self->mCurrentForegroundTabOuterContentWindowId);
rv = pushedStream->ConvertPushHeaders(&self->mDecompressor,
self->mDecompressBuffer,
@ -4464,5 +4493,17 @@ Http2Session::RealJoinConnection(const nsACString &hostname, int32_t port,
return joinedReturn;
}
void
Http2Session::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
{
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
mCurrentForegroundTabOuterContentWindowId = windowId;
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
iter.Data()->TopLevelOuterContentWindowIdChanged(windowId);
}
}
} // namespace net
} // namespace mozilla

View File

@ -258,6 +258,8 @@ public:
// For use by an HTTP2Stream
void Received421(nsHttpConnectionInfo *ci);
void SendPriorityFrame(uint32_t streamID, uint32_t dependsOn, uint8_t weight);
private:
// These internal states do not correspond to the states of the HTTP/2 specification
@ -307,6 +309,7 @@ private:
MOZ_MUST_USE nsresult SetInputFrameDataStream(uint32_t);
void CreatePriorityNode(uint32_t, uint32_t, uint8_t, const char *);
char *CreatePriorityFrame(uint32_t, uint32_t, uint8_t);
bool VerifyStream(Http2Stream *, uint32_t);
void SetNeedsCleanup();
@ -533,6 +536,8 @@ private:
nsDataHashtable<nsCStringHashKey, bool> mJoinConnectionCache;
uint64_t mCurrentForegroundTabOuterContentWindowId;
class CachePushCheckCallback final : public nsICacheEntryOpenCallback
{
public:

View File

@ -38,7 +38,8 @@ namespace net {
Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
Http2Session *session,
int32_t priority)
int32_t priority,
uint64_t windowId)
: mStreamID(0)
, mSession(session)
, mSegmentReader(nullptr)
@ -72,6 +73,8 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
, mTotalRead(0)
, mPushSource(nullptr)
, mAttempting0RTT(false)
, mCurrentForegroundTabOuterContentWindowId(windowId)
, mTransactionTabId(0)
, mIsTunnel(false)
, mPlainTextTunnel(false)
{
@ -100,6 +103,11 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
}
MOZ_ASSERT(httpPriority >= 0);
SetPriority(static_cast<uint32_t>(httpPriority));
nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
if (trans) {
mTransactionTabId = trans->TopLevelOuterContentWindowId();
}
}
Http2Stream::~Http2Stream()
@ -1202,6 +1210,40 @@ Http2Stream::SetPriorityDependency(uint32_t newDependency, uint8_t newWeight,
exclusive));
}
static uint32_t
GetPriorityDependencyFromTransaction(nsHttpTransaction *trans)
{
MOZ_ASSERT(trans);
uint32_t classFlags = trans->ClassOfService();
if (classFlags & nsIClassOfService::UrgentStart) {
return Http2Session::kUrgentStartGroupID;
}
if (classFlags & nsIClassOfService::Leader) {
return Http2Session::kLeaderGroupID;
}
if (classFlags & nsIClassOfService::Follower) {
return Http2Session::kFollowerGroupID;
}
if (classFlags & nsIClassOfService::Speculative) {
return Http2Session::kSpeculativeGroupID;
}
if (classFlags & nsIClassOfService::Background) {
return Http2Session::kBackgroundGroupID;
}
if (classFlags & nsIClassOfService::Unblocked) {
return Http2Session::kOtherGroupID;
}
return Http2Session::kFollowerGroupID; // unmarked followers
}
void
Http2Stream::UpdatePriorityDependency()
{
@ -1230,27 +1272,56 @@ Http2Stream::UpdatePriorityDependency()
// spculative bg streams depend on 9
// urgent-start streams depend on d
uint32_t classFlags = trans->ClassOfService();
mPriorityDependency = GetPriorityDependencyFromTransaction(trans);
if (classFlags & nsIClassOfService::Leader) {
mPriorityDependency = Http2Session::kLeaderGroupID;
} else if (classFlags & nsIClassOfService::Follower) {
mPriorityDependency = Http2Session::kFollowerGroupID;
} else if (classFlags & nsIClassOfService::Speculative) {
mPriorityDependency = Http2Session::kSpeculativeGroupID;
} else if (classFlags & nsIClassOfService::Background) {
if (mTransactionTabId != mCurrentForegroundTabOuterContentWindowId &&
mPriorityDependency != Http2Session::kUrgentStartGroupID) {
LOG3(("Http2Stream::UpdatePriorityDependency %p "
" depends on background group for trans %p\n",
this, trans));
mPriorityDependency = Http2Session::kBackgroundGroupID;
} else if (classFlags & nsIClassOfService::Unblocked) {
mPriorityDependency = Http2Session::kOtherGroupID;
} else if (classFlags & nsIClassOfService::UrgentStart) {
mPriorityDependency = Http2Session::kUrgentStartGroupID;
} else {
mPriorityDependency = Http2Session::kFollowerGroupID; // unmarked followers
}
LOG3(("Http2Stream::UpdatePriorityDependency %p "
"classFlags %X depends on stream 0x%X\n",
this, classFlags, mPriorityDependency));
"depends on stream 0x%X\n",
this, mPriorityDependency));
}
void
Http2Stream::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
{
LOG3(("Http2Stream::TopLevelOuterContentWindowIdChanged "
"%p windowId=%" PRIx64 "\n",
this, windowId));
mCurrentForegroundTabOuterContentWindowId = windowId;
if (!mSession->UseH2Deps()) {
return;
}
// Urgent start takes an absolute precedence, so don't
// change mPriorityDependency here.
if (mPriorityDependency == Http2Session::kUrgentStartGroupID) {
return;
}
if (mTransactionTabId != mCurrentForegroundTabOuterContentWindowId) {
mPriorityDependency = Http2Session::kBackgroundGroupID;
LOG3(("Http2Stream::TopLevelOuterContentWindowIdChanged %p "
"move into background group.\n", this));
} else {
nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
if (!trans) {
return;
}
mPriorityDependency = GetPriorityDependencyFromTransaction(trans);
LOG3(("Http2Stream::TopLevelOuterContentWindowIdChanged %p "
"depends on stream 0x%X\n", this, mPriorityDependency));
}
mSession->SendPriorityFrame(mStreamID, mPriorityDependency, mPriorityWeight);
}
void

View File

@ -52,7 +52,7 @@ public:
const static int32_t kWorstPriority = kNormalPriority + nsISupportsPriority::PRIORITY_LOWEST;
const static int32_t kBestPriority = kNormalPriority + nsISupportsPriority::PRIORITY_HIGHEST;
Http2Stream(nsAHttpTransaction *, Http2Session *, int32_t);
Http2Stream(nsAHttpTransaction *, Http2Session *, int32_t, uint64_t);
uint32_t StreamID() { return mStreamID; }
Http2PushedStream *PushSource() { return mPushSource; }
@ -170,6 +170,8 @@ public:
nsresult GetOriginAttributes(mozilla::OriginAttributes *oa);
void TopLevelOuterContentWindowIdChanged(uint64_t windowId);
protected:
static void CreatePushHashKey(const nsCString &scheme,
const nsCString &hostHeader,
@ -347,6 +349,10 @@ private:
bool mAttempting0RTT;
uint64_t mCurrentForegroundTabOuterContentWindowId;
uint64_t mTransactionTabId;
/// connect tunnels
public:
bool IsTunnel() { return mIsTunnel; }

View File

@ -144,6 +144,9 @@ public:
// nsHttp.h version
virtual uint32_t Version() = 0;
// A notification of the current active tab id change.
virtual void TopLevelOuterContentWindowIdChanged(uint64_t windowId) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpConnection, NS_AHTTPCONNECTION_IID)
@ -163,6 +166,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpConnection, NS_AHTTPCONNECTION_IID)
MOZ_MUST_USE nsresult PushBack(const char *, uint32_t) override; \
already_AddRefed<nsHttpConnection> TakeHttpConnection() override; \
already_AddRefed<nsHttpConnection> HttpConnection() override; \
void TopLevelOuterContentWindowIdChanged(uint64_t windowId) override; \
/* \
Thes methods below have automatic definitions that just forward the \
function to a lower level connection object \

View File

@ -3413,6 +3413,47 @@ nsHttpConnectionMgr::ResumeReadOf(nsTArray<RefPtr<nsHttpTransaction>>* transacti
}
}
void
nsHttpConnectionMgr::NotifyConnectionOfWindowIdChange(uint64_t previousWindowId)
{
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
nsTArray<RefPtr<nsHttpTransaction>> *transactions = nullptr;
nsTArray<RefPtr<nsAHttpConnection>> connections;
auto addConnectionHelper =
[&connections](nsTArray<RefPtr<nsHttpTransaction>> *trans) {
if (!trans) {
return;
}
for (auto t : *trans) {
RefPtr<nsAHttpConnection> conn = t->Connection();
if (conn && !connections.Contains(conn)) {
connections.AppendElement(conn);
}
}
};
// Get unthrottled transactions with the previous and current window id.
transactions = mActiveTransactions[false].Get(previousWindowId);
addConnectionHelper(transactions);
transactions =
mActiveTransactions[false].Get(mCurrentTopLevelOuterContentWindowId);
addConnectionHelper(transactions);
// Get throttled transactions with the previous and current window id.
transactions = mActiveTransactions[true].Get(previousWindowId);
addConnectionHelper(transactions);
transactions =
mActiveTransactions[true].Get(mCurrentTopLevelOuterContentWindowId);
addConnectionHelper(transactions);
for (auto conn : connections) {
conn->TopLevelOuterContentWindowIdChanged(mCurrentTopLevelOuterContentWindowId);
}
}
void
nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId(
int32_t aLoading, ARefBase *param)
@ -3429,8 +3470,11 @@ nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId(
bool activeTabWasLoading = mActiveTabTransactionsExist;
bool activeTabIdChanged = mCurrentTopLevelOuterContentWindowId != winId;
uint64_t previousWindowId = mCurrentTopLevelOuterContentWindowId;
mCurrentTopLevelOuterContentWindowId = winId;
NotifyConnectionOfWindowIdChange(previousWindowId);
LOG(("nsHttpConnectionMgr::OnMsgUpdateCurrentTopLevelOuterContentWindowId"
" id=%" PRIx64 "\n",
mCurrentTopLevelOuterContentWindowId));
@ -4898,6 +4942,12 @@ ConnectionHandle::HttpConnection()
return rv.forget();
}
void
ConnectionHandle::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
{
// Do nothing.
}
// nsConnectionEntry
nsHttpConnectionMgr::

View File

@ -242,6 +242,11 @@ public:
// NOTE: relatively expensive to call, there are two hashtable lookups.
bool IsConnEntryUnderPressure(nsHttpConnectionInfo*);
uint64_t CurrentTopLevelOuterContentWindowId()
{
return mCurrentTopLevelOuterContentWindowId;
}
private:
virtual ~nsHttpConnectionMgr();
@ -760,6 +765,11 @@ private:
nsTArray<RefPtr<PendingTransactionInfo>>*
GetTransactionPendingQHelper(nsConnectionEntry *ent, nsAHttpTransaction *trans);
// When current active tab is changed, this function uses
// |previousWindowId| to select background transactions and
// mCurrentTopLevelOuterContentWindowId| to select foreground transactions.
// Then, it notifies selected transactions' connection of the new active tab id.
void NotifyConnectionOfWindowIdChange(uint64_t previousWindowId);
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnectionMgr::nsHalfOpenSocket, NS_HALFOPENSOCKET_IID)