Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
d0854927
Commit
d0854927
authored
Jan 31, 2021
by
Oran Agra
Browse files
Merge branch 'unstable' into 6.2
parents
ec2d1807
b57d0eb4
Changes
89
Hide whitespace changes
Inline
Side-by-side
.github/workflows/ci.yml
View file @
d0854927
...
@@ -58,3 +58,14 @@ jobs:
...
@@ -58,3 +58,14 @@ jobs:
run
:
|
run
:
|
yum -y install gcc make
yum -y install gcc make
make REDIS_CFLAGS='-Werror'
make REDIS_CFLAGS='-Werror'
build-freebsd
:
runs-on
:
macos-latest
steps
:
-
uses
:
actions/checkout@v2
-
name
:
make
uses
:
vmactions/freebsd-vm@v0.1.0
with
:
usesh
:
true
prepare
:
pkg install -y gmake
run
:
gmake
.github/workflows/daily.yml
View file @
d0854927
...
@@ -99,6 +99,23 @@ jobs:
...
@@ -99,6 +99,23 @@ jobs:
./runtest-cluster --tls
./runtest-cluster --tls
./runtest-cluster
./runtest-cluster
test-ubuntu-io-threads
:
runs-on
:
ubuntu-latest
if
:
github.repository == 'redis/redis'
timeout-minutes
:
14400
steps
:
-
uses
:
actions/checkout@v2
-
name
:
make
run
:
|
make
-
name
:
test
run
:
|
sudo apt-get install tcl8.5 tcl-tls
./runtest --config io-threads 4 --config io-threads-do-reads yes --accurate --verbose --tags network
-
name
:
cluster tests
run
:
|
./runtest-cluster --config io-threads 4 --config io-threads-do-reads yes
test-valgrind
:
test-valgrind
:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
if
:
github.repository == 'redis/redis'
if
:
github.repository == 'redis/redis'
...
@@ -186,3 +203,20 @@ jobs:
...
@@ -186,3 +203,20 @@ jobs:
-
name
:
cluster tests
-
name
:
cluster tests
run
:
./runtest-cluster
run
:
./runtest-cluster
test-freebsd
:
runs-on
:
macos-latest
if
:
github.repository == 'redis/redis'
timeout-minutes
:
14400
steps
:
-
uses
:
actions/checkout@v2
-
name
:
test
uses
:
vmactions/freebsd-vm@v0.1.0
with
:
usesh
:
true
prepare
:
pkg install -y gmake lang/tcl85
run
:
|
gmake
./runtest --accurate --verbose --no-latency
MAKE=gmake ./runtest-moduleapi --verbose
./runtest-sentinel
./runtest-cluster
redis.conf
View file @
d0854927
...
@@ -325,31 +325,52 @@ databases 16
...
@@ -325,31 +325,52 @@ databases 16
# ASCII art logo in startup logs by setting the following option to yes.
# ASCII art logo in startup logs by setting the following option to yes.
always
-
show
-
logo
no
always
-
show
-
logo
no
# By default, Redis modifies the process title (as seen in 'top' and 'ps') to
# provide some runtime information. It is possible to disable this and leave
# the process name as executed by setting the following to no.
set
-
proc
-
title
yes
# When changing the process title, Redis uses the following template to construct
# the modified title.
#
# Template variables are specified in curly brackets. The following variables are
# supported:
#
# {title} Name of process as executed if parent, or type of child process.
# {listen-addr} Bind address or '*' followed by TCP or TLS port listening on, or
# Unix socket if only that's available.
# {server-mode} Special mode, i.e. "[sentinel]" or "[cluster]".
# {port} TCP port listening on, or 0.
# {tls-port} TLS port listening on, or 0.
# {unixsocket} Unix domain socket listening on, or "".
# {config-file} Name of configuration file used.
#
proc
-
title
-
template
"{title} {listen-addr} {server-mode}"
################################ SNAPSHOTTING ################################
################################ SNAPSHOTTING ################################
# Save the DB to disk.
#
#
#
S
ave
the DB on disk:
#
s
ave
<seconds> <changes>
#
#
# save <seconds> <changes>
# Redis will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
#
#
Will save the DB if both the given number of seconds and the given
#
Snapshotting can be completely disabled with a single empty string argument
#
number of write operations against the DB occurred.
#
as in following example:
#
#
# In the example below the behavior will be to save:
# save ""
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
#
# Note: you can disable saving completely by commenting out all "save" lines.
# Unless specified otherwise, by default Redis will save the DB:
# * After 3600 seconds (an hour) if at least 1 key changed
# * After 300 seconds (5 minutes) if at least 100 keys changed
# * After 60 seconds if at least 10000 keys changed
#
#
# It is also possible to remove all the previously configured save
# You can set these explicitly by uncommenting the three following lines.
# points by adding a save directive with a single empty string argument
# like in the following example:
#
#
# save ""
# save 3600 1
# save 300 100
save
900
1
# save 60 10000
save
300
10
save
60
10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# (at least one save point) and the latest background save failed.
...
@@ -1089,6 +1110,13 @@ replica-lazy-flush no
...
@@ -1089,6 +1110,13 @@ replica-lazy-flush no
lazyfree
-
lazy
-
user
-
del
no
lazyfree
-
lazy
-
user
-
del
no
# FLUSHDB, FLUSHALL, and SCRIPT FLUSH support both asynchronous and synchronous
# deletion, which can be controlled by passing the [SYNC|ASYNC] flags into the
# commands. When neither flag is passed, this directive will be used to determine
# if the data should be deleted asynchronously.
lazyfree
-
lazy
-
user
-
flush
no
################################ THREADED I/O #################################
################################ THREADED I/O #################################
# Redis is mostly single threaded, however there are certain threaded
# Redis is mostly single threaded, however there are certain threaded
...
...
runtest-moduleapi
View file @
d0854927
...
@@ -23,6 +23,7 @@ $TCLSH tests/test_helper.tcl \
...
@@ -23,6 +23,7 @@ $TCLSH tests/test_helper.tcl \
--single
unit/moduleapi/hooks
\
--single
unit/moduleapi/hooks
\
--single
unit/moduleapi/misc
\
--single
unit/moduleapi/misc
\
--single
unit/moduleapi/blockonkeys
\
--single
unit/moduleapi/blockonkeys
\
--single
unit/moduleapi/blockonbackground
\
--single
unit/moduleapi/scan
\
--single
unit/moduleapi/scan
\
--single
unit/moduleapi/datatype
\
--single
unit/moduleapi/datatype
\
--single
unit/moduleapi/auth
\
--single
unit/moduleapi/auth
\
...
@@ -31,4 +32,5 @@ $TCLSH tests/test_helper.tcl \
...
@@ -31,4 +32,5 @@ $TCLSH tests/test_helper.tcl \
--single
unit/moduleapi/getkeys
\
--single
unit/moduleapi/getkeys
\
--single
unit/moduleapi/test_lazyfree
\
--single
unit/moduleapi/test_lazyfree
\
--single
unit/moduleapi/defrag
\
--single
unit/moduleapi/defrag
\
--single
unit/moduleapi/stream
\
"
${
@
}
"
"
${
@
}
"
sentinel.conf
View file @
d0854927
...
@@ -321,3 +321,21 @@ sentinel deny-scripts-reconfig yes
...
@@ -321,3 +321,21 @@ sentinel deny-scripts-reconfig yes
# is possible to just rename a command to itself:
# is possible to just rename a command to itself:
#
#
# SENTINEL rename-command mymaster CONFIG CONFIG
# SENTINEL rename-command mymaster CONFIG CONFIG
# HOSTNAMES SUPPORT
#
# Normally Sentinel uses only IP addresses and requires SENTINEL MONITOR
# to specify an IP address. Also, it requires the Redis replica-announce-ip
# keyword to specify only IP addresses.
#
# You may enable hostnames support by enabling resolve-hostnames. Note
# that you must make sure your DNS is configured properly and that DNS
# resolution does not introduce very long delays.
#
SENTINEL
resolve
-
hostnames
no
# When resolve-hostnames is enabled, Sentinel still uses IP addresses
# when exposing instances to users, configuration files, etc. If you want
# to retain the hostnames when announced, enable announce-hostnames below.
#
SENTINEL
announce
-
hostnames
no
src/acl.c
View file @
d0854927
...
@@ -1024,8 +1024,8 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
...
@@ -1024,8 +1024,8 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
/* Return a description of the error that occurred in ACLSetUser() according to
/* Return a description of the error that occurred in ACLSetUser() according to
* the errno value set by the function on error. */
* the errno value set by the function on error. */
char
*
ACLSetUserStringError
(
void
)
{
const
char
*
ACLSetUserStringError
(
void
)
{
char
*
errmsg
=
"Wrong format"
;
const
char
*
errmsg
=
"Wrong format"
;
if
(
errno
==
ENOENT
)
if
(
errno
==
ENOENT
)
errmsg
=
"Unknown command or category name in ACL"
;
errmsg
=
"Unknown command or category name in ACL"
;
else
if
(
errno
==
EINVAL
)
else
if
(
errno
==
EINVAL
)
...
@@ -1454,7 +1454,7 @@ int ACLLoadConfiguredUsers(void) {
...
@@ -1454,7 +1454,7 @@ int ACLLoadConfiguredUsers(void) {
/* Load every rule defined for this user. */
/* Load every rule defined for this user. */
for
(
int
j
=
1
;
aclrules
[
j
];
j
++
)
{
for
(
int
j
=
1
;
aclrules
[
j
];
j
++
)
{
if
(
ACLSetUser
(
u
,
aclrules
[
j
],
sdslen
(
aclrules
[
j
]))
!=
C_OK
)
{
if
(
ACLSetUser
(
u
,
aclrules
[
j
],
sdslen
(
aclrules
[
j
]))
!=
C_OK
)
{
char
*
errmsg
=
ACLSetUserStringError
();
const
char
*
errmsg
=
ACLSetUserStringError
();
serverLog
(
LL_WARNING
,
"Error loading ACL rule '%s' for "
serverLog
(
LL_WARNING
,
"Error loading ACL rule '%s' for "
"the user named '%s': %s"
,
"the user named '%s': %s"
,
aclrules
[
j
],
aclrules
[
0
],
errmsg
);
aclrules
[
j
],
aclrules
[
0
],
errmsg
);
...
@@ -1587,7 +1587,7 @@ sds ACLLoadFromFile(const char *filename) {
...
@@ -1587,7 +1587,7 @@ sds ACLLoadFromFile(const char *filename) {
for
(
j
=
2
;
j
<
argc
;
j
++
)
{
for
(
j
=
2
;
j
<
argc
;
j
++
)
{
argv
[
j
]
=
sdstrim
(
argv
[
j
],
"
\t\r\n
"
);
argv
[
j
]
=
sdstrim
(
argv
[
j
],
"
\t\r\n
"
);
if
(
ACLSetUser
(
fakeuser
,
argv
[
j
],
sdslen
(
argv
[
j
]))
!=
C_OK
)
{
if
(
ACLSetUser
(
fakeuser
,
argv
[
j
],
sdslen
(
argv
[
j
]))
!=
C_OK
)
{
char
*
errmsg
=
ACLSetUserStringError
();
const
char
*
errmsg
=
ACLSetUserStringError
();
errors
=
sdscatprintf
(
errors
,
errors
=
sdscatprintf
(
errors
,
"%s:%d: %s. "
,
"%s:%d: %s. "
,
server
.
acl_filename
,
linenum
,
errmsg
);
server
.
acl_filename
,
linenum
,
errmsg
);
...
@@ -1908,7 +1908,7 @@ void aclCommand(client *c) {
...
@@ -1908,7 +1908,7 @@ void aclCommand(client *c) {
for
(
int
j
=
3
;
j
<
c
->
argc
;
j
++
)
{
for
(
int
j
=
3
;
j
<
c
->
argc
;
j
++
)
{
if
(
ACLSetUser
(
tempu
,
c
->
argv
[
j
]
->
ptr
,
sdslen
(
c
->
argv
[
j
]
->
ptr
))
!=
C_OK
)
{
if
(
ACLSetUser
(
tempu
,
c
->
argv
[
j
]
->
ptr
,
sdslen
(
c
->
argv
[
j
]
->
ptr
))
!=
C_OK
)
{
char
*
errmsg
=
ACLSetUserStringError
();
const
char
*
errmsg
=
ACLSetUserStringError
();
addReplyErrorFormat
(
c
,
addReplyErrorFormat
(
c
,
"Error in ACL SETUSER modifier '%s': %s"
,
"Error in ACL SETUSER modifier '%s': %s"
,
(
char
*
)
c
->
argv
[
j
]
->
ptr
,
errmsg
);
(
char
*
)
c
->
argv
[
j
]
->
ptr
,
errmsg
);
...
...
src/ae.c
View file @
d0854927
...
@@ -31,6 +31,7 @@
...
@@ -31,6 +31,7 @@
*/
*/
#include "ae.h"
#include "ae.h"
#include "anet.h"
#include <stdio.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/time.h>
...
...
src/ae_epoll.c
View file @
d0854927
...
@@ -51,6 +51,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
...
@@ -51,6 +51,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
zfree
(
state
);
zfree
(
state
);
return
-
1
;
return
-
1
;
}
}
anetCloexec
(
state
->
epfd
);
eventLoop
->
apidata
=
state
;
eventLoop
->
apidata
=
state
;
return
0
;
return
0
;
}
}
...
...
src/ae_evport.c
View file @
d0854927
...
@@ -82,6 +82,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
...
@@ -82,6 +82,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
zfree
(
state
);
zfree
(
state
);
return
-
1
;
return
-
1
;
}
}
anetCloexec
(
state
->
portfd
);
state
->
npending
=
0
;
state
->
npending
=
0
;
...
...
src/ae_kqueue.c
View file @
d0854927
...
@@ -53,6 +53,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
...
@@ -53,6 +53,7 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
zfree
(
state
);
zfree
(
state
);
return
-
1
;
return
-
1
;
}
}
anetCloexec
(
state
->
kqfd
);
eventLoop
->
apidata
=
state
;
eventLoop
->
apidata
=
state
;
return
0
;
return
0
;
}
}
...
...
src/anet.c
View file @
d0854927
...
@@ -69,6 +69,11 @@ int anetSetBlock(char *err, int fd, int non_block) {
...
@@ -69,6 +69,11 @@ int anetSetBlock(char *err, int fd, int non_block) {
return
ANET_ERR
;
return
ANET_ERR
;
}
}
/* Check if this flag has been set or unset, if so,
* then there is no need to call fcntl to set/unset it again. */
if
(
!!
(
flags
&
O_NONBLOCK
)
==
!!
non_block
)
return
ANET_OK
;
if
(
non_block
)
if
(
non_block
)
flags
|=
O_NONBLOCK
;
flags
|=
O_NONBLOCK
;
else
else
...
@@ -89,6 +94,29 @@ int anetBlock(char *err, int fd) {
...
@@ -89,6 +94,29 @@ int anetBlock(char *err, int fd) {
return
anetSetBlock
(
err
,
fd
,
0
);
return
anetSetBlock
(
err
,
fd
,
0
);
}
}
/* Enable the FD_CLOEXEC on the given fd to avoid fd leaks.
* This function should be invoked for fd's on specific places
* where fork + execve system calls are called. */
int
anetCloexec
(
int
fd
)
{
int
r
;
int
flags
;
do
{
r
=
fcntl
(
fd
,
F_GETFD
);
}
while
(
r
==
-
1
&&
errno
==
EINTR
);
if
(
r
==
-
1
||
(
r
&
FD_CLOEXEC
))
return
r
;
flags
=
r
|
FD_CLOEXEC
;
do
{
r
=
fcntl
(
fd
,
F_SETFD
,
flags
);
}
while
(
r
==
-
1
&&
errno
==
EINTR
);
return
r
;
}
/* Set TCP keep alive option to detect dead peers. The interval option
/* Set TCP keep alive option to detect dead peers. The interval option
* is only used for Linux as we are using Linux-specific APIs to set
* is only used for Linux as we are using Linux-specific APIs to set
* the probe send time, interval, and count. */
* the probe send time, interval, and count. */
...
@@ -207,14 +235,13 @@ int anetRecvTimeout(char *err, int fd, long long ms) {
...
@@ -207,14 +235,13 @@ int anetRecvTimeout(char *err, int fd, long long ms) {
return
ANET_OK
;
return
ANET_OK
;
}
}
/* anetGenericResolve() is called by anetResolve() and anetResolveIP() to
/* Resolve the hostname "host" and set the string representation of the
* do the actual work. It resolves the hostname "host" and set the string
* IP address into the buffer pointed by "ipbuf".
* representation of the IP address into the buffer pointed by "ipbuf".
*
*
* If flags is set to ANET_IP_ONLY the function only resolves hostnames
* If flags is set to ANET_IP_ONLY the function only resolves hostnames
* that are actually already IPv4 or IPv6 addresses. This turns the function
* that are actually already IPv4 or IPv6 addresses. This turns the function
* into a validating / normalizing function. */
* into a validating / normalizing function. */
int
anet
Generic
Resolve
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
,
int
anetResolve
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
,
int
flags
)
int
flags
)
{
{
struct
addrinfo
hints
,
*
info
;
struct
addrinfo
hints
,
*
info
;
...
@@ -241,14 +268,6 @@ int anetGenericResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len,
...
@@ -241,14 +268,6 @@ int anetGenericResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len,
return
ANET_OK
;
return
ANET_OK
;
}
}
int
anetResolve
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
)
{
return
anetGenericResolve
(
err
,
host
,
ipbuf
,
ipbuf_len
,
ANET_NONE
);
}
int
anetResolveIP
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
)
{
return
anetGenericResolve
(
err
,
host
,
ipbuf
,
ipbuf_len
,
ANET_IP_ONLY
);
}
static
int
anetSetReuseAddr
(
char
*
err
,
int
fd
)
{
static
int
anetSetReuseAddr
(
char
*
err
,
int
fd
)
{
int
yes
=
1
;
int
yes
=
1
;
/* Make sure connection-intensive things like the redis benchmark
/* Make sure connection-intensive things like the redis benchmark
...
...
src/anet.h
View file @
d0854927
...
@@ -60,8 +60,7 @@ int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
...
@@ -60,8 +60,7 @@ int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
int
anetUnixConnect
(
char
*
err
,
const
char
*
path
);
int
anetUnixConnect
(
char
*
err
,
const
char
*
path
);
int
anetUnixNonBlockConnect
(
char
*
err
,
const
char
*
path
);
int
anetUnixNonBlockConnect
(
char
*
err
,
const
char
*
path
);
int
anetRead
(
int
fd
,
char
*
buf
,
int
count
);
int
anetRead
(
int
fd
,
char
*
buf
,
int
count
);
int
anetResolve
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
);
int
anetResolve
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
,
int
flags
);
int
anetResolveIP
(
char
*
err
,
char
*
host
,
char
*
ipbuf
,
size_t
ipbuf_len
);
int
anetTcpServer
(
char
*
err
,
int
port
,
char
*
bindaddr
,
int
backlog
);
int
anetTcpServer
(
char
*
err
,
int
port
,
char
*
bindaddr
,
int
backlog
);
int
anetTcp6Server
(
char
*
err
,
int
port
,
char
*
bindaddr
,
int
backlog
);
int
anetTcp6Server
(
char
*
err
,
int
port
,
char
*
bindaddr
,
int
backlog
);
int
anetUnixServer
(
char
*
err
,
char
*
path
,
mode_t
perm
,
int
backlog
);
int
anetUnixServer
(
char
*
err
,
char
*
path
,
mode_t
perm
,
int
backlog
);
...
@@ -70,6 +69,7 @@ int anetUnixAccept(char *err, int serversock);
...
@@ -70,6 +69,7 @@ int anetUnixAccept(char *err, int serversock);
int
anetWrite
(
int
fd
,
char
*
buf
,
int
count
);
int
anetWrite
(
int
fd
,
char
*
buf
,
int
count
);
int
anetNonBlock
(
char
*
err
,
int
fd
);
int
anetNonBlock
(
char
*
err
,
int
fd
);
int
anetBlock
(
char
*
err
,
int
fd
);
int
anetBlock
(
char
*
err
,
int
fd
);
int
anetCloexec
(
int
fd
);
int
anetEnableTcpNoDelay
(
char
*
err
,
int
fd
);
int
anetEnableTcpNoDelay
(
char
*
err
,
int
fd
);
int
anetDisableTcpNoDelay
(
char
*
err
,
int
fd
);
int
anetDisableTcpNoDelay
(
char
*
err
,
int
fd
);
int
anetTcpKeepAlive
(
char
*
err
,
int
fd
);
int
anetTcpKeepAlive
(
char
*
err
,
int
fd
);
...
...
src/aof.c
View file @
d0854927
...
@@ -235,6 +235,8 @@ void stopAppendOnly(void) {
...
@@ -235,6 +235,8 @@ void stopAppendOnly(void) {
serverAssert
(
server
.
aof_state
!=
AOF_OFF
);
serverAssert
(
server
.
aof_state
!=
AOF_OFF
);
flushAppendOnlyFile
(
1
);
flushAppendOnlyFile
(
1
);
redis_fsync
(
server
.
aof_fd
);
redis_fsync
(
server
.
aof_fd
);
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
server
.
aof_last_fsync
=
server
.
unixtime
;
close
(
server
.
aof_fd
);
close
(
server
.
aof_fd
);
server
.
aof_fd
=
-
1
;
server
.
aof_fd
=
-
1
;
...
@@ -242,6 +244,8 @@ void stopAppendOnly(void) {
...
@@ -242,6 +244,8 @@ void stopAppendOnly(void) {
server
.
aof_state
=
AOF_OFF
;
server
.
aof_state
=
AOF_OFF
;
server
.
aof_rewrite_scheduled
=
0
;
server
.
aof_rewrite_scheduled
=
0
;
killAppendOnlyChild
();
killAppendOnlyChild
();
sdsfree
(
server
.
aof_buf
);
server
.
aof_buf
=
sdsempty
();
}
}
/* Called when the user switches from "appendonly no" to "appendonly yes"
/* Called when the user switches from "appendonly no" to "appendonly yes"
...
@@ -285,6 +289,12 @@ int startAppendOnly(void) {
...
@@ -285,6 +289,12 @@ int startAppendOnly(void) {
server
.
aof_state
=
AOF_WAIT_REWRITE
;
server
.
aof_state
=
AOF_WAIT_REWRITE
;
server
.
aof_last_fsync
=
server
.
unixtime
;
server
.
aof_last_fsync
=
server
.
unixtime
;
server
.
aof_fd
=
newfd
;
server
.
aof_fd
=
newfd
;
/* If AOF was in error state, we just ignore it and log the event. */
if
(
server
.
aof_last_write_status
==
C_ERR
)
{
serverLog
(
LL_WARNING
,
"AOF reopen, just ignore the last error."
);
server
.
aof_last_write_status
=
C_OK
;
}
return
C_OK
;
return
C_OK
;
}
}
...
@@ -451,10 +461,11 @@ void flushAppendOnlyFile(int force) {
...
@@ -451,10 +461,11 @@ void flushAppendOnlyFile(int force) {
/* Handle the AOF write error. */
/* Handle the AOF write error. */
if
(
server
.
aof_fsync
==
AOF_FSYNC_ALWAYS
)
{
if
(
server
.
aof_fsync
==
AOF_FSYNC_ALWAYS
)
{
/* We can't recover when the fsync policy is ALWAYS since the
/* We can't recover when the fsync policy is ALWAYS since the reply
* reply for the client is already in the output buffers, and we
* for the client is already in the output buffers (both writes and
* have the contract with the user that on acknowledged write data
* reads), and the changes to the db can't be rolled back. Since we
* is synced on disk. */
* have a contract with the user that on acknowledged or observed
* writes are is synced on disk, we must exit. */
serverLog
(
LL_WARNING
,
"Can't recover from AOF write error when the AOF fsync policy is 'always'. Exiting..."
);
serverLog
(
LL_WARNING
,
"Can't recover from AOF write error when the AOF fsync policy is 'always'. Exiting..."
);
exit
(
1
);
exit
(
1
);
}
else
{
}
else
{
...
@@ -502,7 +513,14 @@ try_fsync:
...
@@ -502,7 +513,14 @@ try_fsync:
/* redis_fsync is defined as fdatasync() for Linux in order to avoid
/* redis_fsync is defined as fdatasync() for Linux in order to avoid
* flushing metadata. */
* flushing metadata. */
latencyStartMonitor
(
latency
);
latencyStartMonitor
(
latency
);
redis_fsync
(
server
.
aof_fd
);
/* Let's try to get this data on the disk */
/* Let's try to get this data on the disk. To guarantee data safe when
* the AOF fsync policy is 'always', we should exit if failed to fsync
* AOF (see comment next to the exit(1) after write error above). */
if
(
redis_fsync
(
server
.
aof_fd
)
==
-
1
)
{
serverLog
(
LL_WARNING
,
"Can't persist AOF for fsync error when the "
"AOF fsync policy is 'always': %s. Exiting..."
,
strerror
(
errno
));
exit
(
1
);
}
latencyEndMonitor
(
latency
);
latencyEndMonitor
(
latency
);
latencyAddSampleIfNeeded
(
"aof-fsync-always"
,
latency
);
latencyAddSampleIfNeeded
(
"aof-fsync-always"
,
latency
);
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
...
@@ -581,8 +599,6 @@ sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, r
...
@@ -581,8 +599,6 @@ sds catAppendOnlyExpireAtCommand(sds buf, struct redisCommand *cmd, robj *key, r
void
feedAppendOnlyFile
(
struct
redisCommand
*
cmd
,
int
dictid
,
robj
**
argv
,
int
argc
)
{
void
feedAppendOnlyFile
(
struct
redisCommand
*
cmd
,
int
dictid
,
robj
**
argv
,
int
argc
)
{
sds
buf
=
sdsempty
();
sds
buf
=
sdsempty
();
robj
*
tmpargv
[
3
];
/* The DB this command was targeting is not the same as the last command
/* The DB this command was targeting is not the same as the last command
* we appended. To issue a SELECT command is needed. */
* we appended. To issue a SELECT command is needed. */
if
(
dictid
!=
server
.
aof_selected_db
)
{
if
(
dictid
!=
server
.
aof_selected_db
)
{
...
@@ -598,32 +614,31 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
...
@@ -598,32 +614,31 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
cmd
->
proc
==
expireatCommand
)
{
cmd
->
proc
==
expireatCommand
)
{
/* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */
/* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */
buf
=
catAppendOnlyExpireAtCommand
(
buf
,
cmd
,
argv
[
1
],
argv
[
2
]);
buf
=
catAppendOnlyExpireAtCommand
(
buf
,
cmd
,
argv
[
1
],
argv
[
2
]);
}
else
if
(
cmd
->
proc
==
setexCommand
||
cmd
->
proc
==
psetexCommand
)
{
/* Translate SETEX/PSETEX to SET and PEXPIREAT */
tmpargv
[
0
]
=
createStringObject
(
"SET"
,
3
);
tmpargv
[
1
]
=
argv
[
1
];
tmpargv
[
2
]
=
argv
[
3
];
buf
=
catAppendOnlyGenericCommand
(
buf
,
3
,
tmpargv
);
decrRefCount
(
tmpargv
[
0
]);
buf
=
catAppendOnlyExpireAtCommand
(
buf
,
cmd
,
argv
[
1
],
argv
[
2
]);
}
else
if
(
cmd
->
proc
==
setCommand
&&
argc
>
3
)
{
}
else
if
(
cmd
->
proc
==
setCommand
&&
argc
>
3
)
{
int
i
;
robj
*
pxarg
=
NULL
;
robj
*
exarg
=
NULL
,
*
pxarg
=
NULL
;
/* When SET is used with EX/PX argument setGenericCommand propagates them with PX millisecond argument.
for
(
i
=
3
;
i
<
argc
;
i
++
)
{
* So since the command arguments are re-written there, we can rely here on the index of PX being 3. */
if
(
!
strcasecmp
(
argv
[
i
]
->
ptr
,
"
e
x"
))
exarg
=
argv
[
i
+
1
];
if
(
!
strcasecmp
(
argv
[
3
]
->
ptr
,
"
p
x"
))
{
if
(
!
strcasecmp
(
argv
[
i
]
->
ptr
,
"px"
))
pxarg
=
argv
[
i
+
1
];
pxarg
=
argv
[
4
];
}
}
serverAssert
(
!
(
exarg
&&
pxarg
));
/* For AOF we convert SET key value relative time in milliseconds to SET key value absolute time in
* millisecond. Whenever the condition is true it implies that original SET has been transformed
if
(
exarg
||
pxarg
)
{
* to SET PX with millisecond time argument so we do not need to worry about unit here.*/
/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */
if
(
pxarg
)
{
buf
=
catAppendOnlyGenericCommand
(
buf
,
3
,
argv
);
robj
*
millisecond
=
getDecodedObject
(
pxarg
);
if
(
exarg
)
long
long
when
=
strtoll
(
millisecond
->
ptr
,
NULL
,
10
);
buf
=
catAppendOnlyExpireAtCommand
(
buf
,
server
.
expireCommand
,
argv
[
1
],
when
+=
mstime
();
exarg
);
if
(
pxarg
)
decrRefCount
(
millisecond
);
buf
=
catAppendOnlyExpireAtCommand
(
buf
,
server
.
pexpireCommand
,
argv
[
1
],
pxarg
);
robj
*
newargs
[
5
];
newargs
[
0
]
=
argv
[
0
];
newargs
[
1
]
=
argv
[
1
];
newargs
[
2
]
=
argv
[
2
];
newargs
[
3
]
=
shared
.
pxat
;
newargs
[
4
]
=
createStringObjectFromLongLong
(
when
);
buf
=
catAppendOnlyGenericCommand
(
buf
,
5
,
newargs
);
decrRefCount
(
newargs
[
4
]);
}
else
{
}
else
{
buf
=
catAppendOnlyGenericCommand
(
buf
,
argc
,
argv
);
buf
=
catAppendOnlyGenericCommand
(
buf
,
argc
,
argv
);
}
}
...
@@ -1852,6 +1867,20 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
...
@@ -1852,6 +1867,20 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
}
}
latencyEndMonitor
(
latency
);
latencyEndMonitor
(
latency
);
latencyAddSampleIfNeeded
(
"aof-rewrite-diff-write"
,
latency
);
latencyAddSampleIfNeeded
(
"aof-rewrite-diff-write"
,
latency
);
if
(
server
.
aof_fsync
==
AOF_FSYNC_EVERYSEC
)
{
aof_background_fsync
(
newfd
);
}
else
if
(
server
.
aof_fsync
==
AOF_FSYNC_ALWAYS
)
{
latencyStartMonitor
(
latency
);
if
(
redis_fsync
(
newfd
)
==
-
1
)
{
serverLog
(
LL_WARNING
,
"Error trying to fsync the parent diff to the rewritten AOF: %s"
,
strerror
(
errno
));
close
(
newfd
);
goto
cleanup
;
}
latencyEndMonitor
(
latency
);
latencyAddSampleIfNeeded
(
"aof-rewrite-done-fsync"
,
latency
);
}
serverLog
(
LL_NOTICE
,
serverLog
(
LL_NOTICE
,
"Residual parent diff successfully flushed to the rewritten AOF (%.2f MB)"
,
(
double
)
aofRewriteBufferSize
()
/
(
1024
*
1024
));
"Residual parent diff successfully flushed to the rewritten AOF (%.2f MB)"
,
(
double
)
aofRewriteBufferSize
()
/
(
1024
*
1024
));
...
@@ -1919,14 +1948,11 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
...
@@ -1919,14 +1948,11 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
/* AOF enabled, replace the old fd with the new one. */
/* AOF enabled, replace the old fd with the new one. */
oldfd
=
server
.
aof_fd
;
oldfd
=
server
.
aof_fd
;
server
.
aof_fd
=
newfd
;
server
.
aof_fd
=
newfd
;
if
(
server
.
aof_fsync
==
AOF_FSYNC_ALWAYS
)
redis_fsync
(
newfd
);
else
if
(
server
.
aof_fsync
==
AOF_FSYNC_EVERYSEC
)
aof_background_fsync
(
newfd
);
server
.
aof_selected_db
=
-
1
;
/* Make sure SELECT is re-issued */
server
.
aof_selected_db
=
-
1
;
/* Make sure SELECT is re-issued */
aofUpdateCurrentSize
();
aofUpdateCurrentSize
();
server
.
aof_rewrite_base_size
=
server
.
aof_current_size
;
server
.
aof_rewrite_base_size
=
server
.
aof_current_size
;
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
server
.
aof_last_fsync
=
server
.
unixtime
;
/* Clear regular AOF buffer since its contents was just written to
/* Clear regular AOF buffer since its contents was just written to
* the new AOF from the background rewrite buffer. */
* the new AOF from the background rewrite buffer. */
...
...
src/blocked.c
View file @
d0854927
...
@@ -61,6 +61,9 @@
...
@@ -61,6 +61,9 @@
*/
*/
#include "server.h"
#include "server.h"
#include "slowlog.h"
#include "latency.h"
#include "monotonic.h"
int
serveClientBlockedOnList
(
client
*
receiver
,
robj
*
key
,
robj
*
dstkey
,
redisDb
*
db
,
robj
*
value
,
int
wherefrom
,
int
whereto
);
int
serveClientBlockedOnList
(
client
*
receiver
,
robj
*
key
,
robj
*
dstkey
,
redisDb
*
db
,
robj
*
value
,
int
wherefrom
,
int
whereto
);
int
getListPositionFromObjectOrReply
(
client
*
c
,
robj
*
arg
,
int
*
position
);
int
getListPositionFromObjectOrReply
(
client
*
c
,
robj
*
arg
,
int
*
position
);
...
@@ -97,6 +100,20 @@ void blockClient(client *c, int btype) {
...
@@ -97,6 +100,20 @@ void blockClient(client *c, int btype) {
}
}
}
}
/* This function is called after a client has finished a blocking operation
* in order to update the total command duration, log the command into
* the Slow log if needed, and log the reply duration event if needed. */
void
updateStatsOnUnblock
(
client
*
c
,
long
blocked_us
,
long
reply_us
){
const
ustime_t
total_cmd_duration
=
c
->
duration
+
blocked_us
+
reply_us
;
c
->
lastcmd
->
microseconds
+=
total_cmd_duration
;
/* Log the command into the Slow log if needed. */
if
(
!
(
c
->
lastcmd
->
flags
&
CMD_SKIP_SLOWLOG
))
{
slowlogPushEntryIfNeeded
(
c
,
c
->
argv
,
c
->
argc
,
total_cmd_duration
);
/* Log the reply duration event. */
latencyAddSampleIfNeeded
(
"command-unblocking"
,
reply_us
/
1000
);
}
}
/* This function is called in the beforeSleep() function of the event loop
/* This function is called in the beforeSleep() function of the event loop
* in order to process the pending input buffer of clients that were
* in order to process the pending input buffer of clients that were
* unblocked after a blocking operation. */
* unblocked after a blocking operation. */
...
@@ -264,6 +281,8 @@ void serveClientsBlockedOnListKey(robj *o, readyList *rl) {
...
@@ -264,6 +281,8 @@ void serveClientsBlockedOnListKey(robj *o, readyList *rl) {
if
(
dstkey
)
incrRefCount
(
dstkey
);
if
(
dstkey
)
incrRefCount
(
dstkey
);
unblockClient
(
receiver
);
unblockClient
(
receiver
);
monotime
replyTimer
;
elapsedStart
(
&
replyTimer
);
if
(
serveClientBlockedOnList
(
receiver
,
if
(
serveClientBlockedOnList
(
receiver
,
rl
->
key
,
dstkey
,
rl
->
db
,
value
,
rl
->
key
,
dstkey
,
rl
->
db
,
value
,
wherefrom
,
whereto
)
==
C_ERR
)
wherefrom
,
whereto
)
==
C_ERR
)
...
@@ -272,6 +291,7 @@ void serveClientsBlockedOnListKey(robj *o, readyList *rl) {
...
@@ -272,6 +291,7 @@ void serveClientsBlockedOnListKey(robj *o, readyList *rl) {
* to also undo the POP operation. */
* to also undo the POP operation. */
listTypePush
(
o
,
value
,
wherefrom
);
listTypePush
(
o
,
value
,
wherefrom
);
}
}
updateStatsOnUnblock
(
receiver
,
0
,
elapsedUs
(
replyTimer
));
if
(
dstkey
)
decrRefCount
(
dstkey
);
if
(
dstkey
)
decrRefCount
(
dstkey
);
decrRefCount
(
value
);
decrRefCount
(
value
);
...
@@ -316,7 +336,10 @@ void serveClientsBlockedOnSortedSetKey(robj *o, readyList *rl) {
...
@@ -316,7 +336,10 @@ void serveClientsBlockedOnSortedSetKey(robj *o, readyList *rl) {
receiver
->
lastcmd
->
proc
==
bzpopminCommand
)
receiver
->
lastcmd
->
proc
==
bzpopminCommand
)
?
ZSET_MIN
:
ZSET_MAX
;
?
ZSET_MIN
:
ZSET_MAX
;
unblockClient
(
receiver
);
unblockClient
(
receiver
);
monotime
replyTimer
;
elapsedStart
(
&
replyTimer
);
genericZpopCommand
(
receiver
,
&
rl
->
key
,
1
,
where
,
1
,
NULL
);
genericZpopCommand
(
receiver
,
&
rl
->
key
,
1
,
where
,
1
,
NULL
);
updateStatsOnUnblock
(
receiver
,
0
,
elapsedUs
(
replyTimer
));
zcard
--
;
zcard
--
;
/* Replicate the command. */
/* Replicate the command. */
...
@@ -406,6 +429,8 @@ void serveClientsBlockedOnStreamKey(robj *o, readyList *rl) {
...
@@ -406,6 +429,8 @@ void serveClientsBlockedOnStreamKey(robj *o, readyList *rl) {
}
}
}
}
monotime
replyTimer
;
elapsedStart
(
&
replyTimer
);
/* Emit the two elements sub-array consisting of
/* Emit the two elements sub-array consisting of
* the name of the stream and the data we
* the name of the stream and the data we
* extracted from it. Wrapped in a single-item
* extracted from it. Wrapped in a single-item
...
@@ -425,6 +450,7 @@ void serveClientsBlockedOnStreamKey(robj *o, readyList *rl) {
...
@@ -425,6 +450,7 @@ void serveClientsBlockedOnStreamKey(robj *o, readyList *rl) {
streamReplyWithRange
(
receiver
,
s
,
&
start
,
NULL
,
streamReplyWithRange
(
receiver
,
s
,
&
start
,
NULL
,
receiver
->
bpop
.
xread_count
,
receiver
->
bpop
.
xread_count
,
0
,
group
,
consumer
,
noack
,
&
pi
);
0
,
group
,
consumer
,
noack
,
&
pi
);
updateStatsOnUnblock
(
receiver
,
0
,
elapsedUs
(
replyTimer
));
/* Note that after we unblock the client, 'gt'
/* Note that after we unblock the client, 'gt'
* and other receiver->bpop stuff are no longer
* and other receiver->bpop stuff are no longer
...
@@ -471,7 +497,10 @@ void serveClientsBlockedOnKeyByModule(readyList *rl) {
...
@@ -471,7 +497,10 @@ void serveClientsBlockedOnKeyByModule(readyList *rl) {
* different modules with different triggers to consider if a key
* different modules with different triggers to consider if a key
* is ready or not. This means we can't exit the loop but need
* is ready or not. This means we can't exit the loop but need
* to continue after the first failure. */
* to continue after the first failure. */
monotime
replyTimer
;
elapsedStart
(
&
replyTimer
);
if
(
!
moduleTryServeClientBlockedOnKey
(
receiver
,
rl
->
key
))
continue
;
if
(
!
moduleTryServeClientBlockedOnKey
(
receiver
,
rl
->
key
))
continue
;
updateStatsOnUnblock
(
receiver
,
0
,
elapsedUs
(
replyTimer
));
moduleUnblockClient
(
receiver
);
moduleUnblockClient
(
receiver
);
}
}
...
@@ -684,10 +713,20 @@ static int getBlockedTypeByType(int type) {
...
@@ -684,10 +713,20 @@ static int getBlockedTypeByType(int type) {
void
signalKeyAsReady
(
redisDb
*
db
,
robj
*
key
,
int
type
)
{
void
signalKeyAsReady
(
redisDb
*
db
,
robj
*
key
,
int
type
)
{
readyList
*
rl
;
readyList
*
rl
;
/*
If no clients are blocked on this type, just
return */
/*
Quick
return
s.
*/
int
btype
=
getBlockedTypeByType
(
type
);
int
btype
=
getBlockedTypeByType
(
type
);
if
(
btype
==
BLOCKED_NONE
||
!
server
.
blocked_clients_by_type
[
btype
])
if
(
btype
==
BLOCKED_NONE
)
{
/* The type can never block. */
return
;
return
;
}
if
(
!
server
.
blocked_clients_by_type
[
btype
]
&&
!
server
.
blocked_clients_by_type
[
BLOCKED_MODULE
])
{
/* No clients block on this type. Note: Blocked modules are represented
* by BLOCKED_MODULE, even if the intention is to wake up by normal
* types (list, zset, stream), so we need to check that there are no
* blocked modules before we do a quick return here. */
return
;
}
/* No clients blocking for this key? No need to queue it. */
/* No clients blocking for this key? No need to queue it. */
if
(
dictFind
(
db
->
blocking_keys
,
key
)
==
NULL
)
return
;
if
(
dictFind
(
db
->
blocking_keys
,
key
)
==
NULL
)
return
;
...
...
src/cluster.c
View file @
d0854927
...
@@ -398,7 +398,7 @@ int clusterLockConfig(char *filename) {
...
@@ -398,7 +398,7 @@ int clusterLockConfig(char *filename) {
/* To lock it, we need to open the file in a way it is created if
/* To lock it, we need to open the file in a way it is created if
* it does not exist, otherwise there is a race condition with other
* it does not exist, otherwise there is a race condition with other
* processes. */
* processes. */
int
fd
=
open
(
filename
,
O_WRONLY
|
O_CREAT
,
0644
);
int
fd
=
open
(
filename
,
O_WRONLY
|
O_CREAT
|
O_CLOEXEC
,
0644
);
if
(
fd
==
-
1
)
{
if
(
fd
==
-
1
)
{
serverLog
(
LL_WARNING
,
serverLog
(
LL_WARNING
,
"Can't open %s in order to acquire a lock: %s"
,
"Can't open %s in order to acquire a lock: %s"
,
...
@@ -509,8 +509,7 @@ void clusterInit(void) {
...
@@ -509,8 +509,7 @@ void clusterInit(void) {
serverLog
(
LL_WARNING
,
"Redis port number too high. "
serverLog
(
LL_WARNING
,
"Redis port number too high. "
"Cluster communication port is 10,000 port "
"Cluster communication port is 10,000 port "
"numbers higher than your Redis port. "
"numbers higher than your Redis port. "
"Your Redis port number must be "
"Your Redis port number must be 55535 or less."
);
"lower than 55535."
);
exit
(
1
);
exit
(
1
);
}
}
if
(
listenToPort
(
port
+
CLUSTER_PORT_INCR
,
if
(
listenToPort
(
port
+
CLUSTER_PORT_INCR
,
...
@@ -779,6 +778,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
...
@@ -779,6 +778,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
node
->
configEpoch
=
0
;
node
->
configEpoch
=
0
;
node
->
flags
=
flags
;
node
->
flags
=
flags
;
memset
(
node
->
slots
,
0
,
sizeof
(
node
->
slots
));
memset
(
node
->
slots
,
0
,
sizeof
(
node
->
slots
));
node
->
slots_info
=
NULL
;
node
->
numslots
=
0
;
node
->
numslots
=
0
;
node
->
numslaves
=
0
;
node
->
numslaves
=
0
;
node
->
slaves
=
NULL
;
node
->
slaves
=
NULL
;
...
@@ -4144,8 +4144,8 @@ sds clusterGenNodeDescription(clusterNode *node) {
...
@@ -4144,8 +4144,8 @@ sds clusterGenNodeDescription(clusterNode *node) {
sds
ci
;
sds
ci
;
/* Node coordinates */
/* Node coordinates */
ci
=
sdscat
printf
(
sdsempty
(),
"%.40s %s:%d@%d "
,
ci
=
sdscat
len
(
sdsempty
(),
node
->
name
,
CLUSTER_NAMELEN
);
node
->
name
,
ci
=
sdscatfmt
(
ci
,
" %s:%i@%i "
,
node
->
ip
,
node
->
ip
,
node
->
port
,
node
->
port
,
node
->
cport
);
node
->
cport
);
...
@@ -4154,40 +4154,46 @@ sds clusterGenNodeDescription(clusterNode *node) {
...
@@ -4154,40 +4154,46 @@ sds clusterGenNodeDescription(clusterNode *node) {
ci
=
representClusterNodeFlags
(
ci
,
node
->
flags
);
ci
=
representClusterNodeFlags
(
ci
,
node
->
flags
);
/* Slave of... or just "-" */
/* Slave of... or just "-" */
ci
=
sdscatlen
(
ci
,
" "
,
1
);
if
(
node
->
slaveof
)
if
(
node
->
slaveof
)
ci
=
sdscat
printf
(
ci
,
" %.40s "
,
node
->
slaveof
->
name
);
ci
=
sdscat
len
(
ci
,
node
->
slaveof
->
name
,
CLUSTER_NAMELEN
);
else
else
ci
=
sdscatlen
(
ci
,
"
-
"
,
3
);
ci
=
sdscatlen
(
ci
,
"
-
"
,
1
);
unsigned
long
long
nodeEpoch
=
node
->
configEpoch
;
unsigned
long
long
nodeEpoch
=
node
->
configEpoch
;
if
(
nodeIsSlave
(
node
)
&&
node
->
slaveof
)
{
if
(
nodeIsSlave
(
node
)
&&
node
->
slaveof
)
{
nodeEpoch
=
node
->
slaveof
->
configEpoch
;
nodeEpoch
=
node
->
slaveof
->
configEpoch
;
}
}
/* Latency from the POV of this node, config epoch, link status */
/* Latency from the POV of this node, config epoch, link status */
ci
=
sdscat
printf
(
ci
,
"%lld %lld %llu
%s"
,
ci
=
sdscat
fmt
(
ci
,
" %I %I %U
%s"
,
(
long
long
)
node
->
ping_sent
,
(
long
long
)
node
->
ping_sent
,
(
long
long
)
node
->
pong_received
,
(
long
long
)
node
->
pong_received
,
nodeEpoch
,
nodeEpoch
,
(
node
->
link
||
node
->
flags
&
CLUSTER_NODE_MYSELF
)
?
(
node
->
link
||
node
->
flags
&
CLUSTER_NODE_MYSELF
)
?
"connected"
:
"disconnected"
);
"connected"
:
"disconnected"
);
/* Slots served by this instance */
/* Slots served by this instance. If we already have slots info,
start
=
-
1
;
* append it diretly, otherwise, generate slots only if it has. */
for
(
j
=
0
;
j
<
CLUSTER_SLOTS
;
j
++
)
{
if
(
node
->
slots_info
)
{
int
bit
;
ci
=
sdscatsds
(
ci
,
node
->
slots_info
);
}
else
if
(
node
->
numslots
>
0
)
{
start
=
-
1
;
for
(
j
=
0
;
j
<
CLUSTER_SLOTS
;
j
++
)
{
int
bit
;
if
((
bit
=
clusterNodeGetSlotBit
(
node
,
j
))
!=
0
)
{
if
((
bit
=
clusterNodeGetSlotBit
(
node
,
j
))
!=
0
)
{
if
(
start
==
-
1
)
start
=
j
;
if
(
start
==
-
1
)
start
=
j
;
}
}
if
(
start
!=
-
1
&&
(
!
bit
||
j
==
CLUSTER_SLOTS
-
1
))
{
if
(
start
!=
-
1
&&
(
!
bit
||
j
==
CLUSTER_SLOTS
-
1
))
{
if
(
bit
&&
j
==
CLUSTER_SLOTS
-
1
)
j
++
;
if
(
bit
&&
j
==
CLUSTER_SLOTS
-
1
)
j
++
;
if
(
start
==
j
-
1
)
{
if
(
start
==
j
-
1
)
{
ci
=
sdscatprintf
(
ci
,
" %d"
,
start
);
ci
=
sdscatfmt
(
ci
,
" %i"
,
start
);
}
else
{
}
else
{
ci
=
sdscatprintf
(
ci
,
" %d-%d"
,
start
,
j
-
1
);
ci
=
sdscatfmt
(
ci
,
" %i-%i"
,
start
,
j
-
1
);
}
start
=
-
1
;
}
}
start
=
-
1
;
}
}
}
}
...
@@ -4208,6 +4214,41 @@ sds clusterGenNodeDescription(clusterNode *node) {
...
@@ -4208,6 +4214,41 @@ sds clusterGenNodeDescription(clusterNode *node) {
return
ci
;
return
ci
;
}
}
/* Generate the slot topology for all nodes and store the string representation
* in the slots_info struct on the node. This is used to improve the efficiency
* of clusterGenNodesDescription() because it removes looping of the slot space
* for generating the slot info for each node individually. */
void
clusterGenNodesSlotsInfo
(
int
filter
)
{
clusterNode
*
n
=
NULL
;
int
start
=
-
1
;
for
(
int
i
=
0
;
i
<=
CLUSTER_SLOTS
;
i
++
)
{
/* Find start node and slot id. */
if
(
n
==
NULL
)
{
if
(
i
==
CLUSTER_SLOTS
)
break
;
n
=
server
.
cluster
->
slots
[
i
];
start
=
i
;
continue
;
}
/* Generate slots info when occur different node with start
* or end of slot. */
if
(
i
==
CLUSTER_SLOTS
||
n
!=
server
.
cluster
->
slots
[
i
])
{
if
(
!
(
n
->
flags
&
filter
))
{
if
(
n
->
slots_info
==
NULL
)
n
->
slots_info
=
sdsempty
();
if
(
start
==
i
-
1
)
{
n
->
slots_info
=
sdscatfmt
(
n
->
slots_info
,
" %i"
,
start
);
}
else
{
n
->
slots_info
=
sdscatfmt
(
n
->
slots_info
,
" %i-%i"
,
start
,
i
-
1
);
}
}
if
(
i
==
CLUSTER_SLOTS
)
break
;
n
=
server
.
cluster
->
slots
[
i
];
start
=
i
;
}
}
}
/* Generate a csv-alike representation of the nodes we are aware of,
/* Generate a csv-alike representation of the nodes we are aware of,
* including the "myself" node, and return an SDS string containing the
* including the "myself" node, and return an SDS string containing the
* representation (it is up to the caller to free it).
* representation (it is up to the caller to free it).
...
@@ -4225,6 +4266,9 @@ sds clusterGenNodesDescription(int filter) {
...
@@ -4225,6 +4266,9 @@ sds clusterGenNodesDescription(int filter) {
dictIterator
*
di
;
dictIterator
*
di
;
dictEntry
*
de
;
dictEntry
*
de
;
/* Generate all nodes slots info firstly. */
clusterGenNodesSlotsInfo
(
filter
);
di
=
dictGetSafeIterator
(
server
.
cluster
->
nodes
);
di
=
dictGetSafeIterator
(
server
.
cluster
->
nodes
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
clusterNode
*
node
=
dictGetVal
(
de
);
clusterNode
*
node
=
dictGetVal
(
de
);
...
@@ -4234,6 +4278,12 @@ sds clusterGenNodesDescription(int filter) {
...
@@ -4234,6 +4278,12 @@ sds clusterGenNodesDescription(int filter) {
ci
=
sdscatsds
(
ci
,
ni
);
ci
=
sdscatsds
(
ci
,
ni
);
sdsfree
(
ni
);
sdsfree
(
ni
);
ci
=
sdscatlen
(
ci
,
"
\n
"
,
1
);
ci
=
sdscatlen
(
ci
,
"
\n
"
,
1
);
/* Release slots info. */
if
(
node
->
slots_info
)
{
sdsfree
(
node
->
slots_info
);
node
->
slots_info
=
NULL
;
}
}
}
dictReleaseIterator
(
di
);
dictReleaseIterator
(
di
);
return
ci
;
return
ci
;
...
...
src/cluster.h
View file @
d0854927
...
@@ -118,6 +118,7 @@ typedef struct clusterNode {
...
@@ -118,6 +118,7 @@ typedef struct clusterNode {
int
flags
;
/* CLUSTER_NODE_... */
int
flags
;
/* CLUSTER_NODE_... */
uint64_t
configEpoch
;
/* Last configEpoch observed for this node */
uint64_t
configEpoch
;
/* Last configEpoch observed for this node */
unsigned
char
slots
[
CLUSTER_SLOTS
/
8
];
/* slots handled by this node */
unsigned
char
slots
[
CLUSTER_SLOTS
/
8
];
/* slots handled by this node */
sds
slots_info
;
/* Slots info represented by string. */
int
numslots
;
/* Number of slots handled by this node */
int
numslots
;
/* Number of slots handled by this node */
int
numslaves
;
/* Number of slave nodes, if this is a master */
int
numslaves
;
/* Number of slave nodes, if this is a master */
struct
clusterNode
**
slaves
;
/* pointers to slave nodes */
struct
clusterNode
**
slaves
;
/* pointers to slave nodes */
...
...
src/config.c
View file @
d0854927
...
@@ -153,15 +153,15 @@ int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };
...
@@ -153,15 +153,15 @@ int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };
typedef
struct
boolConfigData
{
typedef
struct
boolConfigData
{
int
*
config
;
/* The pointer to the server config this value is stored in */
int
*
config
;
/* The pointer to the server config this value is stored in */
const
int
default_value
;
/* The default value of the config on rewrite */
const
int
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
int
val
,
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
is_valid_fn
)(
int
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
update_fn
)(
int
val
,
int
prev
,
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
(
*
update_fn
)(
int
val
,
int
prev
,
const
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
}
boolConfigData
;
}
boolConfigData
;
typedef
struct
stringConfigData
{
typedef
struct
stringConfigData
{
char
**
config
;
/* Pointer to the server config this value is stored in. */
char
**
config
;
/* Pointer to the server config this value is stored in. */
const
char
*
default_value
;
/* Default value of the config on rewrite. */
const
char
*
default_value
;
/* Default value of the config on rewrite. */
int
(
*
is_valid_fn
)(
char
*
val
,
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
is_valid_fn
)(
char
*
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
update_fn
)(
char
*
val
,
char
*
prev
,
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
(
*
update_fn
)(
char
*
val
,
char
*
prev
,
const
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
convert_empty_to_null
;
/* Boolean indicating if empty strings should
int
convert_empty_to_null
;
/* Boolean indicating if empty strings should
be stored as a NULL value. */
be stored as a NULL value. */
}
stringConfigData
;
}
stringConfigData
;
...
@@ -169,8 +169,8 @@ typedef struct stringConfigData {
...
@@ -169,8 +169,8 @@ typedef struct stringConfigData {
typedef
struct
sdsConfigData
{
typedef
struct
sdsConfigData
{
sds
*
config
;
/* Pointer to the server config this value is stored in. */
sds
*
config
;
/* Pointer to the server config this value is stored in. */
const
char
*
default_value
;
/* Default value of the config on rewrite. */
const
char
*
default_value
;
/* Default value of the config on rewrite. */
int
(
*
is_valid_fn
)(
sds
val
,
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
is_valid_fn
)(
sds
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
update_fn
)(
sds
val
,
sds
prev
,
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
(
*
update_fn
)(
sds
val
,
sds
prev
,
const
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
convert_empty_to_null
;
/* Boolean indicating if empty SDS strings should
int
convert_empty_to_null
;
/* Boolean indicating if empty SDS strings should
be stored as a NULL value. */
be stored as a NULL value. */
}
sdsConfigData
;
}
sdsConfigData
;
...
@@ -179,8 +179,8 @@ typedef struct enumConfigData {
...
@@ -179,8 +179,8 @@ typedef struct enumConfigData {
int
*
config
;
/* The pointer to the server config this value is stored in */
int
*
config
;
/* The pointer to the server config this value is stored in */
configEnum
*
enum_value
;
/* The underlying enum type this data represents */
configEnum
*
enum_value
;
/* The underlying enum type this data represents */
const
int
default_value
;
/* The default value of the config on rewrite */
const
int
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
int
val
,
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
is_valid_fn
)(
int
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
update_fn
)(
int
val
,
int
prev
,
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
(
*
update_fn
)(
int
val
,
int
prev
,
const
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
}
enumConfigData
;
}
enumConfigData
;
typedef
enum
numericType
{
typedef
enum
numericType
{
...
@@ -214,8 +214,8 @@ typedef struct numericConfigData {
...
@@ -214,8 +214,8 @@ typedef struct numericConfigData {
long
long
lower_bound
;
/* The lower bound of this numeric value */
long
long
lower_bound
;
/* The lower bound of this numeric value */
long
long
upper_bound
;
/* The upper bound of this numeric value */
long
long
upper_bound
;
/* The upper bound of this numeric value */
const
long
long
default_value
;
/* The default value of the config on rewrite */
const
long
long
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
long
long
val
,
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
is_valid_fn
)(
long
long
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
(
*
update_fn
)(
long
long
val
,
long
long
prev
,
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
int
(
*
update_fn
)(
long
long
val
,
long
long
prev
,
const
char
**
err
);
/* Optional function to apply new value at runtime (generic doc above) */
}
numericConfigData
;
}
numericConfigData
;
typedef
union
typeData
{
typedef
union
typeData
{
...
@@ -230,10 +230,10 @@ typedef struct typeInterface {
...
@@ -230,10 +230,10 @@ typedef struct typeInterface {
/* Called on server start, to init the server with default value */
/* Called on server start, to init the server with default value */
void
(
*
init
)(
typeData
data
);
void
(
*
init
)(
typeData
data
);
/* Called on server start, should return 1 on success, 0 on error and should set err */
/* Called on server start, should return 1 on success, 0 on error and should set err */
int
(
*
load
)(
typeData
data
,
sds
*
argc
,
int
argv
,
char
**
err
);
int
(
*
load
)(
typeData
data
,
sds
*
argc
,
int
argv
,
const
char
**
err
);
/* Called on server startup and CONFIG SET, returns 1 on success, 0 on error
/* Called on server startup and CONFIG SET, returns 1 on success, 0 on error
* and can set a verbose err string, update is true when called from CONFIG SET */
* and can set a verbose err string, update is true when called from CONFIG SET */
int
(
*
set
)(
typeData
data
,
sds
value
,
int
update
,
char
**
err
);
int
(
*
set
)(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
);
/* Called on CONFIG GET, required to add output to the client */
/* Called on CONFIG GET, required to add output to the client */
void
(
*
get
)(
client
*
c
,
typeData
data
);
void
(
*
get
)(
client
*
c
,
typeData
data
);
/* Called on CONFIG REWRITE, required to rewrite the config state */
/* Called on CONFIG REWRITE, required to rewrite the config state */
...
@@ -325,7 +325,7 @@ void queueLoadModule(sds path, sds *argv, int argc) {
...
@@ -325,7 +325,7 @@ void queueLoadModule(sds path, sds *argv, int argc) {
* server.oom_score_adj_values if valid.
* server.oom_score_adj_values if valid.
*/
*/
static
int
updateOOMScoreAdjValues
(
sds
*
args
,
char
**
err
,
int
apply
)
{
static
int
updateOOMScoreAdjValues
(
sds
*
args
,
const
char
**
err
,
int
apply
)
{
int
i
;
int
i
;
int
values
[
CONFIG_OOM_COUNT
];
int
values
[
CONFIG_OOM_COUNT
];
...
@@ -385,7 +385,7 @@ void initConfigValues() {
...
@@ -385,7 +385,7 @@ void initConfigValues() {
}
}
void
loadServerConfigFromString
(
char
*
config
)
{
void
loadServerConfigFromString
(
char
*
config
)
{
char
*
err
=
NULL
;
const
char
*
err
=
NULL
;
int
linenum
=
0
,
totlines
,
i
;
int
linenum
=
0
,
totlines
,
i
;
int
slaveof_linenum
=
0
;
int
slaveof_linenum
=
0
;
sds
*
lines
;
sds
*
lines
;
...
@@ -608,7 +608,7 @@ void loadServerConfigFromString(char *config) {
...
@@ -608,7 +608,7 @@ void loadServerConfigFromString(char *config) {
int
argc_err
;
int
argc_err
;
if
(
ACLAppendUserForLoading
(
argv
,
argc
,
&
argc_err
)
==
C_ERR
)
{
if
(
ACLAppendUserForLoading
(
argv
,
argc
,
&
argc_err
)
==
C_ERR
)
{
char
buf
[
1024
];
char
buf
[
1024
];
char
*
errmsg
=
ACLSetUserStringError
();
const
char
*
errmsg
=
ACLSetUserStringError
();
snprintf
(
buf
,
sizeof
(
buf
),
"Error in user declaration '%s': %s"
,
snprintf
(
buf
,
sizeof
(
buf
),
"Error in user declaration '%s': %s"
,
argv
[
argc_err
],
errmsg
);
argv
[
argc_err
],
errmsg
);
err
=
buf
;
err
=
buf
;
...
@@ -624,8 +624,7 @@ void loadServerConfigFromString(char *config) {
...
@@ -624,8 +624,7 @@ void loadServerConfigFromString(char *config) {
err
=
"sentinel directive while not in sentinel mode"
;
err
=
"sentinel directive while not in sentinel mode"
;
goto
loaderr
;
goto
loaderr
;
}
}
err
=
sentinelHandleConfiguration
(
argv
+
1
,
argc
-
1
);
queueSentinelConfig
(
argv
+
1
,
argc
-
1
,
linenum
,
lines
[
i
]);
if
(
err
)
goto
loaderr
;
}
}
}
else
{
}
else
{
err
=
"Bad directive or wrong number of arguments"
;
goto
loaderr
;
err
=
"Bad directive or wrong number of arguments"
;
goto
loaderr
;
...
@@ -730,7 +729,7 @@ void configSetCommand(client *c) {
...
@@ -730,7 +729,7 @@ void configSetCommand(client *c) {
robj
*
o
;
robj
*
o
;
long
long
ll
;
long
long
ll
;
int
err
;
int
err
;
char
*
errstr
=
NULL
;
const
char
*
errstr
=
NULL
;
serverAssertWithInfo
(
c
,
c
->
argv
[
2
],
sdsEncodedObject
(
c
->
argv
[
2
]));
serverAssertWithInfo
(
c
,
c
->
argv
[
2
],
sdsEncodedObject
(
c
->
argv
[
2
]));
serverAssertWithInfo
(
c
,
c
->
argv
[
3
],
sdsEncodedObject
(
c
->
argv
[
3
]));
serverAssertWithInfo
(
c
,
c
->
argv
[
3
],
sdsEncodedObject
(
c
->
argv
[
3
]));
o
=
c
->
argv
[
3
];
o
=
c
->
argv
[
3
];
...
@@ -1221,7 +1220,16 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
...
@@ -1221,7 +1220,16 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
sdsfree
(
argv
[
0
]);
sdsfree
(
argv
[
0
]);
argv
[
0
]
=
alt
;
argv
[
0
]
=
alt
;
}
}
rewriteConfigAddLineNumberToOption
(
state
,
argv
[
0
],
linenum
);
/* If this is sentinel config, we use sentinel "sentinel <config>" as option
to avoid messing up the sequence. */
if
(
server
.
sentinel_mode
&&
argc
>
1
&&
!
strcasecmp
(
argv
[
0
],
"sentinel"
))
{
sds
sentinelOption
=
sdsempty
();
sentinelOption
=
sdscatfmt
(
sentinelOption
,
"%S %S"
,
argv
[
0
],
argv
[
1
]);
rewriteConfigAddLineNumberToOption
(
state
,
sentinelOption
,
linenum
);
sdsfree
(
sentinelOption
);
}
else
{
rewriteConfigAddLineNumberToOption
(
state
,
argv
[
0
],
linenum
);
}
sdsfreesplitres
(
argv
,
argc
);
sdsfreesplitres
(
argv
,
argc
);
}
}
fclose
(
fp
);
fclose
(
fp
);
...
@@ -1683,7 +1691,7 @@ int rewriteConfigOverwriteFile(char *configfile, sds content) {
...
@@ -1683,7 +1691,7 @@ int rewriteConfigOverwriteFile(char *configfile, sds content) {
if
(
fsync
(
fd
))
if
(
fsync
(
fd
))
serverLog
(
LL_WARNING
,
"Could not sync tmp config file to disk (%s)"
,
strerror
(
errno
));
serverLog
(
LL_WARNING
,
"Could not sync tmp config file to disk (%s)"
,
strerror
(
errno
));
else
if
(
fchmod
(
fd
,
0644
)
==
-
1
)
else
if
(
fchmod
(
fd
,
0644
&
~
server
.
umask
)
==
-
1
)
serverLog
(
LL_WARNING
,
"Could not chmod config file (%s)"
,
strerror
(
errno
));
serverLog
(
LL_WARNING
,
"Could not chmod config file (%s)"
,
strerror
(
errno
));
else
if
(
rename
(
tmp_conffile
,
configfile
)
==
-
1
)
else
if
(
rename
(
tmp_conffile
,
configfile
)
==
-
1
)
serverLog
(
LL_WARNING
,
"Could not rename tmp config file (%s)"
,
strerror
(
errno
));
serverLog
(
LL_WARNING
,
"Could not rename tmp config file (%s)"
,
strerror
(
errno
));
...
@@ -1795,7 +1803,7 @@ static void boolConfigInit(typeData data) {
...
@@ -1795,7 +1803,7 @@ static void boolConfigInit(typeData data) {
*
data
.
yesno
.
config
=
data
.
yesno
.
default_value
;
*
data
.
yesno
.
config
=
data
.
yesno
.
default_value
;
}
}
static
int
boolConfigSet
(
typeData
data
,
sds
value
,
int
update
,
char
**
err
)
{
static
int
boolConfigSet
(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
)
{
int
yn
=
yesnotoi
(
value
);
int
yn
=
yesnotoi
(
value
);
if
(
yn
==
-
1
)
{
if
(
yn
==
-
1
)
{
*
err
=
"argument must be 'yes' or 'no'"
;
*
err
=
"argument must be 'yes' or 'no'"
;
...
@@ -1836,7 +1844,7 @@ static void stringConfigInit(typeData data) {
...
@@ -1836,7 +1844,7 @@ static void stringConfigInit(typeData data) {
*
data
.
string
.
config
=
(
data
.
string
.
convert_empty_to_null
&&
!
data
.
string
.
default_value
)
?
NULL
:
zstrdup
(
data
.
string
.
default_value
);
*
data
.
string
.
config
=
(
data
.
string
.
convert_empty_to_null
&&
!
data
.
string
.
default_value
)
?
NULL
:
zstrdup
(
data
.
string
.
default_value
);
}
}
static
int
stringConfigSet
(
typeData
data
,
sds
value
,
int
update
,
char
**
err
)
{
static
int
stringConfigSet
(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
)
{
if
(
data
.
string
.
is_valid_fn
&&
!
data
.
string
.
is_valid_fn
(
value
,
err
))
if
(
data
.
string
.
is_valid_fn
&&
!
data
.
string
.
is_valid_fn
(
value
,
err
))
return
0
;
return
0
;
char
*
prev
=
*
data
.
string
.
config
;
char
*
prev
=
*
data
.
string
.
config
;
...
@@ -1863,7 +1871,7 @@ static void sdsConfigInit(typeData data) {
...
@@ -1863,7 +1871,7 @@ static void sdsConfigInit(typeData data) {
*
data
.
sds
.
config
=
(
data
.
sds
.
convert_empty_to_null
&&
!
data
.
sds
.
default_value
)
?
NULL
:
sdsnew
(
data
.
sds
.
default_value
);
*
data
.
sds
.
config
=
(
data
.
sds
.
convert_empty_to_null
&&
!
data
.
sds
.
default_value
)
?
NULL
:
sdsnew
(
data
.
sds
.
default_value
);
}
}
static
int
sdsConfigSet
(
typeData
data
,
sds
value
,
int
update
,
char
**
err
)
{
static
int
sdsConfigSet
(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
)
{
if
(
data
.
sds
.
is_valid_fn
&&
!
data
.
sds
.
is_valid_fn
(
value
,
err
))
if
(
data
.
sds
.
is_valid_fn
&&
!
data
.
sds
.
is_valid_fn
(
value
,
err
))
return
0
;
return
0
;
sds
prev
=
*
data
.
sds
.
config
;
sds
prev
=
*
data
.
sds
.
config
;
...
@@ -1922,7 +1930,7 @@ static void enumConfigInit(typeData data) {
...
@@ -1922,7 +1930,7 @@ static void enumConfigInit(typeData data) {
*
data
.
enumd
.
config
=
data
.
enumd
.
default_value
;
*
data
.
enumd
.
config
=
data
.
enumd
.
default_value
;
}
}
static
int
enumConfigSet
(
typeData
data
,
sds
value
,
int
update
,
char
**
err
)
{
static
int
enumConfigSet
(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
)
{
int
enumval
=
configEnumGetValue
(
data
.
enumd
.
enum_value
,
value
);
int
enumval
=
configEnumGetValue
(
data
.
enumd
.
enum_value
,
value
);
if
(
enumval
==
INT_MIN
)
{
if
(
enumval
==
INT_MIN
)
{
sds
enumerr
=
sdsnew
(
"argument must be one of the following: "
);
sds
enumerr
=
sdsnew
(
"argument must be one of the following: "
);
...
@@ -2028,7 +2036,7 @@ static void numericConfigInit(typeData data) {
...
@@ -2028,7 +2036,7 @@ static void numericConfigInit(typeData data) {
SET_NUMERIC_TYPE
(
data
.
numeric
.
default_value
)
SET_NUMERIC_TYPE
(
data
.
numeric
.
default_value
)
}
}
static
int
numericBoundaryCheck
(
typeData
data
,
long
long
ll
,
char
**
err
)
{
static
int
numericBoundaryCheck
(
typeData
data
,
long
long
ll
,
const
char
**
err
)
{
if
(
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG_LONG
||
if
(
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG_LONG
||
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_UINT
||
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_UINT
||
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SIZE_T
)
{
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SIZE_T
)
{
...
@@ -2058,7 +2066,7 @@ static int numericBoundaryCheck(typeData data, long long ll, char **err) {
...
@@ -2058,7 +2066,7 @@ static int numericBoundaryCheck(typeData data, long long ll, char **err) {
return
1
;
return
1
;
}
}
static
int
numericConfigSet
(
typeData
data
,
sds
value
,
int
update
,
char
**
err
)
{
static
int
numericConfigSet
(
typeData
data
,
sds
value
,
int
update
,
const
char
**
err
)
{
long
long
ll
,
prev
=
0
;
long
long
ll
,
prev
=
0
;
if
(
data
.
numeric
.
is_memory
)
{
if
(
data
.
numeric
.
is_memory
)
{
int
memerr
;
int
memerr
;
...
@@ -2196,7 +2204,7 @@ static void numericConfigRewrite(typeData data, const char *name, struct rewrite
...
@@ -2196,7 +2204,7 @@ static void numericConfigRewrite(typeData data, const char *name, struct rewrite
} \
} \
}
}
static
int
isValidActiveDefrag
(
int
val
,
char
**
err
)
{
static
int
isValidActiveDefrag
(
int
val
,
const
char
**
err
)
{
#ifndef HAVE_DEFRAG
#ifndef HAVE_DEFRAG
if
(
val
)
{
if
(
val
)
{
*
err
=
"Active defragmentation cannot be enabled: it "
*
err
=
"Active defragmentation cannot be enabled: it "
...
@@ -2212,7 +2220,7 @@ static int isValidActiveDefrag(int val, char **err) {
...
@@ -2212,7 +2220,7 @@ static int isValidActiveDefrag(int val, char **err) {
return
1
;
return
1
;
}
}
static
int
isValidDBfilename
(
char
*
val
,
char
**
err
)
{
static
int
isValidDBfilename
(
char
*
val
,
const
char
**
err
)
{
if
(
!
pathIsBaseName
(
val
))
{
if
(
!
pathIsBaseName
(
val
))
{
*
err
=
"dbfilename can't be a path, just a filename"
;
*
err
=
"dbfilename can't be a path, just a filename"
;
return
0
;
return
0
;
...
@@ -2220,7 +2228,7 @@ static int isValidDBfilename(char *val, char **err) {
...
@@ -2220,7 +2228,7 @@ static int isValidDBfilename(char *val, char **err) {
return
1
;
return
1
;
}
}
static
int
isValidAOFfilename
(
char
*
val
,
char
**
err
)
{
static
int
isValidAOFfilename
(
char
*
val
,
const
char
**
err
)
{
if
(
!
pathIsBaseName
(
val
))
{
if
(
!
pathIsBaseName
(
val
))
{
*
err
=
"appendfilename can't be a path, just a filename"
;
*
err
=
"appendfilename can't be a path, just a filename"
;
return
0
;
return
0
;
...
@@ -2228,7 +2236,26 @@ static int isValidAOFfilename(char *val, char **err) {
...
@@ -2228,7 +2236,26 @@ static int isValidAOFfilename(char *val, char **err) {
return
1
;
return
1
;
}
}
static
int
updateHZ
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
/* Validate specified string is a valid proc-title-template */
static
int
isValidProcTitleTemplate
(
char
*
val
,
const
char
**
err
)
{
if
(
!
validateProcTitleTemplate
(
val
))
{
*
err
=
"template format is invalid or contains unknown variables"
;
return
0
;
}
return
1
;
}
static
int
updateProcTitleTemplate
(
char
*
val
,
char
*
prev
,
const
char
**
err
)
{
UNUSED
(
val
);
UNUSED
(
prev
);
if
(
redisSetProcTitle
(
NULL
)
==
C_ERR
)
{
*
err
=
"failed to set process title"
;
return
0
;
}
return
1
;
}
static
int
updateHZ
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
UNUSED
(
prev
);
UNUSED
(
prev
);
UNUSED
(
err
);
UNUSED
(
err
);
/* Hz is more a hint from the user, so we accept values out of range
/* Hz is more a hint from the user, so we accept values out of range
...
@@ -2240,14 +2267,14 @@ static int updateHZ(long long val, long long prev, char **err) {
...
@@ -2240,14 +2267,14 @@ static int updateHZ(long long val, long long prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateJemallocBgThread
(
int
val
,
int
prev
,
char
**
err
)
{
static
int
updateJemallocBgThread
(
int
val
,
int
prev
,
const
char
**
err
)
{
UNUSED
(
prev
);
UNUSED
(
prev
);
UNUSED
(
err
);
UNUSED
(
err
);
set_jemalloc_bg_thread
(
val
);
set_jemalloc_bg_thread
(
val
);
return
1
;
return
1
;
}
}
static
int
updateReplBacklogSize
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
static
int
updateReplBacklogSize
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
/* resizeReplicationBacklog sets server.repl_backlog_size, and relies on
/* resizeReplicationBacklog sets server.repl_backlog_size, and relies on
* being able to tell when the size changes, so restore prev before calling it. */
* being able to tell when the size changes, so restore prev before calling it. */
UNUSED
(
err
);
UNUSED
(
err
);
...
@@ -2256,7 +2283,7 @@ static int updateReplBacklogSize(long long val, long long prev, char **err) {
...
@@ -2256,7 +2283,7 @@ static int updateReplBacklogSize(long long val, long long prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateMaxmemory
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
static
int
updateMaxmemory
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
UNUSED
(
prev
);
UNUSED
(
prev
);
UNUSED
(
err
);
UNUSED
(
err
);
if
(
val
)
{
if
(
val
)
{
...
@@ -2269,7 +2296,7 @@ static int updateMaxmemory(long long val, long long prev, char **err) {
...
@@ -2269,7 +2296,7 @@ static int updateMaxmemory(long long val, long long prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateGoodSlaves
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
static
int
updateGoodSlaves
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
UNUSED
(
val
);
UNUSED
(
val
);
UNUSED
(
prev
);
UNUSED
(
prev
);
UNUSED
(
err
);
UNUSED
(
err
);
...
@@ -2277,7 +2304,7 @@ static int updateGoodSlaves(long long val, long long prev, char **err) {
...
@@ -2277,7 +2304,7 @@ static int updateGoodSlaves(long long val, long long prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateAppendonly
(
int
val
,
int
prev
,
char
**
err
)
{
static
int
updateAppendonly
(
int
val
,
int
prev
,
const
char
**
err
)
{
UNUSED
(
prev
);
UNUSED
(
prev
);
if
(
val
==
0
&&
server
.
aof_state
!=
AOF_OFF
)
{
if
(
val
==
0
&&
server
.
aof_state
!=
AOF_OFF
)
{
stopAppendOnly
();
stopAppendOnly
();
...
@@ -2290,7 +2317,7 @@ static int updateAppendonly(int val, int prev, char **err) {
...
@@ -2290,7 +2317,7 @@ static int updateAppendonly(int val, int prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateSighandlerEnabled
(
int
val
,
int
prev
,
char
**
err
)
{
static
int
updateSighandlerEnabled
(
int
val
,
int
prev
,
const
char
**
err
)
{
UNUSED
(
err
);
UNUSED
(
err
);
UNUSED
(
prev
);
UNUSED
(
prev
);
if
(
val
)
if
(
val
)
...
@@ -2300,7 +2327,7 @@ static int updateSighandlerEnabled(int val, int prev, char **err) {
...
@@ -2300,7 +2327,7 @@ static int updateSighandlerEnabled(int val, int prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateMaxclients
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
static
int
updateMaxclients
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
/* Try to check if the OS is capable of supporting so many FDs. */
/* Try to check if the OS is capable of supporting so many FDs. */
if
(
val
>
prev
)
{
if
(
val
>
prev
)
{
adjustOpenFilesLimit
();
adjustOpenFilesLimit
();
...
@@ -2328,7 +2355,7 @@ static int updateMaxclients(long long val, long long prev, char **err) {
...
@@ -2328,7 +2355,7 @@ static int updateMaxclients(long long val, long long prev, char **err) {
return
1
;
return
1
;
}
}
static
int
updateOOMScoreAdj
(
int
val
,
int
prev
,
char
**
err
)
{
static
int
updateOOMScoreAdj
(
int
val
,
int
prev
,
const
char
**
err
)
{
UNUSED
(
prev
);
UNUSED
(
prev
);
if
(
val
)
{
if
(
val
)
{
...
@@ -2342,7 +2369,7 @@ static int updateOOMScoreAdj(int val, int prev, char **err) {
...
@@ -2342,7 +2369,7 @@ static int updateOOMScoreAdj(int val, int prev, char **err) {
}
}
#ifdef USE_OPENSSL
#ifdef USE_OPENSSL
static
int
updateTlsCfg
(
char
*
val
,
char
*
prev
,
char
**
err
)
{
static
int
updateTlsCfg
(
char
*
val
,
char
*
prev
,
const
char
**
err
)
{
UNUSED
(
val
);
UNUSED
(
val
);
UNUSED
(
prev
);
UNUSED
(
prev
);
UNUSED
(
err
);
UNUSED
(
err
);
...
@@ -2355,13 +2382,13 @@ static int updateTlsCfg(char *val, char *prev, char **err) {
...
@@ -2355,13 +2382,13 @@ static int updateTlsCfg(char *val, char *prev, char **err) {
}
}
return
1
;
return
1
;
}
}
static
int
updateTlsCfgBool
(
int
val
,
int
prev
,
char
**
err
)
{
static
int
updateTlsCfgBool
(
int
val
,
int
prev
,
const
char
**
err
)
{
UNUSED
(
val
);
UNUSED
(
val
);
UNUSED
(
prev
);
UNUSED
(
prev
);
return
updateTlsCfg
(
NULL
,
NULL
,
err
);
return
updateTlsCfg
(
NULL
,
NULL
,
err
);
}
}
static
int
updateTlsCfgInt
(
long
long
val
,
long
long
prev
,
char
**
err
)
{
static
int
updateTlsCfgInt
(
long
long
val
,
long
long
prev
,
const
char
**
err
)
{
UNUSED
(
val
);
UNUSED
(
val
);
UNUSED
(
prev
);
UNUSED
(
prev
);
return
updateTlsCfg
(
NULL
,
NULL
,
err
);
return
updateTlsCfg
(
NULL
,
NULL
,
err
);
...
@@ -2380,11 +2407,13 @@ standardConfig configs[] = {
...
@@ -2380,11 +2407,13 @@ standardConfig configs[] = {
createBoolConfig
(
"rdb-del-sync-files"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
rdb_del_sync_files
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"rdb-del-sync-files"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
rdb_del_sync_files
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"activerehashing"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
activerehashing
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"activerehashing"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
activerehashing
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"stop-writes-on-bgsave-error"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
stop_writes_on_bgsave_err
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"stop-writes-on-bgsave-error"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
stop_writes_on_bgsave_err
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"set-proc-title"
,
NULL
,
IMMUTABLE_CONFIG
,
server
.
set_proc_title
,
1
,
NULL
,
NULL
),
/* Should setproctitle be used? */
createBoolConfig
(
"dynamic-hz"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
dynamic_hz
,
1
,
NULL
,
NULL
),
/* Adapt hz to # of clients.*/
createBoolConfig
(
"dynamic-hz"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
dynamic_hz
,
1
,
NULL
,
NULL
),
/* Adapt hz to # of clients.*/
createBoolConfig
(
"lazyfree-lazy-eviction"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_eviction
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-eviction"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_eviction
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-expire"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_expire
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-expire"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_expire
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-server-del"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_server_del
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-server-del"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_server_del
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-user-del"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_user_del
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-user-del"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_user_del
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"lazyfree-lazy-user-flush"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
lazyfree_lazy_user_flush
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"repl-disable-tcp-nodelay"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
repl_disable_tcp_nodelay
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"repl-disable-tcp-nodelay"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
repl_disable_tcp_nodelay
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"repl-diskless-sync"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
repl_diskless_sync
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"repl-diskless-sync"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
repl_diskless_sync
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"gopher-enabled"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
gopher_enabled
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"gopher-enabled"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
gopher_enabled
,
0
,
NULL
,
NULL
),
...
@@ -2425,6 +2454,7 @@ standardConfig configs[] = {
...
@@ -2425,6 +2454,7 @@ standardConfig configs[] = {
createStringConfig
(
"aof_rewrite_cpulist"
,
NULL
,
IMMUTABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
aof_rewrite_cpulist
,
NULL
,
NULL
,
NULL
),
createStringConfig
(
"aof_rewrite_cpulist"
,
NULL
,
IMMUTABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
aof_rewrite_cpulist
,
NULL
,
NULL
,
NULL
),
createStringConfig
(
"bgsave_cpulist"
,
NULL
,
IMMUTABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
bgsave_cpulist
,
NULL
,
NULL
,
NULL
),
createStringConfig
(
"bgsave_cpulist"
,
NULL
,
IMMUTABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
bgsave_cpulist
,
NULL
,
NULL
,
NULL
),
createStringConfig
(
"ignore-warnings"
,
NULL
,
MODIFIABLE_CONFIG
,
ALLOW_EMPTY_STRING
,
server
.
ignore_warnings
,
""
,
NULL
,
NULL
),
createStringConfig
(
"ignore-warnings"
,
NULL
,
MODIFIABLE_CONFIG
,
ALLOW_EMPTY_STRING
,
server
.
ignore_warnings
,
""
,
NULL
,
NULL
),
createStringConfig
(
"proc-title-template"
,
NULL
,
MODIFIABLE_CONFIG
,
ALLOW_EMPTY_STRING
,
server
.
proc_title_template
,
CONFIG_DEFAULT_PROC_TITLE_TEMPLATE
,
isValidProcTitleTemplate
,
updateProcTitleTemplate
),
/* SDS Configs */
/* SDS Configs */
createSDSConfig
(
"masterauth"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
masterauth
,
NULL
,
NULL
,
NULL
),
createSDSConfig
(
"masterauth"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
masterauth
,
NULL
,
NULL
,
NULL
),
...
...
src/db.c
View file @
d0854927
...
@@ -226,7 +226,7 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
...
@@ -226,7 +226,7 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
/* Although the key is not really deleted from the database, we regard
/* Although the key is not really deleted from the database, we regard
overwrite as two steps of unlink+add, so we still need to call the unlink
overwrite as two steps of unlink+add, so we still need to call the unlink
callback of the module. */
callback of the module. */
moduleNotifyKeyUnlink
(
key
,
val
);
moduleNotifyKeyUnlink
(
key
,
old
);
dictSetVal
(
db
->
dict
,
de
,
val
);
dictSetVal
(
db
->
dict
,
de
,
val
);
if
(
server
.
lazyfree_lazy_server_del
)
{
if
(
server
.
lazyfree_lazy_server_del
)
{
...
@@ -595,21 +595,23 @@ void signalFlushedDb(int dbid, int async) {
...
@@ -595,21 +595,23 @@ void signalFlushedDb(int dbid, int async) {
/* Return the set of flags to use for the emptyDb() call for FLUSHALL
/* Return the set of flags to use for the emptyDb() call for FLUSHALL
* and FLUSHDB commands.
* and FLUSHDB commands.
*
*
* Currently the command just attempts to parse the "ASYNC" option. It
* sync: flushes the database in an sync manner.
* also checks if the command arity is wrong.
* async: flushes the database in an async manner.
* no option: determine sync or async according to the value of lazyfree-lazy-user-flush.
*
*
* On success C_OK is returned and the flags are stored in *flags, otherwise
* On success C_OK is returned and the flags are stored in *flags, otherwise
* C_ERR is returned and the function sends an error to the client. */
* C_ERR is returned and the function sends an error to the client. */
int
getFlushCommandFlags
(
client
*
c
,
int
*
flags
)
{
int
getFlushCommandFlags
(
client
*
c
,
int
*
flags
)
{
/* Parse the optional ASYNC option. */
/* Parse the optional ASYNC option. */
if
(
c
->
argc
>
1
)
{
if
(
c
->
argc
==
2
&&
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"sync"
))
{
if
(
c
->
argc
>
2
||
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"async"
))
{
*
flags
=
EMPTYDB_NO_FLAGS
;
addReplyErrorObject
(
c
,
shared
.
syntaxerr
);
}
else
if
(
c
->
argc
==
2
&&
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"async"
))
{
return
C_ERR
;
}
*
flags
=
EMPTYDB_ASYNC
;
*
flags
=
EMPTYDB_ASYNC
;
}
else
if
(
c
->
argc
==
1
)
{
*
flags
=
server
.
lazyfree_lazy_user_flush
?
EMPTYDB_ASYNC
:
EMPTYDB_NO_FLAGS
;
}
else
{
}
else
{
*
flags
=
EMPTYDB_NO_FLAGS
;
addReplyErrorObject
(
c
,
shared
.
syntaxerr
);
return
C_ERR
;
}
}
return
C_OK
;
return
C_OK
;
}
}
...
@@ -951,7 +953,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
...
@@ -951,7 +953,7 @@ void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
int
filter
=
0
;
int
filter
=
0
;
/* Filter element if it does not match the pattern. */
/* Filter element if it does not match the pattern. */
if
(
!
filter
&&
use_pattern
)
{
if
(
use_pattern
)
{
if
(
sdsEncodedObject
(
kobj
))
{
if
(
sdsEncodedObject
(
kobj
))
{
if
(
!
stringmatchlen
(
pat
,
patlen
,
kobj
->
ptr
,
sdslen
(
kobj
->
ptr
),
0
))
if
(
!
stringmatchlen
(
pat
,
patlen
,
kobj
->
ptr
,
sdslen
(
kobj
->
ptr
),
0
))
filter
=
1
;
filter
=
1
;
...
...
src/defrag.c
View file @
d0854927
...
@@ -367,7 +367,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
...
@@ -367,7 +367,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
}
else
if
(
dict_val_type
==
DEFRAG_SDS_DICT_VAL_VOID_PTR
)
{
}
else
if
(
dict_val_type
==
DEFRAG_SDS_DICT_VAL_VOID_PTR
)
{
void
*
newptr
,
*
ptr
=
dictGetVal
(
de
);
void
*
newptr
,
*
ptr
=
dictGetVal
(
de
);
if
((
newptr
=
activeDefragAlloc
(
ptr
)))
if
((
newptr
=
activeDefragAlloc
(
ptr
)))
ln
->
val
ue
=
newptr
,
defragged
++
;
de
->
v
.
v
al
=
newptr
,
defragged
++
;
}
}
defragged
+=
dictIterDefragEntry
(
di
);
defragged
+=
dictIterDefragEntry
(
di
);
}
}
...
...
src/expire.c
View file @
d0854927
...
@@ -53,15 +53,19 @@
...
@@ -53,15 +53,19 @@
* to the function to avoid too many gettimeofday() syscalls. */
* to the function to avoid too many gettimeofday() syscalls. */
int
activeExpireCycleTryExpire
(
redisDb
*
db
,
dictEntry
*
de
,
long
long
now
)
{
int
activeExpireCycleTryExpire
(
redisDb
*
db
,
dictEntry
*
de
,
long
long
now
)
{
long
long
t
=
dictGetSignedIntegerVal
(
de
);
long
long
t
=
dictGetSignedIntegerVal
(
de
);
mstime_t
expire_latency
;
if
(
now
>
t
)
{
if
(
now
>
t
)
{
sds
key
=
dictGetKey
(
de
);
sds
key
=
dictGetKey
(
de
);
robj
*
keyobj
=
createStringObject
(
key
,
sdslen
(
key
));
robj
*
keyobj
=
createStringObject
(
key
,
sdslen
(
key
));
propagateExpire
(
db
,
keyobj
,
server
.
lazyfree_lazy_expire
);
propagateExpire
(
db
,
keyobj
,
server
.
lazyfree_lazy_expire
);
latencyStartMonitor
(
expire_latency
);
if
(
server
.
lazyfree_lazy_expire
)
if
(
server
.
lazyfree_lazy_expire
)
dbAsyncDelete
(
db
,
keyobj
);
dbAsyncDelete
(
db
,
keyobj
);
else
else
dbSyncDelete
(
db
,
keyobj
);
dbSyncDelete
(
db
,
keyobj
);
latencyEndMonitor
(
expire_latency
);
latencyAddSampleIfNeeded
(
"expire-del"
,
expire_latency
);
notifyKeyspaceEvent
(
NOTIFY_EXPIRED
,
notifyKeyspaceEvent
(
NOTIFY_EXPIRED
,
"expired"
,
keyobj
,
db
->
id
);
"expired"
,
keyobj
,
db
->
id
);
signalModifiedKey
(
NULL
,
db
,
keyobj
);
signalModifiedKey
(
NULL
,
db
,
keyobj
);
...
@@ -224,7 +228,7 @@ void activeExpireCycle(int type) {
...
@@ -224,7 +228,7 @@ void activeExpireCycle(int type) {
/* When there are less than 1% filled slots, sampling the key
/* When there are less than 1% filled slots, sampling the key
* space is expensive, so stop here waiting for better times...
* space is expensive, so stop here waiting for better times...
* The dictionary will be resized asap. */
* The dictionary will be resized asap. */
if
(
num
&&
slots
>
DICT_HT_INITIAL_SIZE
&&
if
(
slots
>
DICT_HT_INITIAL_SIZE
&&
(
num
*
100
/
slots
<
1
))
break
;
(
num
*
100
/
slots
<
1
))
break
;
/* The main collection cycle. Sample random keys among keys
/* The main collection cycle. Sample random keys among keys
...
...
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment