Minimalistic C client for Redis >= 1.2

Related tags

Database hiredis
Overview

Build Status

This Readme reflects the latest changed in the master branch. See v1.0.0 for the Readme and documentation for the latest release (API/ABI history).

HIREDIS

Hiredis is a minimalistic C client library for the Redis database.

It is minimalistic because it just adds minimal support for the protocol, but at the same time it uses a high level printf-alike API in order to make it much higher level than otherwise suggested by its minimal code base and the lack of explicit bindings for every Redis command.

Apart from supporting sending commands and receiving replies, it comes with a reply parser that is decoupled from the I/O layer. It is a stream parser designed for easy reusability, which can for instance be used in higher level language bindings for efficient reply parsing.

Hiredis only supports the binary-safe Redis protocol, so you can use it with any Redis version >= 1.2.0.

The library comes with multiple APIs. There is the synchronous API, the asynchronous API and the reply parsing API.

Upgrading to 1.0.0

Version 1.0.0 marks the first stable release of Hiredis. It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. It also bundles the updated sds library, to sync up with upstream and Redis. For code changes see the Changelog.

Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling.

IMPORTANT: Breaking changes from 0.14.1 -> 1.0.0

  • redisContext has two additional members (free_privdata, and privctx).
  • redisOptions.timeout has been renamed to redisOptions.connect_timeout, and we've added redisOptions.command_timeout.
  • redisReplyObjectFunctions.createArray now takes size_t instead of int for its length parameter.

IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x

Bulk and multi-bulk lengths less than -1 or greater than LLONG_MAX are now protocol errors. This is consistent with the RESP specification. On 32-bit platforms, the upper bound is lowered to SIZE_MAX.

Change redisReply.len to size_t, as it denotes the the size of a string

User code should compare this to size_t values as well. If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.

Upgrading from <0.9.0

Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing code using hiredis should not be a big pain. The key thing to keep in mind when upgrading is that hiredis >= 0.9.0 uses a redisContext* to keep state, in contrast to the stateless 0.0.1 that only has a file descriptor to work with.

Synchronous API

To consume the synchronous API, there are only a few function calls that need to be introduced:

redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);

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 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. 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);
if (c == NULL || c->err) {
    if (c) {
        printf("Error: %s\n", c->errstr);
        // handle error
    } else {
        printf("Can't allocate redis context\n");
    }
}

Note: A redisContext is not thread-safe.

Sending commands

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, it is used like this:

reply = redisCommand(context, "SET foo bar");

The specifier %s interpolates a string in the command, and uses strlen to determine the length of the string:

reply = redisCommand(context, "SET foo %s", value);

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 of the string:

reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);

Internally, Hiredis 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:

reply = redisCommand(context, "SET key:%s %s", myid, value);

Using replies

The return value of redisCommand holds a reply when the command was 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.

The standard replies that redisCommand are of the type redisReply. The type field in the redisReply should be used to test what kind of reply was received:

RESP2

  • REDIS_REPLY_STATUS:

    • The command replied with a status reply. The status string can be accessed using reply->str. The length of this string can be accessed using reply->len.
  • REDIS_REPLY_ERROR:

    • The command replied with an error. The error string can be accessed identical to REDIS_REPLY_STATUS.
  • REDIS_REPLY_INTEGER:

    • The command replied with an integer. The integer value can be accessed using the reply->integer field of type long long.
  • REDIS_REPLY_NIL:

    • The command replied with a nil object. There is no data to access.
  • REDIS_REPLY_STRING:

    • A bulk (string) reply. The value of the reply can be accessed using reply->str. The length of this string can be accessed using reply->len.
  • 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->element[..index..]. Redis may reply with nested arrays but this is fully supported.

RESP3

Hiredis also supports every new RESP3 data type which are as follows. For more information about the protocol see the RESP3 specification.

  • REDIS_REPLY_DOUBLE:

    • The command replied with a double-precision floating point number. The value is stored as a string in the str member, and can be converted with strtod or similar.
  • REDIS_REPLY_BOOL:

    • A boolean true/false reply. The value is stored in the integer member and will be either 0 or 1.
  • REDIS_REPLY_MAP:

    • An array with the added invariant that there will always be an even number of elements. The MAP is functionally equivelant to REDIS_REPLY_ARRAY except for the previously mentioned invariant.
  • REDIS_REPLY_SET:

    • An array response where each entry is unique. Like the MAP type, the data is identical to an array response except there are no duplicate values.
  • REDIS_REPLY_PUSH:

    • An array that can be generated spontaneously by Redis. This array response will always contain at least two subelements. The first contains the type of PUSH message (e.g. message, or invalidate), and the second being a sub-array with the PUSH payload itself.
  • REDIS_REPLY_ATTR:

    • An array structurally identical to a MAP but intended as meta-data about a reply. As of Redis 6.0.6 this reply type is not used in Redis
  • REDIS_REPLY_BIGNUM:

    • A string representing an arbitrarily large signed or unsigned integer value. The number will be encoded as a string in the str member of redisReply.
  • REDIS_REPLY_VERB:

    • A verbatim string, intended to be presented to the user without modification. The string payload is stored in the str memeber, and type data is stored in the vtype member (e.g. txt for raw text or md for markdown).

