blob: de45dc3497bfd39a9adcd36dd5109885f61d23e7 [file] [log] [blame]
QUICHE team02542a22021-03-22 09:00:16 -07001#include "http2/adapter/window_manager.h"
2
3#include <utility>
4
QUICHE team33a4aa62021-04-08 11:10:59 -07005#include "common/platform/api/quiche_bug_tracker.h"
QUICHE team02542a22021-03-22 09:00:16 -07006#include "common/platform/api/quiche_logging.h"
QUICHE team02542a22021-03-22 09:00:16 -07007
8namespace http2 {
9namespace adapter {
10
11WindowManager::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
16void 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 team33a4aa62021-04-08 11:10:59 -070023 QUICHE_BUG(H2 window decrease)
QUICHE team02542a22021-03-22 09:00:16 -070024 << "Window size limit decrease not currently supported.";
25 }
26 limit_ = new_limit;
27}
28
29void 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
37bool 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
55void WindowManager::MarkDataFlushed(size_t bytes) {
56 QUICHE_VLOG(2) << "WindowManager@" << this << " buffered: " << buffered_
57 << " bytes: " << bytes;
58 if (buffered_ < bytes) {
QUICHE team33a4aa62021-04-08 11:10:59 -070059 QUICHE_BUG(bug_2816_1) << "WindowManager@" << this << " buffered underflow "
60 << "buffered_: " << buffered_ << " bytes: " << bytes;
QUICHE team02542a22021-03-22 09:00:16 -070061 buffered_ = 0;
62 } else {
63 buffered_ -= bytes;
64 }
65 MaybeNotifyListener();
66}
67
68void 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 team02542a22021-03-22 09:00:16 -070076 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