зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1493204
- Add pushed streams to the priority tree. r=dragana
Previously, we had not put pushed streams in the priority tree, we just let them be top-level items in the tree. With this change, we will put them into the tree initially based on the priority of the associated stream. The only exception is if the associated stream is either a Leader or Urgent Start (in which case, we will turn the pushed streams into followers). Once the pushed stream is matched with a request generated by gecko, that pushed stream will be re-prioritized based on the priority gecko has for the request, just like a regular pulled stream. This also allows us to re-prioritize pushed streams into the background on tab switch (we assume that, before they are matched, they belong to the same window as the associated stream). Differential Revision: https://phabricator.services.mozilla.com/D7223 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a56f9d6b1a
Коммит
44ca650a2b
|
@ -81,7 +81,18 @@ Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction,
|
|||
mBufferedPush->SetPushStream(this);
|
||||
mRequestContext = aAssociatedStream->RequestContext();
|
||||
mLastRead = TimeStamp::Now();
|
||||
SetPriority(aAssociatedStream->Priority() + 1);
|
||||
mPriorityDependency = aAssociatedStream->PriorityDependency();
|
||||
if (mPriorityDependency == Http2Session::kUrgentStartGroupID ||
|
||||
mPriorityDependency == Http2Session::kLeaderGroupID) {
|
||||
mPriorityDependency = Http2Session::kFollowerGroupID;
|
||||
}
|
||||
// Cache this for later use in case of tab switch.
|
||||
mDefaultPriorityDependency = mPriorityDependency;
|
||||
SetPriorityDependency(aAssociatedStream->Priority() + 1, mPriorityDependency);
|
||||
// Assume we are on the same tab as our associated stream, for priority purposes.
|
||||
// It's possible this could change when we get paired with a sink, but it's unlikely
|
||||
// and doesn't much matter anyway.
|
||||
mTransactionTabId = aAssociatedStream->TransactionTabId();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -310,6 +321,36 @@ Http2PushedStream::GetBufferedData(char *buf,
|
|||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
Http2PushedStream::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
|
||||
{
|
||||
if (mConsumerStream) {
|
||||
// Pass through to our sink, who will handle things appropriately.
|
||||
mConsumerStream->TopLevelOuterContentWindowIdChangedInternal(windowId);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gHttpHandler->ActiveTabPriority());
|
||||
|
||||
mCurrentForegroundTabOuterContentWindowId = windowId;
|
||||
|
||||
if (!mSession->UseH2Deps()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t oldDependency = mPriorityDependency;
|
||||
if (mTransactionTabId != mCurrentForegroundTabOuterContentWindowId) {
|
||||
mPriorityDependency = Http2Session::kBackgroundGroupID;
|
||||
nsHttp::NotifyActiveTabLoadOptimization();
|
||||
} else {
|
||||
mPriorityDependency = mDefaultPriorityDependency;
|
||||
}
|
||||
|
||||
if (mPriorityDependency != oldDependency) {
|
||||
mSession->SendPriorityFrame(mStreamID, mPriorityDependency, mPriorityWeight);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Http2PushTransactionBuffer
|
||||
// This is the nsAHttpTransction owned by the stream when the pushed
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
// overload of Http2Stream
|
||||
virtual bool HasSink() override { return !!mConsumerStream; }
|
||||
virtual void SetPushComplete() override { mPushCompleted = true; }
|
||||
virtual void TopLevelOuterContentWindowIdChanged(uint64_t) override;
|
||||
|
||||
nsCString &GetRequestString() { return mRequestString; }
|
||||
|
||||
|
@ -99,6 +100,7 @@ private:
|
|||
bool mOnPushFailed;
|
||||
nsCString mRequestString;
|
||||
|
||||
uint32_t mDefaultPriorityDependency;
|
||||
};
|
||||
|
||||
class Http2PushTransactionBuffer final : public nsAHttpTransaction
|
||||
|
|
|
@ -1533,11 +1533,11 @@ Http2Session::RecvPriority(Http2Session *self)
|
|||
bool exclusive = !!(newPriorityDependency & 0x80000000);
|
||||
newPriorityDependency &= 0x7fffffff;
|
||||
uint8_t newPriorityWeight = *(self->mInputFrameBuffer.get() + kFrameHeaderBytes + 4);
|
||||
if (self->mInputFrameDataStream) {
|
||||
self->mInputFrameDataStream->SetPriorityDependency(newPriorityDependency,
|
||||
newPriorityWeight,
|
||||
exclusive);
|
||||
}
|
||||
|
||||
// undefined what it means when the server sends a priority frame. ignore it.
|
||||
LOG3(("Http2Session::RecvPriority %p 0x%X received dependency=0x%X "
|
||||
"weight=%u exclusive=%d", self->mInputFrameDataStream, self->mInputFrameID,
|
||||
newPriorityDependency, newPriorityWeight, exclusive));
|
||||
|
||||
self->ResetDownstreamState();
|
||||
return NS_OK;
|
||||
|
@ -1982,10 +1982,9 @@ Http2Session::RecvPushPromise(Http2Session *self)
|
|||
pushedStream->SetHTTPState(Http2Stream::RESERVED_BY_REMOTE);
|
||||
static_assert(Http2Stream::kWorstPriority >= 0,
|
||||
"kWorstPriority out of range");
|
||||
uint8_t priorityWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
|
||||
(Http2Stream::kWorstPriority - Http2Stream::kNormalPriority);
|
||||
pushedStream->SetPriority(Http2Stream::kWorstPriority);
|
||||
self->GeneratePriority(promisedID, priorityWeight);
|
||||
uint32_t priorityDependency = pushedStream->PriorityDependency();
|
||||
uint8_t priorityWeight = pushedStream->PriorityWeight();
|
||||
self->SendPriorityFrame(promisedID, priorityDependency, priorityWeight);
|
||||
self->ResetDownstreamState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
|||
, mAllHeadersReceived(0)
|
||||
, mQueued(0)
|
||||
, mSocketTransport(session->SocketTransport())
|
||||
, mCurrentForegroundTabOuterContentWindowId(windowId)
|
||||
, mTransactionTabId(0)
|
||||
, mTransaction(httpTransaction)
|
||||
, mChunkSize(session->SendingChunkSize())
|
||||
, mRequestBlockedOnRead(0)
|
||||
|
@ -73,8 +75,6 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
|||
, mTotalRead(0)
|
||||
, mPushSource(nullptr)
|
||||
, mAttempting0RTT(false)
|
||||
, mCurrentForegroundTabOuterContentWindowId(windowId)
|
||||
, mTransactionTabId(0)
|
||||
, mIsTunnel(false)
|
||||
, mPlainTextTunnel(false)
|
||||
{
|
||||
|
@ -789,6 +789,9 @@ Http2Stream::AdjustPushedPriority()
|
|||
if (mPushSource->RecvdFin() || mPushSource->RecvdReset())
|
||||
return;
|
||||
|
||||
// Ensure we pick up the right dependency to place the pushed stream under.
|
||||
UpdatePriorityDependency();
|
||||
|
||||
EnsureBuffer(mTxInlineFrame, mTxInlineFrameUsed + Http2Session::kFrameHeaderBytes + 5,
|
||||
mTxInlineFrameUsed, mTxInlineFrameSize);
|
||||
uint8_t *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
|
||||
|
@ -798,12 +801,13 @@ Http2Stream::AdjustPushedPriority()
|
|||
Http2Session::FRAME_TYPE_PRIORITY, 0,
|
||||
mPushSource->mStreamID);
|
||||
|
||||
mPushSource->SetPriority(mPriority);
|
||||
memset(packet + Http2Session::kFrameHeaderBytes, 0, 4);
|
||||
mPushSource->SetPriorityDependency(mPriority, mPriorityDependency);
|
||||
uint32_t wireDep = PR_htonl(mPriorityDependency);
|
||||
memcpy(packet + Http2Session::kFrameHeaderBytes, &wireDep, 4);
|
||||
memcpy(packet + Http2Session::kFrameHeaderBytes + 4, &mPriorityWeight, 1);
|
||||
|
||||
LOG3(("AdjustPushedPriority %p id 0x%X to weight %X\n", this, mPushSource->mStreamID,
|
||||
mPriorityWeight));
|
||||
LOG3(("AdjustPushedPriority %p id 0x%X to dep %X weight %X\n", this, mPushSource->mStreamID,
|
||||
mPriorityDependency, mPriorityWeight));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1241,13 +1245,10 @@ Http2Stream::SetPriority(uint32_t newPriority)
|
|||
}
|
||||
|
||||
void
|
||||
Http2Stream::SetPriorityDependency(uint32_t newDependency, uint8_t newWeight,
|
||||
bool exclusive)
|
||||
Http2Stream::SetPriorityDependency(uint32_t newPriority, uint32_t newDependency)
|
||||
{
|
||||
// undefined what it means when the server sends a priority frame. ignore it.
|
||||
LOG3(("Http2Stream::SetPriorityDependency %p 0x%X received dependency=0x%X "
|
||||
"weight=%u exclusive=%d", this, mStreamID, newDependency, newWeight,
|
||||
exclusive));
|
||||
SetPriority(newPriority);
|
||||
mPriorityDependency = newDependency;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
@ -1332,6 +1333,19 @@ Http2Stream::UpdatePriorityDependency()
|
|||
|
||||
void
|
||||
Http2Stream::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
|
||||
{
|
||||
if (!mStreamID) {
|
||||
// For pushed streams, we ignore the direct call from the session and
|
||||
// instead let it come to the internal function from the pushed stream, so
|
||||
// we don't accidentally send two PRIORITY frames for the same stream.
|
||||
return;
|
||||
}
|
||||
|
||||
TopLevelOuterContentWindowIdChangedInternal(windowId);
|
||||
}
|
||||
|
||||
void
|
||||
Http2Stream::TopLevelOuterContentWindowIdChangedInternal(uint64_t windowId)
|
||||
{
|
||||
MOZ_ASSERT(gHttpHandler->ActiveTabPriority());
|
||||
|
||||
|
@ -1368,8 +1382,12 @@ Http2Stream::TopLevelOuterContentWindowIdChanged(uint64_t windowId)
|
|||
"depends on stream 0x%X\n", this, mPriorityDependency));
|
||||
}
|
||||
|
||||
if (mStreamID) {
|
||||
mSession->SendPriorityFrame(mStreamID, mPriorityDependency, mPriorityWeight);
|
||||
uint32_t modifyStreamID = mStreamID;
|
||||
if (!modifyStreamID && mPushSource) {
|
||||
modifyStreamID = mPushSource->StreamID();
|
||||
}
|
||||
if (modifyStreamID) {
|
||||
mSession->SendPriorityFrame(modifyStreamID, mPriorityDependency, mPriorityWeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,10 +148,14 @@ public:
|
|||
bool BlockedOnRwin() { return mBlockedOnRwin; }
|
||||
|
||||
uint32_t Priority() { return mPriority; }
|
||||
uint32_t PriorityDependency() { return mPriorityDependency; }
|
||||
uint8_t PriorityWeight() { return mPriorityWeight; }
|
||||
void SetPriority(uint32_t);
|
||||
void SetPriorityDependency(uint32_t, uint8_t, bool);
|
||||
void SetPriorityDependency(uint32_t, uint32_t);
|
||||
void UpdatePriorityDependency();
|
||||
|
||||
uint64_t TransactionTabId() { return mTransactionTabId; }
|
||||
|
||||
// A pull stream has an implicit sink, a pushed stream has a sink
|
||||
// once it is matched to a pull stream.
|
||||
virtual bool HasSink() { return true; }
|
||||
|
@ -176,7 +180,8 @@ public:
|
|||
|
||||
nsresult GetOriginAttributes(mozilla::OriginAttributes *oa);
|
||||
|
||||
void TopLevelOuterContentWindowIdChanged(uint64_t windowId);
|
||||
virtual void TopLevelOuterContentWindowIdChanged(uint64_t windowId);
|
||||
void TopLevelOuterContentWindowIdChangedInternal(uint64_t windowId); // For use by pushed streams only
|
||||
|
||||
protected:
|
||||
static void CreatePushHashKey(const nsCString &scheme,
|
||||
|
@ -241,6 +246,11 @@ protected:
|
|||
// The underlying socket transport object is needed to propogate some events
|
||||
nsISocketTransport *mSocketTransport;
|
||||
|
||||
uint8_t mPriorityWeight; // h2 weight
|
||||
uint32_t mPriorityDependency; // h2 stream id this one depends on
|
||||
uint64_t mCurrentForegroundTabOuterContentWindowId;
|
||||
uint64_t mTransactionTabId;
|
||||
|
||||
private:
|
||||
friend class nsAutoPtr<Http2Stream>;
|
||||
|
||||
|
@ -318,8 +328,6 @@ private:
|
|||
int64_t mRequestBodyLenRemaining;
|
||||
|
||||
uint32_t mPriority; // geckoish weight
|
||||
uint32_t mPriorityDependency; // h2 stream id 3 - 0xb
|
||||
uint8_t mPriorityWeight; // h2 weight
|
||||
|
||||
// mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow control.
|
||||
// *window are signed because the race conditions in asynchronous SETTINGS
|
||||
|
@ -355,10 +363,6 @@ private:
|
|||
|
||||
bool mAttempting0RTT;
|
||||
|
||||
uint64_t mCurrentForegroundTabOuterContentWindowId;
|
||||
|
||||
uint64_t mTransactionTabId;
|
||||
|
||||
/// connect tunnels
|
||||
public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче