Remove BodyReader::is_deferred (API Change):

The is_deferred nested type is removed from the BodyReader
requirements.

Performance for sending messages with `file_body` was cut
almost in half with is_deferred as `std::true_type` since
it caused double the number of socket writes. If the
deferred behavior is absolutely necessary, callers can get
the same effect by manually sending the headers first.

Actions Required:

* Callers who need the behavior of is_deferred as `std::true_type`
  should manually construct a serializer and serialize the header
  first, followed by the body.
This commit is contained in:
Vinnie Falco
2017-06-25 10:14:18 -07:00
parent bf59634bc2
commit edeb44617b
12 changed files with 24 additions and 86 deletions

View File

@@ -3,6 +3,7 @@ Version 68:
API Changes: API Changes:
* Change BodyReader, BodyWriter requirements * Change BodyReader, BodyWriter requirements
* Remove BodyReader::is_deferred
Actions Required: Actions Required:

View File

@@ -45,22 +45,6 @@ In this table:
A type which meets the requirements of __ConstBufferSequence__. A type which meets the requirements of __ConstBufferSequence__.
This is the type of buffer returned by `X::get`. This is the type of buffer returned by `X::get`.
] ]
][
[`X::is_deferred`]
[]
[
The type `std::true_type` if the serialization implementation
should only attempt to retrieve buffers from the reader after
the header has been serialized. Otherwise, if this type is
`std::false_type` the implementation will activate an
optimization: the first buffer produced during serialization
will contain both the header and some or all of this body.
Implementations of [*BodyReader] for which initialization is
expensive, should use `std::false_type` here, to reduce the
latency experienced by the remote host when expecting to read
the HTTP header.
]
][ ][
[`X(m,ec);`] [`X(m,ec);`]
[] []

View File

@@ -98,14 +98,6 @@ class file_body::reader
char buf_[4096]; // Small buffer for reading char buf_[4096]; // Small buffer for reading
public: public:
// This nested type informs the serializer that it should
// wait until after sending the header to initialize the
// reader. We set this to true, otherwise opening the file
// during `init` could introduce latency which delays
// the remote endpoint from receiving the header quickly.
//
using is_deferred = std::true_type;
// The type of buffer sequence returned by `get`. // The type of buffer sequence returned by `get`.
// //
using const_buffers_type = using const_buffers_type =
@@ -113,8 +105,6 @@ public:
// Constructor. // Constructor.
// //
// This is called after the header is serialized, because
// we declared `is_deferred` to be `std::true_type`.
// `m` holds the message we are sending, which will // `m` holds the message we are sending, which will
// always have the `file_body` as the body type. // always have the `file_body` as the body type.
// //

View File

@@ -96,8 +96,6 @@ struct buffer_body
value_type const& body_; value_type const& body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;

View File

@@ -45,8 +45,6 @@ struct basic_dynamic_body
DynamicBuffer const& body_; DynamicBuffer const& body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
typename DynamicBuffer::const_buffers_type; typename DynamicBuffer::const_buffers_type;

View File

@@ -49,8 +49,6 @@ struct empty_body
#else #else
struct reader struct reader
{ {
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::null_buffers; boost::asio::null_buffers;

View File

@@ -74,12 +74,10 @@ get(error_code& ec, Visit&& visit)
if(ec) if(ec)
return; return;
auto result = rd_->get(ec); auto result = rd_->get(ec);
if(ec == error::need_more)
goto go_header_only;
if(ec) if(ec)
{
// Can't use need_more when ! is_deferred
BOOST_ASSERT(ec != error::need_more);
return; return;
}
if(! result) if(! result)
goto go_header_only; goto go_header_only;
more_ = result->second; more_ = result->second;
@@ -103,10 +101,12 @@ get(error_code& ec, Visit&& visit)
break; break;
case do_body: case do_body:
BOOST_ASSERT(! rd_); if(! rd_)
rd_.emplace(m_, ec); {
if(ec) rd_.emplace(m_, ec);
return; if(ec)
return;
}
s_ = do_body + 1; s_ = do_body + 1;
BOOST_FALLTHROUGH; BOOST_FALLTHROUGH;
@@ -139,12 +139,10 @@ get(error_code& ec, Visit&& visit)
if(ec) if(ec)
return; return;
auto result = rd_->get(ec); auto result = rd_->get(ec);
if(ec == error::need_more)
goto go_header_only_c;
if(ec) if(ec)
{
// Can't use need_more when ! is_deferred
BOOST_ASSERT(ec != error::need_more);
return; return;
}
if(! result) if(! result)
goto go_header_only_c; goto go_header_only_c;
more_ = result->second; more_ = result->second;
@@ -179,10 +177,12 @@ get(error_code& ec, Visit&& visit)
break; break;
case do_body_c: case do_body_c:
BOOST_ASSERT(! rd_); if(! rd_)
rd_.emplace(m_, ec); {
if(ec) rd_.emplace(m_, ec);
return; if(ec)
return;
}
s_ = do_body_c + 1; s_ = do_body_c + 1;
BOOST_FALLTHROUGH; BOOST_FALLTHROUGH;

View File

@@ -144,16 +144,11 @@ class serializer
do_complete = 110 do_complete = 110
}; };
void split(bool, std::true_type) {}
void split(bool v, std::false_type) { split_ = v; }
void frdinit(std::true_type); void frdinit(std::true_type);
void frdinit(std::false_type); void frdinit(std::false_type);
using reader = typename Body::reader; using reader = typename Body::reader;
using is_deferred =
typename reader::is_deferred;
using ch_t = consuming_buffers<typename using ch_t = consuming_buffers<typename
Fields::reader::const_buffers_type>; // header Fields::reader::const_buffers_type>; // header
@@ -190,7 +185,7 @@ class serializer
boost::variant<boost::blank, boost::variant<boost::blank,
ch_t, cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_; ch_t, cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
int s_ = do_construct; int s_ = do_construct;
bool split_ = is_deferred::value; bool split_ = false;
bool header_done_ = false; bool header_done_ = false;
bool chunked_; bool chunked_;
bool close_; bool close_;
@@ -227,14 +222,12 @@ public:
When the split feature is enabled, the implementation will When the split feature is enabled, the implementation will
write only the octets corresponding to the serialized header write only the octets corresponding to the serialized header
first. If the header has already been written, this function first. If the header has already been written, this function
will have no effect on output. This function should be called will have no effect on output.
before retrieving any buffers using @ref get, otherwise the
behavior is undefined.
*/ */
void void
split(bool v) split(bool v)
{ {
split(v, is_deferred{}); split_ = v;
} }
/** Return `true` if serialization of the header is complete. /** Return `true` if serialization of the header is complete.

View File

@@ -47,8 +47,6 @@ struct string_body
value_type const& body_; value_type const& body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;

View File

@@ -48,8 +48,6 @@ struct string_view_body
string_view body_; string_view body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;

View File

@@ -48,14 +48,6 @@ struct Body_BodyReader {
struct BodyReader struct BodyReader
{ {
public: public:
/** Controls when the implementation requests buffers.
If false, the implementation will request the first buffer
immediately and try to serialize both the header and some
or all of the body in a single buffer.
*/
using is_deferred = std::false_type;
/// The type of buffer returned by `get`. /// The type of buffer returned by `get`.
using const_buffers_type = boost::asio::const_buffers_1; using const_buffers_type = boost::asio::const_buffers_1;

View File

@@ -42,8 +42,6 @@ public:
value_type const& body_; value_type const& body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
@@ -67,7 +65,6 @@ public:
}; };
template< template<
bool isDeferred,
bool isSplit, bool isSplit,
bool isFinalEmpty bool isFinalEmpty
> >
@@ -85,9 +82,6 @@ public:
value_type const& body_; value_type const& body_;
public: public:
using is_deferred =
std::integral_constant<bool, isDeferred>;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
@@ -220,8 +214,6 @@ public:
value_type const& body_; value_type const& body_;
public: public:
using is_deferred = std::false_type;
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
@@ -844,14 +836,10 @@ public:
yield_to( yield_to(
[&](yield_context yield) [&](yield_context yield)
{ {
testWriteStream<test_body<false, false, false>>(yield); testWriteStream<test_body<false, false>>(yield);
testWriteStream<test_body<false, false, true>>(yield); testWriteStream<test_body<false, true>>(yield);
testWriteStream<test_body<false, true, false>>(yield); testWriteStream<test_body< true, false>>(yield);
testWriteStream<test_body<false, true, true>>(yield); testWriteStream<test_body< true, true>>(yield);
testWriteStream<test_body< true, false, false>>(yield);
testWriteStream<test_body< true, false, true>>(yield);
testWriteStream<test_body< true, true, false>>(yield);
testWriteStream<test_body< true, true, true>>(yield);
}); });
} }
}; };