Replies should be freed using the freeReplyObject() function. Note that this function will take care of freeing sub-reply 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).

Important: the current version of hiredis (1.0.0) frees 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. We may introduce a flag to make this configurable in future versions of the library.

Cleaning up

To disconnect and free the context the following function can be used:

void redisFree(redisContext *c);

This function immediately closes the socket and then frees the allocations done in creating the context.

Sending commands (cont'd)

Together with redisCommand, the function redisCommandArgv can be used to issue commands. It has the following prototype:

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 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 need to be binary safe, the entire array of lengths argvlen should be provided.

The return value has the same semantic as redisCommand.

Pipelining

To explain how Hiredis supports pipelining in a blocking connection, there needs to be understanding of the internal execution flow.

When any of the functions in the redisCommand family is called, Hiredis first formats the command according to the Redis protocol. The formatted command is then put in the output buffer of the context. This output buffer is dynamic, so it can hold any number of commands. After the command is put in the output buffer, redisGetReply is called. This function has the following two execution paths:

  1. The input buffer is non-empty:
    • Try to parse a single reply from the input buffer and return it
    • If no reply could be parsed, continue at 2
  2. The input buffer is empty:
    • Write the entire output buffer to the socket
    • Read from the socket until a single reply could be parsed

The function redisGetReply 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 redisCommand family, apart from not returning a reply:

void redisAppendCommand(redisContext *c, const char *format, ...);
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 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.

The following examples shows a simple pipeline (resulting in only a single call to write(2) and a single call to read(2)):

redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,(void *)&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,(void *)&reply); // reply for GET
freeReplyObject(reply);

This API can also be used to implement a blocking subscriber:

reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
    // 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. Examples are bundled that show using Hiredis with libev and libevent.

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.

Note: A redisAsyncContext is not thread-safe.

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
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 connection is disconnected (either because of an error or per user request). This function should 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 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 freed after the disconnect callback fired. When a reconnect is needed, 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 return REDIS_ERR. The function to set the disconnect callback has the following prototype:

int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

ac->data may be used to pass user data to this callback, the same can be done for redisConnectCallback.

Sending commands and their callbacks

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. 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:

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 command is initially queued for execution.

The functions that can be used to issue commands in an asynchronous context are:

int redisAsyncCommand(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  const char *format, ...);
int redisAsyncCommandArgv(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  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 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 redisAsyncCommand 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 asynchronous connection can be terminated using:

void redisAsyncDisconnect(redisAsyncContext *ac);

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 context object after it is created. See the adapters/ directory for bindings to libev and libevent.

Reply parsing API

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).

The parser limits the level of nesting for multi bulk payloads to 7. If the multi bulk nesting level is higher than this, the parser returns an 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 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 KiB 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.

Reader max array elements

By default the hiredis reply parser sets the maximum number of multi-bulk elements to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies with more than this many elements you can set the value higher or to zero, meaning unlimited with:

context->reader->maxelements = 0;

SSL/TLS Support

Building

SSL/TLS support is not built by default and requires an explicit flag:

make USE_SSL=1

