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

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

Issue 2919011: Implement MAX_CONCURRENT_STREAMS SETTINGS header (Closed)
Patch Set: landing soon on a repo near you Created 10 years, 5 months 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
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_test_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/linked_ptr.h" 8 #include "base/linked_ptr.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 connection_(new ClientSocketHandle), 149 connection_(new ClientSocketHandle),
150 read_buffer_(new IOBuffer(kReadBufferSize)), 150 read_buffer_(new IOBuffer(kReadBufferSize)),
151 read_pending_(false), 151 read_pending_(false),
152 stream_hi_water_mark_(1), // Always start at 1 for the first stream id. 152 stream_hi_water_mark_(1), // Always start at 1 for the first stream id.
153 write_pending_(false), 153 write_pending_(false),
154 delayed_write_pending_(false), 154 delayed_write_pending_(false),
155 is_secure_(false), 155 is_secure_(false),
156 certificate_error_code_(OK), 156 certificate_error_code_(OK),
157 error_(OK), 157 error_(OK),
158 state_(IDLE), 158 state_(IDLE),
159 max_concurrent_streams_(kDefaultMaxConcurrentStreams),
159 streams_initiated_count_(0), 160 streams_initiated_count_(0),
160 streams_pushed_count_(0), 161 streams_pushed_count_(0),
161 streams_pushed_and_claimed_count_(0), 162 streams_pushed_and_claimed_count_(0),
162 streams_abandoned_count_(0), 163 streams_abandoned_count_(0),
163 sent_settings_(false), 164 sent_settings_(false),
164 received_settings_(false), 165 received_settings_(false),
165 in_session_pool_(true), 166 in_session_pool_(true),
166 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { 167 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) {
167 net_log_.BeginEvent( 168 net_log_.BeginEvent(
168 NetLog::TYPE_SPDY_SESSION, 169 NetLog::TYPE_SPDY_SESSION,
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 it->second = *stream; 286 it->second = *stream;
286 return OK; 287 return OK;
287 } 288 }
288 return OK; 289 return OK;
289 } 290 }
290 291
291 int SpdySession::CreateStream( 292 int SpdySession::CreateStream(
292 const GURL& url, 293 const GURL& url,
293 RequestPriority priority, 294 RequestPriority priority,
294 scoped_refptr<SpdyStream>* spdy_stream, 295 scoped_refptr<SpdyStream>* spdy_stream,
296 const BoundNetLog& stream_net_log,
297 CompletionCallback* callback,
298 const SpdyHttpStream* spdy_http_stream) {
299 if (!max_concurrent_streams_ ||
300 active_streams_.size() < max_concurrent_streams_) {
301 return CreateStreamImpl(url, priority, spdy_stream, stream_net_log);
302 }
303
304 create_stream_queues_[priority].push(
305 PendingCreateStream(url, priority, spdy_stream,
306 stream_net_log, callback, spdy_http_stream));
307 return ERR_IO_PENDING;
308 }
309
310 void SpdySession::ProcessPendingCreateStreams() {
311 while (!max_concurrent_streams_ ||
312 active_streams_.size() < max_concurrent_streams_) {
313 bool no_pending_create_streams = true;
314 for (int i = 0;i < NUM_PRIORITIES;++i) {
315 if (!create_stream_queues_[i].empty()) {
316 PendingCreateStream& pending_create = create_stream_queues_[i].front();
317 no_pending_create_streams = false;
318 int error = CreateStreamImpl(*pending_create.url,
319 pending_create.priority,
320 pending_create.spdy_stream,
321 *pending_create.stream_net_log);
322 pending_create.callback->Run(error);
323 create_stream_queues_[i].pop();
324 break;
325 }
326 }
327 if (no_pending_create_streams)
328 return; // there were no streams in any queue
329 }
330 }
331
332 void SpdySession::CancelPendingCreateStreams(
333 const SpdyHttpStream *const spdy_http_stream) {
334 for (int i = 0;i < NUM_PRIORITIES;++i) {
335 PendingCreateStreamQueue tmp;
336 // Make a copy removing this trans
337 while (!create_stream_queues_[i].empty()) {
338 PendingCreateStream& pending_create = create_stream_queues_[i].front();
339 if (pending_create.spdy_http_stream != spdy_http_stream)
340 tmp.push(pending_create);
341 create_stream_queues_[i].pop();
342 }
343 // Now copy it back
344 while (!tmp.empty()) {
345 create_stream_queues_[i].push(tmp.front());
346 tmp.pop();
347 }
348 }
349 }
350
351 int SpdySession::CreateStreamImpl(
352 const GURL& url,
353 RequestPriority priority,
354 scoped_refptr<SpdyStream>* spdy_stream,
295 const BoundNetLog& stream_net_log) { 355 const BoundNetLog& stream_net_log) {
296 // Make sure that we don't try to send https/wss over an unauthenticated, but 356 // Make sure that we don't try to send https/wss over an unauthenticated, but
297 // encrypted SSL socket. 357 // encrypted SSL socket.
298 if (is_secure_ && certificate_error_code_ != OK && 358 if (is_secure_ && certificate_error_code_ != OK &&
299 (url.SchemeIs("https") || url.SchemeIs("wss"))) { 359 (url.SchemeIs("https") || url.SchemeIs("wss"))) {
300 LOG(DFATAL) << "Tried to create spdy stream for secure content over an " 360 LOG(DFATAL) << "Tried to create spdy stream for secure content over an "
301 << "unauthenticated session."; 361 << "unauthenticated session.";
302 return certificate_error_code_; 362 return certificate_error_code_;
303 } 363 }
304 364
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 static StatsCounter abandoned_streams("spdy.abandoned_streams"); 760 static StatsCounter abandoned_streams("spdy.abandoned_streams");
701 static StatsCounter abandoned_push_streams("spdy.abandoned_push_streams"); 761 static StatsCounter abandoned_push_streams("spdy.abandoned_push_streams");
702 762
703 if (!active_streams_.empty()) 763 if (!active_streams_.empty())
704 abandoned_streams.Add(active_streams_.size()); 764 abandoned_streams.Add(active_streams_.size());
705 if (!pushed_streams_.empty()) { 765 if (!pushed_streams_.empty()) {
706 streams_abandoned_count_ += pushed_streams_.size(); 766 streams_abandoned_count_ += pushed_streams_.size();
707 abandoned_push_streams.Add(pushed_streams_.size()); 767 abandoned_push_streams.Add(pushed_streams_.size());
708 } 768 }
709 769
770 for (int i = 0;i < NUM_PRIORITIES;++i) {
771 while (!create_stream_queues_[i].empty()) {
772 PendingCreateStream& pending_create = create_stream_queues_[i].front();
773 pending_create.callback->Run(ERR_ABORTED);
774 create_stream_queues_[i].pop();
775 }
776 }
777
710 while (!active_streams_.empty()) { 778 while (!active_streams_.empty()) {
711 ActiveStreamMap::iterator it = active_streams_.begin(); 779 ActiveStreamMap::iterator it = active_streams_.begin();
712 const scoped_refptr<SpdyStream>& stream = it->second; 780 const scoped_refptr<SpdyStream>& stream = it->second;
713 DCHECK(stream); 781 DCHECK(stream);
714 LOG(ERROR) << "ABANDONED (stream_id=" << stream->stream_id() 782 LOG(ERROR) << "ABANDONED (stream_id=" << stream->stream_id()
715 << "): " << stream->path(); 783 << "): " << stream->path();
716 DeleteStream(stream->stream_id(), status); 784 DeleteStream(stream->stream_id(), status);
717 } 785 }
718 786
719 // TODO(erikchen): ideally stream->OnClose() is only ever called by 787 // TODO(erikchen): ideally stream->OnClose() is only ever called by
720 // DeleteStream, but pending streams fall into their own category for now. 788 // DeleteStream, but pending streams fall into their own category for now.
721 PendingStreamMap::iterator it; 789 PendingStreamMap::iterator it;
722 for (it = pending_streams_.begin(); it != pending_streams_.end(); ++it) 790 for (it = pending_streams_.begin(); it != pending_streams_.end(); ++it) {
723 {
724 const scoped_refptr<SpdyStream>& stream = it->second; 791 const scoped_refptr<SpdyStream>& stream = it->second;
725 if (stream) 792 if (stream)
726 stream->OnClose(ERR_ABORTED); 793 stream->OnClose(ERR_ABORTED);
727 } 794 }
728 pending_streams_.clear(); 795 pending_streams_.clear();
729 796
730 // We also need to drain the queue. 797 // We also need to drain the queue.
731 while (queue_.size()) 798 while (queue_.size())
732 queue_.pop(); 799 queue_.pop();
733 } 800 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 // The stream might have been deleted. 859 // The stream might have been deleted.
793 ActiveStreamMap::iterator it2 = active_streams_.find(id); 860 ActiveStreamMap::iterator it2 = active_streams_.find(id);
794 if (it2 == active_streams_.end()) 861 if (it2 == active_streams_.end())
795 return; 862 return;
796 863
797 // If this is an active stream, call the callback. 864 // If this is an active stream, call the callback.
798 const scoped_refptr<SpdyStream> stream(it2->second); 865 const scoped_refptr<SpdyStream> stream(it2->second);
799 active_streams_.erase(it2); 866 active_streams_.erase(it2);
800 if (stream) 867 if (stream)
801 stream->OnClose(status); 868 stream->OnClose(status);
869 ProcessPendingCreateStreams();
802 } 870 }
803 871
804 void SpdySession::RemoveFromPool() { 872 void SpdySession::RemoveFromPool() {
805 if (in_session_pool_) { 873 if (in_session_pool_) {
806 session_->spdy_session_pool()->Remove(this); 874 session_->spdy_session_pool()->Remove(this);
807 in_session_pool_ = false; 875 in_session_pool_ = false;
808 } 876 }
809 } 877 }
810 878
811 scoped_refptr<SpdyStream> SpdySession::GetActivePushStream( 879 scoped_refptr<SpdyStream> SpdySession::GetActivePushStream(
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1111 // |last_accepted_stream_id|. 1179 // |last_accepted_stream_id|.
1112 1180
1113 // Don't bother killing any streams that are still reading. They'll either 1181 // Don't bother killing any streams that are still reading. They'll either
1114 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is 1182 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is
1115 // closed. 1183 // closed.
1116 } 1184 }
1117 1185
1118 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) { 1186 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) {
1119 spdy::SpdySettings settings; 1187 spdy::SpdySettings settings;
1120 if (spdy_framer_.ParseSettings(&frame, &settings)) { 1188 if (spdy_framer_.ParseSettings(&frame, &settings)) {
1189 HandleSettings(settings);
1121 SpdySettingsStorage* settings_storage = session_->mutable_spdy_settings(); 1190 SpdySettingsStorage* settings_storage = session_->mutable_spdy_settings();
1122 settings_storage->Set(host_port_pair_, settings); 1191 settings_storage->Set(host_port_pair_, settings);
1123 } 1192 }
1124 1193
1125 received_settings_ = true; 1194 received_settings_ = true;
1126 1195
1127 net_log_.AddEvent( 1196 net_log_.AddEvent(
1128 NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS, 1197 NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS,
1129 new NetLogSpdySettingsParameter(settings)); 1198 new NetLogSpdySettingsParameter(settings));
1130 } 1199 }
1131 1200
1132 void SpdySession::SendSettings() { 1201 void SpdySession::SendSettings() {
1133 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); 1202 const SpdySettingsStorage& settings_storage = session_->spdy_settings();
1134 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); 1203 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_);
1135 if (settings.empty()) 1204 if (settings.empty())
1136 return; 1205 return;
1206 HandleSettings(settings);
1137 1207
1138 net_log_.AddEvent( 1208 net_log_.AddEvent(
1139 NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS, 1209 NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS,
1140 new NetLogSpdySettingsParameter(settings)); 1210 new NetLogSpdySettingsParameter(settings));
1141 1211
1142 // Create the SETTINGS frame and send it. 1212 // Create the SETTINGS frame and send it.
1143 scoped_ptr<spdy::SpdySettingsControlFrame> settings_frame( 1213 scoped_ptr<spdy::SpdySettingsControlFrame> settings_frame(
1144 spdy_framer_.CreateSettings(settings)); 1214 spdy_framer_.CreateSettings(settings));
1145 sent_settings_ = true; 1215 sent_settings_ = true;
1146 QueueFrame(settings_frame.get(), 0, NULL); 1216 QueueFrame(settings_frame.get(), 0, NULL);
1147 } 1217 }
1148 1218
1219 void SpdySession::HandleSettings(const spdy::SpdySettings& settings) {
1220 for (spdy::SpdySettings::const_iterator i = settings.begin(),
1221 end = settings.end(); i != end; ++i) {
1222 const uint32 id = i->first.id();
1223 const uint32 val = i->second;
1224 switch (id) {
1225 case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
1226 max_concurrent_streams_ = val;
1227 ProcessPendingCreateStreams();
1228 break;
1229 }
1230 }
1231 }
1232
1149 void SpdySession::RecordHistograms() { 1233 void SpdySession::RecordHistograms() {
1150 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", 1234 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
1151 streams_initiated_count_, 1235 streams_initiated_count_,
1152 0, 300, 50); 1236 0, 300, 50);
1153 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", 1237 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
1154 streams_pushed_count_, 1238 streams_pushed_count_,
1155 0, 300, 50); 1239 0, 300, 50);
1156 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession", 1240 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
1157 streams_pushed_and_claimed_count_, 1241 streams_pushed_and_claimed_count_,
1158 0, 300, 50); 1242 0, 300, 50);
1159 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession", 1243 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
1160 streams_abandoned_count_, 1244 streams_abandoned_count_,
1161 0, 300, 50); 1245 0, 300, 50);
1162 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent", 1246 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent",
1163 sent_settings_ ? 1 : 0, 2); 1247 sent_settings_ ? 1 : 0, 2);
1164 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived", 1248 UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
1165 received_settings_ ? 1 : 0, 2); 1249 received_settings_ ? 1 : 0, 2);
1166 1250
1167 if (received_settings_) { 1251 if (received_settings_) {
1168 // Enumerate the saved settings, and set histograms for it. 1252 // Enumerate the saved settings, and set histograms for it.
1169 const SpdySettingsStorage& settings_storage = session_->spdy_settings(); 1253 const SpdySettingsStorage& settings_storage = session_->spdy_settings();
1170 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_); 1254 const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_);
1171 if (settings.empty()) {
1172 NOTREACHED(); // If we lost our settings already, something is wrong!
1173 return;
1174 }
1175 1255
1176 spdy::SpdySettings::const_iterator it; 1256 spdy::SpdySettings::const_iterator it;
1177 for (it = settings.begin(); it != settings.end(); ++it) { 1257 for (it = settings.begin(); it != settings.end(); ++it) {
1178 const spdy::SpdySetting setting = *it; 1258 const spdy::SpdySetting setting = *it;
1179 switch (setting.first.id()) { 1259 switch (setting.first.id()) {
1180 case spdy::SETTINGS_CURRENT_CWND: 1260 case spdy::SETTINGS_CURRENT_CWND:
1181 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd", 1261 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd",
1182 setting.second, 1262 setting.second,
1183 1, 200, 100); 1263 1, 200, 100);
1184 break; 1264 break;
1185 case spdy::SETTINGS_ROUND_TRIP_TIME: 1265 case spdy::SETTINGS_ROUND_TRIP_TIME:
1186 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT", 1266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT",
1187 setting.second, 1267 setting.second,
1188 1, 1200, 100); 1268 1, 1200, 100);
1189 break; 1269 break;
1190 case spdy::SETTINGS_DOWNLOAD_RETRANS_RATE: 1270 case spdy::SETTINGS_DOWNLOAD_RETRANS_RATE:
1191 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate", 1271 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRetransRate",
1192 setting.second, 1272 setting.second,
1193 1, 100, 50); 1273 1, 100, 50);
1194 break; 1274 break;
1195 } 1275 }
1196 } 1276 }
1197 } 1277 }
1198 } 1278 }
1199 1279
1200 } // namespace net 1280 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_session.h ('k') | net/spdy/spdy_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698