Unverified Commit b6a052fe authored by Viktor Söderqvist's avatar Viktor Söderqvist Committed by GitHub
Browse files

Helper for setting TCP_USER_TIMEOUT socket option (#1188)

* Implement redisSetTcpUserTimeout to set socket option TCP_USER_TIMEOUT

* Documentation for redisSetTcpUserTimeout and some more undocumented functions

Documentation for redisReconnect() and the setters of socket options:

* redisKeepAlive()
* redisEnableKeepAliveWithInterval()
* redisSetTcpUserTimeout()
parent 3fa9b694
...@@ -123,6 +123,8 @@ REDIS_OPTIONS_SET_PRIVDATA(&opt, myPrivData, myPrivDataDtor); ...@@ -123,6 +123,8 @@ REDIS_OPTIONS_SET_PRIVDATA(&opt, myPrivData, myPrivDataDtor);
opt->options |= REDIS_OPT_PREFER_IPV4; opt->options |= REDIS_OPT_PREFER_IPV4;
``` ```
If a connection is lost, `int redisReconnect(redisContext *c)` can be used to restore the connection using the same endpoint and options as the given context.
### Configurable redisOptions flags ### Configurable redisOptions flags
There are several flags you may set in the `redisOptions` struct to change default behavior. You can specify the flags via the `redisOptions->options` member. There are several flags you may set in the `redisOptions` struct to change default behavior. You can specify the flags via the `redisOptions->options` member.
...@@ -138,6 +140,36 @@ There are several flags you may set in the `redisOptions` struct to change defau ...@@ -138,6 +140,36 @@ There are several flags you may set in the `redisOptions` struct to change defau
*Note: A `redisContext` is not thread-safe.* *Note: A `redisContext` is not thread-safe.*
### Other configuration using socket options
The following socket options are applied directly to the underlying socket.
The values are not stored in the `redisContext`, so they are not automatically applied when reconnecting using `redisReconnect()`.
These functions return `REDIS_OK` on success.
On failure, `REDIS_ERR` is returned and the underlying connection is closed.
To configure these for an asyncronous context (see *Asynchronous API* below), use `ac->c` to get the redisContext out of an asyncRedisContext.
```C
int redisEnableKeepAlive(redisContext *c);
int redisEnableKeepAliveWithInterval(redisContext *c, int interval);
```
Enables TCP keepalive by setting the following socket options (with some variations depending on OS):
* `SO_KEEPALIVE`;
* `TCP_KEEPALIVE` or `TCP_KEEPIDLE`, value configurable using the `interval` parameter, default 15 seconds;
* `TCP_KEEPINTVL` set to 1/3 of `interval`;
* `TCP_KEEPCNT` set to 3.
```C
int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout);
```
Set the `TCP_USER_TIMEOUT` Linux-specific socket option which is as described in the `tcp` man page:
> When the value is greater than 0, it specifies the maximum amount of time in milliseconds that trans mitted data may remain unacknowledged before TCP will forcibly close the corresponding connection and return ETIMEDOUT to the application.
> If the option value is specified as 0, TCP will use the system default.
### Sending commands ### Sending commands
There are several ways to issue commands to Redis. The first that will be introduced is There are several ways to issue commands to Redis. The first that will be introduced is
...@@ -451,7 +483,6 @@ void appOnDisconnect(redisAsyncContext *c, int status) ...@@ -451,7 +483,6 @@ void appOnDisconnect(redisAsyncContext *c, int status)
} }
``` ```
### Sending commands and their callbacks ### Sending commands and their callbacks
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
......
...@@ -953,6 +953,11 @@ int redisEnableKeepAlive(redisContext *c) { ...@@ -953,6 +953,11 @@ int redisEnableKeepAlive(redisContext *c) {
return redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL); return redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL);
} }
/* Set the socket option TCP_USER_TIMEOUT. */
int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout) {
return redisContextSetTcpUserTimeout(c, timeout);
}
/* Set a user provided RESP3 PUSH handler and return any old one set. */ /* Set a user provided RESP3 PUSH handler and return any old one set. */
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) { redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) {
redisPushFn *old = c->push_cb; redisPushFn *old = c->push_cb;
......
...@@ -323,6 +323,7 @@ redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); ...@@ -323,6 +323,7 @@ redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn);
int redisSetTimeout(redisContext *c, const struct timeval tv); int redisSetTimeout(redisContext *c, const struct timeval tv);
int redisEnableKeepAlive(redisContext *c); int redisEnableKeepAlive(redisContext *c);
int redisEnableKeepAliveWithInterval(redisContext *c, int interval); int redisEnableKeepAliveWithInterval(redisContext *c, int interval);
int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout);
void redisFree(redisContext *c); void redisFree(redisContext *c);
redisFD redisFreeKeepFd(redisContext *c); redisFD redisFreeKeepFd(redisContext *c);
int redisBufferRead(redisContext *c); int redisBufferRead(redisContext *c);
......
...@@ -228,6 +228,22 @@ int redisSetTcpNoDelay(redisContext *c) { ...@@ -228,6 +228,22 @@ int redisSetTcpNoDelay(redisContext *c) {
return REDIS_OK; return REDIS_OK;
} }
int redisContextSetTcpUserTimeout(redisContext *c, unsigned int timeout) {
int res;
#ifdef TCP_USER_TIMEOUT
res = setsockopt(c->fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout));
#else
res = -1;
(void)timeout;
#endif
if (res == -1); {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_USER_TIMEOUT)");
redisNetClose(c);
return REDIS_ERR;
}
return REDIS_OK;
}
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) #define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
static int redisContextTimeoutMsec(redisContext *c, long *result) static int redisContextTimeoutMsec(redisContext *c, long *result)
......
...@@ -52,5 +52,6 @@ int redisKeepAlive(redisContext *c, int interval); ...@@ -52,5 +52,6 @@ int redisKeepAlive(redisContext *c, int interval);
int redisCheckConnectDone(redisContext *c, int *completed); int redisCheckConnectDone(redisContext *c, int *completed);
int redisSetTcpNoDelay(redisContext *c); int redisSetTcpNoDelay(redisContext *c);
int redisContextSetTcpUserTimeout(redisContext *c, unsigned int timeout);
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment