2
0
mirror of https://github.com/boostorg/redis.git synced 2026-01-19 04:42:09 +00:00

Many improvements in the docs.

This commit is contained in:
Marcelo Zimbres
2022-03-06 11:34:59 +01:00
parent 0723922ac1
commit 8cc142d55b
8 changed files with 86 additions and 80 deletions

View File

@@ -24,58 +24,84 @@
\section Overview
Aedis is low-level redis client library built on top of Boost.Asio
that implements communication with a Redis server over the latests
version of its protocol RESP3. Some of its most important features
are
Aedis is a low-level redis client library that provides simple and
efficient communication with a Redis server built on top of
Boost.Asio. Some of its distinctive features are
1. First class support for asynchronous communication.
2. Support for STL containers.
3. Serialization and deserialization of your own data types built directly in the parser to avoid unnecessary copies.
4. Client class that encapsulates handling of requests for the user.
5. etc.
1. Support for the latest version of the Redis communication protocol RESP3.
2. Asynchronous interface that handles servers pushs optimally.
3. Firt class support for STL containers.
4. Serialization and deserialization of your own data types built directly into the parser that avoids temporaries.
5. Client class that abstracts the management of output messages away from the user.
6. Asymptotic zero allocations by means of memory reuse.
For more information about Redis see https://redis.io/
\section tutorial Tutorial
The general structure of a program involves writing a receiver like this
@code
class myreceiver : receiver<std::vector<node<std::string>>> {
public:
void on_read(command cmd) override
{
switch (cmd) {
case command::hello: on_hello(); break;
case command::set: on_set(); break;
case command::get: on_get(); break;
...
default:
}
}
};
@endcode
and to start communication with Redis
The general form of a program looks like
@code
int main()
{
net::io_context ioc;
client<net::ip::tcp::socket> db(ioc.get_executor());
myreceiver recv;
client<net::ip::tcp::socket> db{ioc.get_executor()};
receiver recv;
db.async_run(
recv,
{net::ip::make_address("127.0.0.1"), 6379},
[](auto ec){ std::cout << ec.message() << std::endl;});
[](auto ec){ ... });
ioc.run();
}
@endcode
Most of the time users will be concerned only with the
implementation of the \c receiver class, to make that simpler,
Aedis provides a base receiver class that abstracts all the
complexity away from the user. A typical implementation will look
like the following
@code
class myreceiver : receiver<response_type> {
public:
void on_read_impl(command cmd) override
{
// Handle commands here.
}
};
@endcode
Sending commands to Redis is also simple, for example
@code
db.>send(command::ping, "O rato roeu a roupa do rei de Roma");
db.>send(command::incr, "counter");
db.>send(command::set, "key", "Três pratos de trigo para três tigres");
db.>send(command::get, "key");
db.>send(command::quit);
@endcode
See Tutorial for more details on how to use the library.
For more information about Redis see https://redis.io/
\section tutorial Tutorial
In the last secion we have seem the general structure of an Aedis
program. Here we will give more detail.
\subsection Requests
\subsection Responses
\subsubsection Serializaiton
\subsubsection Transactions
Redis commands can fail only if called with a wrong syntax (and
the problem is not detectable during the command queueing),
or against keys holding the wrong data type: this means that in
practical terms a failing command is the result of a programming
errors, and a kind of error that is very likely to be detected
during development, and not in production.
\section examples Examples
https://redis.io/topics/data-types.
See also https://redis.io/topics/transactions.
\b Basics: Focuses on small examples that show basic usage of
the library.
@@ -83,11 +109,12 @@
- intro.cpp: A good starting point. Some commands are sent to the
Redis server and the responses are printed to screen.
- aggregates.cpp:
- aggregates.cpp: Shows how receive RESP3 aggregate data types.
- transaction.cpp: Shows how to read the responses to a trasaction
efficiently. See also https://redis.io/topics/transactions.
- stl_containers.cpp:
- serialization.cpp: Shows how to de/serialize your own
non-aggregate data-structures.
- subscriber.cpp: Shows how channel subscription works at a low
level. See also https://redis.io/topics/pubsub.
@@ -100,34 +127,9 @@
- chat_room.cpp: Shows how to build a scalable chat room that
scales to millions of users.
\b STL \b Containers: Many of the Redis data structures can be
directly translated in to STL containers, below you will find some
example code. For a list of Redis data types see
https://redis.io/topics/data-types.
- hashes.cpp: Shows how to read Redis hashes in a \c std::map, \c
std::unordered_map and \c std::vector.
- lists.cpp: Shows how to read Redis lists in \c std::list,
\c std::deque, \c std::vector. It also illustrates basic serialization.
- sets.cpp: Shows how to read Redis sets in a \c std::set, \c
std::unordered_set and \c std::vector.
\b Customization \b points: Shows how de/serialize user types
avoiding copies. This is particularly useful for low latency
applications that want to avoid unneeded copies, for examples when
storing json strings in Redis keys.
- serialization.cpp: Shows how to de/serialize your own
non-aggregate data-structures.
- response_adapter.cpp: Customization point for users that want to
- receiver.cpp: Customization point for users that want to
de/serialize their own data-structures like containers for example.
- key_expiration.cpp: Shows how to use \c std::optional to deal
with keys that may have expired or do not exist.
\section using-aedis Using Aedis
To install and use Aedis you will need

