parent
8f60ee6532
commit
a1f6ce0194
166
README.md
166
README.md
@ -31,9 +31,11 @@ the stateless 0.0.1 that only has a file descriptor to work with.
|
|||||||
|
|
||||||
To consume the synchronous API, there are only a few function calls that need to be introduced:
|
To consume the synchronous API, there are only a few function calls that need to be introduced:
|
||||||
|
|
||||||
redisContext *redisConnect(const char *ip, int port);
|
```c
|
||||||
void *redisCommand(redisContext *c, const char *format, ...);
|
redisContext *redisConnect(const char *ip, int port);
|
||||||
void freeReplyObject(void *reply);
|
void *redisCommand(redisContext *c, const char *format, ...);
|
||||||
|
void freeReplyObject(void *reply);
|
||||||
|
```
|
||||||
|
|
||||||
### Connecting
|
### Connecting
|
||||||
|
|
||||||
@ -44,38 +46,41 @@ an error state. The field `errstr` will contain a string with a description of
|
|||||||
the error. More information on errors can be found in the **Errors** section.
|
the error. More information on errors can be found in the **Errors** section.
|
||||||
After trying to connect to Redis using `redisConnect` you should
|
After trying to connect to Redis using `redisConnect` you should
|
||||||
check the `err` field to see if establishing the connection was successful:
|
check the `err` field to see if establishing the connection was successful:
|
||||||
|
```c
|
||||||
redisContext *c = redisConnect("127.0.0.1", 6379);
|
redisContext *c = redisConnect("127.0.0.1", 6379);
|
||||||
if (c != NULL && c->err) {
|
if (c != NULL && c->err) {
|
||||||
printf("Error: %s\n", c->errstr);
|
printf("Error: %s\n", c->errstr);
|
||||||
// handle error
|
// handle error
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Sending commands
|
### Sending commands
|
||||||
|
|
||||||
There are several ways to issue commands to Redis. The first that will be introduced is
|
There are several ways to issue commands to Redis. The first that will be introduced is
|
||||||
`redisCommand`. This function takes a format similar to printf. In the simplest form,
|
`redisCommand`. This function takes a format similar to printf. In the simplest form,
|
||||||
it is used like this:
|
it is used like this:
|
||||||
|
```c
|
||||||
reply = redisCommand(context, "SET foo bar");
|
reply = redisCommand(context, "SET foo bar");
|
||||||
|
```
|
||||||
|
|
||||||
The specifier `%s` interpolates a string in the command, and uses `strlen` to
|
The specifier `%s` interpolates a string in the command, and uses `strlen` to
|
||||||
determine the length of the string:
|
determine the length of the string:
|
||||||
|
```c
|
||||||
reply = redisCommand(context, "SET foo %s", value);
|
reply = redisCommand(context, "SET foo %s", value);
|
||||||
|
```
|
||||||
When you need to pass binary safe strings in a command, the `%b` specifier can be
|
When you need to pass binary safe strings in a command, the `%b` specifier can be
|
||||||
used. Together with a pointer to the string, it requires a `size_t` length argument
|
used. Together with a pointer to the string, it requires a `size_t` length argument
|
||||||
of the string:
|
of the string:
|
||||||
|
```c
|
||||||
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
|
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
|
||||||
|
```
|
||||||
Internally, Hiredis splits the command in different arguments and will
|
Internally, Hiredis splits the command in different arguments and will
|
||||||
convert it to the protocol used to communicate with Redis.
|
convert it to the protocol used to communicate with Redis.
|
||||||
One or more spaces separates arguments, so you can use the specifiers
|
One or more spaces separates arguments, so you can use the specifiers
|
||||||
anywhere in an argument:
|
anywhere in an argument:
|
||||||
|
```c
|
||||||
reply = redisCommand(context, "SET key:%s %s", myid, value);
|
reply = redisCommand(context, "SET key:%s %s", myid, value);
|
||||||
|
```
|
||||||
|
|
||||||
### Using replies
|
### Using replies
|
||||||
|
|
||||||
@ -127,9 +132,9 @@ keep an eye on the changelog when upgrading (see issue #39).
|
|||||||
### Cleaning up
|
### Cleaning up
|
||||||
|
|
||||||
To disconnect and free the context the following function can be used:
|
To disconnect and free the context the following function can be used:
|
||||||
|
```c
|
||||||
void redisFree(redisContext *c);
|
void redisFree(redisContext *c);
|
||||||
|
```
|
||||||
This function immediately closes the socket and then free's the allocations done in
|
This function immediately closes the socket and then free's the allocations done in
|
||||||
creating the context.
|
creating the context.
|
||||||
|
|
||||||
@ -137,9 +142,9 @@ creating the context.
|
|||||||
|
|
||||||
Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
|
Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
|
||||||
It has the following prototype:
|
It has the following prototype:
|
||||||
|
```c
|
||||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||||
|
```
|
||||||
It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
|
It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
|
||||||
arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
|
arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
|
||||||
use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
|
use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
|
||||||
@ -169,10 +174,10 @@ The function `redisGetReply` is exported as part of the Hiredis API and can be u
|
|||||||
is expected on the socket. To pipeline commands, the only things that needs to be done is
|
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
|
filling up the output buffer. For this cause, two commands can be used that are identical
|
||||||
to the `redisCommand` family, apart from not returning a reply:
|
to the `redisCommand` family, apart from not returning a reply:
|
||||||
|
```c
|
||||||
void redisAppendCommand(redisContext *c, const char *format, ...);
|
void redisAppendCommand(redisContext *c, const char *format, ...);
|
||||||
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||||
|
```
|
||||||
After calling either function one or more times, `redisGetReply` can be used to receive the
|
After calling either function one or more times, `redisGetReply` can be used to receive the
|
||||||
subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
|
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 latter means an error occurred while reading a reply. Just as with the other commands,
|
||||||
@ -180,24 +185,24 @@ the `err` field in the context can be used to find out what the cause of this er
|
|||||||
|
|
||||||
The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
|
The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
|
||||||
a single call to `read(2)`):
|
a single call to `read(2)`):
|
||||||
|
```c
|
||||||
redisReply *reply;
|
redisReply *reply;
|
||||||
redisAppendCommand(context,"SET foo bar");
|
redisAppendCommand(context,"SET foo bar");
|
||||||
redisAppendCommand(context,"GET foo");
|
redisAppendCommand(context,"GET foo");
|
||||||
redisGetReply(context,&reply); // reply for SET
|
redisGetReply(context,&reply); // reply for SET
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
redisGetReply(context,&reply); // reply for GET
|
redisGetReply(context,&reply); // reply for GET
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
|
```
|
||||||
This API can also be used to implement a blocking subscriber:
|
This API can also be used to implement a blocking subscriber:
|
||||||
|
```c
|
||||||
reply = redisCommand(context,"SUBSCRIBE foo");
|
reply = redisCommand(context,"SUBSCRIBE foo");
|
||||||
|
freeReplyObject(reply);
|
||||||
|
while(redisGetReply(context,&reply) == REDIS_OK) {
|
||||||
|
// consume message
|
||||||
freeReplyObject(reply);
|
freeReplyObject(reply);
|
||||||
while(redisGetReply(context,&reply) == REDIS_OK) {
|
}
|
||||||
// consume message
|
```
|
||||||
freeReplyObject(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
### Errors
|
### Errors
|
||||||
|
|
||||||
When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
|
When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
|
||||||
@ -236,19 +241,20 @@ Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The
|
|||||||
should be checked after creation to see if there were errors creating the connection.
|
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
|
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.
|
instantly return if the specified host and port is able to accept a connection.
|
||||||
|
```c
|
||||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||||
if (c->err) {
|
if (c->err) {
|
||||||
printf("Error: %s\n", c->errstr);
|
printf("Error: %s\n", c->errstr);
|
||||||
// handle error
|
// handle error
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The asynchronous context can hold a disconnect callback function that is called when the
|
The 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
|
connection is disconnected (either because of an error or per user request). This function should
|
||||||
have the following prototype:
|
have the following prototype:
|
||||||
|
```c
|
||||||
void(const redisAsyncContext *c, int status);
|
void(const redisAsyncContext *c, int status);
|
||||||
|
```
|
||||||
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
|
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`
|
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.
|
field in the context can be accessed to find out the cause of the error.
|
||||||
@ -258,30 +264,30 @@ the disconnect callback is a good point to do so.
|
|||||||
|
|
||||||
Setting the disconnect callback can only be done once per context. For subsequent calls it will
|
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:
|
return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
|
||||||
|
```c
|
||||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||||
|
```
|
||||||
### Sending commands and their callbacks
|
### Sending commands and their callbacks
|
||||||
|
|
||||||
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
||||||
Therefore, unlike the synchronous API, there is only a single way to send commands.
|
Therefore, unlike the synchronous API, there is only a single way to send commands.
|
||||||
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
|
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
|
||||||
that is called when the reply is received. Reply callbacks should have the following prototype:
|
that is called when the reply is received. Reply callbacks should have the following prototype:
|
||||||
|
```c
|
||||||
void(redisAsyncContext *c, void *reply, void *privdata);
|
void(redisAsyncContext *c, void *reply, void *privdata);
|
||||||
|
```
|
||||||
The `privdata` argument can be used to curry arbitrary data to the callback from the point where
|
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 command is initially queued for execution.
|
||||||
|
|
||||||
The functions that can be used to issue commands in an asynchronous context are:
|
The functions that can be used to issue commands in an asynchronous context are:
|
||||||
|
```c
|
||||||
int redisAsyncCommand(
|
int redisAsyncCommand(
|
||||||
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
||||||
const char *format, ...);
|
const char *format, ...);
|
||||||
int redisAsyncCommandArgv(
|
int redisAsyncCommandArgv(
|
||||||
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
||||||
int argc, const char **argv, const size_t *argvlen);
|
int argc, const char **argv, const size_t *argvlen);
|
||||||
|
```
|
||||||
Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
|
Both functions 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
|
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
|
is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
|
||||||
@ -296,9 +302,9 @@ All pending callbacks are called with a `NULL` reply when the context encountere
|
|||||||
### Disconnecting
|
### Disconnecting
|
||||||
|
|
||||||
An asynchronous connection can be terminated using:
|
An asynchronous connection can be terminated using:
|
||||||
|
```c
|
||||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||||
|
```
|
||||||
When this function is called, the connection is **not** immediately terminated. Instead, new
|
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
|
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
|
have been written to the socket, their respective replies have been read and their respective
|
||||||
@ -316,12 +322,12 @@ Hiredis comes with a reply parsing API that makes it easy for writing higher
|
|||||||
level language bindings.
|
level language bindings.
|
||||||
|
|
||||||
The reply parsing API consists of the following functions:
|
The reply parsing API consists of the following functions:
|
||||||
|
```c
|
||||||
redisReader *redisReaderCreate(void);
|
redisReader *redisReaderCreate(void);
|
||||||
void redisReaderFree(redisReader *reader);
|
void redisReaderFree(redisReader *reader);
|
||||||
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
|
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
|
||||||
int redisReaderGetReply(redisReader *reader, void **reply);
|
int redisReaderGetReply(redisReader *reader, void **reply);
|
||||||
|
```
|
||||||
The same set of functions are used internally by hiredis when creating a
|
The same set of functions are used internally by hiredis when creating a
|
||||||
normal Redis context, the above API just exposes it to the user for a direct
|
normal Redis context, the above API just exposes it to the user for a direct
|
||||||
usage.
|
usage.
|
||||||
@ -371,9 +377,9 @@ value for an idle buffer, so the buffer will never get freed.
|
|||||||
|
|
||||||
For instance if you have a normal Redis context you can set the maximum idle
|
For instance if you have a normal Redis context you can set the maximum idle
|
||||||
buffer to zero (unlimited) just with:
|
buffer to zero (unlimited) just with:
|
||||||
|
```c
|
||||||
context->reader->maxbuf = 0;
|
context->reader->maxbuf = 0;
|
||||||
|
```
|
||||||
This should be done only in order to maximize performances when working with
|
This should be done only in order to maximize performances when working with
|
||||||
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
|
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
|
||||||
as soon as possible in order to prevent allocation of useless memory.
|
as soon as possible in order to prevent allocation of useless memory.
|
||||||
|
Loading…
Reference in New Issue
Block a user