Skip to content

Commit

Permalink
Configurable reader max idle buffer size.
Browse files Browse the repository at this point in the history
Hiredis used to free unused redisReader buffers bigger than 16k. Now
this limit is configurable (see the documentation updated by this commit)
in order to allow working with big payloads without incurring to speed
penalty.
  • Loading branch information
antirez committed Aug 21, 2012
1 parent 7f34647 commit 7f09505
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ The reply parsing API consists of the following functions:
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
Expand All @@ -346,6 +350,29 @@ 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

Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Expand Down
3 changes: 2 additions & 1 deletion hiredis.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ redisReader *redisReaderCreate(void) {
r->errstr[0] = '\0';
r->fn = &defaultFunctions;
r->buf = sdsempty();
r->maxbuf = REDIS_READER_MAX_BUF;
if (r->buf == NULL) {
free(r);
return NULL;
Expand Down Expand Up @@ -591,7 +592,7 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
/* Copy the provided buffer. */
if (buf != NULL && len >= 1) {
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
sdsfree(r->buf);
r->buf = sdsempty();
r->pos = 0;
Expand Down
3 changes: 3 additions & 0 deletions hiredis.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6

#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -125,6 +127,7 @@ typedef struct redisReader {
char *buf; /* Read buffer */
size_t pos; /* Buffer cursor */
size_t len; /* Buffer length */
size_t maxbuf; /* Max length of unused buffer */

redisReadTask rstack[4];
int ridx; /* Index of current read task */
Expand Down

0 comments on commit 7f09505

Please sign in to comment.