]> git.saurik.com Git - redis.git/blobdiff - deps/hiredis/README.md
Merge pull request #743 from Cofyc/fixtypo
[redis.git] / deps / hiredis / README.md
index 51ca2a93f052e756428a770d546e325251ab2181..62fe1067b7cf2f20fba08ae5d98edb6e75bc6cdf 100644 (file)
@@ -35,16 +35,18 @@ To consume the synchronous API, there are only a few function calls that need to
 
 ### Connecting
 
 
 ### Connecting
 
-The function `redisConnect` is used to create a so-called `redisContext`. The context is where
-Hiredis holds state for a connection. The `redisContext` struct has an `error` field that is
-non-NULL when the connection is in an error state. It contains a string with a textual
-representation of the error. After trying to connect to Redis using `redisConnect` you should
-check the `error` field to see if establishing the connection was successful:
+The function `redisConnect` is used to create a so-called `redisContext`. The
+context is where Hiredis holds state for a connection. The `redisContext`
+struct has an integer `err` field that is non-zero when an the connection is in
+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.
+After trying to connect to Redis using `redisConnect` you should
+check the `err` field to see if establishing the connection was successful:
 
     redisContext *c = redisConnect("127.0.0.1", 6379);
 
     redisContext *c = redisConnect("127.0.0.1", 6379);
-    if (c->error != NULL) {
-      printf("Error: %s\n", c->error);
-      // handle error
+    if (c->err) {
+        printf("Error: %s\n", c->errstr);
+        // handle error
     }
 
 ### Sending commands
     }
 
 ### Sending commands
@@ -71,13 +73,13 @@ 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:
 
 One or more spaces separates arguments, so you can use the specifiers
 anywhere in an argument:
 
-    reply = redisCommand("SET key:%s %s", myid, value);
+    reply = redisCommand(context, "SET key:%s %s", myid, value);
 
 ### Using replies
 
 The return value of `redisCommand` holds a reply when the command was
 
 ### Using replies
 
 The return value of `redisCommand` holds a reply when the command was
-successfully executed. When the return value is `NULL`, the `error` field
-in the context can be used to find out what was the cause of failure.
+successfully executed. When an error occurs, the return value is `NULL` and
+the `err` field in the context will be set (see section on **Errors**).
 Once an error is returned the context cannot be reused and you should set up
 a new connection.
 
 Once an error is returned the context cannot be reused and you should set up
 a new connection.
 
@@ -106,7 +108,7 @@ was received:
 * **`REDIS_REPLY_ARRAY`**:
     * A multi bulk reply. The number of elements in the multi bulk reply is stored in
       `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
 * **`REDIS_REPLY_ARRAY`**:
     * A multi bulk reply. The number of elements in the multi bulk reply is stored in
       `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
-      and can be accessed via `reply->elements[..index..]`.
+      and can be accessed via `reply->element[..index..]`.
       Redis may reply with nested arrays but this is fully supported.
 
 Replies should be freed using the `freeReplyObject()` function.
       Redis may reply with nested arrays but this is fully supported.
 
 Replies should be freed using the `freeReplyObject()` function.
@@ -114,6 +116,12 @@ Note that this function will take care of freeing sub-replies objects
 contained in arrays and nested arrays, so there is no need for the user to
 free the sub replies (it is actually harmful and will corrupt the memory).
 
 contained in arrays and nested arrays, so there is no need for the user to
 free the sub replies (it is actually harmful and will corrupt the memory).
 
+**Important:** the current version of hiredis (0.10.0) free's replies when the
+asynchronous API is used. This means you should not call `freeReplyObject` when
+you use this API. The reply is cleaned up by hiredis _after_ the callback
+returns. This behavior will probably change in future releases, so make sure to
+keep an eye on the changelog when upgrading (see issue #39).
+
 ### Cleaning up
 
 To disconnect and free the context the following function can be used:
 ### Cleaning up
 
 To disconnect and free the context the following function can be used:
@@ -166,10 +174,10 @@ to the `redisCommand` family, apart from not returning a reply:
 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
 the latter means an error occurred while reading a reply. Just as with the other commands,
 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
 the latter means an error occurred while reading a reply. Just as with the other commands,
-the `error` field in the context can be used to find out what the cause of this error is.
+the `err` field in the context can be used to find out what the cause of this error is.
 
 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 `write(2)`):
+a single call to `read(2)`):
 
     redisReply *reply;
     redisAppendCommand(context,"SET foo bar");
 
     redisReply *reply;
     redisAppendCommand(context,"SET foo bar");
@@ -184,10 +192,35 @@ This API can also be used to implement a blocking subscriber:
     reply = redisCommand(context,"SUBSCRIBE foo");
     freeReplyObject(reply);
     while(redisGetReply(context,&reply) == REDIS_OK) {
     reply = redisCommand(context,"SUBSCRIBE foo");
     freeReplyObject(reply);
     while(redisGetReply(context,&reply) == REDIS_OK) {
-      // consume message
-      freeReplyObject(reply);
+        // consume message
+        freeReplyObject(reply);
     }
 
     }
 