This requires OpenSSL development package (e.g. including header files to be available.

When enabled, SSL/TLS support is built into extra libhiredis_ssl.a and libhiredis_ssl.so static/dynamic libraries. This leaves the original libraries unaffected so no additional dependencies are introduced.

Using it

First, you'll need to make sure you include the SSL header file:

#include "hiredis.h"
#include "hiredis_ssl.h"

You will also need to link against libhiredis_ssl, in addition to libhiredis and add -lssl -lcrypto to satisfy its dependencies.

Hiredis implements SSL/TLS on top of its normal redisContext or redisAsyncContext, so you will need to establish a connection first and then initiate an SSL/TLS handshake.

Hiredis OpenSSL Wrappers

Before Hiredis can negotiate an SSL/TLS connection, it is necessary to initialize OpenSSL and create a context. You can do that in two ways:

  1. Work directly with the OpenSSL API to initialize the library's global context and create SSL_CTX * and SSL * contexts. With an SSL * object you can call redisInitiateSSL().
  2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a redisSSLContext object to hold configuration and use redisInitiateSSLWithContext() to initiate the SSL/TLS handshake.
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
 * many contexts.
 */
redisSSLContext *ssl_context;

/* An error variable to indicate what went wrong, if the context fails to
 * initialize.
 */
redisSSLContextError ssl_error;

/* Initialize global OpenSSL state.
 *
 * You should call this only once when your app initializes, and only if
 * you don't explicitly or implicitly initialize OpenSSL it elsewhere.
 */
redisInitOpenSSL();

/* Create SSL context */
ssl_context = redisCreateSSLContext(
    "cacertbundle.crt",     /* File name of trusted CA/ca bundle file, optional */
    "/path/to/certs",       /* Path of trusted certificates, optional */
    "client_cert.pem",      /* File name of client certificate file, optional */
    "client_key.pem",       /* File name of client private key, optional */
    "redis.mydomain.com",   /* Server name to request (SNI), optional */
    &ssl_error);

if(ssl_context == NULL || ssl_error != 0) {
    /* Handle error and abort... */
    /* e.g. 
    printf("SSL error: %s\n", 
        (ssl_error != 0) ? 
            redisSSLContextGetError(ssl_error) : "Unknown error");
    // Abort
    */
}

/* Create Redis context and establish connection */
c = redisConnect("localhost", 6443);
if (c == NULL || c->err) {
    /* Handle error and abort... */
}

/* Negotiate SSL/TLS */
if (redisInitiateSSLWithContext(c, ssl_context) != REDIS_OK) {
    /* Handle error, in c->err / c->errstr */
}

RESP3 PUSH replies

Redis 6.0 introduced PUSH replies with the reply-type >. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.

Default behavior

Hiredis installs handlers on redisContext and redisAsyncContext by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to RESP3.

Custom PUSH handler prototypes

The callback prototypes differ between redisContext and redisAsyncContext.

redisContext

void my_push_handler(void *privdata, void *reply) {
    /* Handle the reply */

    /* Note: We need to free the reply in our custom handler for
             blocking contexts.  This lets us keep the reply if
             we want. */
    freeReplyObject(reply);
}

redisAsyncContext

void my_async_push_handler(redisAsyncContext *ac, void *reply) {
    /* Handle the reply */

    /* Note:  Because async hiredis always frees replies, you should
              not call freeReplyObject in an async push callback. */
}

Installing a custom handler

There are two ways to set your own PUSH handlers.

  1. Set push_cb or async_push_cb in the redisOptions struct and connect with redisConnectWithOptions or redisAsyncConnectWithOptions.

    redisOptions = {0};
    REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
    options->push_cb = my_push_handler;
    redisContext *context = redisConnectWithOptions(&options);
  2. Call redisSetPushCallback or redisAsyncSetPushCallback on a connected context.

    redisContext *context = redisConnect("127.0.0.1", 6379);
    redisSetPushCallback(context, my_push_handler);

    Note redisSetPushCallback and redisAsyncSetPushCallback both return any currently configured handler, making it easy to override and then return to the old value.

Specifying no handler

If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.

  1. Set the REDIS_OPT_NO_PUSH_AUTOFREE flag in redisOptions and leave the callback function pointer NULL.

    redisOptions = {0};
    REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
    options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
    redisContext *context = redisConnectWithOptions(&options);
  2. Call redisSetPushCallback with NULL once connected.

    redisContext *context = redisConnect("127.0.0.1", 6379);
    redisSetPushCallback(context, NULL);

    Note: With no handler configured, calls to redisCommand may generate more than one reply, so this strategy is only applicable when there's some kind of blockingredisGetReply() loop (e.g. MONITOR or SUBSCRIBE workloads).

Allocator injection

Hiredis uses a pass-thru structure of function pointers defined in alloc.h that contain the currently configured allocation and deallocation functions. By default they just point to libc (malloc, calloc, realloc, etc).

Overriding

One can override the allocators like so:

hiredisAllocFuncs myfuncs = {
    .mallocFn = my_malloc,
    .callocFn = my_calloc,
    .reallocFn = my_realloc,
    .strdupFn = my_strdup,
    .freeFn = my_free,
};

// Override allocators (function returns current allocators if needed)
hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);

To reset the allocators to their default libc function simply call:

hiredisResetAllocators();

AUTHORS

Salvatore Sanfilippo (antirez at gmail),
Pieter Noordhuis (pcnoordhuis at gmail)
Michael Grunder (michael dot grunder at gmail)

Hiredis is released under the BSD license.

