Skip to content

Commit

Permalink
WIP: More README work
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-grunder committed Aug 4, 2024
1 parent 1702739 commit f5777e7
Showing 1 changed file with 79 additions and 7 deletions.
86 changes: 79 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ Libvalkey is the official C client for the [Valkey](https://valkey.io) database.
- [Disconnecting / cleanup](#disconnecting--cleanup)
- [Pipelining](#pipelining)
- [Errors](#errors)
- [Other mechanisms](#other-mechanisms)
- [Maxbuffer](#maxbuffer)
- [Maxelements](#maxelements)
- [RESP3 Push Replies](#resp3-push-replies)
- [Allocator injection](#allocator-injection)
- [Asynchronous API] (#asynchronous-api)
- [Connecting](#connecting-1)

Expand All @@ -37,7 +42,7 @@ This library supports and is tested against `Linux`, `FreeBSD`, `macOS`, and `Wi

## Building

You have the choice of building with `make` or `CMake`.
You have the choice of building with `make` or `CMake`.

### Building with make

Expand All @@ -57,8 +62,8 @@ sudo USE_SSL=1 OPENSSL_PREFIX=/path/to/openssl make install
See [CMakeLists.txt](CMakeLists.txt) for all available options.

```bash
# Build and install
mkdir build && cd build
# Build and install
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
sudo make install

Expand Down Expand Up @@ -209,7 +214,7 @@ for (size_t i = 0; i < 100000; i++) {
if (valkeyAppendCommand(c, "INCRBY key:%zu %zu", i, i) != VALKEY_OK) {
fprintf(stderr, "Error appending command: %s\n", c->errstr);
exit(1);
}
}
}
// The entire output buffer will be delivered on the first call to `valkeyGetReply`.
Expand Down Expand Up @@ -244,19 +249,87 @@ while (valkeyGetReply(c, (void**)&reply) == VALKEY_OK) {
As previously mentioned, when there is a communication error libvalkey will return `NULL` and set the `err` and `errstr` members with the nature of the problem. The specific error types are as follows.
- `VALKEY_ERR_IO` - A problem with the connection.
- `VALKEY_ERR_EOF` - The server closed the connection.
- `VALKEY_ERR_EOF` - The server closed the connection.
- `VALKEY_ERR_PROTOCOL` - There was an error parsing the reply.
- `VALKEY_ERR_TIMEOUT` - A connect, read, or write timeout.
- `VALKEY_ERR_OOM` - Out of memory.
- `VALKEY_ERR_OTHER` - Some other error (check `c->errstr` for details).
#### Other mechanisms
Libvalkey has a few other mechanisms worth detailing in the README.
##### Maxbuffer
libvalkey uses a buffer to hold incomming bytes, which is typically restored to the configurable max buffer size (`16KB`) when it is empty. To avoid continually reallocating this buffer you can set the value higher, or to zero which means "no limit".
##### Maxelements
By default, libvalkey will refuse to parse array-like replies if they have more than 2^32-1 or 4,294,967,295 elements. This value can be set to any arbitrary 64-bit value or zero which just means "no limit".
##### RESP3 Push Replies
The `RESP` protocol introduced out-of-band "push" replies in the third version of the specification. These replies may come at any point in the data stream. By default, libvalkey will simply process these messages and discard them.
If your application needs to perform specific actions on PUSH messages you can install your own handler which will be called as they are received. It is also possible to set the push handler to NULL, in which case the messages will be delivered "in-band". This can be useful for example in a blocking subscribe loop.
**Note**: You may also specify a push handler in the `valkeyOptions` struct and set it on initialization .
###### Syncronous context
```c
void my_push_handler(void *privdata, void *reply) {
// In a synchronous context, you are expected to free the reply after you're done with it.
}
// Initialization, etc.
valkeySetPushCallback(c, my_push_handler);
```

###### Asynchronous context

```c
void my_async_push_handler(valkeyAsyncContext *ac, void *reply) {
// As with other async replies, libvalkey will free it for you, unless you have
// configured the context with `VALKEY_OPT_NOAUTOFREE`.
}

// Initialization, etc
valkeyAsyncSetPushCallback(ac, my_async_push_handler);
```
##### Allocator injection
Internally libvalkey uses a layer of indirection from the standard allocation functions, by keeping a global structure with function pointers to the allocators we are going to use. By default they are just set to `malloc`, `calloc`, `realloc`, etc.
These can be overridden like so
```c
valkeyAllocatorFuncs my_allocators = {
.mallocFn = my_malloc,
.callocFn = my_calloc,
.reallocFn = my_realloc,
.strdupFn = my_strdup,
.freeFn = my_free,
};
// libvalkey will return the previously set allocators.
valkeyAllocFuncs old = valkeySetAllocators(&my_allocators);
```

They can also be reset to GLIBC/MUSL

```c
valkeyResetAllocators();
```

### Asynchronous API

Libvalkey also has an asynchronous API which supports a great many different event libraries. See the [examples](examples) directory for specific information about each individual event library.

#### Connecting

Libvalkey provides an `valkeyAsyncContext` to manage asynchronous connections which works similarly to the synchronous context.
Libvalkey provides an `valkeyAsyncContext` to manage asynchronous connections which works similarly to the synchronous context.

```c
valkeyAsyncContext *ac = valkeyAsyncConnect("loalhost", 6379);
Expand All @@ -278,5 +351,4 @@ if (valkeyAsyncCommand(ac, NULL, NULL, "SET %s %s", "foo", "bar") != VALKEY_OK)
fprintf(stderr, "Error sending async command: %s\n", ac->errstr);
exit(1);
}
```

0 comments on commit f5777e7

Please sign in to comment.