diff options
| author | byte2016 <[email protected]> | 2018-06-12 19:40:56 +0800 |
|---|---|---|
| committer | byte2016 <[email protected]> | 2018-06-12 19:40:56 +0800 |
| commit | c99fe40d6c3fff9bd87702c1faf2048bfdc4a5b5 (patch) | |
| tree | b8c53d5ccc86cebd10c44bf1d94ed8384c7f8f97 /README.md | |
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc69f55 --- /dev/null +++ b/README.md @@ -0,0 +1,281 @@ + +# HIREDIS-VIP + +Hiredis-vip is a C client library for the [Redis](http://redis.io/) database. + +Hiredis-vip supported redis cluster. + +Hiredis-vip fully contained and based on [Hiredis](https://github.com/redis/hiredis) . + +## CLUSTER SUPPORT + +### FEATURES: + +* **`SUPPORT REDIS CLUSTER`**: + * Connect to redis cluster and run commands. + +* **`SUPPORT MULTI-KEY COMMAND`**: + * Support `MSET`, `MGET` and `DEL`. + +* **`SUPPORT PIPELING`**: + * Support redis pipeline and can contain multi-key command like above. + +* **`SUPPORT Asynchronous API`**: + * User can run commands with asynchronous mode. + +### CLUSTER API: + +```c +redisClusterContext *redisClusterConnect(const char *addrs, int flags); +redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, const struct timeval tv, int flags); +redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags); +void redisClusterFree(redisClusterContext *cc); +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); +void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len); +void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap); +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); +void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); +redisContext *ctx_get_by_node(struct cluster_node *node, const struct timeval *timeout, int flags); +int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, int len); +int redisClustervAppendCommand(redisClusterContext *cc, const char *format, va_list ap); +int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); +int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); +int redisClusterGetReply(redisClusterContext *cc, void **reply); +void redisCLusterReset(redisClusterContext *cc); + +redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags); +int redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn); +int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); +int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, char *cmd, int len); +int redisClustervAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap); +int redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, ...); +int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); + +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); +void redisClusterAsyncFree(redisClusterAsyncContext *acc); +``` + +## Quick usage + +If you want used but not read the follow, please reference the examples: +https://github.com/vipshop/hiredis-vip/wiki + +## Cluster synchronous API + +To consume the synchronous API, there are only a few function calls that need to be introduced: + +```c +redisClusterContext *redisClusterConnect(const char *addrs, int flags); +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); +void redisClusterFree(redisClusterContext *cc); +``` + +### Cluster connecting + +The function `redisClusterConnect` is used to create a so-called `redisClusterContext`. The +context is where Hiredis-vip Cluster holds state for connections. The `redisClusterContext` +struct has an integer `err` field that is non-zero when the connection is in +an error state. The field `errstr` will contain a string with a description of +the error. +After trying to connect to Redis using `redisClusterContext` you should +check the `err` field to see if establishing the connection was successful: +```c +redisClusterContext *cc = redisClusterConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); +if (cc != NULL && cc->err) { + printf("Error: %s\n", cc->errstr); + // handle error +} +``` + +### Cluster sending commands + +The next that will be introduced is `redisClusterCommand`. +This function takes a format similar to printf. In the simplest form, +it is used like this: +```c +reply = redisClusterCommand(clustercontext, "SET foo bar"); +``` + +The specifier `%s` interpolates a string in the command, and uses `strlen` to +determine the length of the string: +```c +reply = redisClusterCommand(clustercontext, "SET foo %s", value); +``` +Internally, Hiredis-vip splits the command in different arguments and will +convert it to the protocol used to communicate with Redis. +One or more spaces separates arguments, so you can use the specifiers +anywhere in an argument: +```c +reply = redisClusterCommand(clustercontext, "SET key:%s %s", myid, value); +``` + +### Cluster multi-key commands + +Hiredis-vip supports mget/mset/del multi-key commands. +Those multi-key commands is highly effective. +Millions of keys in one mget command just used several seconds. + +Example: +```c +reply = redisClusterCommand(clustercontext, "mget %s %s %s %s", key1, key2, key3, key4); +``` + +### Cluster cleaning up + +To disconnect and free the context the following function can be used: +```c +void redisClusterFree(redisClusterContext *cc); +``` +This function immediately closes the socket and then frees the allocations done in +creating the context. + +### Cluster pipelining + +The function `redisClusterGetReply` is exported as part of the Hiredis API and can be used +when a reply is expected on the socket. To pipeline commands, the only things that needs +to be done is filling up the output buffer. For this cause, two commands can be used that +are identical to the `redisClusterCommand` family, apart from not returning a reply: +```c +int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); +int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv); +``` +After calling either function one or more times, `redisClusterGetReply` can be used to receive the +subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where +the latter means an error occurred while reading a reply. Just as with the other commands, +the `err` field in the context can be used to find out what the cause of this error is. +```c +void redisCLusterReset(redisClusterContext *cc); +``` +Warning: You must call `redisCLusterReset` function after one pipelining anyway. + +The following examples shows a simple cluster pipeline: +```c +redisReply *reply; +redisClusterAppendCommand(clusterContext,"SET foo bar"); +redisClusterAppendCommand(clusterContext,"GET foo"); +redisClusterGetReply(clusterContext,&reply); // reply for SET +freeReplyObject(reply); +redisClusterGetReply(clusterContext,&reply); // reply for GET +freeReplyObject(reply); +redisCLusterReset(clusterContext); +``` +This API can also be used to implement a blocking subscriber: +```c +reply = redisClusterCommand(clusterContext,"SUBSCRIBE foo"); +freeReplyObject(reply); +while(redisClusterGetReply(clusterContext,&reply) == REDIS_OK) { + // consume message + freeReplyObject(reply); +} +redisCLusterReset(clusterContext); +``` + +## Cluster asynchronous API + +Hiredis-vip comes with an cluster asynchronous API that works easily with any event library. +Now we just support and test for libevent and redis ae, if you need for other event libraries, +please contact with us, and we will support it quickly. + +### Connecting + +The function `redisAsyncConnect` can be used to establish a non-blocking connection to +Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field +should be checked after creation to see if there were errors creating the connection. +Because the connection that will be created is non-blocking, the kernel is not able to +instantly return if the specified host and port is able to accept a connection. +```c +redisClusterAsyncContext *acc = redisClusterAsyncConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); +if (acc->err) { + printf("Error: %s\n", acc->errstr); + // handle error +} +``` + +The cluster asynchronous context can hold a disconnect callback function that is called when the +connection is disconnected (either because of an error or per user request). This function should +have the following prototype: +```c +void(const redisAsyncContext *c, int status); +``` +On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the +user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err` +field in the context can be accessed to find out the cause of the error. + +You not need to reconnect in the disconnect callback, hiredis-vip will reconnect this connection itself +when commands come to this redis node. + +Setting the disconnect callback can only be done once per context. For subsequent calls it will +return `REDIS_ERR`. The function to set the disconnect callback has the following prototype: +```c +int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); +``` +### Sending commands and their callbacks + +In an cluster asynchronous context, commands are automatically pipelined due to the nature of an event loop. +Therefore, unlike the cluster synchronous API, there is only a single way to send commands. +Because commands are sent to Redis cluster asynchronously, issuing a command requires a callback function +that is called when the reply is received. Reply callbacks should have the following prototype: +```c +void(redisClusterAsyncContext *acc, void *reply, void *privdata); +``` +The `privdata` argument can be used to curry arbitrary data to the callback from the point where +the command is initially queued for execution. + +The functions that can be used to issue commands in an asynchronous context are: +```c +int redisClusterAsyncCommand( + redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, + void *privdata, const char *format, ...); +``` +This function work like their blocking counterparts. The return value is `REDIS_OK` when the command +was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection +is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is +returned on calls to the `redisClusterAsyncCommand` family. + +If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback +for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only +valid for the duration of the callback. + +All pending callbacks are called with a `NULL` reply when the context encountered an error. + +### Disconnecting + +An cluster asynchronous connection can be terminated using: +```c +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); +``` +When this function is called, the connection is **not** immediately terminated. Instead, new +commands are no longer accepted and the connection is only terminated when all pending commands +have been written to the socket, their respective replies have been read and their respective +callbacks have been executed. After this, the disconnection callback is executed with the +`REDIS_OK` status and the context object is freed. + +### Hooking it up to event library *X* + +There are a few hooks that need to be set on the cluster context object after it is created. +See the `adapters/` directory for bindings to *ae* and *libevent*. + +## Package + +If you only want get library, you can "yum install hiredis-vip" or "apt-get install hiredis-vip" instead of building from source code. + +If you used hiredis-vip in your project, you can install "hiredis-vip-devel" package for development. + +Before install the package, execute the follow command first: + +**deb package** : `curl -s https://packagecloud.io/install/repositories/deep/packages/script.deb.sh | sudo bash` + +**rpm package** : `curl -s https://packagecloud.io/install/repositories/deep/packages/script.rpm.sh | sudo bash` + +You can also download the packages from "https://packagecloud.io/deep/packages" and install by yourself. + +If you want to support other OS packages, please contact with me. + +## AUTHORS + +Hiredis-vip was maintained and used at vipshop(https://github.com/vipshop). +The redis client library part in hiredis-vip is same as hiredis(https://github.com/redis/hiredis). +The redis cluster client library part in hiredis-vip is written by deep(https://github.com/deep011). +Hiredis-vip is released under the BSD license. |