View File

@@ -12,6 +12,10 @@
#include <aedis/redis/detail/client_ops.hpp>
#include <aedis/redis/command.hpp>
// TODO: What to do if a users send a discard not contained in a
// transaction. The client object will try to pop the queue until a
// multi is found.
namespace aedis {
namespace redis {
@@ -20,7 +24,8 @@ namespace redis {
*
* This Redis client keeps a connection to the database open and
* uses it for all communication with Redis. For examples on how to
* use see the examples chat_room.cpp, echo_server.cpp and redis_client.cpp.
* use see the examples chat_room.cpp, echo_server.cpp and
* redis_client.cpp.
*
* \remarks This class reuses its internal buffers for requests and
* for reading Redis responses. With time it will allocate less and
@@ -95,8 +100,11 @@ private:
}
// Returns true when the next request can be writen.
bool on_cmd()
bool on_cmd(command)
{
// TODO: If the response to a discard is received we have to
// remove all commands up until multi.
assert(!std::empty(req_info_));
assert(!std::empty(commands_));

View File

@@ -182,7 +182,7 @@ struct read_op {
return;
}
if (t != resp3::type::push && cli->on_cmd())
if (t != resp3::type::push && cli->on_cmd(cmd))
cli->timer_.cancel_one();
recv->on_read(cmd);

View File

@@ -13,8 +13,6 @@ namespace redis {
char const* to_string(command c)
{
assert(c != command::invalid);
static char const* table[] = {
"ACL",
"APPEND",
@@ -220,6 +218,7 @@ char const* to_string(command c)
"ZSCAN",
"ZSCORE",
"ZUNIONSTORE",
"INVALID",
};
return table[static_cast<int>(c)];

View File

@@ -69,6 +69,9 @@ public:
void on_read(command cmd)
{
if (cmd == command::discard)
on_transaction_ = false;
if (on_transaction_)
return;

View File

@@ -20,7 +20,7 @@ using aedis::resp3::node;
using client_type = aedis::redis::client<net::ip::tcp::socket>;
using response_type = std::vector<node<std::string>>;
// Prints aggregates that don't contain nested aggregates.
// Prints aggregates that don't contain any nested aggregates.
void print_aggregate(response_type const& v)
{
auto const m = element_multiplicity(v.front().data_type);

View File

@@ -31,7 +31,7 @@ private:
public:
myreceiver(std::shared_ptr<client_type> db) : db_{db} {}
void on_message(command cmd)
void on_read(command cmd)
{
switch (cmd) {
case command::hello:
@@ -72,8 +72,8 @@ listener(
for (;;) {
auto socket = co_await acc->async_accept(net::use_awaitable);
auto session = std::make_shared<user_session>(std::move(socket));
recv->add(session);
session->start(on_user_msg);
recv->add(session);
}
}
@@ -95,10 +95,7 @@ int main()
co_spawn(ioc, listener(acc, db, recv), net::detached);
net::signal_set signals(ioc.get_executor(), SIGINT, SIGTERM);
signals.async_wait([=] (auto, int) {
db->send(command::quit);
acc->cancel();
});
signals.async_wait([&] (auto, int) { ioc.stop(); });
ioc.run();
} catch (std::exception const& e) {

View File

@@ -91,10 +91,7 @@ int main()
co_spawn(ioc, listener(acc, db, recv), net::detached);
net::signal_set signals(ioc.get_executor(), SIGINT, SIGTERM);
signals.async_wait([=] (auto, int) {
db->send(command::quit);
acc->cancel();
});
signals.async_wait([&] (auto, int) { ioc.stop(); });
ioc.run();
} catch (std::exception const& e) {