Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/admin-guide/files/records.config.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4286,6 +4286,13 @@ HTTP/2 Configuration
frames. Write operation will be triggered at least once every this configured
number of millisecond regardless of pending data size.

.. ts:cv:: CONFIG proxy.config.http2.default_buffer_water_mark INT -1
:reloadable:
:units: bytes

Specifies the high water mark for all HTTP/2 frames on an outoging connection.
Default is -1 to preserve existing water marking behavior.

HTTP/3 Configuration
====================

Expand Down
4 changes: 2 additions & 2 deletions iocore/net/UnixNetVConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread)
int signalled = 0;

// signal write ready to allow user to fill the buffer
if (towrite != ntodo && buf.writer()->write_avail()) {
if (towrite != ntodo && !buf.writer()->high_water()) {
if (write_signal_and_update(VC_EVENT_WRITE_READY, vc) != EVENT_CONT) {
return;
}
Expand Down Expand Up @@ -519,7 +519,7 @@ write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread)
}

int e = 0;
if (!signalled) {
if (!signalled || (s->vio.ntodo() > 0 && !buf.writer()->high_water())) {
e = VC_EVENT_WRITE_READY;
} else if (wbe_event != vc->write_buffer_empty_event) {
// @a signalled means we won't send an event, and the event values differing means we
Expand Down
2 changes: 2 additions & 0 deletions mgmt/RecordsConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,8 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.http2.write_time_threshold", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http2.default_buffer_water_mark", RECD_INT, "-1", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,

//############
//#
Expand Down
2 changes: 2 additions & 0 deletions proxy/http2/HTTP2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ uint32_t Http2::header_table_size_limit = 65536;
uint32_t Http2::write_buffer_block_size = 262144;
float Http2::write_size_threshold = 0.5;
uint32_t Http2::write_time_threshold = 100;
uint32_t Http2::buffer_water_mark = 0;

void
Http2::init()
Expand Down Expand Up @@ -843,6 +844,7 @@ Http2::init()
REC_EstablishStaticConfigInt32U(write_buffer_block_size, "proxy.config.http2.write_buffer_block_size");
REC_EstablishStaticConfigFloat(write_size_threshold, "proxy.config.http2.write_size_threshold");
REC_EstablishStaticConfigInt32U(write_time_threshold, "proxy.config.http2.write_time_threshold");
REC_EstablishStaticConfigInt32U(buffer_water_mark, "proxy.config.http2.default_buffer_water_mark");

// If any settings is broken, ATS should not start
ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, max_concurrent_streams_in}));
Expand Down
1 change: 1 addition & 0 deletions proxy/http2/HTTP2.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ class Http2
static uint32_t write_buffer_block_size;
static float write_size_threshold;
static uint32_t write_time_threshold;
static uint32_t buffer_water_mark;

static void init();
};
10 changes: 6 additions & 4 deletions proxy/http2/Http2ClientSession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,12 @@ Http2ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB
this->_read_buffer_reader = reader ? reader : this->read_buffer->alloc_reader();

// This block size is the buffer size that we pass to SSLWriteBuffer
auto buffer_block_size_index = iobuffer_size_to_index(Http2::write_buffer_block_size, MAX_BUFFER_SIZE_INDEX);
this->write_buffer = new_MIOBuffer(buffer_block_size_index);
this->_write_buffer_reader = this->write_buffer->alloc_reader();
this->_write_size_threshold = index_to_buffer_size(buffer_block_size_index) * Http2::write_size_threshold;
auto buffer_block_size_index = iobuffer_size_to_index(Http2::write_buffer_block_size, MAX_BUFFER_SIZE_INDEX);
this->write_buffer = new_MIOBuffer(buffer_block_size_index);
this->write_buffer->water_mark = Http2::buffer_water_mark;

this->_write_buffer_reader = this->write_buffer->alloc_reader();
this->_write_size_threshold = index_to_buffer_size(buffer_block_size_index) * Http2::write_size_threshold;

this->_handle_if_ssl(new_vc);

Expand Down
6 changes: 6 additions & 0 deletions proxy/http2/Http2CommonSession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ Http2CommonSession::write_avail()
return this->write_buffer->write_avail();
}

bool
Http2CommonSession::is_write_high_water() const
{
return this->write_buffer->high_water();
}

void
Http2CommonSession::write_reenable()
{
Expand Down
1 change: 1 addition & 0 deletions proxy/http2/Http2CommonSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class Http2CommonSession
void remember(const SourceLocation &location, int event, int reentrant = NO_REENTRANT);

int64_t write_avail();
bool is_write_high_water() const;

virtual ProxySession *get_proxy_session() = 0;

Expand Down
12 changes: 6 additions & 6 deletions proxy/http2/Http2ConnectionState.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1655,12 +1655,6 @@ Http2ConnectionState::send_a_data_frame(Http2Stream *stream, size_t &payload_len
return Http2SendDataFrameResult::ERROR;
}

if (this->session->write_avail() == 0) {
Http2StreamDebug(this->session, stream->get_id(), "Not write avail");
this->session->flush();
return Http2SendDataFrameResult::NOT_WRITE_AVAIL;
}

// Select appropriate payload length
if (resp_reader->is_read_avail_more_than(0)) {
// We only need to check for window size when there is a payload
Expand All @@ -1679,6 +1673,12 @@ Http2ConnectionState::send_a_data_frame(Http2Stream *stream, size_t &payload_len
payload_length = 0;
}

if (payload_length > 0 && this->session->is_write_high_water()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not going to send data to the client unless there is 32k to send?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're wondering about the timing of the this->session->flush(), it is called with several conditions.

  • e.g. if the response body is 10 bytes, it'll be sent to the client immediately.

This is checking the high watermark of the session buffer to stop it keep growing.

Http2StreamDebug(this->session, stream->get_id(), "Not write avail");
this->session->flush();
return Http2SendDataFrameResult::NOT_WRITE_AVAIL;
}

stream->update_sent_count(payload_length);

// Are we at the end?
Expand Down