Coalesce adjacent stream frames.
gfe-relnote: protected by gfe2_reloadable_flag_quic_coalesce_stream_frames.
PiperOrigin-RevId: 275506579
Change-Id: I94697cc2ceaffc05d03511a342fcf8743780dd77
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 07fa4b1..ee2dc02 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -11,7 +11,9 @@
#include <utility>
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
@@ -1369,6 +1371,14 @@
QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details);
return false;
}
+
+ if (GetQuicReloadableFlag(quic_coalesce_stream_frames) &&
+ frame.type == STREAM_FRAME &&
+ MaybeCoalesceStreamFrame(frame.stream_frame)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_coalesce_stream_frames);
+ return true;
+ }
+
size_t frame_len = framer_->GetSerializedFrameLength(
frame, BytesFree(), queued_frames_.empty(),
/* last_frame_in_packet= */ true, GetPacketNumberLength());
@@ -1412,6 +1422,36 @@
return true;
}
+bool QuicPacketCreator::MaybeCoalesceStreamFrame(const QuicStreamFrame& frame) {
+ if (queued_frames_.empty() || queued_frames_.back().type != STREAM_FRAME) {
+ return false;
+ }
+ QuicStreamFrame* candidate = &queued_frames_.back().stream_frame;
+ if (candidate->stream_id != frame.stream_id ||
+ candidate->offset + candidate->data_length != frame.offset ||
+ frame.data_length > BytesFree()) {
+ return false;
+ }
+ candidate->data_length += frame.data_length;
+ candidate->fin = frame.fin;
+
+ // The back of retransmittable frames must be the same as the original
+ // queued frames' back.
+ DCHECK_EQ(packet_.retransmittable_frames.back().type, STREAM_FRAME);
+ QuicStreamFrame* retransmittable =
+ &packet_.retransmittable_frames.back().stream_frame;
+ DCHECK_EQ(retransmittable->stream_id, frame.stream_id);
+ DCHECK_EQ(retransmittable->offset + retransmittable->data_length,
+ frame.offset);
+ retransmittable->data_length = candidate->data_length;
+ retransmittable->fin = candidate->fin;
+ packet_size_ += frame.data_length;
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnStreamFrameCoalesced(*candidate);
+ }
+ return true;
+}
+
void QuicPacketCreator::MaybeAddPadding() {
// The current packet should have no padding bytes because padding is only
// added when this method is called just before the packet is serialized.