diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d753f779..eb66dfb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: uses: MarkusJx/install-boost@v2.3.0 id: install-boost with: - boost_version: 1.79.0 + boost_version: 1.80.0 platform_version: 22.04 - name: Run CMake run: | diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2904b675..126b98c3 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -30,7 +30,7 @@ jobs: uses: MarkusJx/install-boost@v2.3.0 id: install-boost with: - boost_version: 1.79.0 + boost_version: 1.80.0 platform_version: 22.04 - name: Run CMake run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 523f3e6c..910d2cdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.14) project( Aedis - VERSION 1.3.0 + VERSION 1.3.1 DESCRIPTION "A redis client designed for performance and scalability" HOMEPAGE_URL "https://mzimbres.github.io/aedis" LANGUAGES CXX diff --git a/README.md b/README.md index dfbc839b..cf01136e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Some of its distinctive features are * Back pressure, cancellation and low latency. In addition to that, Aedis hides most of the low-level Asio code away -from the user, which in the majority of the case will be concerned +from the user, which in the majority of the cases will be concerned with three library entities * `aedis::resp3::request`: A container of Redis commands. @@ -73,10 +73,10 @@ reading from the socket. The reationale behind this design is concurrently. Before we see with more detail how connections, requests and responses -work, users might find it helpful to skim over the examples, to gain a -better feeling about the library capabilities. +work, users might find it useful to skim over the examples in order to +gain a better feeling about the library capabilities. -* intro.cpp: The Aedis hello-world program. Sends one command to Redis and quits the connection. +* intro.cpp: The Aedis hello-world program. Sends one command and quits the connection. * intro_tls.cpp: Same as intro.cpp but over TLS. * intro_sync.cpp: Shows how to use the conneciton class synchronously. * containers.cpp: Shows how to send and receive STL containers and how to use transactions. @@ -89,8 +89,8 @@ better feeling about the library capabilities. * low_level_async.cpp: Sends a ping asynchronously using the low-level API. To avoid repetition code that is common to all examples have been -grouped in common.hpp. The main function is defined in main.cpp and -used by all examples. +grouped in common.hpp. The main function used in some async examples +has been factored out in the main.cpp file. ### Requests @@ -842,18 +842,18 @@ library, so you can starting using it right away by adding the ```cpp #include - ``` -in no more than one source file in your applications. For example, to -compile one of the examples manually + +in no more than one source file in your applications. To build the +examples and test cmake is supported, for example ```cpp -g++ -std=c++20 -pthread -I/opt/boost_1_79_0/include/ -Iinclude -Iexamples examples/intro.cpp examples/common.cpp +BOOST_ROOT=/opt/boost_1_80_0 cmake --preset dev ``` The requirements for using Aedis are -- Boost 1.79 or greater. +- Boost 1.80 or greater. - C++17 minimum. - Redis 6 or higher (must support RESP3). - Optionally also redis-cli and Redis Sentinel. @@ -865,8 +865,7 @@ The following compilers are supported ## Acknowledgement -Acknowledgement to people that helped shape Aedis in one way or -another. +Acknowledgement to people that helped shape Aedis * Richard Hodges ([madmongo1](https://github.com/madmongo1)): For very helpful support with Asio, the design of asynchronous programs, etc. * Vinícius dos Santos Oliveira ([vinipsmaker](https://github.com/vinipsmaker)): For useful discussion about how Aedis consumes buffers in the read operation. @@ -876,7 +875,7 @@ another. ## Changelog -### v1.3.0 +### v1.3.0-1 * Removes automatic sending of the `HELLO` command. This can't be implemented properly without bloating the connection class. It is diff --git a/include/aedis/detail/connection_ops.hpp b/include/aedis/detail/connection_ops.hpp index 29de0296..09347b24 100644 --- a/include/aedis/detail/connection_ops.hpp +++ b/include/aedis/detail/connection_ops.hpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -31,47 +29,11 @@ namespace aedis::detail { -template -auto async_guarded(Channel& channel, Op op, CompletionToken&& token) -{ - return boost::asio::deferred.values(&channel) - | boost::asio::deferred( - [](Channel* ch) - { - return ch->async_receive(boost::asio::append(boost::asio::deferred, ch)); - } - ) - | boost::asio::deferred( - [op2 = std::move(op)](std::error_code ec, std::size_t, Channel* ch) - { - return boost::asio::deferred.when(!ec) - .then(op2(boost::asio::append(boost::asio::deferred, ch))) - .otherwise(boost::asio::deferred.values(ec, 0, ch)); - } - ) - | boost::asio::deferred( - [&](std::error_code ec, std::size_t n, Channel* ch) - { - return boost::asio::deferred.when(!ec) - .then(ch->async_send({}, 0, boost::asio::append(boost::asio::deferred, n))) - .otherwise(boost::asio::deferred.values(ec, 0)); - } - ) - | boost::asio::deferred( - [](std::error_code ec, std::size_t n) - { - return boost::asio::deferred.when(!ec) - .then(boost::asio::deferred.values(boost::system::error_code{}, n)) - .otherwise(boost::asio::deferred.values(ec, 0)); - } - ) - | std::forward(token); -} - template struct receive_op { Conn* conn = nullptr; Adapter adapter; + std::size_t read_size = 0; boost::asio::coroutine coro{}; template @@ -82,16 +44,26 @@ struct receive_op { { reenter (coro) { + yield conn->push_channel_.async_receive(std::move(self)); + AEDIS_CHECK_OP1(); + yield - async_guarded( - conn->push_channel_, - resp3::async_read( - conn->next_layer(), - conn->make_dynamic_buffer(adapter.get_max_read_size(0)), - adapter, boost::asio::deferred), - std::move(self)); + resp3::async_read( + conn->next_layer(), + conn->make_dynamic_buffer(adapter.get_max_read_size(0)), + adapter, std::move(self)); + + // cancel(receive) is needed to cancel the channel, otherwise + // the read operation will be blocked forever see + // test_push_adapter. AEDIS_CHECK_OP1(conn->cancel(operation::run); conn->cancel(operation::receive)); - self.complete({}, n); + + read_size = n; + + yield conn->push_channel_.async_send({}, 0, std::move(self)); + AEDIS_CHECK_OP1(); + + self.complete({}, read_size); return; } }