2
0
mirror of https://github.com/boostorg/redis.git synced 2026-02-08 23:12:14 +00:00
Files
redis/include/aedis/write.hpp
Marcelo Zimbres 767ccd1877 Changes:
- Makes async_writer a composed op instead of a coroutine.
- Removes the response buffers from the receiver.
2021-01-30 20:52:07 +01:00

166 lines
4.1 KiB
C++

/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <queue>
#include <chrono>
#include <boost/asio.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <aedis/request.hpp>
namespace aedis { namespace resp {
template<
class SyncWriteStream,
class Event>
std::size_t
write(
SyncWriteStream& stream,
request<Event>& req,
boost::system::error_code& ec)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
return write(stream, net::buffer(req.payload), ec);
}
template<
class SyncWriteStream,
class Event>
std::size_t
write(
SyncWriteStream& stream,
request<Event>& req)
{
static_assert(boost::beast::is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
boost::system::error_code ec;
auto const bytes_transferred = write(stream, req, ec);
if (ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return bytes_transferred;
}
template<
class AsyncWriteStream,
class Event,
class CompletionToken =
net::default_completion_token_t<typename AsyncWriteStream::executor_type>>
auto
async_write(
AsyncWriteStream& stream,
request<Event>& req,
CompletionToken&& token =
net::default_completion_token_t<typename AsyncWriteStream::executor_type>{})
{
static_assert(boost::beast::is_async_write_stream<
AsyncWriteStream>::value,
"AsyncWriteStream type requirements not met");
return net::async_write(stream, net::buffer(req.payload), token);
}
template <
class AsyncReadStream,
class Event>
struct writer_op {
AsyncReadStream& stream;
net::steady_timer& st;
std::queue<request<Event>>* reqs;
template <class Self>
void operator()(
Self& self,
boost::system::error_code ec = {},
std::size_t bytes_transferred = 0)
{
// To stop the operation users are required to close the socket
// and cancel the timer.
if (!stream.is_open()) {
self.complete({});
return;
}
// We don't leave on operation aborted as that is the error we
// get when users cancel the timer to signal there is message to
// be written. This relies on the fact that async_write does
// not complete with this error.
if (ec && ec != net::error::operation_aborted) {
self.complete(ec);
return;
}
// When the condition below holds we are coming from a
// successful write and should wait for the next write trigger.
if (bytes_transferred != 0) {
st.expires_after(std::chrono::years{10});
st.async_wait(std::move(self));
return;
}
if (!std::empty(*reqs)) {
async_write(
stream,
net::buffer(reqs->front().payload),
std::move(self));
return;
}
}
};
template <
class AsyncWriteStream,
class Event,
class CompletionToken =
net::default_completion_token_t<typename AsyncWriteStream::executor_type>
>
auto async_writer(
AsyncWriteStream& stream,
std::queue<request<Event>>& reqs,
net::steady_timer& writeTrigger,
CompletionToken&& token =
net::default_completion_token_t<typename AsyncWriteStream::executor_type>{})
{
return net::async_compose
< CompletionToken
, void(boost::system::error_code)
>(writer_op<AsyncWriteStream, Event> {stream, writeTrigger, &reqs},
token,
stream,
writeTrigger);
}
// Returns true id a write has been triggered.
template <class Event, class Filler>
bool queue_writer(
std::queue<resp::request<Event>>& reqs,
Filler filler,
net::steady_timer& st)
{
auto const empty = std::empty(reqs);
if (empty || std::size(reqs) == 1)
reqs.push({});
filler(reqs.back());
if (empty)
st.cancel();
return empty;
}
} // resp
} // aedis