Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(880)

Side by Side Diff: net/spdy/spdy_session.cc

Issue 1411383005: Initial implementation of RequestPriority-based HTTP/2 dependencies. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated tests. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/spdy_session.h" 5 #include "net/spdy/spdy_session.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 52
53 namespace { 53 namespace {
54 54
55 const int kReadBufferSize = 8 * 1024; 55 const int kReadBufferSize = 8 * 1024;
56 const int kDefaultConnectionAtRiskOfLossSeconds = 10; 56 const int kDefaultConnectionAtRiskOfLossSeconds = 10;
57 const int kHungIntervalSeconds = 10; 57 const int kHungIntervalSeconds = 10;
58 58
59 // Minimum seconds that unclaimed pushed streams will be kept in memory. 59 // Minimum seconds that unclaimed pushed streams will be kept in memory.
60 const int kMinPushedStreamLifetimeSeconds = 300; 60 const int kMinPushedStreamLifetimeSeconds = 300;
61 61
62 // Field trial constants
63 const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies";
64 const char kSpdyDepencenciesFieldTrialEnable[] = "Enable";
65
66 // Whether the creation of SPDY dependencies based on priority is
67 // enabled by default.
68 static bool priority_dependency_enabled_default = false;
69
62 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue( 70 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue(
63 const SpdyHeaderBlock& headers, 71 const SpdyHeaderBlock& headers,
64 NetLogCaptureMode capture_mode) { 72 NetLogCaptureMode capture_mode) {
65 scoped_ptr<base::ListValue> headers_list(new base::ListValue()); 73 scoped_ptr<base::ListValue> headers_list(new base::ListValue());
66 for (SpdyHeaderBlock::const_iterator it = headers.begin(); 74 for (SpdyHeaderBlock::const_iterator it = headers.begin();
67 it != headers.end(); ++it) { 75 it != headers.end(); ++it) {
68 headers_list->AppendString( 76 headers_list->AppendString(
69 it->first.as_string() + ": " + 77 it->first.as_string() + ": " +
70 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(), 78 ElideHeaderValueForNetLog(capture_mode, it->first.as_string(),
71 it->second.as_string())); 79 it->second.as_string()));
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 enable_sending_initial_data_(enable_sending_initial_data), 692 enable_sending_initial_data_(enable_sending_initial_data),
685 enable_compression_(enable_compression), 693 enable_compression_(enable_compression),
686 enable_ping_based_connection_checking_( 694 enable_ping_based_connection_checking_(
687 enable_ping_based_connection_checking), 695 enable_ping_based_connection_checking),
688 protocol_(default_protocol), 696 protocol_(default_protocol),
689 connection_at_risk_of_loss_time_( 697 connection_at_risk_of_loss_time_(
690 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)), 698 base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
691 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)), 699 hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
692 trusted_spdy_proxy_(trusted_spdy_proxy), 700 trusted_spdy_proxy_(trusted_spdy_proxy),
693 time_func_(time_func), 701 time_func_(time_func),
702 send_priority_dependency_(priority_dependency_enabled_default),
694 weak_factory_(this) { 703 weak_factory_(this) {
695 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); 704 DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
696 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); 705 DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
697 DCHECK(HttpStreamFactory::spdy_enabled()); 706 DCHECK(HttpStreamFactory::spdy_enabled());
698 net_log_.BeginEvent( 707 net_log_.BeginEvent(
699 NetLog::TYPE_HTTP2_SESSION, 708 NetLog::TYPE_HTTP2_SESSION,
700 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); 709 base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
701 next_unclaimed_push_stream_sweep_time_ = time_func_() + 710 next_unclaimed_push_stream_sweep_time_ = time_func_() +
702 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); 711 base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
712 if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) ==
713 kSpdyDepencenciesFieldTrialEnable) {
714 send_priority_dependency_ = true;
715 }
703 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. 716 // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
704 } 717 }
705 718
706 SpdySession::~SpdySession() { 719 SpdySession::~SpdySession() {
707 CHECK(!in_io_loop_); 720 CHECK(!in_io_loop_);
708 DcheckDraining(); 721 DcheckDraining();
709 722
710 // TODO(akalin): Check connection->is_initialized() instead. This 723 // TODO(akalin): Check connection->is_initialized() instead. This
711 // requires re-working CreateFakeSpdySession(), though. 724 // requires re-working CreateFakeSpdySession(), though.
712 DCHECK(connection_->socket()); 725 DCHECK(connection_->socket());
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 bool SpdySession::CloseOneIdleConnection() { 1051 bool SpdySession::CloseOneIdleConnection() {
1039 CHECK(!in_io_loop_); 1052 CHECK(!in_io_loop_);
1040 DCHECK(pool_); 1053 DCHECK(pool_);
1041 if (active_streams_.empty()) { 1054 if (active_streams_.empty()) {
1042 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); 1055 DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
1043 } 1056 }
1044 // Return false as the socket wasn't immediately closed. 1057 // Return false as the socket wasn't immediately closed.
1045 return false; 1058 return false;
1046 } 1059 }
1047 1060
1061 // static
1062 void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) {
1063 priority_dependency_enabled_default = enable;
1064 }
1065
1048 void SpdySession::EnqueueStreamWrite( 1066 void SpdySession::EnqueueStreamWrite(
1049 const base::WeakPtr<SpdyStream>& stream, 1067 const base::WeakPtr<SpdyStream>& stream,
1050 SpdyFrameType frame_type, 1068 SpdyFrameType frame_type,
1051 scoped_ptr<SpdyBufferProducer> producer) { 1069 scoped_ptr<SpdyBufferProducer> producer) {
1052 DCHECK(frame_type == HEADERS || 1070 DCHECK(frame_type == HEADERS ||
1053 frame_type == DATA || 1071 frame_type == DATA ||
1054 frame_type == CREDENTIAL || 1072 frame_type == CREDENTIAL ||
1055 frame_type == SYN_STREAM); 1073 frame_type == SYN_STREAM);
1056 EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream); 1074 EnqueueWrite(stream->priority(), frame_type, producer.Pass(), stream);
1057 } 1075 }
(...skipping 20 matching lines...) Expand all
1078 syn_stream.set_associated_to_stream_id(0); 1096 syn_stream.set_associated_to_stream_id(0);
1079 syn_stream.set_priority(spdy_priority); 1097 syn_stream.set_priority(spdy_priority);
1080 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0); 1098 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1081 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); 1099 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
1082 syn_stream.set_header_block(block); 1100 syn_stream.set_header_block(block);
1083 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream)); 1101 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream));
1084 } else { 1102 } else {
1085 SpdyHeadersIR headers(stream_id); 1103 SpdyHeadersIR headers(stream_id);
1086 headers.set_priority(spdy_priority); 1104 headers.set_priority(spdy_priority);
1087 headers.set_has_priority(true); 1105 headers.set_has_priority(true);
1106
1107 if (send_priority_dependency_) {
1108 // Set dependencies to reflect request priority. A newly created
1109 // stream should be dependent on the most recent previously created
1110 // stream of the same priority level. The newly created stream
1111 // should also have all streams of a lower priority level dependent
1112 // on it, which is guaranteed by setting the exclusive bit.
1113 //
1114 // Note that this depends on stream ids being allocated in a monotonically
1115 // increasing fashion, and on all streams in
1116 // active_streams_{,by_priority_} having stream ids set.
1117 for (int i = priority; i >= IDLE; --i) {
1118 if (active_streams_by_priority_[i].empty())
1119 continue;
1120
1121 auto candidate_it = active_streams_by_priority_[i].rbegin();
1122
1123 // |active_streams_by_priority_| is updated before the
1124 // SYN stream frame is created, so the current streams
1125 // id is already on the list. Skip over it, skipping this
1126 // priority level if it's singular.
1127 if (candidate_it->second->stream_id() == stream_id)
1128 ++candidate_it;
1129 if (candidate_it == active_streams_by_priority_[i].rend())
1130 continue;
1131
1132 headers.set_parent_stream_id(candidate_it->second->stream_id());
1133 break;
1134 }
1135
1136 // If there are no streams of priority <= the current stream, the
1137 // current stream will default to a child of the idle node (0).
1138 headers.set_exclusive(true);
1139 }
1140
1088 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); 1141 headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
1089 headers.set_header_block(block); 1142 headers.set_header_block(block);
1090 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); 1143 syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
1091 } 1144 }
1092 1145
1093 streams_initiated_count_++; 1146 streams_initiated_count_++;
1094 1147
1095 if (net_log().IsCapturing()) { 1148 if (net_log().IsCapturing()) {
1096 const NetLog::EventType type = 1149 const NetLog::EventType type =
1097 (GetProtocolVersion() <= SPDY3) 1150 (GetProtocolVersion() <= SPDY3)
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1284 return LOAD_STATE_IDLE; 1337 return LOAD_STATE_IDLE;
1285 } 1338 }
1286 1339
1287 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, 1340 void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
1288 int status) { 1341 int status) {
1289 // TODO(mbelshe): We should send a RST_STREAM control frame here 1342 // TODO(mbelshe): We should send a RST_STREAM control frame here
1290 // so that the server can cancel a large send. 1343 // so that the server can cancel a large send.
1291 1344
1292 scoped_ptr<SpdyStream> owned_stream(it->second.stream); 1345 scoped_ptr<SpdyStream> owned_stream(it->second.stream);
1293 active_streams_.erase(it); 1346 active_streams_.erase(it);
1347 active_streams_by_priority_[owned_stream->priority()].erase(
1348 owned_stream->stream_id());
1294 1349
1295 // TODO(akalin): When SpdyStream was ref-counted (and 1350 // TODO(akalin): When SpdyStream was ref-counted (and
1296 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this 1351 // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
1297 // was only done when status was not OK. This meant that pushed 1352 // was only done when status was not OK. This meant that pushed
1298 // streams can still be claimed after they're closed. This is 1353 // streams can still be claimed after they're closed. This is
1299 // probably something that we still want to support, although server 1354 // probably something that we still want to support, although server
1300 // push is hardly used. Write tests for this and fix this. (See 1355 // push is hardly used. Write tests for this and fix this. (See
1301 // http://crbug.com/261712 .) 1356 // http://crbug.com/261712 .)
1302 if (owned_stream->type() == SPDY_PUSH_STREAM) { 1357 if (owned_stream->type() == SPDY_PUSH_STREAM) {
1303 unclaimed_pushed_streams_.erase(owned_stream->url()); 1358 unclaimed_pushed_streams_.erase(owned_stream->url());
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after
1945 created_streams_.erase(stream); 2000 created_streams_.erase(stream);
1946 return owned_stream.Pass(); 2001 return owned_stream.Pass();
1947 } 2002 }
1948 2003
1949 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { 2004 void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) {
1950 SpdyStreamId stream_id = stream->stream_id(); 2005 SpdyStreamId stream_id = stream->stream_id();
1951 CHECK_NE(stream_id, 0u); 2006 CHECK_NE(stream_id, 0u);
1952 std::pair<ActiveStreamMap::iterator, bool> result = 2007 std::pair<ActiveStreamMap::iterator, bool> result =
1953 active_streams_.insert( 2008 active_streams_.insert(
1954 std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); 2009 std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
2010 active_streams_by_priority_[stream->priority()].insert(
2011 std::make_pair(stream_id, stream.get()));
1955 CHECK(result.second); 2012 CHECK(result.second);
1956 ignore_result(stream.release()); 2013 ignore_result(stream.release());
1957 } 2014 }
1958 2015
1959 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) { 2016 void SpdySession::DeleteStream(scoped_ptr<SpdyStream> stream, int status) {
1960 if (in_flight_write_stream_.get() == stream.get()) { 2017 if (in_flight_write_stream_.get() == stream.get()) {
1961 // If we're deleting the stream for the in-flight write, we still 2018 // If we're deleting the stream for the in-flight write, we still
1962 // need to let the write complete, so we clear 2019 // need to let the write complete, so we clear
1963 // |in_flight_write_stream_| and let the write finish on its own 2020 // |in_flight_write_stream_| and let the write finish on its own
1964 // without notifying |in_flight_write_stream_|. 2021 // without notifying |in_flight_write_stream_|.
(...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after
3277 if (!queue->empty()) { 3334 if (!queue->empty()) {
3278 SpdyStreamId stream_id = queue->front(); 3335 SpdyStreamId stream_id = queue->front();
3279 queue->pop_front(); 3336 queue->pop_front();
3280 return stream_id; 3337 return stream_id;
3281 } 3338 }
3282 } 3339 }
3283 return 0; 3340 return 0;
3284 } 3341 }
3285 3342
3286 } // namespace net 3343 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698