The FreeRADIUS server
$Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
|
conf functions for interacting with Redis cluster via Hiredis. More...
#include <freeradius-devel/redis/base.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/value.h>
Go to the source code of this file.
Functions | |
fr_redis_rcode_t | fr_redis_command_status (fr_redis_conn_t *conn, redisReply *reply) |
Check the reply for errors. More... | |
fr_redis_rcode_t | fr_redis_get_version (char *out, size_t out_len, fr_redis_conn_t *conn) |
Get the version of Redis running on the remote server. More... | |
fr_redis_rcode_t | fr_redis_pipeline_result (unsigned int *pipelined, fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn) |
Simplifies handling of pipelined commands with Redis cluster. More... | |
void | fr_redis_reply_print (fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx) |
Print the response data in a useful treelike form. More... | |
int | fr_redis_reply_to_map (TALLOC_CTX *ctx, map_list_t *out, request_t *request, redisReply *key, redisReply *op, redisReply *value) |
Convert a pair of redis reply objects to a map. More... | |
int | fr_redis_reply_to_value_box (TALLOC_CTX *ctx, fr_value_box_t *out, redisReply *reply, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, bool box_error, bool shallow) |
Convert a string or integer type to fr_value_box_t of specified type. More... | |
int | fr_redis_tuple_from_map (TALLOC_CTX *pool, char const *out[], size_t out_len[], map_t *map) |
Add a single map pair to an existing command string as three elements. More... | |
uint32_t | fr_redis_version_num (char const *version) |
Convert version string into a 32bit unsigned integer for comparisons. More... | |
void | fr_redis_version_print (void) |
Print the version of libhiredis the server was built against. More... | |
Variables | |
fr_table_num_sorted_t const | redis_rcodes [] |
size_t | redis_rcodes_len = NUM_ELEMENTS(redis_rcodes) |
fr_table_num_sorted_t const | redis_reply_types [] |
size_t | redis_reply_types_len = NUM_ELEMENTS(redis_reply_types) |
conf functions for interacting with Redis cluster via Hiredis.
Common functions for interacting with Redis via hiredis.
Read and understand this http://redis.io/topics/cluster-spec first, else the text below will not be useful.
The two functions used at runtime to issue commands are fr_redis_cluster_state_init and fr_redis_cluster_state_next.
fr_redis_cluster_state_init initialises the structure we use to track which node we're communicating with, and uses a key (string) to determine which node we should try and contact first.
fr_redis_cluster_state_next examines the result of the last command, and either gets a new connection, or errors out.
In both cases the connection should not be released by the caller, only by fr_redis_cluster_state_next.
Below is the sequence of calls required to use the cluster:
1. During initialization allocate a cluster configuration structure with #fr_redis_cluster_alloc. This holds the cluster configuration and state. 2. Declare a #fr_redis_cluster_state_t in the function that needs to issue commands against the cluster. 3. Call #fr_redis_cluster_state_init with relevant arguments including a pointer to the #fr_redis_cluster_state_t struct, and a key/key_len used for initial lookup. For most commands the key is the value of the second argument. #fr_redis_cluster_state_init will then and reserve/pass back a connection for the pool associated with the node associated with the key. 4. Use the connection that was passed back, to issue a Redis command against. 5. Use #fr_redis_command_status to translate the result of the command into a #fr_redis_rcode_t value. 6. Call #fr_redis_cluster_state_next with relevant arguments including a pointer to the #fr_redis_cluster_state_t struct and the #fr_redis_rcode_t value for the last command. 7. If #fr_redis_cluster_state_next returns 0, repeat steps 4-7. Otherwise stop and analyse the return value.
See fr_redis_cluster_state_init for example code.
This code maintains a series structures for efficient lookup and lockless operations.
The important ones are:
Each fr_redis_cluster_node_t contains a master ID, and an array of slave IDs. The IDs are array indexes in the fr_redis_cluster_t.node array. We use 8bit unsigned integers instead of pointers to save space. Using pointers, the node[] array would need 784K, using IDs it uses 112K. Still not light on memory, but a bit more acceptable. Currently the key_slot array is shadowed by key_slot_pending, used to stage new key_slot mappings. This doubles the memory used. We may want to consider allocating key_slot_pending only during remappings and freeing it after.
On startup, and during cluster operation, a remap may be performed. A remap involves the following steps:
cluster_map_get and cluster_map_apply, perform the operations described above. The get function, issues the 'cluster slots' command and performs validation, the apply function processes and applies the map.
Failing to apply a map is not a fatal error at runtime, and is only fatal on startup if pool.start > 0.
The cluster client can continue to operate, albeit inefficiently, with a stale cluster map by following '-ASK' and '-MOVE' redirects.
Remaps are limited to one per second. If any operation sets the remap_needed flag, or attempts a remap directly, the remap may be skipped if one occurred recently.
The code treats '-ASK' (temporary redirect) and '-MOVE' (permanent redirect) responses similarly. If the node is known, then a connection is reserved from its pool, if the node is not known, a new pool is established, and a connection reserved.
The difference between '-ASK' and '-MOVE' is that '-MOVE' attempts a cluster remap before following the redirect.
The data from '-MOVE' responses, is not used to alter the cluster map. That is only done on successful remap.
If the cluster is in a state of flux, a node may return '-TRYAGAIN' to indicated that we should attempt the operation again. The cluster spec says we should attempt the operation after some time. This time is configurable.
Definition in file redis.c.
fr_redis_rcode_t fr_redis_command_status | ( | fr_redis_conn_t * | conn, |
redisReply * | reply | ||
) |
Check the reply for errors.
[in] | conn | used to issue the command. |
[in] | reply | to process. |
Definition at line 71 of file redis.c.
fr_redis_rcode_t fr_redis_get_version | ( | char * | out, |
size_t | out_len, | ||
fr_redis_conn_t * | conn | ||
) |
Get the version of Redis running on the remote server.
This can be useful for some modules, as it allows adaptive behaviour, or early termination.
[out] | out | Where to write the version string. |
[in] | out_len | Length of the version string buffer. |
[in] | conn | Used to query the version string. |
Definition at line 638 of file redis.c.
fr_redis_rcode_t fr_redis_pipeline_result | ( | unsigned int * | pipelined, |
fr_redis_rcode_t * | rcode, | ||
redisReply * | out[], | ||
size_t | out_len, | ||
fr_redis_conn_t * | conn | ||
) |
Simplifies handling of pipelined commands with Redis cluster.
Retrieve all available pipelined responses, and write them to the array.
On encountering an error, all previously retrieved responses are freed, and the reply containing the error is written to the first element of out. All responses after the error are also freed.
If the number of responses != pipelined, that's also an error, a very serious one, in libhiredis or Redis. We can't really do much here apart from error out.
[out] | pipelined | Number of pipelined commands we sent to the server. |
[out] | rcode | Status of the first errored response, or REDIS_RCODE_SUCCESS if all responses were processed. |
[out] | out | Where to write the replies from pipelined commands. Will contain exactly 1 element on error WHICH MUST BE FREED, else the number passed in pipelined. |
[in] | out_len | number of elements in out. |
[in] | conn | the pipelined commands were issued on. |
Definition at line 535 of file redis.c.
void fr_redis_reply_print | ( | fr_log_lvl_t | lvl, |
redisReply * | reply, | ||
request_t * | request, | ||
int | idx | ||
) |
int fr_redis_reply_to_map | ( | TALLOC_CTX * | ctx, |
map_list_t * | out, | ||
request_t * | request, | ||
redisReply * | key, | ||
redisReply * | op, | ||
redisReply * | value | ||
) |
Convert a pair of redis reply objects to a map.
The maps can then be applied using map_to_request.
[in,out] | ctx | to allocate maps in. |
[out] | out | Where to write the head of the new maps list. |
[in] | request | The current request. |
[in] | key | to process. |
[in] | op | to process. |
[in] | value | to process. |
Definition at line 365 of file redis.c.
int fr_redis_reply_to_value_box | ( | TALLOC_CTX * | ctx, |
fr_value_box_t * | out, | ||
redisReply * | reply, | ||
fr_type_t | dst_type, | ||
fr_dict_attr_t const * | dst_enumv, | ||
bool | box_error, | ||
bool | shallow | ||
) |
Convert a string or integer type to fr_value_box_t of specified type.
Will work with REDIS_REPLY_STRING (which is converted to FR_TYPE_STRING then cast to dst_type), or REDIS_REPLY_INTEGER (which is converted to FR_TYPE_UINT64, then cast to dst_type).
[in,out] | ctx | to allocate any buffers in. |
[out] | out | Where to write the cast type. |
[in] | reply | to process. |
[in] | dst_type | to convert to. May be FR_TYPE_VOID to infer type. |
[in] | dst_enumv | Used to convert string types to integers for attribute with enumerated values. |
[in] | box_error | If true then REDIS_REPLY_ERROR will be copied to a box, otherwise we'll return and error with the contents of the error available on the thread local error stack. |
[in] | shallow | If true, we shallow copy strings. |
Definition at line 206 of file redis.c.
int fr_redis_tuple_from_map | ( | TALLOC_CTX * | pool, |
char const * | out[], | ||
size_t | out_len[], | ||
map_t * | map | ||
) |
Add a single map pair to an existing command string as three elements.
pool | to allocate any buffers in. |
out | Where to write pointers to the member of the tuple. Unused elements should be a multiple of three, and it should have at least three unused elements. |
out_len | Where to write the size of the data pointed to by the equivalent index in the out array. |
map | to convert. |
Definition at line 459 of file redis.c.
uint32_t fr_redis_version_num | ( | char const * | version | ) |
void fr_redis_version_print | ( | void | ) |
fr_table_num_sorted_t const redis_rcodes[] |
size_t redis_rcodes_len = NUM_ELEMENTS(redis_rcodes) |
fr_table_num_sorted_t const redis_reply_types[] |
size_t redis_reply_types_len = NUM_ELEMENTS(redis_reply_types) |