| Index: net/spdy/spdy_session.cc
|
| diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
|
| index 80e24c6dd79ebf42ec56f304563a9581be9efe6a..28bab83f51e3b78b0b419be874bcf4d751ad47c8 100644
|
| --- a/net/spdy/spdy_session.cc
|
| +++ b/net/spdy/spdy_session.cc
|
| @@ -59,6 +59,14 @@ const int kHungIntervalSeconds = 10;
|
| // Minimum seconds that unclaimed pushed streams will be kept in memory.
|
| const int kMinPushedStreamLifetimeSeconds = 300;
|
|
|
| +// Field trial constants
|
| +const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies";
|
| +const char kSpdyDepencenciesFieldTrialEnable[] = "Enable";
|
| +
|
| +// Whether the creation of SPDY dependencies based on priority is
|
| +// enabled by default.
|
| +static bool priority_dependency_enabled_default = false;
|
| +
|
| scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue(
|
| const SpdyHeaderBlock& headers,
|
| NetLogCaptureMode capture_mode) {
|
| @@ -691,6 +699,7 @@ SpdySession::SpdySession(
|
| hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
|
| trusted_spdy_proxy_(trusted_spdy_proxy),
|
| time_func_(time_func),
|
| + send_priority_dependency_(priority_dependency_enabled_default),
|
| weak_factory_(this) {
|
| DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
|
| DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
|
| @@ -700,6 +709,10 @@ SpdySession::SpdySession(
|
| base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
|
| next_unclaimed_push_stream_sweep_time_ = time_func_() +
|
| base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
|
| + if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) ==
|
| + kSpdyDepencenciesFieldTrialEnable) {
|
| + send_priority_dependency_ = true;
|
| + }
|
| // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
|
| }
|
|
|
| @@ -1045,6 +1058,11 @@ bool SpdySession::CloseOneIdleConnection() {
|
| return false;
|
| }
|
|
|
| +// static
|
| +void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) {
|
| + priority_dependency_enabled_default = enable;
|
| +}
|
| +
|
| void SpdySession::EnqueueStreamWrite(
|
| const base::WeakPtr<SpdyStream>& stream,
|
| SpdyFrameType frame_type,
|
| @@ -1085,6 +1103,41 @@ scoped_ptr<SpdyFrame> SpdySession::CreateSynStream(
|
| SpdyHeadersIR headers(stream_id);
|
| headers.set_priority(spdy_priority);
|
| headers.set_has_priority(true);
|
| +
|
| + if (send_priority_dependency_) {
|
| + // Set dependencies to reflect request priority. A newly created
|
| + // stream should be dependent on the most recent previously created
|
| + // stream of the same priority level. The newly created stream
|
| + // should also have all streams of a lower priority level dependent
|
| + // on it, which is guaranteed by setting the exclusive bit.
|
| + //
|
| + // Note that this depends on stream ids being allocated in a monotonically
|
| + // increasing fashion, and on all streams in
|
| + // active_streams_{,by_priority_} having stream ids set.
|
| + for (int i = priority; i >= IDLE; --i) {
|
| + if (active_streams_by_priority_[i].empty())
|
| + continue;
|
| +
|
| + auto candidate_it = active_streams_by_priority_[i].rbegin();
|
| +
|
| + // |active_streams_by_priority_| is updated before the
|
| + // SYN stream frame is created, so the current streams
|
| + // id is already on the list. Skip over it, skipping this
|
| + // priority level if it's singular.
|
| + if (candidate_it->second->stream_id() == stream_id)
|
| + ++candidate_it;
|
| + if (candidate_it == active_streams_by_priority_[i].rend())
|
| + continue;
|
| +
|
| + headers.set_parent_stream_id(candidate_it->second->stream_id());
|
| + break;
|
| + }
|
| +
|
| + // If there are no streams of priority <= the current stream, the
|
| + // current stream will default to a child of the idle node (0).
|
| + headers.set_exclusive(true);
|
| + }
|
| +
|
| headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
|
| headers.set_header_block(block);
|
| syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
|
| @@ -1291,6 +1344,8 @@ void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
|
|
|
| scoped_ptr<SpdyStream> owned_stream(it->second.stream);
|
| active_streams_.erase(it);
|
| + active_streams_by_priority_[owned_stream->priority()].erase(
|
| + owned_stream->stream_id());
|
|
|
| // TODO(akalin): When SpdyStream was ref-counted (and
|
| // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
|
| @@ -1952,6 +2007,8 @@ void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
|
| std::pair<ActiveStreamMap::iterator, bool> result =
|
| active_streams_.insert(
|
| std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
|
| + active_streams_by_priority_[stream->priority()].insert(
|
| + std::make_pair(stream_id, stream.get()));
|
| CHECK(result.second);
|
| ignore_result(stream.release());
|
| }
|
|
|