xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/adapter/window_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 #include "quiche/http2/adapter/window_manager.h"
2 
3 #include <utility>
4 
5 #include "quiche/common/platform/api/quiche_bug_tracker.h"
6 #include "quiche/common/platform/api/quiche_logging.h"
7 
8 namespace http2 {
9 namespace adapter {
10 
DefaultShouldWindowUpdateFn(int64_t limit,int64_t window,int64_t delta)11 bool DefaultShouldWindowUpdateFn(int64_t limit, int64_t window, int64_t delta) {
12   // For the sake of efficiency, we want to send window updates if less than
13   // half of the max quota is available to the peer at any point in time.
14   const int64_t kDesiredMinWindow = limit / 2;
15   const int64_t kDesiredMinDelta = limit / 3;
16   if (delta >= kDesiredMinDelta) {
17     // This particular window update was sent because the available delta
18     // exceeded the desired minimum.
19     return true;
20   } else if (window < kDesiredMinWindow) {
21     // This particular window update was sent because the quota available to the
22     // peer at this moment is less than the desired minimum.
23     return true;
24   }
25   return false;
26 }
27 
WindowManager(int64_t window_size_limit,WindowUpdateListener listener,ShouldWindowUpdateFn should_window_update_fn,bool update_window_on_notify)28 WindowManager::WindowManager(int64_t window_size_limit,
29                              WindowUpdateListener listener,
30                              ShouldWindowUpdateFn should_window_update_fn,
31                              bool update_window_on_notify)
32     : limit_(window_size_limit),
33       window_(window_size_limit),
34       buffered_(0),
35       listener_(std::move(listener)),
36       should_window_update_fn_(std::move(should_window_update_fn)),
37       update_window_on_notify_(update_window_on_notify) {
38   if (!should_window_update_fn_) {
39     should_window_update_fn_ = DefaultShouldWindowUpdateFn;
40   }
41 }
42 
OnWindowSizeLimitChange(const int64_t new_limit)43 void WindowManager::OnWindowSizeLimitChange(const int64_t new_limit) {
44   QUICHE_VLOG(2) << "WindowManager@" << this
45                  << " OnWindowSizeLimitChange from old limit of " << limit_
46                  << " to new limit of " << new_limit;
47   window_ += (new_limit - limit_);
48   limit_ = new_limit;
49 }
50 
SetWindowSizeLimit(int64_t new_limit)51 void WindowManager::SetWindowSizeLimit(int64_t new_limit) {
52   QUICHE_VLOG(2) << "WindowManager@" << this
53                  << " SetWindowSizeLimit from old limit of " << limit_
54                  << " to new limit of " << new_limit;
55   limit_ = new_limit;
56   MaybeNotifyListener();
57 }
58 
MarkDataBuffered(int64_t bytes)59 bool WindowManager::MarkDataBuffered(int64_t bytes) {
60   QUICHE_VLOG(2) << "WindowManager@" << this << " window: " << window_
61                  << " bytes: " << bytes;
62   if (window_ < bytes) {
63     QUICHE_VLOG(2) << "WindowManager@" << this << " window underflow "
64                    << "window: " << window_ << " bytes: " << bytes;
65     window_ = 0;
66   } else {
67     window_ -= bytes;
68   }
69   buffered_ += bytes;
70   if (window_ == 0) {
71     // If data hasn't been flushed in a while there may be space available.
72     MaybeNotifyListener();
73   }
74   return window_ > 0;
75 }
76 
MarkDataFlushed(int64_t bytes)77 void WindowManager::MarkDataFlushed(int64_t bytes) {
78   QUICHE_VLOG(2) << "WindowManager@" << this << " buffered: " << buffered_
79                  << " bytes: " << bytes;
80   if (buffered_ < bytes) {
81     QUICHE_BUG(bug_2816_1) << "WindowManager@" << this << " buffered underflow "
82                            << "buffered_: " << buffered_ << " bytes: " << bytes;
83     buffered_ = 0;
84   } else {
85     buffered_ -= bytes;
86   }
87   MaybeNotifyListener();
88 }
89 
MaybeNotifyListener()90 void WindowManager::MaybeNotifyListener() {
91   const int64_t delta = limit_ - (buffered_ + window_);
92   if (should_window_update_fn_(limit_, window_, delta) && delta > 0) {
93     QUICHE_VLOG(2) << "WindowManager@" << this
94                    << " Informing listener of delta: " << delta;
95     listener_(delta);
96     if (update_window_on_notify_) {
97       window_ += delta;
98     }
99   }
100 }
101 
102 }  // namespace adapter
103 }  // namespace http2
104