+### Errors
+
+When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
+returned. The `err` field inside the context will be non-zero and set to one of the
+following constants:
+
+* **`REDIS_ERR_IO`**:
+    There was an I/O error while creating the connection, trying to write
+    to the socket or read from the socket. If you included `errno.h` in your
+    application, you can use the global `errno` variable to find out what is
+    wrong.
+
+* **`REDIS_ERR_EOF`**:
+    The server closed the connection which resulted in an empty read.
+
+* **`REDIS_ERR_PROTOCOL`**:
+    There was an error while parsing the protocol.
+
+* **`REDIS_ERR_OTHER`**:
+    Any other error. Currently, it is only used when a specified hostname to connect
+    to cannot be resolved.
+
+In every case, the `errstr` field in the context will be set to hold a string representation
+of the error.
+
 ## Asynchronous API
 
 Hiredis comes with an asynchronous API that works easily with any event library.
 ## Asynchronous API
 
 Hiredis comes with an asynchronous API that works easily with any event library.
@@ -197,15 +230,15 @@ and [libevent](http://monkey.org/~provos/libevent/).
 ### Connecting
 
 The function `redisAsyncConnect` can be used to establish a non-blocking connection to
 ### 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 `error` field
+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.
 
     redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
 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.
 
     redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
-    if (c->error != NULL) {
-      printf("Error: %s\n", c->error);
-      // handle error
+    if (c->err) {
+        printf("Error: %s\n", c->errstr);
+        // 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
@@ -215,7 +248,7 @@ have the following prototype:
     void(const redisAsyncContext *c, int status);
 
 On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
     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 `error`
+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.
 
 The context object is always free'd after the disconnect callback fired. When a reconnect is needed,
 field in the context can be accessed to find out the cause of the error.
 
 The context object is always free'd after the disconnect callback fired. When a reconnect is needed,
@@ -253,7 +286,8 @@ is being disconnected per user-request, no new commands may be added to the outp
 returned on calls to the `redisAsyncCommand` family.
 
 If the reply for a command with a `NULL` callback is read, it is immediately free'd. When the callback
 returned on calls to the `redisAsyncCommand` family.
 
 If the reply for a command with a `NULL` callback is read, it is immediately free'd. When the callback
-for a command is non-`NULL`, it is responsible for cleaning up the reply.
+for a command is non-`NULL`, the memory is free'd 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.
 
 
 All pending callbacks are called with a `NULL` reply when the context encountered an error.
 
@@ -276,7 +310,68 @@ See the `adapters/` directory for bindings to *libev* and *libevent*.
 
 ## Reply parsing API
 
 
 ## Reply parsing API
 
-To be done.
+Hiredis comes with a reply parsing API that makes it easy for writing higher
+level language bindings.
+
+The reply parsing API consists of the following functions:
+
+    redisReader *redisReaderCreate(void);
+    void redisReaderFree(redisReader *reader);
+    int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
+    int redisReaderGetReply(redisReader *reader, void **reply);
+
+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
+usage.
+
+### Usage
+
+The function `redisReaderCreate` creates a `redisReader` structure that holds a
+buffer with unparsed data and state for the protocol parser.
+
+Incoming data -- most likely from a socket -- can be placed in the internal
+buffer of the `redisReader` using `redisReaderFeed`. This function will make a
+copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed
+when `redisReaderGetReply` is called. This function returns an integer status
+and a reply object (as described above) via `void **reply`. The returned status
+can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
+wrong (either a protocol error, or an out of memory error).
+
+### Customizing replies
+
+The function `redisReaderGetReply` creates `redisReply` and makes the function
+argument `reply` point to the created `redisReply` variable. For instance, if
+the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`
+will hold the status as a vanilla C string. However, the functions that are
+responsible for creating instances of the `redisReply` can be customized by
+setting the `fn` field on the `redisReader` struct. This should be done
+immediately after creating the `redisReader`.
+
+For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)
+uses customized reply object functions to create Ruby objects.
+
+### Reader max buffer
+
+Both when using the Reader API directly or when using it indirectly via a
+normal Redis context, the redisReader structure uses a buffer in order to
+accumulate data from the server.
+Usually this buffer is destroyed when it is empty and is larger than 16
+kb in order to avoid wasting memory in unused buffers
+
+However when working with very big payloads destroying the buffer may slow
+down performances considerably, so it is possible to modify the max size of
+an idle buffer changing the value of the `maxbuf` field of the reader structure
+to the desired value. The special value of 0 means that there is no maximum
+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
+buffer to zero (unlimited) just with:
+
+    context->reader->maxbuf = 0;
+
+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
+as soon as possible in order to prevent allocation of useless memory.
 
 ## AUTHORS
 
 
 ## AUTHORS