mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 04:47:29 +02:00
Avoid a parser allocation using non-flat buffer:
When the parser is presented with an input buffer sequence with length greater than one, the input is flattened using stack space instead of dynamic allocation if the buffer size is no greater than 8192.
This commit is contained in:
@ -2,6 +2,7 @@ Version 55:
|
|||||||
|
|
||||||
* Don't allocate memory to handle obs-fold
|
* Don't allocate memory to handle obs-fold
|
||||||
* Add Beast CMake interface target
|
* Add Beast CMake interface target
|
||||||
|
* Avoid a parser allocation using non-flat buffer
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -74,6 +74,9 @@ class basic_parser
|
|||||||
// limit on the size of the obs-fold buffer
|
// limit on the size of the obs-fold buffer
|
||||||
static std::size_t constexpr max_obs_fold = 4096;
|
static std::size_t constexpr max_obs_fold = 4096;
|
||||||
|
|
||||||
|
// limit on the size of the stack flat buffer
|
||||||
|
static std::size_t constexpr max_stack_buffer = 8192;
|
||||||
|
|
||||||
// Message will be complete after reading header
|
// Message will be complete after reading header
|
||||||
static unsigned constexpr flagSkipBody = 1<< 0;
|
static unsigned constexpr flagSkipBody = 1<< 0;
|
||||||
|
|
||||||
@ -363,9 +366,10 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
string_view
|
std::size_t
|
||||||
maybe_flatten(
|
put_from_stack(std::size_t size,
|
||||||
ConstBufferSequence const& buffers);
|
ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_header(char const*& p,
|
parse_header(char const*& p,
|
||||||
|
@ -88,9 +88,35 @@ put(ConstBufferSequence const& buffers,
|
|||||||
static_assert(is_const_buffer_sequence<
|
static_assert(is_const_buffer_sequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
auto const buffer = maybe_flatten(buffers);
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
auto const p = buffers.begin();
|
||||||
|
auto const last = buffers.end();
|
||||||
|
if(p == last)
|
||||||
|
return 0;
|
||||||
|
if(std::next(p) == last)
|
||||||
|
{
|
||||||
|
// single buffer
|
||||||
|
auto const b = *p;
|
||||||
|
return put(boost::asio::const_buffers_1{
|
||||||
|
buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b)}, ec);
|
||||||
|
}
|
||||||
|
auto const size = buffer_size(buffers);
|
||||||
|
if(size <= max_stack_buffer)
|
||||||
|
return put_from_stack(size, buffers, ec);
|
||||||
|
if(size > buf_len_)
|
||||||
|
{
|
||||||
|
// reallocate
|
||||||
|
buf_.reset(new char[size]);
|
||||||
|
buf_len_ = size;
|
||||||
|
}
|
||||||
|
// flatten
|
||||||
|
buffer_copy(boost::asio::buffer(
|
||||||
|
buf_.get(), buf_len_), buffers);
|
||||||
return put(boost::asio::const_buffers_1{
|
return put(boost::asio::const_buffers_1{
|
||||||
buffer.data(), buffer.size()}, ec);
|
buf_.get(), buf_len_}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
@ -209,37 +235,18 @@ put_eof(error_code& ec)
|
|||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
inline
|
std::size_t
|
||||||
string_view
|
|
||||||
basic_parser<isRequest, Derived>::
|
basic_parser<isRequest, Derived>::
|
||||||
maybe_flatten(
|
put_from_stack(std::size_t size,
|
||||||
ConstBufferSequence const& buffers)
|
ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_cast;
|
char buf[max_stack_buffer];
|
||||||
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
using boost::asio::buffer_size;
|
buffer_copy(buffer(buf, sizeof(buf)), buffers);
|
||||||
auto const p = buffers.begin();
|
return put(boost::asio::const_buffers_1{
|
||||||
auto const last = buffers.end();
|
buf, size}, ec);
|
||||||
if(p == last)
|
|
||||||
return {nullptr, 0};
|
|
||||||
if(std::next(p) == last)
|
|
||||||
{
|
|
||||||
// single buffer
|
|
||||||
auto const b = *p;
|
|
||||||
return {buffer_cast<char const*>(b),
|
|
||||||
buffer_size(b)};
|
|
||||||
}
|
|
||||||
auto const len = buffer_size(buffers);
|
|
||||||
if(len > buf_len_)
|
|
||||||
{
|
|
||||||
// reallocate
|
|
||||||
buf_.reset(new char[len]);
|
|
||||||
buf_len_ = len;
|
|
||||||
}
|
|
||||||
// flatten
|
|
||||||
buffer_copy(boost::asio::buffer(
|
|
||||||
buf_.get(), buf_len_), buffers);
|
|
||||||
return {buf_.get(), len};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
|
Reference in New Issue
Block a user