Moves //gfe/gfe2/http2:window_manager to //third_party/http2/adapter.

PiperOrigin-RevId: 364328994
Change-Id: I0899a629122cfe88f2f952ad5dae00e1331c57bc
diff --git a/http2/adapter/window_manager.cc b/http2/adapter/window_manager.cc
new file mode 100644
index 0000000..148931f
--- /dev/null
+++ b/http2/adapter/window_manager.cc
@@ -0,0 +1,100 @@
+#include "http2/adapter/window_manager.h"
+
+#include <utility>
+
+#include "common/platform/api/quiche_logging.h"
+#include "spdy/platform/api/spdy_bug_tracker.h"
+
+namespace http2 {
+namespace adapter {
+
+WindowManager::WindowManager(size_t window_size_limit,
+                             WindowUpdateListener listener)
+    : limit_(window_size_limit), window_(window_size_limit), buffered_(0),
+      listener_(std::move(listener)) {}
+
+void WindowManager::OnWindowSizeLimitChange(const size_t new_limit) {
+  QUICHE_VLOG(2) << "WindowManager@" << this
+                 << " OnWindowSizeLimitChange from old limit of " << limit_
+                 << " to new limit of " << new_limit;
+  if (new_limit > limit_) {
+    window_ += (new_limit - limit_);
+  } else {
+    SPDY_BUG_V2(H2 window decrease)
+        << "Window size limit decrease not currently supported.";
+  }
+  limit_ = new_limit;
+}
+
+void WindowManager::SetWindowSizeLimit(size_t new_limit) {
+  QUICHE_VLOG(2) << "WindowManager@" << this
+                 << " SetWindowSizeLimit from old limit of " << limit_
+                 << " to new limit of " << new_limit;
+  limit_ = new_limit;
+  MaybeNotifyListener();
+}
+
+bool WindowManager::MarkDataBuffered(size_t bytes) {
+  QUICHE_VLOG(2) << "WindowManager@" << this << " window: " << window_
+                 << " bytes: " << bytes;
+  if (window_ < bytes) {
+    QUICHE_VLOG(2) << "WindowManager@" << this << " window underflow "
+                   << "window: " << window_ << " bytes: " << bytes;
+    window_ = 0;
+  } else {
+    window_ -= bytes;
+  }
+  buffered_ += bytes;
+  if (window_ == 0) {
+    // If data hasn't been flushed in a while there may be space available.
+    MaybeNotifyListener();
+  }
+  return window_ > 0;
+}
+
+void WindowManager::MarkDataFlushed(size_t bytes) {
+  QUICHE_VLOG(2) << "WindowManager@" << this << " buffered: " << buffered_
+                 << " bytes: " << bytes;
+  if (buffered_ < bytes) {
+    SPDY_BUG_V2(bug_2816_1)
+        << "WindowManager@" << this << " buffered underflow "
+        << "buffered_: " << buffered_ << " bytes: " << bytes;
+    buffered_ = 0;
+  } else {
+    buffered_ -= bytes;
+  }
+  MaybeNotifyListener();
+}
+
+void WindowManager::MaybeNotifyListener() {
+  if (buffered_ + window_ > limit_) {
+    QUICHE_LOG(ERROR) << "Flow control violation; limit: " << limit_
+                      << " buffered: " << buffered_ << " window: " << window_;
+    return;
+  }
+  // For the sake of efficiency, we want to send window updates if less than
+  // half of the max quota is available to the peer at any point in time.
+  // http://google3/gfe/gfe2/stubby/autobahn_fd_wrapper.cc?l=1180-1183&rcl=307416556
+  const size_t kDesiredMinWindow = limit_ / 2;
+  const size_t kDesiredMinDelta = limit_ / 3;
+  const size_t delta = limit_ - (buffered_ + window_);
+  bool send_update = false;
+  if (delta >= kDesiredMinDelta) {
+    // This particular window update was sent because the available delta
+    // exceeded the desired minimum.
+    send_update = true;
+  } else if (window_ < kDesiredMinWindow) {
+    // This particular window update was sent because the quota available to the
+    // peer at this moment is less than the desired minimum.
+    send_update = true;
+  }
+  if (send_update && delta > 0) {
+    QUICHE_VLOG(2) << "WindowManager@" << this
+                   << " Informing listener of delta: " << delta;
+    listener_(delta);
+    window_ += delta;
+  }
+}
+
+}  // namespace adapter
+}  // namespace http2