QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 1 | #include "http2/adapter/window_manager.h" |
| 2 | |
| 3 | #include <utility> |
| 4 | |
QUICHE team | 33a4aa6 | 2021-04-08 11:10:59 -0700 | [diff] [blame] | 5 | #include "common/platform/api/quiche_bug_tracker.h" |
QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 6 | #include "common/platform/api/quiche_logging.h" |
QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 7 | |
| 8 | namespace http2 { |
| 9 | namespace adapter { |
| 10 | |
| 11 | WindowManager::WindowManager(size_t window_size_limit, |
| 12 | WindowUpdateListener listener) |
| 13 | : limit_(window_size_limit), window_(window_size_limit), buffered_(0), |
| 14 | listener_(std::move(listener)) {} |
| 15 | |
| 16 | void WindowManager::OnWindowSizeLimitChange(const size_t new_limit) { |
| 17 | QUICHE_VLOG(2) << "WindowManager@" << this |
| 18 | << " OnWindowSizeLimitChange from old limit of " << limit_ |
| 19 | << " to new limit of " << new_limit; |
| 20 | if (new_limit > limit_) { |
| 21 | window_ += (new_limit - limit_); |
| 22 | } else { |
QUICHE team | 33a4aa6 | 2021-04-08 11:10:59 -0700 | [diff] [blame] | 23 | QUICHE_BUG(H2 window decrease) |
QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 24 | << "Window size limit decrease not currently supported."; |
| 25 | } |
| 26 | limit_ = new_limit; |
| 27 | } |
| 28 | |
| 29 | void WindowManager::SetWindowSizeLimit(size_t new_limit) { |
| 30 | QUICHE_VLOG(2) << "WindowManager@" << this |
| 31 | << " SetWindowSizeLimit from old limit of " << limit_ |
| 32 | << " to new limit of " << new_limit; |
| 33 | limit_ = new_limit; |
| 34 | MaybeNotifyListener(); |
| 35 | } |
| 36 | |
| 37 | bool WindowManager::MarkDataBuffered(size_t bytes) { |
| 38 | QUICHE_VLOG(2) << "WindowManager@" << this << " window: " << window_ |
| 39 | << " bytes: " << bytes; |
| 40 | if (window_ < bytes) { |
| 41 | QUICHE_VLOG(2) << "WindowManager@" << this << " window underflow " |
| 42 | << "window: " << window_ << " bytes: " << bytes; |
| 43 | window_ = 0; |
| 44 | } else { |
| 45 | window_ -= bytes; |
| 46 | } |
| 47 | buffered_ += bytes; |
| 48 | if (window_ == 0) { |
| 49 | // If data hasn't been flushed in a while there may be space available. |
| 50 | MaybeNotifyListener(); |
| 51 | } |
| 52 | return window_ > 0; |
| 53 | } |
| 54 | |
| 55 | void WindowManager::MarkDataFlushed(size_t bytes) { |
| 56 | QUICHE_VLOG(2) << "WindowManager@" << this << " buffered: " << buffered_ |
| 57 | << " bytes: " << bytes; |
| 58 | if (buffered_ < bytes) { |
QUICHE team | 33a4aa6 | 2021-04-08 11:10:59 -0700 | [diff] [blame] | 59 | QUICHE_BUG(bug_2816_1) << "WindowManager@" << this << " buffered underflow " |
| 60 | << "buffered_: " << buffered_ << " bytes: " << bytes; |
QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 61 | buffered_ = 0; |
| 62 | } else { |
| 63 | buffered_ -= bytes; |
| 64 | } |
| 65 | MaybeNotifyListener(); |
| 66 | } |
| 67 | |
| 68 | void WindowManager::MaybeNotifyListener() { |
| 69 | if (buffered_ + window_ > limit_) { |
| 70 | QUICHE_LOG(ERROR) << "Flow control violation; limit: " << limit_ |
| 71 | << " buffered: " << buffered_ << " window: " << window_; |
| 72 | return; |
| 73 | } |
| 74 | // For the sake of efficiency, we want to send window updates if less than |
| 75 | // half of the max quota is available to the peer at any point in time. |
QUICHE team | 02542a2 | 2021-03-22 09:00:16 -0700 | [diff] [blame] | 76 | const size_t kDesiredMinWindow = limit_ / 2; |
| 77 | const size_t kDesiredMinDelta = limit_ / 3; |
| 78 | const size_t delta = limit_ - (buffered_ + window_); |
| 79 | bool send_update = false; |
| 80 | if (delta >= kDesiredMinDelta) { |
| 81 | // This particular window update was sent because the available delta |
| 82 | // exceeded the desired minimum. |
| 83 | send_update = true; |
| 84 | } else if (window_ < kDesiredMinWindow) { |
| 85 | // This particular window update was sent because the quota available to the |
| 86 | // peer at this moment is less than the desired minimum. |
| 87 | send_update = true; |
| 88 | } |
| 89 | if (send_update && delta > 0) { |
| 90 | QUICHE_VLOG(2) << "WindowManager@" << this |
| 91 | << " Informing listener of delta: " << delta; |
| 92 | listener_(delta); |
| 93 | window_ += delta; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | } // namespace adapter |
| 98 | } // namespace http2 |