* Introduce a new `RedisCmd` struct to dynamically append RESP arguments
such that we don't have to precalculate the number of arguments the
command will have up front.
Additionally the new `RedisCmd allows both a `void *` context pointer
but also can attach a `void (*ctx_dtor)(void*)` destructor so we are
still able to clean up any allocated context when commands fail.
This moves the context cleanup out of every individual reply handler
and into the generic processing wrappers.
* Create a small group of `resp_str` helper functions for lower level
concatination of RESP protocol data over the wire.
* Lots of small modernization of the codebase such as using
`zend_string*` instead of (`char *`, `size_t`) pairs.
* Greatly simplify `crosslot` handling logic
Add support for Redis' `DELEX` and Valkey's `DELIFEQ` when deleting the
session lock key. Local testing shows about a 10-15% improvement over
the current `EVAL[SHA]` strategy.
This commit adds a new INI settingg:
```ini
redis.session.lock_release_cmd = delex|delifeq|eval
```
By default we continue to use the `EVAL` logic and if a user specifies
another mechanism but the command doesn't exist, we warn the user and
fall back to EVAL.
This commit also refactors a few functions to avoid UB and simplify key
construction.
Instead of currying around a `php_stream_context` object, just retain
the context array provided by the user itself like we do with other
connection information like host and port. This lets users reconnect in
a loop without leaking memory.
```php
$redis = new \Redis;
while (true) {
// Previously each reconnect call would leak the
// `php_stream_context` structure.
$redis->connect('tls://127.0.0.1', 9999, 1, null, 0, 0, [
'stream' => ['verify_peer' => false, 'verify_peer_name' => false],
]);
$redis->ping();
$redis->close();
}
```
Conditionally add `[[nodiscard]]` (c23) or
`__attribute__((warn_unused_result))` when the compiler supports it.
This commit initially just adds iit to `cluster_map_keyspace` but we can
go throughour API adding it where appropriate.
This wrapper macro implicitly defines an `} else {` block but this is
not clear at the callsite which obsures what is actually going on.
There's no real advantage to the wrapping macro. Instead just call the
underlying macro in an explicit else branch.
This is for Redis 8.0's vector sets.
The command itself can be quite complex with all of the various options but
pretty simple using all defaults.
```php
$redis->vadd('myvec', [3.14, 2.17], 'myelement');
```
The implementation takes a default argument `$options` which can be an array in
order to specify the myriad of other knobs users can send. We just do a bit of
validation on inputs (e.g. certain numeric options must be positive) and make
sure the command is constructed in a valid way (e.g. REDUCE <dim> must come
before the floating point values).
By default we deliver `FP32` blobs but allow the user to send `VALUES` in the
options array which will cause PhpRedis to send N individual values. Sending
values is slower but might be nice for debugging (e.g. watching monitor)
See #2543
Right now we can't implement `HELLO` command to switch protocol
because we don't support new reply types that come with RESP3.
But we can use `HELLO` reply to expose some server information.
Adds an option that instructs PhpRedis to not serialize or compress
numeric values. Specifically where `Z_TYPE_P(z) == IS_LONG` or
`Z_TYPE_P(z) == IS_DOUBLE`.
This flag lets the user enable serialization and/or compression while
still using the various increment/decrement command (`INCR`, `INCRBY`,
`DECR`, `DECRBY`, `INCRBYFLOAT`, `HINCRBY`, and `HINCRBYFLOAT`).
Because PhpRedis can't be certain that this option was enabled when
writing keys, there is a small runtime cost on the read-side that tests
whether or not the value its reading is a pure integer or floating point
value.
See #23
On some glibc implementations strncmp is a macro. This commit simply creates a
`redis_strncmp` static inline wrapper function so we can `ZEND_STRL` instead of
manually counting the length or using `sizeof(s)-1` each time.
Fixes#2565
Replace `SOCKET_WRITE_COMMAND` with `redis_sock_write` because it can't be used
with pre-defined commands (it frees memory in case of failed writing operation).
After replacement `SOCKET_WRITE_COMMAND` becomes redundant so remove it.
* Create inline wrappers of the low-level php_stream_* functions that
also keep track of the number of bytes written/read.
* Change the logic to aggregate network traffic until the user
explicitly "resets" it. I think this will be a more common use-case
(running many commands and then seeing overall network IO).
See #2106
* Suppress implicit fallthrough warnings by using an attribute if we
have it and a do { } while(0) if we don't.
* Move duplicated logic for appending a ZSET score to one utility
function.
This commit is an attempt at detecting unconsumed data on a socket when
we pull it from the connection pool.
Two new INI settings are introduced related to the changes:
redis.pconnect.pool_detect_dirty:
Value Explanation
----- ----------------------------------------------------------------
0 Don't execute new logic at all.
1 Abort and close the socket if we find unconsumed bytes in the
read buffer.
2 Seek to the end of our read buffer if we find unconsumed bytes
and then poll the socket FD to detect if we're still readable
in which case we fail and close the socket.
redis.pconnect.pool_poll_timeout:
The poll timeout to employ when checking if the socket is readable.
This value is in milliseconds and can be zero.