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()); |
} |