Merge remote-tracking branch 'redis/master' into finalizer
This commit is contained in:
commit
cb6fbbfa52
29
.github/spellcheck-settings.yml
vendored
Normal file
29
.github/spellcheck-settings.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
matrix:
|
||||
- name: Markdown
|
||||
expect_match: false
|
||||
apsell:
|
||||
lang: en
|
||||
d: en_US
|
||||
ignore-case: true
|
||||
dictionary:
|
||||
wordlists:
|
||||
- .github/wordlist.txt
|
||||
output: wordlist.dic
|
||||
pipeline:
|
||||
- pyspelling.filters.markdown:
|
||||
markdown_extensions:
|
||||
- markdown.extensions.extra:
|
||||
- pyspelling.filters.html:
|
||||
comments: false
|
||||
attributes:
|
||||
- alt
|
||||
ignores:
|
||||
- ':matches(code, pre)'
|
||||
- code
|
||||
- pre
|
||||
- blockquote
|
||||
- img
|
||||
sources:
|
||||
- 'README.md'
|
||||
- 'FAQ.md'
|
||||
- 'docs/**'
|
||||
99
.github/wordlist.txt
vendored
Normal file
99
.github/wordlist.txt
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
ABI
|
||||
ACLs
|
||||
alloc
|
||||
Allocator
|
||||
allocators
|
||||
antirez
|
||||
api
|
||||
APIs
|
||||
ASYNC
|
||||
asyncRedisContext
|
||||
asyncronous
|
||||
AUTOFREE
|
||||
autoload
|
||||
autoloader
|
||||
autoloading
|
||||
Autoloading
|
||||
backend
|
||||
backends
|
||||
behaviour
|
||||
boolean
|
||||
CAS
|
||||
Changelog
|
||||
customizable
|
||||
Customizable
|
||||
CVE
|
||||
dataset
|
||||
de
|
||||
deallocation
|
||||
ElastiCache
|
||||
extensibility
|
||||
FPM
|
||||
getaddrinfo
|
||||
gmail
|
||||
grunder
|
||||
Grunder
|
||||
hiredis
|
||||
Hiredis
|
||||
HIREDIS
|
||||
hostname
|
||||
IANA
|
||||
IPv
|
||||
IPV
|
||||
keepalive
|
||||
keyspace
|
||||
keyspaces
|
||||
KiB
|
||||
libc
|
||||
libev
|
||||
libevent
|
||||
localhost
|
||||
Lua
|
||||
michael
|
||||
minimalistic
|
||||
namespace
|
||||
NOAUTOFREE
|
||||
NOAUTOFREEREPLIES
|
||||
NONBLOCK
|
||||
Noordhuis
|
||||
OpenSSL
|
||||
Packagist
|
||||
pcnoordhuis
|
||||
PhpRedis
|
||||
Pieter
|
||||
pipelined
|
||||
pipelining
|
||||
pluggable
|
||||
Predis
|
||||
PRERELEASE
|
||||
printf
|
||||
PSR
|
||||
PSUBSCRIBE
|
||||
rb
|
||||
Readme
|
||||
README
|
||||
rebalanced
|
||||
rebalancing
|
||||
redis
|
||||
Redis
|
||||
redisAsyncContext
|
||||
redisContext
|
||||
redisOptions
|
||||
redisReader
|
||||
reusability
|
||||
REUSEADDR
|
||||
runtime
|
||||
Sanfilippo
|
||||
SHA
|
||||
sharding
|
||||
SONAME
|
||||
SSL
|
||||
struct
|
||||
stunnel
|
||||
subelements
|
||||
TCP
|
||||
TLS
|
||||
unparsed
|
||||
UNSPEC
|
||||
URI
|
||||
variadic
|
||||
14
.github/workflows/spellcheck.yml
vendored
Normal file
14
.github/workflows/spellcheck.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: spellcheck
|
||||
on:
|
||||
pull_request:
|
||||
jobs:
|
||||
check-spelling:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Check Spelling
|
||||
uses: rojopolis/spellcheck-github-actions@0.33.1
|
||||
with:
|
||||
config_path: .github/spellcheck-settings.yml
|
||||
task_name: Markdown
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@
|
||||
/*.pc
|
||||
*.dSYM
|
||||
tags
|
||||
compile_commands.json
|
||||
|
||||
13
README.md
13
README.md
@ -23,6 +23,17 @@ 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.2.0 (**PRERELEASE**)
|
||||
|
||||
* After v1.2.0 we modified how we invoke `poll(2)` to wait for connections to complete, such that we will now retry
|
||||
the call if it is interrupted by a signal until:
|
||||
|
||||
a) The connection succeeds or fails.
|
||||
b) The overall connection timeout is reached.
|
||||
|
||||
In previous versions, an interrupted `poll(2)` call would cause the connection to fail
|
||||
with `c->err` set to `REDIS_ERR_IO` and `c->errstr` set to `poll(2): Interrupted system call`.
|
||||
|
||||
## Upgrading to `1.1.0`
|
||||
|
||||
Almost all users will simply need to recompile their applications against the newer version of hiredis.
|
||||
@ -291,7 +302,7 @@ void redisFree(redisContext *c);
|
||||
This function immediately closes the socket and then frees the allocations done in
|
||||
creating the context.
|
||||
|
||||
### Sending commands (cont'd)
|
||||
### Sending commands (continued)
|
||||
|
||||
Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
|
||||
It has the following prototype:
|
||||
|
||||
58
net.c
58
net.c
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "sds.h"
|
||||
@ -172,6 +173,10 @@ int redisKeepAlive(redisContext *c, int interval) {
|
||||
int val = 1;
|
||||
redisFD fd = c->fd;
|
||||
|
||||
/* TCP_KEEPALIVE makes no sense with AF_UNIX connections */
|
||||
if (c->connection_type == REDIS_CONN_UNIX)
|
||||
return REDIS_ERR;
|
||||
|
||||
#ifndef _WIN32
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
@ -271,37 +276,54 @@ static int redisContextTimeoutMsec(redisContext *c, long *result)
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static long redisPollMillis(void) {
|
||||
#ifndef _MSC_VER
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
return (now.tv_sec * 1000) + now.tv_nsec / 1000000;
|
||||
#else
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return (((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime) / 10;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int redisContextWaitReady(redisContext *c, long msec) {
|
||||
struct pollfd wfd[1];
|
||||
struct pollfd wfd;
|
||||
long end;
|
||||
int res;
|
||||
|
||||
wfd[0].fd = c->fd;
|
||||
wfd[0].events = POLLOUT;
|
||||
if (errno != EINPROGRESS) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (errno == EINPROGRESS) {
|
||||
int res;
|
||||
wfd.fd = c->fd;
|
||||
wfd.events = POLLOUT;
|
||||
end = msec >= 0 ? redisPollMillis() + msec : 0;
|
||||
|
||||
if ((res = poll(wfd, 1, msec)) == -1) {
|
||||
while ((res = poll(&wfd, 1, msec)) <= 0) {
|
||||
if (res < 0 && errno != EINTR) {
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else if (res == 0) {
|
||||
} else if (res == 0 || (msec >= 0 && redisPollMillis() >= end)) {
|
||||
errno = ETIMEDOUT;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else {
|
||||
/* res < 0 && errno == EINTR, try again */
|
||||
}
|
||||
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisCheckConnectDone(redisContext *c, int *completed) {
|
||||
|
||||
32
test.c
32
test.c
@ -104,6 +104,13 @@ static long long usec(void) {
|
||||
#define assert(e) (void)(e)
|
||||
#endif
|
||||
|
||||
#define redisTestPanic(msg) \
|
||||
do { \
|
||||
fprintf(stderr, "PANIC: %s (In function \"%s\", file \"%s\", line %d)\n", \
|
||||
msg, __func__, __FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
} while (1)
|
||||
|
||||
/* Helper to extract Redis version information. Aborts on any failure. */
|
||||
#define REDIS_VERSION_FIELD "redis_version:"
|
||||
void get_redis_version(redisContext *c, int *majorptr, int *minorptr) {
|
||||
@ -232,7 +239,7 @@ static redisContext *do_connect(struct config config) {
|
||||
c = redisConnectFd(fd);
|
||||
}
|
||||
} else {
|
||||
assert(NULL);
|
||||
redisTestPanic("Unknown connection type!");
|
||||
}
|
||||
|
||||
if (c == NULL) {
|
||||
@ -424,6 +431,24 @@ static void test_tcp_options(struct config cfg) {
|
||||
redisFree(c);
|
||||
}
|
||||
|
||||
static void test_unix_keepalive(struct config cfg) {
|
||||
redisContext *c;
|
||||
redisReply *r;
|
||||
|
||||
c = do_connect(cfg);
|
||||
|
||||
test("Setting TCP_KEEPALIVE on a unix socket returns an error: ");
|
||||
test_cond(redisEnableKeepAlive(c) == REDIS_ERR && c->err == 0);
|
||||
|
||||
test("Setting TCP_KEEPALIVE on a unix socket doesn't break the connection: ");
|
||||
r = redisCommand(c, "PING");
|
||||
test_cond(r != NULL && r->type == REDIS_REPLY_STATUS && r->len == 4 &&
|
||||
!memcmp(r->str, "PONG", 4));
|
||||
freeReplyObject(r);
|
||||
|
||||
redisFree(c);
|
||||
}
|
||||
|
||||
static void test_reply_reader(void) {
|
||||
redisReader *reader;
|
||||
void *reply, *root;
|
||||
@ -1352,7 +1377,7 @@ static void test_invalid_timeout_errors(struct config config) {
|
||||
} else if(config.type == CONN_UNIX) {
|
||||
c = redisConnectUnixWithTimeout(config.unix_sock.path, config.connect_timeout);
|
||||
} else {
|
||||
assert(NULL);
|
||||
redisTestPanic("Unknown connection type!");
|
||||
}
|
||||
|
||||
test_cond(c != NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
|
||||
@ -1368,7 +1393,7 @@ static void test_invalid_timeout_errors(struct config config) {
|
||||
} else if(config.type == CONN_UNIX) {
|
||||
c = redisConnectUnixWithTimeout(config.unix_sock.path, config.connect_timeout);
|
||||
} else {
|
||||
assert(NULL);
|
||||
redisTestPanic("Unknown connection type!");
|
||||
}
|
||||
|
||||
test_cond(c != NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
|
||||
@ -2473,6 +2498,7 @@ int main(int argc, char **argv) {
|
||||
test_blocking_connection_timeouts(cfg);
|
||||
test_blocking_io_errors(cfg);
|
||||
test_invalid_timeout_errors(cfg);
|
||||
test_unix_keepalive(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
} else {
|
||||
test_skipped();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user