Skip to content

Commit

Permalink
Improvements in the docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
mzimbres committed Aug 7, 2022
1 parent c57f97b commit d26ecb6
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 53 deletions.
58 changes: 43 additions & 15 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,39 @@

## v0.3.0

* Adds `experimental::exec` and `receive_event`
functions to offer a thread safe and synchronous way of executing
requests. See `intro_sync.cpp` and `subscriber_sync.cpp` for
* Adds `experimental::exec` and `receive_event` functions to offer a
thread safe and synchronous way of executing requests across
threads. See `intro_sync.cpp` and `subscriber_sync.cpp` for
examples.

* `connection::async_read_push` was renamed to `async_receive_event`.

* Uses `async_receive_event` to communicate internal events to the
user, see subscriber.cpp and `connection::event`.
* `connection::async_receive_event` is now being used to communicate
internal events to the user, such as resolve, connect, push etc. For
examples see subscriber.cpp and `connection::event`.

* The `aedis` directory has been moved to `include` to look more
similar to Boost libraries. Users should now replace `-I/aedis-path`
with `-I/aedis-path/include` in the compiler flags.

* AUTH and HELLO commands are sent automatically. This change was
necessary to implement reconnection.
* The `AUTH` and `HELLO` commands are now sent automatically. This change was
necessary to implement reconnection. The username and password
used in `AUTH` should be provided by the user on
`connection::config`.

* Adds support for reconnection. See connection::enable reconnect.
* Adds support for reconnection. See `connection::enable_reconnect`.

* Fixes a bug in the `connection::async_exec(host, port)` overload
that was causing crashes reconnection.
* Fixes a bug in the `connection::async_run(host, port)` overload
that was causing crashes on reconnection.

* Fixes the executor usage in the connection class. Before theses
changes it was imposing `any_io_executor` on users.

* `connection::async_receiver_event` is not cancelled anymore when
`connection::async_run` exits. This change simplifies the
implementation failover operations.
`connection::async_run` exits. This change makes user code simpler.

* `connection::async_exec` with host and port overload has been
removed. Use the net `connection::async_run` overload.
removed. Use the other `connection::async_run` overload.

* The host and port parameters from `connection::async_run` have been
move to `connection::config` to better support authentication and
Expand All @@ -43,6 +45,32 @@
* Fixes build in clang the compilers and makes some improvements in
the documentation.

##v0.2.1
## v0.2.1

* Bugfixes and improvements in the documentation.
* Fixes a bug that happens on very high load.

## v0.2.0

* Major rewrite of the high-level API. There is no more need to use the low-level API anymore.
* No more callbacks: Sending requests follows the ASIO asynchrnous model.
* Support for reconnection: Pending requests are not canceled when a connection is lost and are re-sent when a new one is established.
* The library is not sending HELLO-3 on user behalf anymore. This is important to support AUTH properly.

## v0.1.2

* Adds reconnect coroutine in the `echo_server` example.
* Corrects `client::async_wait_for_data` with `make_parallel_group` to launch operation.
* Improvements in the documentation.
* Avoids dynamic memory allocation in the client class after reconnection.

## v0.1.1

* Improves the documentation and adds some features to the high-level client.

## v0.1.0

* Improvements in the design and documentation.

## v0.0.1

* First release to collect design feedback.
2 changes: 1 addition & 1 deletion doc/aedis.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ div.contents {

code
{
background-color:#f0e9ce;
background-color:#fffbeb;
}
4 changes: 1 addition & 3 deletions examples/subscriber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <iostream>
#include <tuple>
#include <boost/asio.hpp>
#include <boost/asio/experimental/as_tuple.hpp>
#include <aedis.hpp>
#include "print.hpp"

Expand All @@ -23,7 +22,6 @@ using aedis::resp3::request;
using node_type = aedis::resp3::node<std::string>;
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::socket>;
using connection = aedis::connection<tcp_socket>;
using net::experimental::as_tuple;

/* This example will subscribe and read pushes indefinitely.
*
Expand All @@ -47,7 +45,7 @@ net::awaitable<void> receiver(std::shared_ptr<connection> db)
req.push("SUBSCRIBE", "channel");

for (std::vector<node_type> resp;;) {
auto [ec, ev] = co_await db->async_receive_event(aedis::adapt(resp), as_tuple(net::use_awaitable));
auto const ev = co_await db->async_receive_event(aedis::adapt(resp));

std::cout << "Event: " << aedis::to_string<tcp_socket>(ev) << std::endl;

Expand Down
117 changes: 83 additions & 34 deletions include/aedis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,36 @@
\li First class support for STL containers and C++ built-in types.
\li Serialization and deserialization of your own data types.
\li Healthy checks, back pressure and low latency.
\li Hides most of the low level asynchronous operations away from the user.
Aedis API hides most of the low level asynchronous operations away
from the user, for example, the code below sends a ping command to
Redis (see intro.cpp)
Let us start with an overview of asynchronous code.
@subsection Async
The code below sends a ping command to Redis (see intro.cpp)
@code
int main()
{
net::io_context ioc;
connection db{ioc};
request req;
req.push("HELLO", 3);
req.push("PING");
req.push("QUIT");
std::tuple<aedis::ignore, std::string, aedis::ignore> resp;
net::io_context ioc;
connection db{ioc};
db.async_exec("127.0.0.1", "6379", req, adapt(resp), handler);
std::tuple<std::string, aedis::ignore> resp;
db.async_run(req, adapt(resp), net::detached);
ioc.run();
// Print the ping message.
std::cout << std::get<1>(resp) << std::endl;
std::cout << std::get<0>(resp) << std::endl;
}
@endcode
The connection class keeps a long lasting connection to the Redis
server over which users can execute commands, without any need of
queuing, for example, to execute more than one command
The connection class maintains a healthy connection with
Redis over which users can execute their commands, without any
need of queuing. For example, to execute more than one command
@code
int main()
Expand All @@ -71,32 +70,80 @@
db.async_exec(req2, adapt(resp2), handler2);
db.async_exec(req3, adapt(resp3), handler3);
db.async_run("127.0.0.1", "6379", handler4);
db.async_run(net::detached);
ioc.run();
...
}
@endcode
See echo_server.cpp for a more complex example. Server-side
pushes are supported on the same connection where commands are
executed, a typical subscriber will look like
The `async_exec` functions above can be called from different
places in the code without knowing about each other, see for
example echo_server.cpp. Server-side pushes are supported on the
same connection where commands are executed, a typical subscriber
will look like
(see subscriber.cpp)
@code
net::awaitable<void> reader(std::shared_ptr<connection> db)
{
...
for (std::vector<node<std::string>> resp;;) {
co_await db->async_receive(adapt(resp));
request req;
req.push("SUBSCRIBE", "channel");
for (std::vector<node_type> resp;;) {
auto ev = co_await db->async_receive_event(aedis::adapt(resp));
// Handle message
switch (ev) {
case connection::event::push:
// Use resp.
resp.clear();
break;
resp.clear();
case connection::event::hello:
// Subscribes to channels when a new connection is
// stablished.
co_await db->async_exec(req);
break;
default:;
}
}
}
@endcode
See subscriber.cpp for a complete example.
@subsection Sync
The `connection` class is async-only, many users however need to
interact with it synchronously, this is also supported by Aedis as long
as this interaction occurs across threads, for example (see
intro_sync.cpp)
@code
int main()
{
try {
net::io_context ioc{1};
connection conn{ioc};
std::thread thread{[&]() {
conn.async_run(net::detached);
ioc.run();
}};
request req;
req.push("PING");
req.push("QUIT");
std::tuple<std::string, aedis::ignore> resp;
exec(conn, req, adapt(resp));
thread.join();
std::cout << "Response: " << std::get<0>(resp) << std::endl;
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
}
}
@endcode
\subsection using-aedis Installation
Expand All @@ -110,7 +157,7 @@
```
# Clone the repository and checkout the lastest release tag.
$ git clone --branch v0.2.1 https://github.com/mzimbres/aedis.git
$ git clone --branch v0.3.0 https://github.com/mzimbres/aedis.git
$ cd aedis
# Build an example
Expand All @@ -121,7 +168,7 @@
```
# Download and unpack the latest release
$ wget https://github.com/mzimbres/aedis/releases/download/v0.2.1/aedis-0.2.1.tar.gz
$ wget https://github.com/mzimbres/aedis/releases/download/v0.3.0/aedis-0.2.1.tar.gz
$ tar -xzvf aedis-0.2.1.tar.gz
# Configure, build and install
Expand Down Expand Up @@ -451,10 +498,12 @@
The examples listed below cover most use cases presented in the documentation above.
@li intro.cpp: Basic steps with Aedis.
@li intro_sync.cpp: Synchronous version of intro.cpp.
@li containers.cpp: Shows how to send and receive stl containers.
@li serialization.cpp: Shows the \c request support to serialization of user types.
@li subscriber.cpp: Shows how to subscribe to a channel and how to reconnect when connection is lost.
@li echo_server.cpp: A simple TCP echo server that users coroutines.
@li subscriber_sync.cpp: Synchronous version of subscriber.cpp.
@li echo_server.cpp: A simple TCP echo server that uses coroutines.
@li chat_room.cpp: A simple chat room that uses coroutines.
\section why-aedis Why Aedis
Expand All @@ -476,8 +525,8 @@
not support
@li RESP3. Without RESP3 is impossible to support some important Redis features like client side caching, among other things.
@li The Asio asynchronous model.
@li Reading response diretly in user data structures avoiding temporaries.
@li Coroutines.
@li Reading responses directly in user data structures avoiding temporaries.
@li Error handling with error-code and exception overloads.
@li Healthy checks.
Expand Down Expand Up @@ -523,11 +572,11 @@
Some of the problems with this API are
@li Heterogeneous treatment of commands, pipelines and transaction.
@li Heterogeneous treatment of commands, pipelines and transaction. This makes auto-pipelining impossible.
@li Any Api that sends individual commands has a very restricted scope of usability and should be avoided for performance reasons.
@li The API imposes exceptions on users, no error-code overload is provided.
@li No way to reuse the buffer for new calls to e.g. \c redis.get in order to avoid further dynamic memory allocations.
@li Error handling of resolve and connection no clear.
@li Error handling of resolve and connection not clear.
According to the documentation, pipelines in redis-plus-plus have
the following characteristics
Expand All @@ -538,7 +587,7 @@
This is clearly a downside of the API as pipelines should be the
default way of communicating and not an exception, paying such a
high price for each pipeline imposes a severe cost in performance.
Transactions also suffer from the very same problem
Transactions also suffer from the very same problem.
> NOTE: Creating a Transaction object is NOT cheap, since it
> creates a new connection.
Expand Down

0 comments on commit d26ecb6

Please sign in to comment.