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

Progresses with docs.

This commit is contained in:
Marcelo Zimbres
2022-03-12 11:08:23 +01:00
parent 1218b2ef01
commit 11b697c572
8 changed files with 177 additions and 40 deletions

View File

@@ -25,8 +25,8 @@
\section Overview
Aedis is a low-level redis client library that provides simple and
efficient communication with a Redis server. It is built on top of
Boost.Asio and some of its distinctive features are
efficient communication with a Redis server (see https://redis.io/).
It is built on top of Boost.Asio and some of its distinctive features are
1. Support for the latest version of the Redis communication protocol RESP3.
2. Asynchronous interface that handles servers pushs optimally.
@@ -57,53 +57,134 @@
implementation of the \c receiver class, to make that simpler,
Aedis provides a base receiver class that abstracts most of the
complexity away from the user. In a typical implementation the
following two function will have to be implemented
following functions will be overriden by the user
@code
class myreceiver : receiver<response_type> {
public:
void on_read_impl(command cmd) override { ... }
void on_push_impl() override { ... }
void on_read_impl(command cmd) override
{
// ...
}
void on_write_impl(std::size_t n) override
{
// ...
}
void on_push_impl() override
{
// ...
}
};
@endcode
Sending commands to Redis is also simple, for example
The \c client object (\c db above) can be passed
around in the program to send commands to Redis, 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);
void foo(client<net::ip::tcp::socket>& db)
{
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");
...
}
@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 section we have seen the general structure of an Aedis
program. Here we will go in depth.
Now let us see how to make requests and receive responses with more detail.
\subsection Requests
A request is composed of one or more commands (in Redis
Request are composed of one or more commands (in Redis
documentation they are called pipeline, see
https://redis.io/topics/pipelining). The individual commands in a
request assume different forms, for example
request assume many different forms
1. With key: \c set, \c get, \c expire etc.
2. Without key: \c hello, \c quit etc.
3. Ranges with a key: \c rpush, \c hgtall etc.
4. Ranges without a key: \c subscribe, etc.
5. etc.
To account for all these possibilities, the \c client class offer
some member functions, for example
@code
// Some data to send to Redis.
std::string value = "some value";
std::list<std::string> list {"channel1", "channel2", "channel3"};
std::map<std::string, mystruct> map
{ {"key1", "value1"}
, {"key2", "value2"}
, {"key3", "value3"}};
// No key or arguments.
db.>send(command::quit);
db.>send(command::subscribe, "channel1", "channel2");
db_->send_range(command::hset, "key", std::cbegin(map), std::cend(map));
// With key and arguments.
db.>send(command::set, "key", value, "EX", "2");
// Sends a container, no key
db.>send_range(command::subscribe, list);
// As above but an iterator range.
db->send_range2(command::subscribe, std::cbegin(list), std::cend(list));
// Sends a container, with key.
db->send_range(command::hset, "key", map);
// As above but as iterator range.
db->send_range2(command::hset, "key", std::cbegin(map), std::cend(map));
@endcode
The \c send functions above adds commands to the output queue and
send only if there is no pending response of a previously sent
command. Users can also easily send their own data types to Redis
by defining a to_string function, for example
@code
struct mystruct {
int a;
int b;
};
std::string to_string(mystruct const& obj)
{
// Convert to string
}
std::map<std::string, mystruct> map
{ {"key1", {1, 2}}
, {"key2", {3, 4}}
, {"key3", {5, 6}}};
db.send_range(command::hset, "serialization-hset-key", map);
@endcode
See https://redis.io/commands/hset for \c hset documentation.
\subsection Responses
The Redis protocol RESP3 defines two types of data, they are.
1. Simple data types: simple string, simple error, \c blob string, \c blob error, number, double, etc.
2. Aggregates: array, push, set, map, etc.
Most of these types can be translated into C++ containers and bilt-in types, for example
1. \c std::string: simple and blob string and error.
2. `long long int`: number
3. \c double: double.
https://redis.io/topics/data-types.
\subsubsection Optional
\subsubsection Serializaiton
\subsubsection Transactions
\subsubsection Serializaiton
See also https://redis.io/topics/transactions.

View File

@@ -12,7 +12,7 @@
#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
// TODO: What to do if users send a discard command not contained in a
// transaction. The client object will try to pop the queue until a
// multi is found.
@@ -203,8 +203,10 @@ public:
timer_.cancel_one();
}
/** \brief Sends and iterator range (overload with key).
*/
template <class Key, class ForwardIterator>
void send_range(command cmd, Key const& key, ForwardIterator begin, ForwardIterator end)
void send_range2(command cmd, Key const& key, ForwardIterator begin, ForwardIterator end)
{
if (begin == end)
return;
@@ -227,6 +229,54 @@ public:
timer_.cancel_one();
}
/** \brief Sends and iterator range (overload without key).
*/
template <class ForwardIterator>
void send_range2(command cmd, ForwardIterator begin, ForwardIterator end)
{
if (begin == end)
return;
auto const can_write = prepare_next();
auto sr = redis::make_serializer(requests_);
auto const before = std::size(requests_);
sr.push_range(cmd, begin, end);
auto const after = std::size(requests_);
assert(after - before != 0);
req_info_.front().size += after - before;;
if (!has_push_response(cmd)) {
commands_.push_back(cmd);
++req_info_.front().cmds;
}
if (can_write)
timer_.cancel_one();
}
/** \brief Sends a range.
*/
template <class Key, class Range>
void send_range(command cmd, Key const& key, Range const& range)
{
using std::begin;
using std::end;
send_range2(cmd, key, begin(range), end(range));
}
/** \brief Sends a range.
*/
template <class Range>
void send_range(command cmd, Range const& range)
{
using std::begin;
using std::end;
send_range2(cmd, begin(range), end(range));
}
/** \brief Starts communication with the Redis server asynchronously.
*/
template <
class Receiver,
class CompletionToken = default_completion_token_type

View File

@@ -11,6 +11,14 @@
#include <string_view>
#include <utility>
// TODO: The signature from to_string should be changed from
//
// std::string to_string(T const&)
// to
//
// void to_string(std::string& s, T const&)
//
namespace aedis {
namespace resp3 {
namespace detail {
@@ -63,8 +71,8 @@ void add_bulk(Storage& to, T const& data, typename std::enable_if<needs_to_strin
add_bulk(to, s);
}
// Consider adding overload for std::tuple.
// Overload for pairs.
// TODO: Overload for tuples.
template <class Storage, class T1, class T2>
void add_bulk(Storage& to, std::pair<T1, T2> const& pair)
{

View File

@@ -24,9 +24,7 @@ div.contents {
padding: 15px;
}
/*
code
{
background-color:#EFD25E;
background-color:#f0e9ce;
}
*/

View File

@@ -54,9 +54,9 @@ private:
{"one", "two", "three", "four"};
// Sends the stl containers.
db_->send_range(command::hset, "hset-key", std::cbegin(map), std::cend(map));
db_->send_range(command::rpush, "rpush-key", std::cbegin(vec), std::cend(vec));
db_->send_range(command::sadd, "sadd-key", std::cbegin(set), std::cend(set));
db_->send_range(command::hset, "hset-key", map);
db_->send_range(command::rpush, "rpush-key", vec);
db_->send_range(command::sadd, "sadd-key", set);
// Retrieves the containers.
db_->send(command::hgetall, "hset-key");

View File

@@ -31,8 +31,8 @@ private:
case command::hello:
db_->send(command::ping, "O rato roeu a roupa do rei de Roma");
db_->send(command::incr, "intro-counter");
db_->send(command::set, "intro-set-key", "Três pratos de trigo para três tigres");
db_->send(command::get, "intro-set-key");
db_->send(command::set, "intro-key", "Três pratos de trigo para três tigres");
db_->send(command::get, "intro-key");
db_->send(command::quit);
break;

View File

@@ -104,9 +104,9 @@ private:
// Sends
db_->send(command::set, "serialization-var-key", var, "EX", "2");
db_->send_range(command::hset, "serialization-hset-key", std::cbegin(map), std::cend(map));
db_->send_range(command::rpush, "serialization-rpush-key", std::cbegin(vec), std::cend(vec));
db_->send_range(command::sadd, "serialization-sadd-key", std::cbegin(set), std::cend(set));
db_->send_range(command::hset, "serialization-hset-key", map);
db_->send_range(command::rpush, "serialization-rpush-key", vec);
db_->send_range(command::sadd, "serialization-sadd-key", set);
// Retrieves
db_->send(command::get, "serialization-var-key");

View File

@@ -70,9 +70,9 @@ private:
{"one", "two", "three", "four"};
// Sends the stl containers.
db_->send_range(command::hset, "hset-key", std::cbegin(map), std::cend(map));
db_->send_range(command::rpush, "rpush-key", std::cbegin(vec), std::cend(vec));
db_->send_range(command::sadd, "sadd-key", std::cbegin(set), std::cend(set));
db_->send_range(command::hset, "hset-key", map);
db_->send_range(command::rpush, "rpush-key", vec);
db_->send_range(command::sadd, "sadd-key", set);
//_ Retrieves the containers.
db_->send(command::hgetall, "hset-key");