Issues
  • Add timeout option to requests

    Add timeout option to requests

    While connectWithTimeout will guard against the use case of a slow initial handshake, there's nothing that guards against delays with requests on current connections. The example case here is if Redis spikes to 100% CPU utilization for any number of reasons (out of sockets, memory issues, etc) then anything left holding a connection will suffer without the ability to timeout. I have run into this a couple times now and would like to see it solved. I am happy to implement, but looking for at least a thumbs up on interest before I start.

    opened by abedra 38
  • difficulty building on aix - cannot locate struct timeval

    difficulty building on aix - cannot locate struct timeval

    receive the following message:

    In file included from hiredis/hiredis.c:39: hiredis/hiredis.h:175: warning: 'struct timeval' declared inside parameter list hiredis/hiredis.h:175: warning: its scope is only this definition or declaration, which is probably not what you want

    I am using gcc 4.4 on aix 5.3.

    opened by slestak 24
  • hiredis hangs on redisBufferRead

    hiredis hangs on redisBufferRead

    We use hiredis to connect to redis server in block mode. Our application runs in RHEL 4 32 bit. It works fine and after some time while trying to do an operation, it hangs. On analysis, found it got hanged in the redisBufferRead. This application act like a switch which gets the data from TCP Socket and store the same in the Redis database for recoverability.

    On netstat output, We found the SendQ of the our client has non-zero value which indicates that request has not reached redis server. This behaviour happens with INCR & INCRBY mostly.

    We opened a redis-client and did the same operation and it works fine.

    gdb output #0 0x008787a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2 #1 0x001de69b in __read_nocancel () from /lib/tls/libpthread.so.0 #2 0x08073a42 in redisBufferRead (c=0x89c2fb8) at hiredis.c:1142 #3 0x08073c59 in redisGetReply (c=0x89c2fb8, reply=0x590dcbc) at hiredis.c:1228 #4 0x08073e99 in redisvCommand (c=0x89c2fb8, format=0x8077f40 "INCRBY %s %ld", ap=0x590dcf8 "t\021\225\b\001") at hiredis.c:1332 #5 0x08073ed2 in redisCommand (c=0x89c2fb8, format=0x8077f40 "INCRBY %s %ld") at hiredis.c:1349

    opened by saravanan-elangovan 23
  • Can't build on macosx 10.7

    Can't build on macosx 10.7

    Hi! I'm getting trouble installing package on Leon. .... Running setup.py install for hiredis building 'hiredis' library /Developer/usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -O2 -fwrapv -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -Ivendor/hiredis -c vendor/hiredis/hiredis.c -o build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis/hiredis.o vendor/hiredis/hiredis.c:691:21: error: second argument to 'va_arg' is of incomplete type 'void' va_arg(ap,void); ^~~~~~~~~~~~~~~ /Developer/usr/bin/../lib/clang/3.0/include/stdarg.h:35:50: note: instantiated from: #define va_arg(ap, type) builtin_va_arg(ap, type) ^ vendor/hiredis/hiredis.c:691:31: note: instantiated from: va_arg(ap,void); ^~~~ 1 error generated. error: command '/Developer/usr/bin/clang' failed with exit status 1 Complete output from command /Users/demon/Work/sportlook.ru/env/bin/python -c "import setuptools;__file='/Users/demon/Work/sportlook.ru/env/build/hiredis/setup.py';exec(compile(open(file).read().replace('\r\n', '\n'), file, 'exec'))" install --single-version-externally-managed --record /var/folders/s5/3z_j0lyx3r9__09nfn7vb7wh0000gn/T/pip-4asypi-record/install-record.txt --install-headers /Users/demon/Work/sportlook.ru/env/bin/../include/site/python2.7: running install

    running build

    running build_py

    creating build

    creating build/lib.macosx-10.7-x86_64-2.7

    creating build/lib.macosx-10.7-x86_64-2.7/hiredis

    copying hiredis/init.py -> build/lib.macosx-10.7-x86_64-2.7/hiredis

    copying hiredis/version.py -> build/lib.macosx-10.7-x86_64-2.7/hiredis

    running build_clib

    building 'hiredis' library

    creating build/temp.macosx-10.7-x86_64-2.7

    creating build/temp.macosx-10.7-x86_64-2.7/vendor

    creating build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis

    /Developer/usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -O2 -fwrapv -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -Ivendor/hiredis -c vendor/hiredis/hiredis.c -o build/temp.macosx-10.7-x86_64-2.7/vendor/hiredis/hiredis.o

    vendor/hiredis/hiredis.c:691:21: error: second argument to 'va_arg' is of incomplete type 'void'

                    va_arg(ap,void);
    
                    ^~~~~~~~~~~~~~~
    

    /Developer/usr/bin/../lib/clang/3.0/include/stdarg.h:35:50: note: instantiated from:

    define va_arg(ap, type) __builtin_va_arg(ap, type)

                                                 ^
    

    vendor/hiredis/hiredis.c:691:31: note: instantiated from:

                    va_arg(ap,void);
    
                              ^~~~
    

    1 error generated.

    error: command '/Developer/usr/bin/clang' failed with exit status 1


    Command /Users/demon/Work/sportlook.ru/env/bin/python -c "import setuptools;file='/Users/demon/Work/sportlook.ru/env/build/hiredis/setup.py';exec(compile(open(file).read().replace('\r\n', '\n'), file, 'exec'))" install --single-version-externally-managed --record /var/folders/s5/3z_j0lyx3r9__09nfn7vb7wh0000gn/T/pip-4asypi-record/install-record.txt --install-headers /Users/demon/Work/sportlook.ru/env/bin/../include/site/python2.7 failed with error code 1 Storing complete log in /Users/demon/.pip/pip.log

    opened by demon-mhm 23
  • Hiredis 0.12.0

    Hiredis 0.12.0

    Hey everybody,

    I have created a develop branch for hiredis, and would like to get this going by going through a variety of outstanding issues and pull requests to see what we might want to get tested and incorporated for the next official release :smiley_cat:!

    Things I'm pretty sure we should merge:

    • #286 -- This one looks good. I agree with @mattsta that we should probably backport dict.c from Redis, but it seems reasonable to incorporate this one first (as it's a quick one).
    • #285, #282, #267 -- Just a tiny grammar fixes, but they look correct to me, so we should merge.
    • #268 -- I need to test this one, but generally speaking I like being idiomatic and using const char * vs. char * so it's clear that the string isn't going to be modified.
    • #260 -- We've been using this in production for ages, and as of yet it has not ruined everything. I think we should merge.
    • #251 -- This fixes a libuv compile error, and I favor it over the similar #258 as the non-static declaration isn't necessary at all as far as I can tell.

    Things we might want to merge:

    • #279 -- This is probably technically correct, but it's not something that really bothers me one way or the other. There are only a few calloc calls in hiredis, and they vary on argument order (when creating just 1 thing).
    • #264 -- This one looks fine to me, but I'm only mildly familiar with this TCP option. Just read up on it and I don't see how it would cause any issues.
    • #261 -- I vote yes on this one, but @pietern mentioned that it would break downstream packages, so I'm curious in what way that would be.
    • #254 -- I would like some input from fancier individuals such as @mattsta or @badboy. :smiley:
    • #250 -- IMHO I can see why this could be useful (in the case where a custom free was being used), but is not something I have personally run into.
    • #239 -- I'll investigate and test this myself, but on first glance it looks good.

    So that takes us back roughly a year for pull requests. I am going to familiarize myself with the ng branch next and see about moving that forward. I think however this is a good start. Most of these are very small and should be pretty safe.

    Cheers guys! Mike

    opened by michael-grunder 22
  • New hiredis maintainer?

    New hiredis maintainer?

    Hello, I created this issue in order to understand how to move forward with hiredis.

    1. I'm not maintaining it for a lot of time, if you exclude fixes that were necessary for Redis.
    2. @mattsta is more or less doing the same as me.
    3. @pietern was the one that was pushing hiredis forward, but I understand he got no time now (and we thank you, Pieter, for the work you put into it so far).

    @pietern are you ok with the idea of looking for a new maintainer? Apparently nobody is handling it right now but it is a critical piece of code since it's also part of Redis, Sentinel, the foundation of many other client libs, and so forth.

    Anyone interested to maintain it? This is not Redis, a more liberal model of development is possible, so we'll give commit access to the new maintainer that will schedule the releases and so forth.

    opened by antirez 19
  • New release?

    New release?

    Howdy -- I maintain the hiredis Debian packages. We've run into an interesting situation because redis vendors/bundles hiredis. The vendored library runs afoul of Debian policy rules, because we'd rather have redis use the system's shared hiredis to avoid unnecessary bloat. However, in trying to modify redis to use the shared/system hiredis (which is a very lightly modified 0.13.3) we've discovered that the bundled version of hiredis is API-incompatible with 0.13.3. See Debian tickets 907258 and 907259 for details of the specific issue we're trying to resolve.

    We can work around this on the Debian side by packaging up Git master as of some arbitrary SHA, but would prefer not to: as you can probably imagine that's both a headache for users who might be building third-party/"external" software against the hiredis Debian packages or package maintainers who might be (reasonably!) trying to port software based on 0.13.3 to Debian.

    Before I go raining on anyone's parade on the Debian side, is there any possibility we could twist your arm for the 1.0.0 release, or at least another 0.x release with an API compatible with the version bundled with redis? If something specific is holding up a release & it's just a question of manpower, let me know how I can help.

    opened by thomaslee 17
  • HiRedis has certain issues when called by another project that is on C89/C90

    HiRedis has certain issues when called by another project that is on C89/C90

    I'd like to re-open discussion about this: https://github.com/redis/hiredis/issues/31

    TLDR: Let's make hiredis header files C89/C90 compatible. Not the whole project.

    I have a hard requirement to go C89/C90 in a project where I'd like to use hiredis. When I try to use the hiredis header files, a number of problems emerge that are hard to work around. It would be better if hiredis's header files were C89/C90 compatible.

    This can be accomplished in a few different ways. I'd like to open discussion on this.

    Approach 1: Write a hello,world test app (not in the examples folder -- because this wouldn't be an example) that uses hiredis with compiler flags set to -std=c90 -pedantic to start (potentially other flags to increase the strictness of the header files) If this .c file creates compiler warnings, they can be caught by developers during check-in time.

    Approach 2 Append certain compiler flags to the Makefile. This would have a broader impact on the project. Where it says: WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings Add some compiler flags such as: -pedantic-errors -Werror -Wextra -Werror -Wmissing-prototypes -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wfloat-equal -Wconversion -Wno-missing-braces -Wold-style-definition -Wdeclaration-after-statement (The appropriate list of flags is debatable)

    Approach 3 Make the examples C89/C90 compliant by adding compiler flags just on the examples.

    opened by dagostinelli 16
  • core dump on calling sdsMakeRoomFor

    core dump on calling sdsMakeRoomFor

    I am getting core dump on realloc of sdsMakeRoomFor. My coredump backtrace is given below: `Program received signal SIGABRT, Aborted. [Switching to Thread 0x7ffff67a5700 (LWP 11207)] 0x0000003fc8c32625 in raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); (gdb) bt #0 0x0000003fc8c32625 in raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x0000003fc8c33e05 in abort () at abort.c:92 #2 0x0000003fc8c70537 in __libc_message (do_abort=2, fmt=0x3fc8d588c0 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:198 #3 0x0000003fc8c75f4e in malloc_printerr (action=3, str=0x3fc8d5687d "corrupted double-linked list", ptr=, ar_ptr=) at malloc.c:6350 #4 0x0000003fc8c763d3 in malloc_consolidate (av=0x7ffff0000020) at malloc.c:5216 #5 0x0000003fc8c79c28 in _int_malloc (av=0x7ffff0000020, bytes=) at malloc.c:4415 #6 0x0000003fc8c7bbda in _int_realloc (av=0x7ffff0000020, oldp=0x7ffff0000b60, oldsize=, nb=1312) at malloc.c:5339 #7 0x0000003fc8c7bf78 in __libc_realloc (oldmem=0x7ffff0000b70, bytes=1299) at malloc.c:3823

    #8 0x00000000004c7c06 in sdsMakeRoomFor (s=, addlen=) at sds.c:142

    #9 0x00000000004c8044 in sdscatlen (s=, t=0x7fffea673080, len=43) at sds.c:241 #10 0x00000000004c5e00 in __redisAppendCommand (c=0x735090, cmd=, len=) at hiredis.c:910 #11 0x00000000004c703c in redisvAppendCommand (c=0x735090, format=, ap=) at hiredis.c:942 #12 0x00000000004c7208 in redisAppendCommand (c=, format=) at hiredis.c:956 #13 0x0000000000446e88 in DataReader::Do (this=0x7ffff6742f50, task=0x7ffff5da3c50) at schsv_dtsvr_V1.0.0/ds/datareader.cpp:106 #14 0x000000000044d1f9 in TaskHandler::Do (p=) at schsv_dtsvr_V1.0.0/ds/task_handler.cpp:41 #15 0x0000003fc9007a51 in start_thread (arg=0x7ffff67a5700) at pthread_create.c:301 #16 0x0000003fc8ce893d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115`

    I have worked on the issue for a long time without no progress. Any idea? Thanks!

    opened by fenglonz 15
  • Wrapping OpenSSL global state initialisation?

    Wrapping OpenSSL global state initialisation?

    Current TLS support in hiredis offers two ways to trigger the OpenSSL global state initialisation:

    • Do it implicitly when calling redisSecureConnection().
    • Do it explicitly calling SSL_library_init() on your own (if that's not already done by another component) and then use redisInitiateSSL() to set up Redis connections.

    In order to avoid unwanted dependencies, it would be very convenient to hide the explicit call to SSL_library_init() in a public hiredis symbol. In other words, wrap the following logic + state from ssl.c in a function and expose it via hiredis.h.

        static int isInit = 0;
        if (!isInit) {
            isInit = 1;
            SSL_library_init();
    #ifdef HIREDIS_USE_CRYPTO_LOCKS
            initOpensslLocks();
    #endif
    

    I'm not very familiar with hiredis internals, but if you agree with the proposal I could try to submit a PR :)

    opened by carlosabalde 14
  • setsockopt(TCP_NODELAY) in Windows

    setsockopt(TCP_NODELAY) in Windows

    There appears to be a Windows-specific issue setting TCP_NODELAY in non-blocking mode.

    See related issues #736, #779.

    Yielding the timeslice (with _sleep(0)) solves the problem, but I have not been able to verify if it is the correct way to solve the problem.

    If it is correct, perhaps adding it to win32_setsockopt is the cleanest solution:

    diff --git sockcompat.c sockcompat.c
    index f99d14b..b7990b8 100644
    --- sockcompat.c
    +++ sockcompat.c
    @@ -216,6 +216,10 @@ int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval,
             DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
             ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
         } else {
    +#if _MSC_VER
    +        /* Windows workaround */
    +        if (optname == TCP_NODELAY) _sleep(0);
    +#endif
             ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
         }
         _updateErrno(ret != SOCKET_ERROR);
    

    @mbitsnbites Do you mind weighing in as you wrote the windows compatibility layer?

    Also curious if @mnunberg or @yossigo have opinions one way or the other.

    opened by michael-grunder 14
  • How use %c in format string on redisCommand?

    How use %c in format string on redisCommand?

    If i use %c in format string then command return NULL reply. Example command (SET Test:1 a): reply = redisCommand(conn,"SET Test:1 %s", "a"); // this work (Command OK) reply = redisCommand(conn,"SET Test:1 a"); // this work (Command OK) reply = redisCommand(conn,"SET Test:1 %c", 'a'); // this d'nt work (reply == NULL) reply = redisCommand(conn,"SET T%cst:1 a", 'e'); // this d'nt work (reply == NULL)

    This problem also exists in redisAppendCommand, redisvAppendCommand and etc

    opened by FAYWORD 1
  • [Question] Protocol error while publishing

    [Question] Protocol error while publishing

    Problem Description I am using hiredis unix socket (version 0.14.0-3) to publish a number of messages (~2 KB per second) on a RPI 4B. I use the code given below to publish messages. I start getting Redis Protocol error messages after approximately 30-45 minutes of operation. Please let me know I can resolve this. Thank you!

    ` #include "RedisDriver.h"

    static redisContext* context;

    const char* REDIS_SERVER_UNIX_SOCKET = (const char*) "/var/run/redis/redis-server.sock"; const char* REDIS_PACKET_CHANNEL_NAME = (const char*) "App-Data"; const char* REDIS_STATS_CHANNEL_NAME = (const char*) "App-Stats";

    int RedisDriver_Initialize() {

    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    context = redisConnectUnixWithTimeout(REDIS_SERVER_UNIX_SOCKET, timeout);
    
    if (context == NULL || context->err) {
        if (context) {
            syslog(LOG_ERR, "REDIS connection error: %s", context->errstr);
            redisFree(context);
        } else {
            syslog(LOG_ERR,"Unable to allocate REDIS context.");
        }
        return FAILURE;
    }
    
    syslog(LOG_INFO, "Connected to REDIS at %s", REDIS_SERVER_UNIX_SOCKET);
    return SUCCESS;
    

    }

    int RedisDriver_Publish(char* msg, const char* channel_name) {

    if (!msg || !channel_name) {
        return FAILURE;
    }
    //syslog(LOG_DEBUG, "message to publish: %s", msg);
    redisReply* reply = (redisReply*) redisCommand(context, "PUBLISH %s %s", channel_name, msg);
    
    if (reply) {
        syslog(LOG_INFO, "Published %s. Reply: %s", channel_name, reply->str);
        freeReplyObject(reply);
        return SUCCESS;
    }
    
    switch(context->err) {
        case REDIS_ERR_IO:
            syslog(LOG_ERR, "There was an I/O error while connecting to REDIS.");
            break;
        case REDIS_ERR_EOF:
            syslog(LOG_ERR, "REDIS server closed the connection.");
            break;
        case REDIS_ERR_PROTOCOL:
            syslog(LOG_ERR, "REDIS protocol error.");
            break;
        case REDIS_ERR_OTHER:
        default:
            syslog(LOG_ERR, "Unknown REDIS Error.");
            break;
    }
    
    return context->err;
    

    }

    int RedisDriver_Finalize() {

    redisFree(context);
    return SUCCESS;
    

    } `

    Environment:

    • Hardware: Raspberry PI 4B with 8 GB RAM
    • OS: Raspbian GNU/Linux 10 (buster)
    • Redis server: v=5.0.14 sha=00000000:0 malloc=libc bits=32 build=a6df2d1b76e73a91
    • Compiler: gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
    • hiredis version: 0.14.0-3 armhf
    opened by tscdemo2020 2
  • command_timeout option does not work in hiredis-cluster

    command_timeout option does not work in hiredis-cluster

    hiredis-cluster with hiredis version hiredis-1.0.0

    I set command_timeout(10ms) with redisSetTimeout, some redis read request still cost more than 10ms?

    any one has any advice?

    opened by wangfuqiang 2
  • Support for non blocking SSL handshake

    Support for non blocking SSL handshake

    I'm working on a new hiredis binding for Ruby, and I'm running into what seem to be a limitation to handle SSL handshake timeout.

    The Ruby binding use redisConnectNonBlock so that it can use the Ruby VM APIs to wait on IO and release the GVL (like Python's GIL). This works well for raw TCP or UNIX sockets, but it seems to me that the SSL APis exposed by hiredis are incomplete.

    My code look like this:

    hiredis_init_ssl(...) {
        if (redisInitiateSSLWithContext(redis_context, ssl_context)) {
          // handle error
        }
    }
    

    redisInitiateSSLWithContext does handle non blocking IOs by returning OK: https://github.com/redis/hiredis/blob/d7683f35aa66e222aad07caf5b345393d0c1b9f1/ssl.c#L334-L339

    However if the error was SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, the caller is expected to call SSL_connect again:

    If the underlying BIO is non-blocking, SSL_connect() will also return when the underlying BIO could not satisfy the needs of SSL_connect() to continue the handshake, indicating the problem by the return value -1. In this case a call to SSL_get_error() with the return value of SSL_connect() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE . The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_connect(). The action depends on the underlying BIO . When using a non-blocking socket, nothing is to be done, but select() can be used to check for the required condition.

    The problem is that the reference to the SSL pointer is entirely hidden, and that calling redisInitiateSSLWithContext again would return an error because it's not meant to be repeated.

    I feel like it's missing a small API to retry the SSL_connect call after waiting on select(2).

    cc @michael-grunder

    opened by casperisfine 3
Owner
Redis
Redis
A redis module, similar to redis zset, but you can set multiple scores for each member to support multi-dimensional sorting

TairZset: Support multi-score sorting zset Introduction Chinese TairZset is a data structure developed based on the redis module. Compared with the na

Alibaba 43 Jun 15, 2022
Modern, asynchronous, and wicked fast C++11 client for Redis

redox Modern, asynchronous, and wicked fast C++11 client for Redis [] (https://travis-ci.org/hmartiro/redox) Redox is a C++ interface to the Redis key

Hayk Martiros 374 Jun 14, 2022
C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

Simon Ninon 967 Jun 22, 2022
Redis client written in C++

redis-plus-plus Overview Features Branches Installation Install hiredis Install redis-plus-plus Run Tests (Optional) Use redis-plus-plus In Your Proje

null 855 Jun 22, 2022
cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

CPP Redis 501 Jun 22, 2022
Aredis - a clean redis C++ client

aredis a clean redis C++ client redis_conn rc; if (rc.connect("127.0.0.1"/*host*/, 6379/*port*/, nullptr/*password*/, 1/*db*/)) { redis_command cmd;

Evan 26 Dec 10, 2021
A C++ Redis client

redis3m A C++ Redis client, born to bring my experience using Redis and C++ on a opensource library. Main goals Provide a simple and efficient wrapper

Luca Marturana 184 Apr 21, 2022
The official C++ client API for PostgreSQL.

libpqxx Welcome to libpqxx, the C++ API to the PostgreSQL database management system. Home page: http://pqxx.org/development/libpqxx/ Find libpqxx on

Jeroen Vermeulen 643 Jun 25, 2022
Beryl-cli is a client for the BerylDB database server

Beryl-cli is a client for the BerylDB database server. It offers multiple commands and is designed to be fast and user-friendly.

BerylDB 11 Apr 21, 2022
The PostgreSQL client API in modern C++

C++ client API to PostgreSQL {#mainpage} Dmitigr Pgfe (PostGres FrontEnd, hereinafter referred to as Pgfe) - is a C++ client API to PostgreSQL servers

Dmitry Igrishin 134 Jun 3, 2022
C++ client library for PostgreSQL

Welcome to taoPQ taoPQ is a lightweight C++ client library for accessing a PostgreSQL➚ database. It has no dependencies beyond libpq➚, the C applicati

The Art of C++ 213 Jun 22, 2022
Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding.

Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding.

GitHub 248 Jun 11, 2022
RediSearch is a Redis module that provides querying, secondary indexing, and full-text search for Redis.

A query and indexing engine for Redis, providing secondary indexing, full-text search, and aggregations.

null 3.8k Jun 27, 2022
redis-cpp is a header-only library in C++17 for Redis (and C++11 backport)

redis-cpp - lightweight C++ client library for Redis redis-cpp is a C++17 library for executing Redis commands with support for pipelines and the publ

null 68 Jun 7, 2022
A redis module, similar to redis zset, but you can set multiple scores for each member to support multi-dimensional sorting

TairZset: Support multi-score sorting zset Introduction Chinese TairZset is a data structure developed based on the redis module. Compared with the na

Alibaba 43 Jun 15, 2022
Modern, asynchronous, and wicked fast C++11 client for Redis

redox Modern, asynchronous, and wicked fast C++11 client for Redis [] (https://travis-ci.org/hmartiro/redox) Redox is a C++ interface to the Redis key

Hayk Martiros 374 Jun 14, 2022
Build a redis client by cpp:)

Redix A light redis client implement by c++. Develop Environment cmake:3.16.3 g++:9.3.0 os:ubuntu 20.04.01 reids:5.0.7 Welcome to see my talk. Benchma

null 3 Apr 15, 2022
C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

Simon Ninon 967 Jun 22, 2022
Redis client written in C++

redis-plus-plus Overview Features Branches Installation Install hiredis Install redis-plus-plus Run Tests (Optional) Use redis-plus-plus In Your Proje

null 855 Jun 22, 2022
cpp_redis is a C++11 Asynchronous Multi-Platform Lightweight Redis Client

C++11 Lightweight Redis client: async, thread-safe, no dependency, pipelining, multi-platform

CPP Redis 501 Jun 22, 2022
Aredis - a clean redis C++ client

aredis a clean redis C++ client redis_conn rc; if (rc.connect("127.0.0.1"/*host*/, 6379/*port*/, nullptr/*password*/, 1/*db*/)) { redis_command cmd;

Evan 26 Dec 10, 2021
Boost::ASIO low-level redis client (connector)

bredis Boost::ASIO low-level redis client (connector), github gitee Features header only zero-copy (currently only for received replies from Redis) lo

Ivan Baidakou 141 Jun 6, 2022
A C++ Redis client

redis3m A C++ Redis client, born to bring my experience using Redis and C++ on a opensource library. Main goals Provide a simple and efficient wrapper

Luca Marturana 184 Apr 21, 2022
Minimalistic server (written in C) and a python3 client to allow calling C function on a remote host

Minimalistic server (written in C) and a python3 client to allow calling C function on a remote host

null 8 Jun 1, 2022
Kvrocks is a key-value NoSQL database based on RocksDB and compatible with Redis protocol.

Kvrocks is a key-value NoSQL database based on RocksDB and compatible with Redis protocol.

Bit Leak 1.6k Jun 23, 2022
Kvrocks is a distributed key value NoSQL database based on RocksDB and compatible with Redis protocol.

Kvrocks is a distributed key value NoSQL database based on RocksDB and compatible with Redis protocol.

Kvrocks Labs 1.6k Jun 24, 2022
Minimalistic MP3 decoder single header library

minimp3 Minimalistic, single-header library for decoding MP3. minimp3 is designed to be small, fast (with SSE and NEON support), and accurate (ISO con

Lion 1.1k Jun 25, 2022
Minimalistic C++/Python GUI library for OpenGL, GLES2/3, Metal, and WebAssembly/WebGL

NanoGUI NanoGUI is a minimalistic cross-platform widget library for OpenGL 3+, GLES 2/3, and Metal. It supports automatic layout generation, stateful

Mitsuba Physically Based Renderer 1k Jun 27, 2022
Minimalistic MP3 decoder single header library

minimp3 Minimalistic, single-header library for decoding MP3. minimp3 is designed to be small, fast (with SSE and NEON support), and accurate (ISO con

Lion 1.1k Jun 25, 2022