| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/quic/core/quic_flow_controller.h" | 5 #include "net/quic/core/quic_flow_controller.h" |
| 6 | 6 |
| 7 #include <cstdint> | 7 #include <cstdint> |
| 8 | 8 |
| 9 #include "net/quic/core/quic_connection.h" | 9 #include "net/quic/core/quic_connection.h" |
| 10 #include "net/quic/core/quic_packets.h" | 10 #include "net/quic/core/quic_packets.h" |
| 11 #include "net/quic/platform/api/quic_bug_tracker.h" | 11 #include "net/quic/platform/api/quic_bug_tracker.h" |
| 12 #include "net/quic/platform/api/quic_logging.h" |
| 12 #include "net/quic/platform/api/quic_str_cat.h" | 13 #include "net/quic/platform/api/quic_str_cat.h" |
| 13 | 14 |
| 14 namespace net { | 15 namespace net { |
| 15 | 16 |
| 16 #define ENDPOINT \ | 17 #define ENDPOINT \ |
| 17 (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") | 18 (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") |
| 18 | 19 |
| 19 QuicFlowController::QuicFlowController(QuicConnection* connection, | 20 QuicFlowController::QuicFlowController(QuicConnection* connection, |
| 20 QuicStreamId id, | 21 QuicStreamId id, |
| 21 Perspective perspective, | 22 Perspective perspective, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 32 receive_window_offset_(receive_window_offset), | 33 receive_window_offset_(receive_window_offset), |
| 33 receive_window_size_(receive_window_offset), | 34 receive_window_size_(receive_window_offset), |
| 34 auto_tune_receive_window_(should_auto_tune_receive_window), | 35 auto_tune_receive_window_(should_auto_tune_receive_window), |
| 35 last_blocked_send_window_offset_(0), | 36 last_blocked_send_window_offset_(0), |
| 36 prev_window_update_time_(QuicTime::Zero()) { | 37 prev_window_update_time_(QuicTime::Zero()) { |
| 37 receive_window_size_limit_ = (id_ == kConnectionLevelId) | 38 receive_window_size_limit_ = (id_ == kConnectionLevelId) |
| 38 ? kSessionReceiveWindowLimit | 39 ? kSessionReceiveWindowLimit |
| 39 : kStreamReceiveWindowLimit; | 40 : kStreamReceiveWindowLimit; |
| 40 DCHECK_LE(receive_window_size_, receive_window_size_limit_); | 41 DCHECK_LE(receive_window_size_, receive_window_size_limit_); |
| 41 | 42 |
| 42 DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_ | 43 QUIC_DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_ |
| 43 << ", setting initial receive window offset to: " | 44 << ", setting initial receive window offset to: " |
| 44 << receive_window_offset_ | 45 << receive_window_offset_ |
| 45 << ", max receive window to: " << receive_window_size_ | 46 << ", max receive window to: " << receive_window_size_ |
| 46 << ", max receive window limit to: " << receive_window_size_limit_ | 47 << ", max receive window limit to: " |
| 47 << ", setting send window offset to: " << send_window_offset_; | 48 << receive_window_size_limit_ |
| 49 << ", setting send window offset to: " << send_window_offset_; |
| 48 } | 50 } |
| 49 | 51 |
| 50 void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) { | 52 void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) { |
| 51 bytes_consumed_ += bytes_consumed; | 53 bytes_consumed_ += bytes_consumed; |
| 52 DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_; | 54 QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_ |
| 55 << " consumed: " << bytes_consumed_; |
| 53 | 56 |
| 54 MaybeSendWindowUpdate(); | 57 MaybeSendWindowUpdate(); |
| 55 } | 58 } |
| 56 | 59 |
| 57 bool QuicFlowController::UpdateHighestReceivedOffset( | 60 bool QuicFlowController::UpdateHighestReceivedOffset( |
| 58 QuicStreamOffset new_offset) { | 61 QuicStreamOffset new_offset) { |
| 59 // Only update if offset has increased. | 62 // Only update if offset has increased. |
| 60 if (new_offset <= highest_received_byte_offset_) { | 63 if (new_offset <= highest_received_byte_offset_) { |
| 61 return false; | 64 return false; |
| 62 } | 65 } |
| 63 | 66 |
| 64 DVLOG(1) << ENDPOINT << "Stream " << id_ | 67 QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_ |
| 65 << " highest byte offset increased from: " | 68 << " highest byte offset increased from: " |
| 66 << highest_received_byte_offset_ << " to " << new_offset; | 69 << highest_received_byte_offset_ << " to " << new_offset; |
| 67 highest_received_byte_offset_ = new_offset; | 70 highest_received_byte_offset_ = new_offset; |
| 68 return true; | 71 return true; |
| 69 } | 72 } |
| 70 | 73 |
| 71 void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) { | 74 void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) { |
| 72 if (bytes_sent_ + bytes_sent > send_window_offset_) { | 75 if (bytes_sent_ + bytes_sent > send_window_offset_) { |
| 73 QUIC_BUG << ENDPOINT << "Stream " << id_ << " Trying to send an extra " | 76 QUIC_BUG << ENDPOINT << "Stream " << id_ << " Trying to send an extra " |
| 74 << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_ | 77 << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_ |
| 75 << ", and send_window_offset_ = " << send_window_offset_; | 78 << ", and send_window_offset_ = " << send_window_offset_; |
| 76 bytes_sent_ = send_window_offset_; | 79 bytes_sent_ = send_window_offset_; |
| 77 | 80 |
| 78 // This is an error on our side, close the connection as soon as possible. | 81 // This is an error on our side, close the connection as soon as possible. |
| 79 connection_->CloseConnection( | 82 connection_->CloseConnection( |
| 80 QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, | 83 QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, |
| 81 QuicStrCat(send_window_offset_ - (bytes_sent_ + bytes_sent), | 84 QuicStrCat(send_window_offset_ - (bytes_sent_ + bytes_sent), |
| 82 "bytes over send window offset"), | 85 "bytes over send window offset"), |
| 83 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | 86 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 84 return; | 87 return; |
| 85 } | 88 } |
| 86 | 89 |
| 87 bytes_sent_ += bytes_sent; | 90 bytes_sent_ += bytes_sent; |
| 88 DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_; | 91 QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_; |
| 89 } | 92 } |
| 90 | 93 |
| 91 bool QuicFlowController::FlowControlViolation() { | 94 bool QuicFlowController::FlowControlViolation() { |
| 92 if (highest_received_byte_offset_ > receive_window_offset_) { | 95 if (highest_received_byte_offset_ > receive_window_offset_) { |
| 93 DVLOG(1) << ENDPOINT << "Flow control violation on stream " << id_ | 96 QUIC_DLOG(INFO) << ENDPOINT << "Flow control violation on stream " << id_ |
| 94 << ", receive window offset: " << receive_window_offset_ | 97 << ", receive window offset: " << receive_window_offset_ |
| 95 << ", highest received byte offset: " | 98 << ", highest received byte offset: " |
| 96 << highest_received_byte_offset_; | 99 << highest_received_byte_offset_; |
| 97 return true; | 100 return true; |
| 98 } | 101 } |
| 99 return false; | 102 return false; |
| 100 } | 103 } |
| 101 | 104 |
| 102 void QuicFlowController::MaybeIncreaseMaxWindowSize() { | 105 void QuicFlowController::MaybeIncreaseMaxWindowSize() { |
| 103 // Core of receive window auto tuning. This method should be called before a | 106 // Core of receive window auto tuning. This method should be called before a |
| 104 // WINDOW_UPDATE frame is sent. Ideally, window updates should occur close to | 107 // WINDOW_UPDATE frame is sent. Ideally, window updates should occur close to |
| 105 // once per RTT. If a window update happens much faster than RTT, it implies | 108 // once per RTT. If a window update happens much faster than RTT, it implies |
| 106 // that the flow control window is imposing a bottleneck. To prevent this, | 109 // that the flow control window is imposing a bottleneck. To prevent this, |
| 107 // this method will increase the receive window size (subject to a reasonable | 110 // this method will increase the receive window size (subject to a reasonable |
| 108 // upper bound). For simplicity this algorithm is deliberately asymmetric, in | 111 // upper bound). For simplicity this algorithm is deliberately asymmetric, in |
| 109 // that it may increase window size but never decreases. | 112 // that it may increase window size but never decreases. |
| 110 | 113 |
| 111 // Keep track of timing between successive window updates. | 114 // Keep track of timing between successive window updates. |
| 112 QuicTime now = connection_->clock()->ApproximateNow(); | 115 QuicTime now = connection_->clock()->ApproximateNow(); |
| 113 QuicTime prev = prev_window_update_time_; | 116 QuicTime prev = prev_window_update_time_; |
| 114 prev_window_update_time_ = now; | 117 prev_window_update_time_ = now; |
| 115 if (!prev.IsInitialized()) { | 118 if (!prev.IsInitialized()) { |
| 116 DVLOG(1) << ENDPOINT << "first window update for stream " << id_; | 119 QUIC_DVLOG(1) << ENDPOINT << "first window update for stream " << id_; |
| 117 return; | 120 return; |
| 118 } | 121 } |
| 119 | 122 |
| 120 if (!auto_tune_receive_window_) { | 123 if (!auto_tune_receive_window_) { |
| 121 return; | 124 return; |
| 122 } | 125 } |
| 123 | 126 |
| 124 // Get outbound RTT. | 127 // Get outbound RTT. |
| 125 QuicTime::Delta rtt = | 128 QuicTime::Delta rtt = |
| 126 connection_->sent_packet_manager().GetRttStats()->smoothed_rtt(); | 129 connection_->sent_packet_manager().GetRttStats()->smoothed_rtt(); |
| 127 if (rtt.IsZero()) { | 130 if (rtt.IsZero()) { |
| 128 DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_; | 131 QUIC_DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_; |
| 129 return; | 132 return; |
| 130 } | 133 } |
| 131 | 134 |
| 132 // Now we can compare timing of window updates with RTT. | 135 // Now we can compare timing of window updates with RTT. |
| 133 QuicTime::Delta since_last = now - prev; | 136 QuicTime::Delta since_last = now - prev; |
| 134 QuicTime::Delta two_rtt = 2 * rtt; | 137 QuicTime::Delta two_rtt = 2 * rtt; |
| 135 | 138 |
| 136 if (since_last >= two_rtt) { | 139 if (since_last >= two_rtt) { |
| 137 // If interval between window updates is sufficiently large, there | 140 // If interval between window updates is sufficiently large, there |
| 138 // is no need to increase receive_window_size_. | 141 // is no need to increase receive_window_size_. |
| 139 return; | 142 return; |
| 140 } | 143 } |
| 141 | 144 |
| 142 QuicByteCount old_window = receive_window_size_; | 145 QuicByteCount old_window = receive_window_size_; |
| 143 receive_window_size_ *= 2; | 146 receive_window_size_ *= 2; |
| 144 receive_window_size_ = | 147 receive_window_size_ = |
| 145 std::min(receive_window_size_, receive_window_size_limit_); | 148 std::min(receive_window_size_, receive_window_size_limit_); |
| 146 | 149 |
| 147 if (receive_window_size_ > old_window) { | 150 if (receive_window_size_ > old_window) { |
| 148 DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_ | 151 QUIC_DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_ |
| 149 << " after " << since_last.ToMicroseconds() << " us, and RTT is " | 152 << " after " << since_last.ToMicroseconds() |
| 150 << rtt.ToMicroseconds() | 153 << " us, and RTT is " << rtt.ToMicroseconds() |
| 151 << "us. max wndw: " << receive_window_size_; | 154 << "us. max wndw: " << receive_window_size_; |
| 152 } else { | 155 } else { |
| 153 // TODO(ckrasic) - add a varz to track this (?). | 156 // TODO(ckrasic) - add a varz to track this (?). |
| 154 DVLOG(1) << ENDPOINT << "Max window at limit for stream " << id_ | 157 QUIC_LOG_FIRST_N(INFO, 1) << ENDPOINT << "Max window at limit for stream " |
| 155 << " after " << since_last.ToMicroseconds() << " us, and RTT is " | 158 << id_ << " after " << since_last.ToMicroseconds() |
| 156 << rtt.ToMicroseconds() | 159 << " us, and RTT is " << rtt.ToMicroseconds() |
| 157 << "us. Limit size: " << receive_window_size_; | 160 << "us. Limit size: " << receive_window_size_; |
| 158 } | 161 } |
| 159 } | 162 } |
| 160 | 163 |
| 161 QuicByteCount QuicFlowController::WindowUpdateThreshold() { | 164 QuicByteCount QuicFlowController::WindowUpdateThreshold() { |
| 162 return receive_window_size_ / 2; | 165 return receive_window_size_ / 2; |
| 163 } | 166 } |
| 164 | 167 |
| 165 void QuicFlowController::MaybeSendWindowUpdate() { | 168 void QuicFlowController::MaybeSendWindowUpdate() { |
| 166 // Send WindowUpdate to increase receive window if | 169 // Send WindowUpdate to increase receive window if |
| 167 // (receive window offset - consumed bytes) < (max window / 2). | 170 // (receive window offset - consumed bytes) < (max window / 2). |
| 168 // This is behaviour copied from SPDY. | 171 // This is behaviour copied from SPDY. |
| 169 DCHECK_LE(bytes_consumed_, receive_window_offset_); | 172 DCHECK_LE(bytes_consumed_, receive_window_offset_); |
| 170 QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_; | 173 QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_; |
| 171 QuicByteCount threshold = WindowUpdateThreshold(); | 174 QuicByteCount threshold = WindowUpdateThreshold(); |
| 172 | 175 |
| 173 if (available_window >= threshold) { | 176 if (available_window >= threshold) { |
| 174 DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_ | 177 QUIC_DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_ |
| 175 << ", available window: " << available_window | 178 << ", available window: " << available_window |
| 176 << " >= threshold: " << threshold; | 179 << " >= threshold: " << threshold; |
| 177 return; | 180 return; |
| 178 } | 181 } |
| 179 | 182 |
| 180 MaybeIncreaseMaxWindowSize(); | 183 MaybeIncreaseMaxWindowSize(); |
| 181 | 184 |
| 182 // Update our receive window. | 185 // Update our receive window. |
| 183 receive_window_offset_ += (receive_window_size_ - available_window); | 186 receive_window_offset_ += (receive_window_size_ - available_window); |
| 184 | 187 |
| 185 DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_ | 188 QUIC_DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_ |
| 186 << ", consumed bytes: " << bytes_consumed_ | 189 << ", consumed bytes: " << bytes_consumed_ |
| 187 << ", available window: " << available_window | 190 << ", available window: " << available_window |
| 188 << ", and threshold: " << threshold | 191 << ", and threshold: " << threshold |
| 189 << ", and receive window size: " << receive_window_size_ | 192 << ", and receive window size: " << receive_window_size_ |
| 190 << ". New receive window offset is: " << receive_window_offset_; | 193 << ". New receive window offset is: " << receive_window_offset_; |
| 191 | 194 |
| 192 // Inform the peer of our new receive window. | 195 // Inform the peer of our new receive window. |
| 193 connection_->SendWindowUpdate(id_, receive_window_offset_); | 196 connection_->SendWindowUpdate(id_, receive_window_offset_); |
| 194 } | 197 } |
| 195 | 198 |
| 196 void QuicFlowController::MaybeSendBlocked() { | 199 void QuicFlowController::MaybeSendBlocked() { |
| 197 if (SendWindowSize() == 0 && | 200 if (SendWindowSize() == 0 && |
| 198 last_blocked_send_window_offset_ < send_window_offset_) { | 201 last_blocked_send_window_offset_ < send_window_offset_) { |
| 199 DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. " | 202 QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id_ |
| 200 << "Send window: " << SendWindowSize() | 203 << " is flow control blocked. " |
| 201 << ", bytes sent: " << bytes_sent_ | 204 << "Send window: " << SendWindowSize() |
| 202 << ", send limit: " << send_window_offset_; | 205 << ", bytes sent: " << bytes_sent_ |
| 206 << ", send limit: " << send_window_offset_; |
| 203 // The entire send_window has been consumed, we are now flow control | 207 // The entire send_window has been consumed, we are now flow control |
| 204 // blocked. | 208 // blocked. |
| 205 connection_->SendBlocked(id_); | 209 connection_->SendBlocked(id_); |
| 206 | 210 |
| 207 // Keep track of when we last sent a BLOCKED frame so that we only send one | 211 // Keep track of when we last sent a BLOCKED frame so that we only send one |
| 208 // at a given send offset. | 212 // at a given send offset. |
| 209 last_blocked_send_window_offset_ = send_window_offset_; | 213 last_blocked_send_window_offset_ = send_window_offset_; |
| 210 } | 214 } |
| 211 } | 215 } |
| 212 | 216 |
| 213 bool QuicFlowController::UpdateSendWindowOffset( | 217 bool QuicFlowController::UpdateSendWindowOffset( |
| 214 QuicStreamOffset new_send_window_offset) { | 218 QuicStreamOffset new_send_window_offset) { |
| 215 // Only update if send window has increased. | 219 // Only update if send window has increased. |
| 216 if (new_send_window_offset <= send_window_offset_) { | 220 if (new_send_window_offset <= send_window_offset_) { |
| 217 return false; | 221 return false; |
| 218 } | 222 } |
| 219 | 223 |
| 220 DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_ | 224 QUIC_DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_ |
| 221 << " with new offset " << new_send_window_offset | 225 << " with new offset " << new_send_window_offset |
| 222 << " current offset: " << send_window_offset_ | 226 << " current offset: " << send_window_offset_ |
| 223 << " bytes_sent: " << bytes_sent_; | 227 << " bytes_sent: " << bytes_sent_; |
| 224 | 228 |
| 225 const bool blocked = IsBlocked(); | 229 const bool blocked = IsBlocked(); |
| 226 send_window_offset_ = new_send_window_offset; | 230 send_window_offset_ = new_send_window_offset; |
| 227 return blocked; | 231 return blocked; |
| 228 } | 232 } |
| 229 | 233 |
| 230 bool QuicFlowController::IsBlocked() const { | 234 bool QuicFlowController::IsBlocked() const { |
| 231 return SendWindowSize() == 0; | 235 return SendWindowSize() == 0; |
| 232 } | 236 } |
| 233 | 237 |
| 234 uint64_t QuicFlowController::SendWindowSize() const { | 238 uint64_t QuicFlowController::SendWindowSize() const { |
| 235 if (bytes_sent_ > send_window_offset_) { | 239 if (bytes_sent_ > send_window_offset_) { |
| 236 return 0; | 240 return 0; |
| 237 } | 241 } |
| 238 return send_window_offset_ - bytes_sent_; | 242 return send_window_offset_ - bytes_sent_; |
| 239 } | 243 } |
| 240 | 244 |
| 241 void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) { | 245 void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) { |
| 242 DCHECK_LE(size, receive_window_size_limit_); | 246 DCHECK_LE(size, receive_window_size_limit_); |
| 243 DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for stream " << id_ << ": " | 247 QUIC_DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for stream " << id_ |
| 244 << size; | 248 << ": " << size; |
| 245 if (receive_window_size_ != receive_window_offset_) { | 249 if (receive_window_size_ != receive_window_offset_) { |
| 246 QUIC_BUG << "receive_window_size_:" << receive_window_size_ | 250 QUIC_BUG << "receive_window_size_:" << receive_window_size_ |
| 247 << " != receive_window_offset:" << receive_window_offset_; | 251 << " != receive_window_offset:" << receive_window_offset_; |
| 248 return; | 252 return; |
| 249 } | 253 } |
| 250 receive_window_size_ = size; | 254 receive_window_size_ = size; |
| 251 receive_window_offset_ = size; | 255 receive_window_offset_ = size; |
| 252 } | 256 } |
| 253 | 257 |
| 254 } // namespace net | 258 } // namespace net |
| OLD | NEW |