Add QpackBlockingManager to track blocked streams and blocking entries.
gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 260829566
Change-Id: I3f2f74384f213f3dfea8460a77f759b070a7d79c
diff --git a/quic/core/qpack/qpack_blocking_manager.cc b/quic/core/qpack/qpack_blocking_manager.cc
new file mode 100644
index 0000000..e8e4f87
--- /dev/null
+++ b/quic/core/qpack/qpack_blocking_manager.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
+
+#include <utility>
+
+namespace quic {
+
+QpackBlockingManager::QpackBlockingManager() : known_received_count_(0) {}
+
+bool QpackBlockingManager::OnHeaderAcknowledgement(QuicStreamId stream_id) {
+ auto it = header_blocks_.find(stream_id);
+ if (it == header_blocks_.end()) {
+ return false;
+ }
+
+ DCHECK(!it->second.empty());
+
+ const IndexSet& indices = it->second.front();
+ DCHECK(!indices.empty());
+
+ const uint64_t required_index_count = RequiredInsertCount(indices);
+ if (known_received_count_ < required_index_count) {
+ known_received_count_ = required_index_count;
+ }
+
+ DecreaseReferenceCounts(indices);
+
+ it->second.pop_front();
+ if (it->second.empty()) {
+ header_blocks_.erase(it);
+ }
+
+ return true;
+}
+
+void QpackBlockingManager::OnStreamCancellation(QuicStreamId stream_id) {
+ auto it = header_blocks_.find(stream_id);
+ if (it == header_blocks_.end()) {
+ return;
+ }
+
+ for (const IndexSet& indices : it->second) {
+ DecreaseReferenceCounts(indices);
+ }
+
+ header_blocks_.erase(it);
+}
+
+void QpackBlockingManager::OnInsertCountIncrement(uint64_t increment) {
+ known_received_count_ += increment;
+}
+
+void QpackBlockingManager::OnHeaderBlockSent(QuicStreamId stream_id,
+ IndexSet indices) {
+ DCHECK(!indices.empty());
+
+ IncreaseReferenceCounts(indices);
+ header_blocks_[stream_id].push_back(std::move(indices));
+}
+
+uint64_t QpackBlockingManager::blocked_stream_count() const {
+ uint64_t blocked_stream_count = 0;
+ for (const auto& header_blocks_for_stream : header_blocks_) {
+ for (const IndexSet& indices : header_blocks_for_stream.second) {
+ if (RequiredInsertCount(indices) > known_received_count_) {
+ ++blocked_stream_count;
+ break;
+ }
+ }
+ }
+
+ return blocked_stream_count;
+}
+
+uint64_t QpackBlockingManager::smallest_blocking_index() const {
+ return entry_reference_counts_.empty()
+ ? std::numeric_limits<uint64_t>::max()
+ : entry_reference_counts_.begin()->first;
+}
+
+// static
+uint64_t QpackBlockingManager::RequiredInsertCount(const IndexSet& indices) {
+ return *indices.rbegin() + 1;
+}
+
+void QpackBlockingManager::IncreaseReferenceCounts(const IndexSet& indices) {
+ for (const uint64_t index : indices) {
+ auto it = entry_reference_counts_.lower_bound(index);
+ if (it != entry_reference_counts_.end() && it->first == index) {
+ ++it->second;
+ } else {
+ entry_reference_counts_.insert(it, {index, 1});
+ }
+ }
+}
+
+void QpackBlockingManager::DecreaseReferenceCounts(const IndexSet& indices) {
+ for (const uint64_t index : indices) {
+ auto it = entry_reference_counts_.find(index);
+ DCHECK(it != entry_reference_counts_.end());
+ DCHECK_NE(0u, it->second);
+
+ if (it->second == 1) {
+ entry_reference_counts_.erase(it);
+ } else {
+ --it->second;
+ }
+ }
+}
+
+} // namespace quic