Compare commits
57
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
570fbd0149 | ||
|
|
da1f09e9b5 | ||
|
|
b2fb4f4b9b | ||
|
|
51277b17a7 | ||
|
|
32f5ef864e | ||
|
|
a8f28297ec | ||
|
|
1895dbb768 | ||
|
|
a6cbbd0f31 | ||
|
|
e3c619eca4 | ||
|
|
57e59d97db | ||
|
|
d7cada0f38 | ||
|
|
fd2ac1fcfc | ||
|
|
0181b0e7a1 | ||
|
|
2b5e5cfa4c | ||
|
|
bfb0d02622 | ||
|
|
534b70643b | ||
|
|
3d0f729572 | ||
|
|
fd4ed1e425 | ||
|
|
693450393c | ||
|
|
8ee7584cff | ||
|
|
0727393627 | ||
|
|
d2ef059471 | ||
|
|
2e894a512b | ||
|
|
34b0209f05 | ||
|
|
046f575632 | ||
|
|
1c77104b5e | ||
|
|
386be8990a | ||
|
|
76d9c7c82a | ||
|
|
98f08034a1 | ||
|
|
308cf77437 | ||
|
|
ce64f469f4 | ||
|
|
e632c3db1b | ||
|
|
239d22ed72 | ||
|
|
fefbe96816 | ||
|
|
e90e5640e7 | ||
|
|
2df6695f2b | ||
|
|
92e3b1802f | ||
|
|
0463520693 | ||
|
|
922e3bf59f | ||
|
|
42f2ad0516 | ||
|
|
1eab6202ac | ||
|
|
d30ee6c44a | ||
|
|
4f2da00e94 | ||
|
|
34b9a3fa2e | ||
|
|
5c7b869e61 | ||
|
|
6cbea7d29b | ||
|
|
8cfa37fc21 | ||
|
|
16c53085f7 | ||
|
|
2ccb926314 | ||
|
|
6384fe3414 | ||
|
|
ef64333e63 | ||
|
|
0851705304 | ||
|
|
b97a4ad7f2 | ||
|
|
d01afe885c | ||
|
|
66547bd28a | ||
|
|
e6ab823473 | ||
|
|
a2c0bce4cc |
No files matched your search
@@ -1,21 +0,0 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask the Redis developers
|
||||
title: '[QUESTION]'
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please keep in mind that this issue tracker should be used for reporting bugs or proposing improvements to the Redis server.
|
||||
|
||||
Generally, questions about using Redis should be directed to the [community](https://redis.io/community):
|
||||
|
||||
* [the mailing list](https://groups.google.com/forum/#!forum/redis-db)
|
||||
* [the `redis` tag at StackOverflow](http://stackoverflow.com/questions/tagged/redis)
|
||||
* [/r/redis subreddit](http://www.reddit.com/r/redis)
|
||||
* [the irc channel #redis](http://webchat.freenode.net/?channels=redis) on freenode
|
||||
|
||||
It is also possible that your question was already asked here, so please do a quick issues search before submitting. Lastly, if your question is about one of Redis' [clients](https://redis.io/clients), you may to contact your client's developers for help.
|
||||
|
||||
That said, please feel free to replace all this with your question :)
|
||||
+2
-1
@@ -30,6 +30,7 @@ redis-check-rdb
|
||||
keydb-check-rdb
|
||||
redis-check-dump
|
||||
keydb-check-dump
|
||||
keydb-diagnostic-tool
|
||||
redis-cli
|
||||
redis-sentinel
|
||||
redis-server
|
||||
@@ -58,4 +59,4 @@ Makefile.dep
|
||||
.ccls
|
||||
.ccls-cache/*
|
||||
compile_commands.json
|
||||
redis.code-workspace
|
||||
keydb.code-workspace
|
||||
@@ -11,6 +11,40 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
|
||||
SECURITY: There are security fixes in the release.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.3 Released Mon May 3 19:00:00 IST 2021
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency: SECURITY, Contains fixes to security issues that affect
|
||||
authenticated client connections. LOW otherwise.
|
||||
|
||||
Integer overflow in STRALGO LCS command (CVE-2021-29477):
|
||||
An integer overflow bug in Redis version 6.0 or newer could be exploited using
|
||||
the STRALGO LCS command to corrupt the heap and potentially result in remote
|
||||
code execution. The integer overflow bug exists in all versions of Redis
|
||||
starting with 6.0.
|
||||
|
||||
Integer overflow in COPY command for large intsets (CVE-2021-29478):
|
||||
An integer overflow bug in Redis 6.2 could be exploited to corrupt the heap and
|
||||
potentially result with remote code execution. The vulnerability involves
|
||||
changing the default set-max-intset-entries configuration value, creating a
|
||||
large set key that consists of integer values and using the COPY command to
|
||||
duplicate it. The integer overflow bug exists in all versions of Redis starting
|
||||
with 2.6, where it could result with a corrupted RDB or DUMP payload, but not
|
||||
exploited through COPY (which did not exist before 6.2).
|
||||
|
||||
Bug fixes that are only applicable to previous releases of Redis 6.2:
|
||||
* Fix memory leak in moduleDefragGlobals (#8853)
|
||||
* Fix memory leak when doing lazy freeing client tracking table (#8822)
|
||||
* Block abusive replicas from sending command that could assert and crash redis (#8868)
|
||||
|
||||
Other bug fixes:
|
||||
* Use a monotonic clock to check for Lua script timeout (#8812)
|
||||
* redis-cli: Do not use unix socket when we got redirected in cluster mode (#8870)
|
||||
|
||||
Modules:
|
||||
* Fix RM_GetClusterNodeInfo() to correctly populate master id (#8846)
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.2 Released Mon April 19 19:00:00 IST 2021
|
||||
================================================================================
|
||||
|
||||
@@ -179,7 +179,7 @@ To compile against jemalloc on Mac OS X systems, use:
|
||||
Monotonic clock
|
||||
---------------
|
||||
|
||||
By default, Redis will build using the POSIX clock_gettime function as the
|
||||
By default, KeyDB will build using the POSIX clock_gettime function as the
|
||||
monotonic clock source. On most modern systems, the internal processor clock
|
||||
can be used to improve performance. Cautions can be found here:
|
||||
http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/
|
||||
|
||||
@@ -28,8 +28,8 @@ To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
|
||||
invoked so sample certificates/keys are available):
|
||||
|
||||
./src/keydb-server --tls-port 6379 --port 0 \
|
||||
--tls-cert-file ./tests/tls/keydb.crt \
|
||||
--tls-key-file ./tests/tls/keydb.key \
|
||||
--tls-cert-file ./tests/tls/client.crt \
|
||||
--tls-key-file ./tests/tls/client.key \
|
||||
--tls-ca-cert-file ./tests/tls/ca.crt
|
||||
|
||||
To connect to this Redis server with `keydb-cli`:
|
||||
|
||||
@@ -241,7 +241,7 @@ iget_defrag_hint(tsdn_t *tsdn, void* ptr) {
|
||||
int free_in_slab = extent_nfree_get(slab);
|
||||
if (free_in_slab) {
|
||||
const bin_info_t *bin_info = &bin_infos[binind];
|
||||
int curslabs = binshard->stats.curslabs;
|
||||
ssize_t curslabs = binshard->stats.curslabs;
|
||||
size_t curregs = binshard->stats.curregs;
|
||||
if (binshard->slabcur) {
|
||||
/* remove slabcur from the overall utilization */
|
||||
|
||||
+3
-3
@@ -141,12 +141,12 @@ tcp-keepalive 300
|
||||
# server to connected clients, masters or cluster peers. These files should be
|
||||
# PEM formatted.
|
||||
#
|
||||
# tls-cert-file redis.crt
|
||||
# tls-key-file redis.key
|
||||
# tls-cert-file keydb.crt
|
||||
# tls-key-file keydb.key
|
||||
|
||||
# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange:
|
||||
#
|
||||
# tls-dh-params-file redis.dh
|
||||
# tls-dh-params-file keydb.dh
|
||||
|
||||
# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL
|
||||
# clients and peers. Redis requires an explicit configuration of at least one
|
||||
|
||||
+157
-158
@@ -1,6 +1,6 @@
|
||||
# Redis configuration file example.
|
||||
# KeyDB configuration file example.
|
||||
#
|
||||
# Note that in order to read the configuration file, Redis must be
|
||||
# Note that in order to read the configuration file, KeyDB must be
|
||||
# started with the file path as first argument:
|
||||
#
|
||||
# ./keydb-server /path/to/keydb.conf
|
||||
@@ -20,12 +20,12 @@
|
||||
################################## INCLUDES ###################################
|
||||
|
||||
# Include one or more other config files here. This is useful if you
|
||||
# have a standard template that goes to all Redis servers but also need
|
||||
# have a standard template that goes to all KeyDB servers but also need
|
||||
# to customize a few per-server settings. Include files can include
|
||||
# other files, so use this wisely.
|
||||
#
|
||||
# Note that option "include" won't be rewritten by command "CONFIG REWRITE"
|
||||
# from admin or Redis Sentinel. Since Redis always uses the last processed
|
||||
# from admin or KeyDB Sentinel. Since KeyDB always uses the last processed
|
||||
# line as value of a configuration directive, you'd better put includes
|
||||
# at the beginning of this file to avoid overwriting config change at runtime.
|
||||
#
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
################################## NETWORK #####################################
|
||||
|
||||
# By default, if no "bind" configuration directive is specified, Redis listens
|
||||
# By default, if no "bind" configuration directive is specified, KeyDB listens
|
||||
# for connections from all available network interfaces on the host machine.
|
||||
# It is possible to listen to just one or multiple selected interfaces using
|
||||
# the "bind" configuration directive, followed by one or more IP addresses.
|
||||
@@ -61,11 +61,11 @@
|
||||
# bind 127.0.0.1 ::1 # listens on loopback IPv4 and IPv6
|
||||
# bind * -::* # like the default, all available interfaces
|
||||
#
|
||||
# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the
|
||||
# ~~~ WARNING ~~~ If the computer running KeyDB is directly exposed to the
|
||||
# internet, binding to all the interfaces is dangerous and will expose the
|
||||
# instance to everybody on the internet. So by default we uncomment the
|
||||
# following bind directive, that will force Redis to listen only on the
|
||||
# IPv4 and IPv6 (if available) loopback interface addresses (this means Redis
|
||||
# following bind directive, that will force KeyDB to listen only on the
|
||||
# IPv4 and IPv6 (if available) loopback interface addresses (this means KeyDB
|
||||
# will only be able to accept client connections from the same host that it is
|
||||
# running on).
|
||||
#
|
||||
@@ -75,7 +75,7 @@
|
||||
bind 127.0.0.1 ::1
|
||||
|
||||
# Protected mode is a layer of security protection, in order to avoid that
|
||||
# Redis instances left open on the internet are accessed and exploited.
|
||||
# KeyDB instances left open on the internet are accessed and exploited.
|
||||
#
|
||||
# When protected mode is on and if:
|
||||
#
|
||||
@@ -88,13 +88,13 @@ bind 127.0.0.1 ::1
|
||||
# sockets.
|
||||
#
|
||||
# By default protected mode is enabled. You should disable it only if
|
||||
# you are sure you want clients from other hosts to connect to Redis
|
||||
# you are sure you want clients from other hosts to connect to KeyDB
|
||||
# even if no authentication is configured, nor a specific set of interfaces
|
||||
# are explicitly listed using the "bind" directive.
|
||||
protected-mode yes
|
||||
|
||||
# Accept connections on the specified port, default is 6379 (IANA #815344).
|
||||
# If port 0 is specified Redis will not listen on a TCP socket.
|
||||
# If port 0 is specified KeyDB will not listen on a TCP socket.
|
||||
port 6379
|
||||
|
||||
# TCP listen() backlog.
|
||||
@@ -109,7 +109,7 @@ tcp-backlog 511
|
||||
# Unix socket.
|
||||
#
|
||||
# Specify the path for the Unix socket that will be used to listen for
|
||||
# incoming connections. There is no default, so Redis will not listen
|
||||
# incoming connections. There is no default, so KeyDB will not listen
|
||||
# on a unix socket when not specified.
|
||||
#
|
||||
# unixsocket /run/keydb.sock
|
||||
@@ -131,8 +131,7 @@ timeout 0
|
||||
# Note that to close the connection the double of the time is needed.
|
||||
# On other kernels the period depends on the kernel configuration.
|
||||
#
|
||||
# A reasonable value for this option is 300 seconds, which is the new
|
||||
# Redis default starting with Redis 3.2.1.
|
||||
# A reasonable value for this option is 300 seconds, which is the default.
|
||||
tcp-keepalive 300
|
||||
|
||||
################################# TLS/SSL #####################################
|
||||
@@ -156,7 +155,7 @@ tcp-keepalive 300
|
||||
#
|
||||
# tls-key-file-pass secret
|
||||
|
||||
# Normally Redis uses the same certificate for both server functions (accepting
|
||||
# Normally KeyDB uses the same certificate for both server functions (accepting
|
||||
# connections) and client functions (replicating from a master, establishing
|
||||
# cluster bus connections, etc.).
|
||||
#
|
||||
@@ -178,7 +177,7 @@ tcp-keepalive 300
|
||||
# tls-dh-params-file keydb.dh
|
||||
|
||||
# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL
|
||||
# clients and peers. Redis requires an explicit configuration of at least one
|
||||
# clients and peers. KeyDB requires an explicit configuration of at least one
|
||||
# of these, and will not implicitly use the system wide configuration.
|
||||
#
|
||||
# tls-ca-cert-file ca.crt
|
||||
@@ -194,14 +193,14 @@ tcp-keepalive 300
|
||||
# tls-auth-clients no
|
||||
# tls-auth-clients optional
|
||||
|
||||
# By default, a Redis replica does not attempt to establish a TLS connection
|
||||
# By default, a KeyDB replica does not attempt to establish a TLS connection
|
||||
# with its master.
|
||||
#
|
||||
# Use the following directive to enable TLS on replication links.
|
||||
#
|
||||
# tls-replication yes
|
||||
|
||||
# By default, the Redis Cluster bus uses a plain TCP connection. To enable
|
||||
# By default, the KeyDB Cluster bus uses a plain TCP connection. To enable
|
||||
# TLS for the bus protocol, use the following directive:
|
||||
#
|
||||
# tls-cluster yes
|
||||
@@ -251,18 +250,18 @@ tcp-keepalive 300
|
||||
|
||||
################################# GENERAL #####################################
|
||||
|
||||
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that Redis will write a pid file in /var/run/keydb.pid when daemonized.
|
||||
# When Redis is supervised by upstart or systemd, this parameter has no impact.
|
||||
# By default KeyDB does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that KeyDB will write a pid file in /var/run/keydb.pid when daemonized.
|
||||
# When KeyDB is supervised by upstart or systemd, this parameter has no impact.
|
||||
daemonize no
|
||||
|
||||
# If you run Redis from upstart or systemd, Redis can interact with your
|
||||
# If you run KeyDB from upstart or systemd, KeyDB can interact with your
|
||||
# supervision tree. Options:
|
||||
# supervised no - no supervision interaction
|
||||
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
|
||||
# supervised upstart - signal upstart by putting KeyDB into SIGSTOP mode
|
||||
# requires "expect stop" in your upstart job config
|
||||
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
|
||||
# on startup, and updating Redis status on a regular
|
||||
# on startup, and updating KeyDB status on a regular
|
||||
# basis.
|
||||
# supervised auto - detect upstart or systemd method based on
|
||||
# UPSTART_JOB or NOTIFY_SOCKET environment variables
|
||||
@@ -274,14 +273,14 @@ daemonize no
|
||||
#
|
||||
# supervised auto
|
||||
|
||||
# If a pid file is specified, Redis writes it where specified at startup
|
||||
# If a pid file is specified, KeyDB writes it where specified at startup
|
||||
# and removes it at exit.
|
||||
#
|
||||
# When the server runs non daemonized, no pid file is created if none is
|
||||
# specified in the configuration. When the server is daemonized, the pid file
|
||||
# is used even if not specified, defaulting to "/var/run/keydb.pid".
|
||||
#
|
||||
# Creating a pid file is best effort: if Redis is not able to create it
|
||||
# Creating a pid file is best effort: if KeyDB is not able to create it
|
||||
# nothing bad happens, the server will start and run normally.
|
||||
#
|
||||
# Note that on modern Linux systems "/run/keydb.pid" is more conforming
|
||||
@@ -297,7 +296,7 @@ pidfile /var/run/keydb_6379.pid
|
||||
loglevel notice
|
||||
|
||||
# Specify the log file name. Also the empty string can be used to force
|
||||
# Redis to log on the standard output. Note that if you use standard
|
||||
# KeyDB to log on the standard output. Note that if you use standard
|
||||
# output for logging but daemonize, logs will be sent to /dev/null
|
||||
logfile /var/log/keydb/keydb-server.log
|
||||
|
||||
@@ -317,7 +316,7 @@ logfile /var/log/keydb/keydb-server.log
|
||||
# crash-log-enabled no
|
||||
|
||||
# To disable the fast memory check that's run as part of the crash log, which
|
||||
# will possibly let keydb terminate sooner, uncomment the following:
|
||||
# will possibly let KeyDB terminate sooner, uncomment the following:
|
||||
#
|
||||
# crash-memcheck-enabled no
|
||||
|
||||
@@ -326,7 +325,7 @@ logfile /var/log/keydb/keydb-server.log
|
||||
# dbid is a number between 0 and 'databases'-1
|
||||
databases 16
|
||||
|
||||
# By default Redis shows an ASCII art logo only when started to log to the
|
||||
# By default KeyDB shows an ASCII art logo only when started to log to the
|
||||
# standard output and if the standard output is a TTY and syslog logging is
|
||||
# disabled. Basically this means that normally a logo is displayed only in
|
||||
# interactive sessions.
|
||||
@@ -335,12 +334,12 @@ databases 16
|
||||
# ASCII art logo in startup logs by setting the following option to yes.
|
||||
always-show-logo no
|
||||
|
||||
# By default, Redis modifies the process title (as seen in 'top' and 'ps') to
|
||||
# By default, KeyDB 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
|
||||
# When changing the process title, KeyDB uses the following template to construct
|
||||
# the modified title.
|
||||
#
|
||||
# Template variables are specified in curly brackets. The following variables are
|
||||
@@ -363,7 +362,7 @@ proc-title-template "{title} {listen-addr} {server-mode}"
|
||||
#
|
||||
# save <seconds> <changes>
|
||||
#
|
||||
# Redis will save the DB if both the given number of seconds and the given
|
||||
# KeyDB will save the DB if both the given number of seconds and the given
|
||||
# number of write operations against the DB occurred.
|
||||
#
|
||||
# Snapshotting can be completely disabled with a single empty string argument
|
||||
@@ -371,7 +370,7 @@ proc-title-template "{title} {listen-addr} {server-mode}"
|
||||
#
|
||||
# save ""
|
||||
#
|
||||
# Unless specified otherwise, by default Redis will save the DB:
|
||||
# Unless specified otherwise, by default KeyDB 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
|
||||
@@ -382,17 +381,17 @@ proc-title-template "{title} {listen-addr} {server-mode}"
|
||||
# save 300 100
|
||||
# save 60 10000
|
||||
|
||||
# By default Redis will stop accepting writes if RDB snapshots are enabled
|
||||
# By default KeyDB will stop accepting writes if RDB snapshots are enabled
|
||||
# (at least one save point) and the latest background save failed.
|
||||
# This will make the user aware (in a hard way) that data is not persisting
|
||||
# on disk properly, otherwise chances are that no one will notice and some
|
||||
# disaster will happen.
|
||||
#
|
||||
# If the background saving process will start working again Redis will
|
||||
# If the background saving process will start working again KeyDB will
|
||||
# automatically allow writes again.
|
||||
#
|
||||
# However if you have setup your proper monitoring of the Redis server
|
||||
# and persistence, you may want to disable this feature so that Redis will
|
||||
# However if you have setup your proper monitoring of the KeyDB server
|
||||
# and persistence, you may want to disable this feature so that KeyDB will
|
||||
# continue to work as usual even if there are problems with disk,
|
||||
# permissions, and so forth.
|
||||
stop-writes-on-bgsave-error yes
|
||||
@@ -455,18 +454,18 @@ dir /var/lib/keydb
|
||||
|
||||
################################# REPLICATION #################################
|
||||
|
||||
# Master-Replica replication. Use replicaof to make a Redis instance a copy of
|
||||
# another Redis server. A few things to understand ASAP about Redis replication.
|
||||
# Master-Replica replication. Use replicaof to make a KeyDB instance a copy of
|
||||
# another KeyDB server. A few things to understand ASAP about KeyDB replication.
|
||||
#
|
||||
# +------------------+ +---------------+
|
||||
# | Master | ---> | Replica |
|
||||
# | (receive writes) | | (exact copy) |
|
||||
# +------------------+ +---------------+
|
||||
#
|
||||
# 1) Redis replication is asynchronous, but you can configure a master to
|
||||
# 1) KeyDB replication is asynchronous, but you can configure a master to
|
||||
# stop accepting writes if it appears to be not connected with at least
|
||||
# a given number of replicas.
|
||||
# 2) Redis replicas are able to perform a partial resynchronization with the
|
||||
# 2) KeyDB replicas are able to perform a partial resynchronization with the
|
||||
# master if the replication link is lost for a relatively small amount of
|
||||
# time. You may want to configure the replication backlog size (see the next
|
||||
# sections of this file) with a sensible value depending on your needs.
|
||||
@@ -483,7 +482,7 @@ dir /var/lib/keydb
|
||||
#
|
||||
# masterauth <master-password>
|
||||
#
|
||||
# However this is not enough if you are using Redis ACLs (for Redis version
|
||||
# However this is not enough if you are using KeyDB ACLs (for KeyDB version
|
||||
# 6 or greater), and the default user is not capable of running the PSYNC
|
||||
# command and/or other commands needed for replication. In this case it's
|
||||
# better to configure a special user to use with replication, and specify the
|
||||
@@ -515,7 +514,7 @@ replica-serve-stale-data yes
|
||||
# may also cause problems if clients are writing to it because of a
|
||||
# misconfiguration.
|
||||
#
|
||||
# Since Redis 2.6 by default replicas are read-only.
|
||||
# Since KeyDB 2.6 by default replicas are read-only.
|
||||
#
|
||||
# Note: read only replicas are not designed to be exposed to untrusted clients
|
||||
# on the internet. It's just a protection layer against misuse of the instance.
|
||||
@@ -536,10 +535,10 @@ replica-read-only yes
|
||||
# synchronization". An RDB file is transmitted from the master to the replicas.
|
||||
# The transmission can happen in two different ways:
|
||||
#
|
||||
# 1) Disk-backed: The Redis master creates a new process that writes the RDB
|
||||
# 1) Disk-backed: The KeyDB master creates a new process that writes the RDB
|
||||
# file on disk. Later the file is transferred by the parent
|
||||
# process to the replicas incrementally.
|
||||
# 2) Diskless: The Redis master creates a new process that directly writes the
|
||||
# 2) Diskless: The KeyDB master creates a new process that directly writes the
|
||||
# RDB file to replica sockets, without touching the disk at all.
|
||||
#
|
||||
# With disk-backed replication, while the RDB file is generated, more replicas
|
||||
@@ -571,8 +570,8 @@ repl-diskless-sync-delay 5
|
||||
# -----------------------------------------------------------------------------
|
||||
# WARNING: RDB diskless load is experimental. Since in this setup the replica
|
||||
# does not immediately store an RDB on disk, it may cause data loss during
|
||||
# failovers. RDB diskless load + Redis modules not handling I/O reads may also
|
||||
# cause Redis to abort in case of I/O errors during the initial synchronization
|
||||
# failovers. RDB diskless load + KeyDB modules not handling I/O reads may also
|
||||
# cause KeyDB to abort in case of I/O errors during the initial synchronization
|
||||
# stage with the master. Use only if you know what you are doing.
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
@@ -615,7 +614,7 @@ repl-diskless-load disabled
|
||||
|
||||
# Disable TCP_NODELAY on the replica socket after SYNC?
|
||||
#
|
||||
# If you select "yes" Redis will use a smaller number of TCP packets and
|
||||
# If you select "yes" KeyDB will use a smaller number of TCP packets and
|
||||
# less bandwidth to send data to replicas. But this can add a delay for
|
||||
# the data to appear on the replica side, up to 40 milliseconds with
|
||||
# Linux kernels using a default configuration.
|
||||
@@ -654,8 +653,8 @@ repl-disable-tcp-nodelay no
|
||||
#
|
||||
# repl-backlog-ttl 3600
|
||||
|
||||
# The replica priority is an integer number published by Redis in the INFO output.
|
||||
# It is used by Redis Sentinel in order to select a replica to promote into a
|
||||
# The replica priority is an integer number published by KeyDB in the INFO output.
|
||||
# It is used by KeyDB Sentinel in order to select a replica to promote into a
|
||||
# master if the master is no longer working correctly.
|
||||
#
|
||||
# A replica with a low priority number is considered better for promotion, so
|
||||
@@ -664,16 +663,16 @@ repl-disable-tcp-nodelay no
|
||||
#
|
||||
# However a special priority of 0 marks the replica as not able to perform the
|
||||
# role of master, so a replica with priority of 0 will never be selected by
|
||||
# Redis Sentinel for promotion.
|
||||
# KeyDB Sentinel for promotion.
|
||||
#
|
||||
# By default the priority is 100.
|
||||
replica-priority 100
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# By default, Redis Sentinel includes all replicas in its reports. A replica
|
||||
# can be excluded from Redis Sentinel's announcements. An unannounced replica
|
||||
# By default, KeyDB Sentinel includes all replicas in its reports. A replica
|
||||
# can be excluded from KeyDB Sentinel's announcements. An unannounced replica
|
||||
# will be ignored by the 'sentinel replicas <master>' command and won't be
|
||||
# exposed to Redis Sentinel's clients.
|
||||
# exposed to KeyDB Sentinel's clients.
|
||||
#
|
||||
# This option does not change the behavior of replica-priority. Even with
|
||||
# replica-announced set to 'no', the replica can be promoted to master. To
|
||||
@@ -703,10 +702,10 @@ replica-priority 100
|
||||
# By default min-replicas-to-write is set to 0 (feature disabled) and
|
||||
# min-replicas-max-lag is set to 10.
|
||||
|
||||
# A Redis master is able to list the address and port of the attached
|
||||
# A KeyDB master is able to list the address and port of the attached
|
||||
# replicas in different ways. For example the "INFO replication" section
|
||||
# offers this information, which is used, among other tools, by
|
||||
# Redis Sentinel in order to discover replica instances.
|
||||
# KeyDB Sentinel in order to discover replica instances.
|
||||
# Another place where this info is available is in the output of the
|
||||
# "ROLE" command of a master.
|
||||
#
|
||||
@@ -734,7 +733,7 @@ replica-priority 100
|
||||
|
||||
############################### KEYS TRACKING #################################
|
||||
|
||||
# Redis implements server assisted support for client side caching of values.
|
||||
# KeyDB implements server assisted support for client side caching of values.
|
||||
# This is implemented using an invalidation table that remembers, using
|
||||
# a radix key indexed by key name, what clients have which keys. In turn
|
||||
# this is used in order to send invalidation messages to clients. Please
|
||||
@@ -743,22 +742,22 @@ replica-priority 100
|
||||
# https://redis.io/topics/client-side-caching
|
||||
#
|
||||
# When tracking is enabled for a client, all the read only queries are assumed
|
||||
# to be cached: this will force Redis to store information in the invalidation
|
||||
# to be cached: this will force KeyDB to store information in the invalidation
|
||||
# table. When keys are modified, such information is flushed away, and
|
||||
# invalidation messages are sent to the clients. However if the workload is
|
||||
# heavily dominated by reads, Redis could use more and more memory in order
|
||||
# heavily dominated by reads, KeyDB could use more and more memory in order
|
||||
# to track the keys fetched by many clients.
|
||||
#
|
||||
# For this reason it is possible to configure a maximum fill value for the
|
||||
# invalidation table. By default it is set to 1M of keys, and once this limit
|
||||
# is reached, Redis will start to evict keys in the invalidation table
|
||||
# is reached, KeyDB will start to evict keys in the invalidation table
|
||||
# even if they were not modified, just to reclaim memory: this will in turn
|
||||
# force the clients to invalidate the cached values. Basically the table
|
||||
# maximum size is a trade off between the memory you want to spend server
|
||||
# side to track information about who cached what, and the ability of clients
|
||||
# to retain cached objects in memory.
|
||||
#
|
||||
# If you set the value to 0, it means there are no limits, and Redis will
|
||||
# If you set the value to 0, it means there are no limits, and KeyDB will
|
||||
# retain as many keys as needed in the invalidation table.
|
||||
# In the "stats" INFO section, you can find information about the number of
|
||||
# keys in the invalidation table at every given moment.
|
||||
@@ -770,7 +769,7 @@ replica-priority 100
|
||||
|
||||
################################## SECURITY ###################################
|
||||
|
||||
# Warning: since Redis is pretty fast, an outside user can try up to
|
||||
# Warning: since KeyDB is pretty fast, an outside user can try up to
|
||||
# 1 million passwords per second against a modern box. This means that you
|
||||
# should use very strong passwords, otherwise they will be very easy to break.
|
||||
# Note that because the password is really a shared secret between the client
|
||||
@@ -778,7 +777,7 @@ replica-priority 100
|
||||
# can be easily a long string from /dev/urandom or whatever, so by using a
|
||||
# long and unguessable password no brute force attack will be possible.
|
||||
|
||||
# Redis ACL users are defined in the following format:
|
||||
# KeyDB ACL users are defined in the following format:
|
||||
#
|
||||
# user <username> ... acl rules ...
|
||||
#
|
||||
@@ -807,7 +806,7 @@ replica-priority 100
|
||||
# +@<category> Allow the execution of all the commands in such category
|
||||
# with valid categories are like @admin, @set, @sortedset, ...
|
||||
# and so forth, see the full list in the server.c file where
|
||||
# the Redis command table is described and defined.
|
||||
# the KeyDB command table is described and defined.
|
||||
# The special category @all means all the commands, but currently
|
||||
# present in the server, and that will be loaded in the future
|
||||
# via modules.
|
||||
@@ -891,7 +890,7 @@ acllog-max-len 128
|
||||
#
|
||||
# aclfile /etc/keydb/users.acl
|
||||
|
||||
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatibility
|
||||
# IMPORTANT NOTE: starting with KeyDB 6 "requirepass" is just a compatibility
|
||||
# layer on top of the new ACL system. The option effect will be just setting
|
||||
# the password for the default user. Clients will still authenticate using
|
||||
# AUTH <password> as usually, or more explicitly with AUTH default <password>
|
||||
@@ -903,7 +902,7 @@ acllog-max-len 128
|
||||
# requirepass foobared
|
||||
|
||||
# New users are initialized with restrictive permissions by default, via the
|
||||
# equivalent of this ACL rule 'off resetkeys -@all'. Starting with Redis 6.2, it
|
||||
# equivalent of this ACL rule 'off resetkeys -@all'. Starting with KeyDB 6.2, it
|
||||
# is possible to manage access to Pub/Sub channels with ACL rules as well. The
|
||||
# default Pub/Sub channels permission if new users is controlled by the
|
||||
# acl-pubsub-default configuration directive, which accepts one of these values:
|
||||
@@ -911,10 +910,10 @@ acllog-max-len 128
|
||||
# allchannels: grants access to all Pub/Sub channels
|
||||
# resetchannels: revokes access to all Pub/Sub channels
|
||||
#
|
||||
# To ensure backward compatibility while upgrading Redis 6.0, acl-pubsub-default
|
||||
# To ensure backward compatibility while upgrading KeyDB 6.0, acl-pubsub-default
|
||||
# defaults to the 'allchannels' permission.
|
||||
#
|
||||
# Future compatibility note: it is very likely that in a future version of Redis
|
||||
# Future compatibility note: it is very likely that in a future version of KeyDB
|
||||
# the directive's default of 'allchannels' will be changed to 'resetchannels' in
|
||||
# order to provide better out-of-the-box Pub/Sub security. Therefore, it is
|
||||
# recommended that you explicitly define Pub/Sub permissions for all users
|
||||
@@ -951,15 +950,15 @@ acllog-max-len 128
|
||||
################################### CLIENTS ####################################
|
||||
|
||||
# Set the max number of connected clients at the same time. By default
|
||||
# this limit is set to 10000 clients, however if the Redis server is not
|
||||
# this limit is set to 10000 clients, however if the KeyDB server is not
|
||||
# able to configure the process file limit to allow for the specified limit
|
||||
# the max number of allowed clients is set to the current file limit
|
||||
# minus 32 (as Redis reserves a few file descriptors for internal uses).
|
||||
# minus 32 (as KeyDB reserves a few file descriptors for internal uses).
|
||||
#
|
||||
# Once the limit is reached Redis will close all the new connections sending
|
||||
# Once the limit is reached KeyDB will close all the new connections sending
|
||||
# an error 'max number of clients reached'.
|
||||
#
|
||||
# IMPORTANT: When Redis Cluster is used, the max number of connections is also
|
||||
# IMPORTANT: When KeyDB Cluster is used, the max number of connections is also
|
||||
# shared with the cluster bus: every node in the cluster will use two
|
||||
# connections, one incoming and another outgoing. It is important to size the
|
||||
# limit accordingly in case of very large clusters.
|
||||
@@ -969,15 +968,15 @@ acllog-max-len 128
|
||||
############################## MEMORY MANAGEMENT ################################
|
||||
|
||||
# Set a memory usage limit to the specified amount of bytes.
|
||||
# When the memory limit is reached Redis will try to remove keys
|
||||
# When the memory limit is reached KeyDB will try to remove keys
|
||||
# according to the eviction policy selected (see maxmemory-policy).
|
||||
#
|
||||
# If Redis can't remove keys according to the policy, or if the policy is
|
||||
# set to 'noeviction', Redis will start to reply with errors to commands
|
||||
# If KeyDB can't remove keys according to the policy, or if the policy is
|
||||
# set to 'noeviction', KeyDB will start to reply with errors to commands
|
||||
# that would use more memory, like SET, LPUSH, and so on, and will continue
|
||||
# to reply to read-only commands like GET.
|
||||
#
|
||||
# This option is usually useful when using Redis as an LRU or LFU cache, or to
|
||||
# This option is usually useful when using KeyDB as an LRU or LFU cache, or to
|
||||
# set a hard memory limit for an instance (using the 'noeviction' policy).
|
||||
#
|
||||
# WARNING: If you have replicas attached to an instance with maxmemory on,
|
||||
@@ -993,7 +992,7 @@ acllog-max-len 128
|
||||
#
|
||||
# maxmemory <bytes>
|
||||
|
||||
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
|
||||
# MAXMEMORY POLICY: how KeyDB will select what to remove when maxmemory
|
||||
# is reached. You can select among five behaviors:
|
||||
#
|
||||
# volatile-lru -> Evict using approximated LRU among the keys with an expire set.
|
||||
@@ -1012,7 +1011,7 @@ acllog-max-len 128
|
||||
# randomized algorithms.
|
||||
#
|
||||
# Note: with any of the above policies, when there are no suitable keys for
|
||||
# eviction, Redis will return an error on write operations that require
|
||||
# eviction, KeyDB will return an error on write operations that require
|
||||
# more memory. These are usually commands that create new keys, add data or
|
||||
# modify existing keys. A few examples are: SET, INCR, HSET, LPUSH, SUNIONSTORE,
|
||||
# SORT (due to the STORE argument), and EXEC (if the transaction includes any
|
||||
@@ -1024,7 +1023,7 @@ acllog-max-len 128
|
||||
|
||||
# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated
|
||||
# algorithms (in order to save memory), so you can tune it for speed or
|
||||
# accuracy. By default Redis will check five keys and pick the one that was
|
||||
# accuracy. By default KeyDB will check five keys and pick the one that was
|
||||
# used least recently, you can change the sample size using the following
|
||||
# configuration directive.
|
||||
#
|
||||
@@ -1041,7 +1040,7 @@ acllog-max-len 128
|
||||
#
|
||||
# maxmemory-eviction-tenacity 10
|
||||
|
||||
# Starting from Redis 5, by default a replica will ignore its maxmemory setting
|
||||
# Starting from KeyDB 5, by default a replica will ignore its maxmemory setting
|
||||
# (unless it is promoted to master after a failover or manually). It means
|
||||
# that the eviction of keys will be just handled by the master, sending the
|
||||
# DEL commands to the replica as keys evict in the master side.
|
||||
@@ -1061,7 +1060,7 @@ acllog-max-len 128
|
||||
#
|
||||
# replica-ignore-maxmemory yes
|
||||
|
||||
# Redis reclaims expired keys in two ways: upon access when those keys are
|
||||
# KeyDB reclaims expired keys in two ways: upon access when those keys are
|
||||
# found to be expired, and also in background, in what is called the
|
||||
# "active expire key". The key space is slowly and interactively scanned
|
||||
# looking for expired keys to reclaim, so that it is possible to free memory
|
||||
@@ -1080,16 +1079,16 @@ acllog-max-len 128
|
||||
|
||||
############################# LAZY FREEING ####################################
|
||||
|
||||
# Redis has two primitives to delete keys. One is called DEL and is a blocking
|
||||
# KeyDB has two primitives to delete keys. One is called DEL and is a blocking
|
||||
# deletion of the object. It means that the server stops processing new commands
|
||||
# in order to reclaim all the memory associated with an object in a synchronous
|
||||
# way. If the key deleted is associated with a small object, the time needed
|
||||
# in order to execute the DEL command is very small and comparable to most other
|
||||
# O(1) or O(log_N) commands in Redis. However if the key is associated with an
|
||||
# O(1) or O(log_N) commands in KeyDB. However if the key is associated with an
|
||||
# aggregated value containing millions of elements, the server can block for
|
||||
# a long time (even seconds) in order to complete the operation.
|
||||
#
|
||||
# For the above reasons Redis also offers non blocking deletion primitives
|
||||
# For the above reasons KeyDB also offers non blocking deletion primitives
|
||||
# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and
|
||||
# FLUSHDB commands, in order to reclaim memory in background. Those commands
|
||||
# are executed in constant time. Another thread will incrementally free the
|
||||
@@ -1097,9 +1096,9 @@ acllog-max-len 128
|
||||
#
|
||||
# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled.
|
||||
# It's up to the design of the application to understand when it is a good
|
||||
# idea to use one or the other. However the Redis server sometimes has to
|
||||
# idea to use one or the other. However the KeyDB server sometimes has to
|
||||
# delete keys or flush the whole database as a side effect of other operations.
|
||||
# Specifically Redis deletes objects independently of a user call in the
|
||||
# Specifically KeyDB deletes objects independently of a user call in the
|
||||
# following scenarios:
|
||||
#
|
||||
# 1) On eviction, because of the maxmemory and maxmemory policy configurations,
|
||||
@@ -1143,21 +1142,21 @@ lazyfree-lazy-user-flush no
|
||||
|
||||
################################ THREADED I/O #################################
|
||||
|
||||
# Redis is mostly single threaded, however there are certain threaded
|
||||
# KeyDB is mostly single threaded, however there are certain threaded
|
||||
# operations such as UNLINK, slow I/O accesses and other things that are
|
||||
# performed on side threads.
|
||||
#
|
||||
# Now it is also possible to handle Redis clients socket reads and writes
|
||||
# Now it is also possible to handle KeyDB clients socket reads and writes
|
||||
# in different I/O threads. Since especially writing is so slow, normally
|
||||
# Redis users use pipelining in order to speed up the Redis performances per
|
||||
# KeyDB users use pipelining in order to speed up the KeyDB performances per
|
||||
# core, and spawn multiple instances in order to scale more. Using I/O
|
||||
# threads it is possible to easily speedup two times Redis without resorting
|
||||
# threads it is possible to easily speedup two times KeyDB without resorting
|
||||
# to pipelining nor sharding of the instance.
|
||||
#
|
||||
# By default threading is disabled, we suggest enabling it only in machines
|
||||
# that have at least 4 or more cores, leaving at least one spare core.
|
||||
# Using more than 8 threads is unlikely to help much. We also recommend using
|
||||
# threaded I/O only if you actually have performance problems, with Redis
|
||||
# threaded I/O only if you actually have performance problems, with KeyDB
|
||||
# instances being able to use a quite big percentage of CPU time, otherwise
|
||||
# there is no point in using this feature.
|
||||
#
|
||||
@@ -1182,9 +1181,9 @@ lazyfree-lazy-user-flush no
|
||||
# CONFIG SET. Aso this feature currently does not work when SSL is
|
||||
# enabled.
|
||||
#
|
||||
# NOTE 2: If you want to test the Redis speedup using keydb-benchmark, make
|
||||
# NOTE 2: If you want to test the KeyDB speedup using keydb-benchmark, make
|
||||
# sure you also run the benchmark itself in threaded mode, using the
|
||||
# --threads option to match the number of Redis threads, otherwise you'll not
|
||||
# --threads option to match the number of KeyDB threads, otherwise you'll not
|
||||
# be able to notice the improvements.
|
||||
|
||||
############################ KERNEL OOM CONTROL ##############################
|
||||
@@ -1192,12 +1191,12 @@ lazyfree-lazy-user-flush no
|
||||
# On Linux, it is possible to hint the kernel OOM killer on what processes
|
||||
# should be killed first when out of memory.
|
||||
#
|
||||
# Enabling this feature makes Redis actively control the oom_score_adj value
|
||||
# Enabling this feature makes KeyDB actively control the oom_score_adj value
|
||||
# for all its processes, depending on their role. The default scores will
|
||||
# attempt to have background child processes killed before all others, and
|
||||
# replicas killed before masters.
|
||||
#
|
||||
# Redis supports three options:
|
||||
# KeyDB supports three options:
|
||||
#
|
||||
# no: Don't make changes to oom-score-adj (default).
|
||||
# yes: Alias to "relative" see below.
|
||||
@@ -1224,7 +1223,7 @@ oom-score-adj-values 0 200 800
|
||||
# Usually the kernel Transparent Huge Pages control is set to "madvise" or
|
||||
# or "never" by default (/sys/kernel/mm/transparent_hugepage/enabled), in which
|
||||
# case this config has no effect. On systems in which it is set to "always",
|
||||
# keydb will attempt to disable it specifically for the keydb process in order
|
||||
# KeyDB will attempt to disable it specifically for the keydb process in order
|
||||
# to avoid latency problems specifically with fork(2) and CoW.
|
||||
# If for some reason you prefer to keep it enabled, you can set this config to
|
||||
# "no" and the kernel global to "always".
|
||||
@@ -1233,20 +1232,20 @@ disable-thp yes
|
||||
|
||||
############################## APPEND ONLY MODE ###############################
|
||||
|
||||
# By default Redis asynchronously dumps the dataset on disk. This mode is
|
||||
# good enough in many applications, but an issue with the Redis process or
|
||||
# By default KeyDB asynchronously dumps the dataset on disk. This mode is
|
||||
# good enough in many applications, but an issue with the KeyDB process or
|
||||
# a power outage may result into a few minutes of writes lost (depending on
|
||||
# the configured save points).
|
||||
#
|
||||
# The Append Only File is an alternative persistence mode that provides
|
||||
# much better durability. For instance using the default data fsync policy
|
||||
# (see later in the config file) Redis can lose just one second of writes in a
|
||||
# (see later in the config file) KeyDB can lose just one second of writes in a
|
||||
# dramatic event like a server power outage, or a single write if something
|
||||
# wrong with the Redis process itself happens, but the operating system is
|
||||
# wrong with the KeyDB process itself happens, but the operating system is
|
||||
# still running correctly.
|
||||
#
|
||||
# AOF and RDB persistence can be enabled at the same time without problems.
|
||||
# If the AOF is enabled on startup Redis will load the AOF, that is the file
|
||||
# If the AOF is enabled on startup KeyDB will load the AOF, that is the file
|
||||
# with the better durability guarantees.
|
||||
#
|
||||
# Please check https://redis.io/topics/persistence for more information.
|
||||
@@ -1261,7 +1260,7 @@ appendfilename "appendonly.aof"
|
||||
# instead of waiting for more data in the output buffer. Some OS will really flush
|
||||
# data on disk, some other OS will just try to do it ASAP.
|
||||
#
|
||||
# Redis supports three different modes:
|
||||
# KeyDB supports three different modes:
|
||||
#
|
||||
# no: don't fsync, just let the OS flush the data when it wants. Faster.
|
||||
# always: fsync after every write to the append only log. Slow, Safest.
|
||||
@@ -1287,7 +1286,7 @@ appendfsync everysec
|
||||
# When the AOF fsync policy is set to always or everysec, and a background
|
||||
# saving process (a background save or AOF log background rewriting) is
|
||||
# performing a lot of I/O against the disk, in some Linux configurations
|
||||
# Redis may block too long on the fsync() call. Note that there is no fix for
|
||||
# KeyDB may block too long on the fsync() call. Note that there is no fix for
|
||||
# this currently, as even performing fsync in a different thread will block
|
||||
# our synchronous write(2) call.
|
||||
#
|
||||
@@ -1295,7 +1294,7 @@ appendfsync everysec
|
||||
# that will prevent fsync() from being called in the main process while a
|
||||
# BGSAVE or BGREWRITEAOF is in progress.
|
||||
#
|
||||
# This means that while another child is saving, the durability of Redis is
|
||||
# This means that while another child is saving, the durability of KeyDB is
|
||||
# the same as "appendfsync none". In practical terms, this means that it is
|
||||
# possible to lose up to 30 seconds of log in the worst scenario (with the
|
||||
# default Linux settings).
|
||||
@@ -1306,10 +1305,10 @@ appendfsync everysec
|
||||
no-appendfsync-on-rewrite no
|
||||
|
||||
# Automatic rewrite of the append only file.
|
||||
# Redis is able to automatically rewrite the log file implicitly calling
|
||||
# KeyDB is able to automatically rewrite the log file implicitly calling
|
||||
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
|
||||
#
|
||||
# This is how it works: Redis remembers the size of the AOF file after the
|
||||
# This is how it works: KeyDB remembers the size of the AOF file after the
|
||||
# latest rewrite (if no rewrite has happened since the restart, the size of
|
||||
# the AOF at startup is used).
|
||||
#
|
||||
@@ -1325,19 +1324,19 @@ no-appendfsync-on-rewrite no
|
||||
auto-aof-rewrite-percentage 100
|
||||
auto-aof-rewrite-min-size 64mb
|
||||
|
||||
# An AOF file may be found to be truncated at the end during the Redis
|
||||
# An AOF file may be found to be truncated at the end during the KeyDB
|
||||
# startup process, when the AOF data gets loaded back into memory.
|
||||
# This may happen when the system where Redis is running
|
||||
# This may happen when the system where KeyDB is running
|
||||
# crashes, especially when an ext4 filesystem is mounted without the
|
||||
# data=ordered option (however this can't happen when Redis itself
|
||||
# data=ordered option (however this can't happen when KeyDB itself
|
||||
# crashes or aborts but the operating system still works correctly).
|
||||
#
|
||||
# Redis can either exit with an error when this happens, or load as much
|
||||
# KeyDB can either exit with an error when this happens, or load as much
|
||||
# data as possible (the default now) and start if the AOF file is found
|
||||
# to be truncated at the end. The following option controls this behavior.
|
||||
#
|
||||
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
|
||||
# the Redis server starts emitting a log to inform the user of the event.
|
||||
# the KeyDB server starts emitting a log to inform the user of the event.
|
||||
# Otherwise if the option is set to no, the server aborts with an error
|
||||
# and refuses to start. When the option is set to no, the user requires
|
||||
# to fix the AOF file using the "keydb-check-aof" utility before to restart
|
||||
@@ -1345,17 +1344,17 @@ auto-aof-rewrite-min-size 64mb
|
||||
#
|
||||
# Note that if the AOF file will be found to be corrupted in the middle
|
||||
# the server will still exit with an error. This option only applies when
|
||||
# Redis will try to read more data from the AOF file but not enough bytes
|
||||
# KeyDB will try to read more data from the AOF file but not enough bytes
|
||||
# will be found.
|
||||
aof-load-truncated yes
|
||||
|
||||
# When rewriting the AOF file, Redis is able to use an RDB preamble in the
|
||||
# When rewriting the AOF file, KeyDB is able to use an RDB preamble in the
|
||||
# AOF file for faster rewrites and recoveries. When this option is turned
|
||||
# on the rewritten AOF file is composed of two different stanzas:
|
||||
#
|
||||
# [RDB file][AOF tail]
|
||||
#
|
||||
# When loading, Redis recognizes that the AOF file starts with the "REDIS"
|
||||
# When loading, KeyDB recognizes that the AOF file starts with the "REDIS"
|
||||
# string and loads the prefixed RDB file, then continues loading the AOF
|
||||
# tail.
|
||||
aof-use-rdb-preamble yes
|
||||
@@ -1364,7 +1363,7 @@ aof-use-rdb-preamble yes
|
||||
|
||||
# Max execution time of a Lua script in milliseconds.
|
||||
#
|
||||
# If the maximum execution time is reached Redis will log that a script is
|
||||
# If the maximum execution time is reached KeyDB will log that a script is
|
||||
# still in execution after the maximum allowed time and will start to
|
||||
# reply to queries with an error.
|
||||
#
|
||||
@@ -1378,23 +1377,23 @@ aof-use-rdb-preamble yes
|
||||
# Set it to 0 or a negative value for unlimited execution without warnings.
|
||||
lua-time-limit 5000
|
||||
|
||||
################################ REDIS CLUSTER ###############################
|
||||
################################ KEYDB CLUSTER ###############################
|
||||
#
|
||||
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however
|
||||
# WARNING EXPERIMENTAL: KeyDB Cluster is considered to be stable code, however
|
||||
# in order to mark it as "mature" we need to wait for a non trivial percentage
|
||||
# of users to deploy it in production.
|
||||
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
#
|
||||
# Normal Redis instances can't be part of a Redis Cluster; only nodes that are
|
||||
# started as cluster nodes can. In order to start a Redis instance as a
|
||||
# Normal KeyDB instances can't be part of a KeyDB Cluster; only nodes that are
|
||||
# started as cluster nodes can. In order to start a KeyDB instance as a
|
||||
# cluster node enable the cluster support uncommenting the following:
|
||||
#
|
||||
# cluster-enabled yes
|
||||
|
||||
# Every cluster node has a cluster configuration file. This file is not
|
||||
# intended to be edited by hand. It is created and updated by Redis nodes.
|
||||
# Every Redis Cluster node requires a different cluster configuration file.
|
||||
# intended to be edited by hand. It is created and updated by KeyDB nodes.
|
||||
# Every KeyDB Cluster node requires a different cluster configuration file.
|
||||
# Make sure that instances running in the same system do not have
|
||||
# overlapping cluster configuration file names.
|
||||
#
|
||||
@@ -1479,7 +1478,7 @@ lua-time-limit 5000
|
||||
#
|
||||
# cluster-allow-replica-migration yes
|
||||
|
||||
# By default Redis Cluster nodes stop accepting queries if they detect there
|
||||
# By default KeyDB Cluster nodes stop accepting queries if they detect there
|
||||
# is at least a hash slot uncovered (no available node is serving it).
|
||||
# This way if the cluster is partially down (for example a range of hash slots
|
||||
# are no longer covered) all the cluster becomes, eventually, unavailable.
|
||||
@@ -1507,11 +1506,11 @@ lua-time-limit 5000
|
||||
|
||||
########################## CLUSTER DOCKER/NAT support ########################
|
||||
|
||||
# In certain deployments, Redis Cluster nodes address discovery fails, because
|
||||
# In certain deployments, KeyDB Cluster nodes address discovery fails, because
|
||||
# addresses are NAT-ted or because ports are forwarded (the typical case is
|
||||
# Docker and other containers).
|
||||
#
|
||||
# In order to make Redis Cluster working in such environments, a static
|
||||
# In order to make KeyDB Cluster working in such environments, a static
|
||||
# configuration where each node knows its public address is needed. The
|
||||
# following four options are used for this scope, and are:
|
||||
#
|
||||
@@ -1529,7 +1528,7 @@ lua-time-limit 5000
|
||||
# to zero, then cluster-announce-port refers to the TLS port. Note also that
|
||||
# cluster-announce-tls-port has no effect if cluster-tls is set to no.
|
||||
#
|
||||
# If the above options are not used, the normal Redis Cluster auto-detection
|
||||
# If the above options are not used, the normal KeyDB Cluster auto-detection
|
||||
# will be used instead.
|
||||
#
|
||||
# Note that when remapped, the bus port may not be at the fixed offset of
|
||||
@@ -1546,14 +1545,14 @@ lua-time-limit 5000
|
||||
|
||||
################################## SLOW LOG ###################################
|
||||
|
||||
# The Redis Slow Log is a system to log queries that exceeded a specified
|
||||
# The KeyDB Slow Log is a system to log queries that exceeded a specified
|
||||
# execution time. The execution time does not include the I/O operations
|
||||
# like talking with the client, sending the reply and so forth,
|
||||
# but just the time needed to actually execute the command (this is the only
|
||||
# stage of command execution where the thread is blocked and can not serve
|
||||
# other requests in the meantime).
|
||||
#
|
||||
# You can configure the slow log with two parameters: one tells Redis
|
||||
# You can configure the slow log with two parameters: one tells KeyDB
|
||||
# what is the execution time, in microseconds, to exceed in order for the
|
||||
# command to get logged, and the other parameter is the length of the
|
||||
# slow log. When a new command is logged the oldest one is removed from the
|
||||
@@ -1570,9 +1569,9 @@ slowlog-max-len 128
|
||||
|
||||
################################ LATENCY MONITOR ##############################
|
||||
|
||||
# The Redis latency monitoring subsystem samples different operations
|
||||
# The KeyDB latency monitoring subsystem samples different operations
|
||||
# at runtime in order to collect data related to possible sources of
|
||||
# latency of a Redis instance.
|
||||
# latency of a KeyDB instance.
|
||||
#
|
||||
# Via the LATENCY command this information is available to the user that can
|
||||
# print graphs and obtain reports.
|
||||
@@ -1591,7 +1590,7 @@ latency-monitor-threshold 0
|
||||
|
||||
############################# EVENT NOTIFICATION ##############################
|
||||
|
||||
# Redis can notify Pub/Sub clients about events happening in the key space.
|
||||
# KeyDB can notify Pub/Sub clients about events happening in the key space.
|
||||
# This feature is documented at https://redis.io/topics/notifications
|
||||
#
|
||||
# For instance if keyspace events notification is enabled, and a client
|
||||
@@ -1601,7 +1600,7 @@ latency-monitor-threshold 0
|
||||
# PUBLISH __keyspace@0__:foo del
|
||||
# PUBLISH __keyevent@0__:del foo
|
||||
#
|
||||
# It is possible to select the events that Redis will notify among a set
|
||||
# It is possible to select the events that KeyDB will notify among a set
|
||||
# of classes. Every class is identified by a single character:
|
||||
#
|
||||
# K Keyspace events, published with __keyspace@<db>__ prefix.
|
||||
@@ -1642,12 +1641,12 @@ notify-keyspace-events ""
|
||||
|
||||
############################### GOPHER SERVER #################################
|
||||
|
||||
# Redis contains an implementation of the Gopher protocol, as specified in
|
||||
# KeyDB contains an implementation of the Gopher protocol, as specified in
|
||||
# the RFC 1436 (https://www.ietf.org/rfc/rfc1436.txt).
|
||||
#
|
||||
# The Gopher protocol was very popular in the late '90s. It is an alternative
|
||||
# to the web, and the implementation both server and client side is so simple
|
||||
# that the Redis server has just 100 lines of code in order to implement this
|
||||
# that the KeyDB server has just 100 lines of code in order to implement this
|
||||
# support.
|
||||
#
|
||||
# What do you do with Gopher nowadays? Well Gopher never *really* died, and
|
||||
@@ -1657,18 +1656,18 @@ notify-keyspace-events ""
|
||||
# controlled, and it's cool to create an alternative space for people that
|
||||
# want a bit of fresh air.
|
||||
#
|
||||
# Anyway for the 10nth birthday of the Redis, we gave it the Gopher protocol
|
||||
# Anyway for the 10nth birthday of the KeyDB, we gave it the Gopher protocol
|
||||
# as a gift.
|
||||
#
|
||||
# --- HOW IT WORKS? ---
|
||||
#
|
||||
# The Redis Gopher support uses the inline protocol of Redis, and specifically
|
||||
# The KeyDB Gopher support uses the inline protocol of KeyDB, and specifically
|
||||
# two kind of inline requests that were anyway illegal: an empty request
|
||||
# or any request that starts with "/" (there are no Redis commands starting
|
||||
# or any request that starts with "/" (there are no KeyDB commands starting
|
||||
# with such a slash). Normal RESP2/RESP3 requests are completely out of the
|
||||
# path of the Gopher protocol implementation and are served as usual as well.
|
||||
#
|
||||
# If you open a connection to Redis when Gopher is enabled and send it
|
||||
# If you open a connection to KeyDB when Gopher is enabled and send it
|
||||
# a string like "/foo", if there is a key named "/foo" it is served via the
|
||||
# Gopher protocol.
|
||||
#
|
||||
@@ -1679,7 +1678,7 @@ notify-keyspace-events ""
|
||||
#
|
||||
# --- SECURITY WARNING ---
|
||||
#
|
||||
# If you plan to put Redis on the internet in a publicly accessible address
|
||||
# If you plan to put KeyDB on the internet in a publicly accessible address
|
||||
# to server Gopher pages MAKE SURE TO SET A PASSWORD to the instance.
|
||||
# Once a password is set:
|
||||
#
|
||||
@@ -1776,8 +1775,8 @@ stream-node-max-bytes 4096
|
||||
stream-node-max-entries 100
|
||||
|
||||
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
|
||||
# order to help rehashing the main Redis hash table (the one mapping top-level
|
||||
# keys to values). The hash table implementation Redis uses (see dict.c)
|
||||
# order to help rehashing the main KeyDB hash table (the one mapping top-level
|
||||
# keys to values). The hash table implementation KeyDB uses (see dict.c)
|
||||
# performs a lazy rehashing: the more operation you run into a hash table
|
||||
# that is rehashing, the more rehashing "steps" are performed, so if the
|
||||
# server is idle the rehashing is never complete and some more memory is used
|
||||
@@ -1788,7 +1787,7 @@ stream-node-max-entries 100
|
||||
#
|
||||
# If unsure:
|
||||
# use "activerehashing no" if you have hard latency requirements and it is
|
||||
# not a good thing in your environment that Redis can reply from time to time
|
||||
# not a good thing in your environment that KeyDB can reply from time to time
|
||||
# to queries with 2 milliseconds delay.
|
||||
#
|
||||
# use "activerehashing yes" if you don't have such hard requirements but
|
||||
@@ -1840,21 +1839,21 @@ client-output-buffer-limit pubsub 32mb 8mb 60
|
||||
#
|
||||
# client-query-buffer-limit 1gb
|
||||
|
||||
# In the Redis protocol, bulk requests, that are, elements representing single
|
||||
# In the KeyDB protocol, bulk requests, that are, elements representing single
|
||||
# strings, are normally limited to 512 mb. However you can change this limit
|
||||
# here, but must be 1mb or greater
|
||||
#
|
||||
# proto-max-bulk-len 512mb
|
||||
|
||||
# Redis calls an internal function to perform many background tasks, like
|
||||
# KeyDB calls an internal function to perform many background tasks, like
|
||||
# closing connections of clients in timeout, purging expired keys that are
|
||||
# never requested, and so forth.
|
||||
#
|
||||
# Not all tasks are performed with the same frequency, but Redis checks for
|
||||
# Not all tasks are performed with the same frequency, but KeyDB checks for
|
||||
# tasks to perform according to the specified "hz" value.
|
||||
#
|
||||
# By default "hz" is set to 10. Raising the value will use more CPU when
|
||||
# Redis is idle, but at the same time will make Redis more responsive when
|
||||
# KeyDB is idle, but at the same time will make KeyDB more responsive when
|
||||
# there are many keys expiring at the same time, and timeouts may be
|
||||
# handled with more precision.
|
||||
#
|
||||
@@ -1868,7 +1867,7 @@ hz 10
|
||||
# avoid too many clients are processed for each background task invocation
|
||||
# in order to avoid latency spikes.
|
||||
#
|
||||
# Since the default HZ value by default is conservatively set to 10, Redis
|
||||
# Since the default HZ value by default is conservatively set to 10, KeyDB
|
||||
# offers, and enables by default, the ability to use an adaptive HZ value
|
||||
# which will temporarily raise when there are many connected clients.
|
||||
#
|
||||
@@ -1891,16 +1890,16 @@ aof-rewrite-incremental-fsync yes
|
||||
# big latency spikes.
|
||||
rdb-save-incremental-fsync yes
|
||||
|
||||
# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good
|
||||
# KeyDB LFU eviction (see maxmemory setting) can be tuned. However it is a good
|
||||
# idea to start with the default settings and only change them after investigating
|
||||
# how to improve the performances and how the keys LFU change over time, which
|
||||
# is possible to inspect via the OBJECT FREQ command.
|
||||
#
|
||||
# There are two tunable parameters in the Redis LFU implementation: the
|
||||
# There are two tunable parameters in the KeyDB LFU implementation: the
|
||||
# counter logarithm factor and the counter decay time. It is important to
|
||||
# understand what the two parameters mean before changing them.
|
||||
#
|
||||
# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis
|
||||
# The LFU counter is just 8 bits per key, it's maximum value is 255, so KeyDB
|
||||
# uses a probabilistic increment with logarithmic behavior. Given the value
|
||||
# of the old counter, when a key is accessed, the counter is incremented in
|
||||
# this way:
|
||||
@@ -1952,7 +1951,7 @@ rdb-save-incremental-fsync yes
|
||||
# What is active defragmentation?
|
||||
# -------------------------------
|
||||
#
|
||||
# Active (online) defragmentation allows a Redis server to compact the
|
||||
# Active (online) defragmentation allows a KeyDB server to compact the
|
||||
# spaces left between small allocations and deallocations of data in memory,
|
||||
# thus allowing to reclaim back memory.
|
||||
#
|
||||
@@ -1960,11 +1959,11 @@ rdb-save-incremental-fsync yes
|
||||
# less so with Jemalloc, fortunately) and certain workloads. Normally a server
|
||||
# restart is needed in order to lower the fragmentation, or at least to flush
|
||||
# away all the data and create it again. However thanks to this feature
|
||||
# implemented by Oran Agra for Redis 4.0 this process can happen at runtime
|
||||
# implemented by Oran Agra for KeyDB 4.0 this process can happen at runtime
|
||||
# in a "hot" way, while the server is running.
|
||||
#
|
||||
# Basically when the fragmentation is over a certain level (see the
|
||||
# configuration options below) Redis will start to create new copies of the
|
||||
# configuration options below) KeyDB will start to create new copies of the
|
||||
# values in contiguous memory regions by exploiting certain specific Jemalloc
|
||||
# features (in order to understand if an allocation is causing fragmentation
|
||||
# and to allocate it in a better place), and at the same time, will release the
|
||||
@@ -1973,8 +1972,8 @@ rdb-save-incremental-fsync yes
|
||||
#
|
||||
# Important things to understand:
|
||||
#
|
||||
# 1. This feature is disabled by default, and only works if you compiled Redis
|
||||
# to use the copy of Jemalloc we ship with the source code of Redis.
|
||||
# 1. This feature is disabled by default, and only works if you compiled KeyDB
|
||||
# to use the copy of Jemalloc we ship with the source code of KeyDB.
|
||||
# This is the default with Linux builds.
|
||||
#
|
||||
# 2. You never need to enable this feature if you don't have fragmentation
|
||||
@@ -2012,14 +2011,14 @@ rdb-save-incremental-fsync yes
|
||||
# Jemalloc background thread for purging will be enabled by default
|
||||
jemalloc-bg-thread yes
|
||||
|
||||
# It is possible to pin different threads and processes of Redis to specific
|
||||
# It is possible to pin different threads and processes of KeyDB to specific
|
||||
# CPUs in your system, in order to maximize the performances of the server.
|
||||
# This is useful both in order to pin different Redis threads in different
|
||||
# CPUs, but also in order to make sure that multiple Redis instances running
|
||||
# This is useful both in order to pin different KeyDB threads in different
|
||||
# CPUs, but also in order to make sure that multiple KeyDB instances running
|
||||
# in the same host will be pinned to different CPUs.
|
||||
#
|
||||
# Normally you can do this using the "taskset" command, however it is also
|
||||
# possible to this via Redis configuration directly, both in Linux and FreeBSD.
|
||||
# possible to this via KeyDB configuration directly, both in Linux and FreeBSD.
|
||||
#
|
||||
# You can pin the server/IO threads, bio threads, aof rewrite child process, and
|
||||
# the bgsave child process. The syntax to specify the cpu list is the same as
|
||||
|
||||
@@ -131,8 +131,8 @@ tcp-keepalive 300
|
||||
|
||||
################################# GENERAL #####################################
|
||||
|
||||
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
||||
# By default KeyDB does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that KeyDB will write a pid file in /var/run/keydb.pid when daemonized.
|
||||
daemonize yes
|
||||
|
||||
# If you run Redis from upstart or systemd, Redis can interact with your
|
||||
@@ -151,7 +151,7 @@ supervised no
|
||||
#
|
||||
# When the server runs non daemonized, no pid file is created if none is
|
||||
# specified in the configuration. When the server is daemonized, the pid file
|
||||
# is used even if not specified, defaulting to "/var/run/redis.pid".
|
||||
# is used even if not specified, defaulting to "/var/run/keydb.pid".
|
||||
#
|
||||
# Creating a pid file is best effort: if Redis is not able to create it
|
||||
# nothing bad happens, the server will start and run normally.
|
||||
|
||||
@@ -10,7 +10,7 @@ done
|
||||
|
||||
if [ -z $TCLSH ]
|
||||
then
|
||||
echo "You need tcl 8.5 or newer in order to run the Redis test"
|
||||
echo "You need tcl 8.5 or newer in order to run the KeyDB test"
|
||||
exit 1
|
||||
fi
|
||||
$TCLSH tests/test_helper.tcl "${@}"
|
||||
+1
-1
@@ -8,7 +8,7 @@ done
|
||||
|
||||
if [ -z $TCLSH ]
|
||||
then
|
||||
echo "You need tcl 8.5 or newer in order to run the Redis Cluster test"
|
||||
echo "You need tcl 8.5 or newer in order to run the KeyDB Cluster test"
|
||||
exit 1
|
||||
fi
|
||||
$TCLSH tests/cluster/run.tcl $*
|
||||
+1
-1
@@ -9,7 +9,7 @@ done
|
||||
|
||||
if [ -z $TCLSH ]
|
||||
then
|
||||
echo "You need tcl 8.5 or newer in order to run the Redis ModuleApi test"
|
||||
echo "You need tcl 8.5 or newer in order to run the KeyDB ModuleApi test"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ done
|
||||
|
||||
if [ -z $TCLSH ]
|
||||
then
|
||||
echo "You need tcl 8.5 or newer in order to run the Redis Sentinel test"
|
||||
echo "You need tcl 8.5 or newer in order to run the KeyDB Sentinel test"
|
||||
exit 1
|
||||
fi
|
||||
$TCLSH tests/sentinel/run.tcl $*
|
||||
+24
-24
@@ -20,12 +20,12 @@
|
||||
# The port that this sentinel instance will run on
|
||||
port 26379
|
||||
|
||||
# By default Redis Sentinel does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that Redis will write a pid file in /var/run/keydb-sentinel.pid when
|
||||
# By default KeyDB Sentinel does not run as a daemon. Use 'yes' if you need it.
|
||||
# Note that KeyDB will write a pid file in /var/run/keydb-sentinel.pid when
|
||||
# daemonized.
|
||||
daemonize no
|
||||
|
||||
# When running daemonized, Redis Sentinel writes a pid file in
|
||||
# When running daemonized, KeyDB Sentinel writes a pid file in
|
||||
# /var/run/keydb-sentinel.pid by default. You can specify a custom pid file
|
||||
# location here.
|
||||
pidfile /var/run/keydb-sentinel.pid
|
||||
@@ -59,7 +59,7 @@ logfile ""
|
||||
|
||||
# dir <working-directory>
|
||||
# Every long running process should have a well-defined working directory.
|
||||
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
|
||||
# For KeyDB Sentinel to chdir to /tmp at startup is the simplest thing
|
||||
# for the process to don't interfere with administrative tasks such as
|
||||
# unmounting filesystems.
|
||||
dir /tmp
|
||||
@@ -86,16 +86,16 @@ sentinel monitor mymaster 127.0.0.1 6379 2
|
||||
# sentinel auth-pass <master-name> <password>
|
||||
#
|
||||
# Set the password to use to authenticate with the master and replicas.
|
||||
# Useful if there is a password set in the Redis instances to monitor.
|
||||
# Useful if there is a password set in the KeyDB instances to monitor.
|
||||
#
|
||||
# Note that the master password is also used for replicas, so it is not
|
||||
# possible to set a different password in masters and replicas instances
|
||||
# if you want to be able to monitor these instances with Sentinel.
|
||||
#
|
||||
# However you can have Redis instances without the authentication enabled
|
||||
# mixed with Redis instances requiring the authentication (as long as the
|
||||
# However you can have KeyDB instances without the authentication enabled
|
||||
# mixed with KeyDB instances requiring the authentication (as long as the
|
||||
# password set is the same for all the instances requiring the password) as
|
||||
# the AUTH command will have no effect in Redis instances with authentication
|
||||
# the AUTH command will have no effect in KeyDB instances with authentication
|
||||
# switched off.
|
||||
#
|
||||
# Example:
|
||||
@@ -105,10 +105,10 @@ sentinel monitor mymaster 127.0.0.1 6379 2
|
||||
# sentinel auth-user <master-name> <username>
|
||||
#
|
||||
# This is useful in order to authenticate to instances having ACL capabilities,
|
||||
# that is, running Redis 6.0 or greater. When just auth-pass is provided the
|
||||
# Sentinel instance will authenticate to Redis using the old "AUTH <pass>"
|
||||
# that is, running KeyDB 6.0 or greater. When just auth-pass is provided the
|
||||
# Sentinel instance will authenticate to KeyDB using the old "AUTH <pass>"
|
||||
# method. When also an username is provided, it will use "AUTH <user> <pass>".
|
||||
# In the Redis servers side, the ACL to provide just minimal access to
|
||||
# In the KeyDB servers side, the ACL to provide just minimal access to
|
||||
# Sentinel instances, should be configured along the following lines:
|
||||
#
|
||||
# user sentinel-user >somepassword +client +subscribe +publish \
|
||||
@@ -125,7 +125,7 @@ sentinel monitor mymaster 127.0.0.1 6379 2
|
||||
sentinel down-after-milliseconds mymaster 30000
|
||||
|
||||
# IMPORTANT NOTE: starting with KeyDB 6.2 ACL capability is supported for
|
||||
# Sentinel mode, please refer to the KeyDB website https://redis.io/topics/acl
|
||||
# Sentinel mode, please refer to the Redis website https://redis.io/topics/acl
|
||||
# for more details.
|
||||
|
||||
# Sentinel's ACL users are defined in the following format:
|
||||
@@ -137,8 +137,8 @@ sentinel down-after-milliseconds mymaster 30000
|
||||
# user worker +@admin +@connection ~* on >ffa9203c493aa99
|
||||
#
|
||||
# For more information about ACL configuration please refer to the Redis
|
||||
# website at https://redis.io/topics/acl and redis server configuration
|
||||
# template redis.conf.
|
||||
# website at https://redis.io/topics/acl and KeyDB server configuration
|
||||
# template keydb.conf.
|
||||
|
||||
# ACL LOG
|
||||
#
|
||||
@@ -156,9 +156,9 @@ acllog-max-len 128
|
||||
# ACL file, the server will refuse to start.
|
||||
#
|
||||
# The format of the external ACL user file is exactly the same as the
|
||||
# format that is used inside redis.conf to describe users.
|
||||
# format that is used inside keydb.conf to describe users.
|
||||
#
|
||||
# aclfile /etc/redis/sentinel-users.acl
|
||||
# aclfile /etc/keydb/sentinel-users.acl
|
||||
|
||||
# requirepass <password>
|
||||
#
|
||||
@@ -168,7 +168,7 @@ acllog-max-len 128
|
||||
# group with the same "requirepass" password. Check the following documentation
|
||||
# for more info: https://redis.io/topics/sentinel
|
||||
#
|
||||
# IMPORTANT NOTE: starting with Redis 6.2 "requirepass" is a compatibility
|
||||
# IMPORTANT NOTE: starting with KeyDB 6.2 "requirepass" is a compatibility
|
||||
# layer on top of the ACL system. The option effect will be just setting
|
||||
# the password for the default user. Clients will still authenticate using
|
||||
# AUTH <password> as usually, or more explicitly with AUTH default <password>
|
||||
@@ -251,7 +251,7 @@ sentinel failover-timeout mymaster 180000
|
||||
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
|
||||
# This script should notify the system administrator via email, SMS, or any
|
||||
# other messaging system, that there is something wrong with the monitored
|
||||
# Redis systems.
|
||||
# KeyDB systems.
|
||||
#
|
||||
# The script is called with just two arguments: the first is the event type
|
||||
# and the second the event description.
|
||||
@@ -261,7 +261,7 @@ sentinel failover-timeout mymaster 180000
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# sentinel notification-script mymaster /var/redis/notify.sh
|
||||
# sentinel notification-script mymaster /var/keydb/notify.sh
|
||||
|
||||
# CLIENTS RECONFIGURATION SCRIPT
|
||||
#
|
||||
@@ -286,7 +286,7 @@ sentinel failover-timeout mymaster 180000
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
|
||||
# sentinel client-reconfig-script mymaster /var/keydb/reconfig.sh
|
||||
|
||||
# SECURITY
|
||||
#
|
||||
@@ -297,11 +297,11 @@ sentinel failover-timeout mymaster 180000
|
||||
|
||||
sentinel deny-scripts-reconfig yes
|
||||
|
||||
# REDIS COMMANDS RENAMING
|
||||
# KEYDB COMMANDS RENAMING
|
||||
#
|
||||
# Sometimes the Redis server has certain commands, that are needed for Sentinel
|
||||
# Sometimes the KeyDB server has certain commands, that are needed for Sentinel
|
||||
# to work correctly, renamed to unguessable strings. This is often the case
|
||||
# of CONFIG and SLAVEOF in the context of providers that provide Redis as
|
||||
# of CONFIG and SLAVEOF in the context of providers that provide KeyDB as
|
||||
# a service, and don't want the customers to reconfigure the instances outside
|
||||
# of the administration console.
|
||||
#
|
||||
@@ -325,7 +325,7 @@ sentinel deny-scripts-reconfig yes
|
||||
# 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
|
||||
# to specify an IP address. Also, it requires the KeyDB replica-announce-ip
|
||||
# keyword to specify only IP addresses.
|
||||
#
|
||||
# You may enable hostnames support by enabling resolve-hostnames. Note
|
||||
|
||||
+26
-16
@@ -3,11 +3,11 @@
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
#
|
||||
# The Makefile composes the final FINAL_CFLAGS and FINAL_LDFLAGS using
|
||||
# what is needed for Redis plus the standard CFLAGS and LDFLAGS passed.
|
||||
# what is needed for KeyDB plus the standard CFLAGS and LDFLAGS passed.
|
||||
# However when building the dependencies (Jemalloc, Lua, Hiredis, ...)
|
||||
# CFLAGS and LDFLAGS are propagated to the dependencies, so to pass
|
||||
# flags only to be used when compiling / linking Redis itself REDIS_CFLAGS
|
||||
# and REDIS_LDFLAGS are used instead (this is the case of 'make gcov').
|
||||
# flags only to be used when compiling / linking KeyDB itself KEYDB_CFLAGS
|
||||
# and KEYDB_LDFLAGS are used instead (this is the case of 'make gcov').
|
||||
#
|
||||
# Dependencies are stored in the Makefile.dep file. To rebuild this file
|
||||
# Just use 'make dep', but this is only needed by developers.
|
||||
@@ -29,7 +29,7 @@ ifneq (,$(findstring FreeBSD,$(uname_S)))
|
||||
STD+=-Wno-c11-extensions
|
||||
endif
|
||||
endif
|
||||
WARN=-Wall -W -Wno-missing-field-initializers
|
||||
WARN=-Wall -W -Wno-missing-field-initializers -Wno-address-of-packed-member -Wno-atomic-alignment
|
||||
OPT=$(OPTIMIZATION)
|
||||
|
||||
# Detect if the compiler supports C11 _Atomic
|
||||
@@ -85,7 +85,7 @@ ifeq ($(COMPILER_NAME),clang)
|
||||
LDFLAGS+= -latomic
|
||||
endif
|
||||
|
||||
# To get ARM stack traces if Redis crashes we need a special C flag.
|
||||
# To get ARM stack traces if KeyDB crashes we need a special C flag.
|
||||
ifneq (,$(filter aarch64 armv,$(uname_M)))
|
||||
CFLAGS+=-funwind-tables
|
||||
CXXFLAGS+=-funwind-tables
|
||||
@@ -116,15 +116,19 @@ endif
|
||||
# Override default settings if possible
|
||||
-include .make-settings
|
||||
|
||||
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CXXFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
|
||||
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(KEYDB_CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CXXFLAGS) $(KEYDB_CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_LDFLAGS=$(LDFLAGS) $(KEYDB_LDFLAGS) $(DEBUG)
|
||||
FINAL_LIBS+=-lm
|
||||
DEBUG=-g -ggdb
|
||||
|
||||
ifneq ($(uname_S),Darwin)
|
||||
FINAL_LIBS+=-latomic
|
||||
endif
|
||||
# Linux ARM32 needs -latomic at linking time
|
||||
ifneq (,$(findstring armv,$(uname_M)))
|
||||
FINAL_LIBS+=-latomic
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
@@ -340,8 +344,10 @@ REDIS_BENCHMARK_NAME=keydb-benchmark$(PROG_SUFFIX)
|
||||
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o redis-benchmark.o storage-lite.o fastlock.o new.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ)
|
||||
REDIS_CHECK_RDB_NAME=keydb-check-rdb$(PROG_SUFFIX)
|
||||
REDIS_CHECK_AOF_NAME=keydb-check-aof$(PROG_SUFFIX)
|
||||
KEYDB_DIAGNOSTIC_NAME=keydb-diagnostic-tool$(PROG_SUFFIX)
|
||||
KEYDB_DIAGNOSTIC_OBJ=ae.o anet.o keydb-diagnostic-tool.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o keydb-diagnostic-tool.o storage-lite.o fastlock.o new.o monotonic.o cli_common.o mt19937-64.o $(ASM_OBJ)
|
||||
|
||||
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME)
|
||||
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(KEYDB_DIAGNOSTIC_NAME)
|
||||
@echo ""
|
||||
@echo "Hint: It's a good idea to run 'make test' ;)"
|
||||
@echo ""
|
||||
@@ -365,9 +371,9 @@ persist-settings: distclean
|
||||
echo CFLAGS=$(CFLAGS) >> .make-settings
|
||||
echo CXXFLAGS=$(CXXFLAGS) >> .make-settings
|
||||
echo LDFLAGS=$(LDFLAGS) >> .make-settings
|
||||
echo REDIS_CFLAGS=$(REDIS_CFLAGS) >> .make-settings
|
||||
echo REDIS_CXXFLAGS=$(REDIS_CXXFLAGS) >> .make-settings
|
||||
echo REDIS_LDFLAGS=$(REDIS_LDFLAGS) >> .make-settings
|
||||
echo KEYDB_CFLAGS=$(KEYDB_CFLAGS) >> .make-settings
|
||||
echo KEYDB_CXXFLAGS=$(KEYDB_CXXFLAGS) >> .make-settings
|
||||
echo KEYDB_LDFLAGS=$(KEYDB_LDFLAGS) >> .make-settings
|
||||
echo PREV_FINAL_CFLAGS=$(FINAL_CFLAGS) >> .make-settings
|
||||
echo PREV_FINAL_CXXFLAGS=$(FINAL_CXXFLAGS) >> .make-settings
|
||||
echo PREV_FINAL_LDFLAGS=$(FINAL_LDFLAGS) >> .make-settings
|
||||
@@ -413,6 +419,10 @@ $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
|
||||
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
|
||||
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/hdr_histogram.o $(FINAL_LIBS)
|
||||
|
||||
# keydb-diagnostic-tool
|
||||
$(KEYDB_DIAGNOSTIC_NAME): $(KEYDB_DIAGNOSTIC_OBJ)
|
||||
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)
|
||||
|
||||
DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d)
|
||||
-include $(DEP)
|
||||
|
||||
@@ -429,7 +439,7 @@ DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ
|
||||
$(KEYDB_AS) $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov KeyDB.info lcov-html Makefile.dep
|
||||
rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(KEYDB_DIAGNOSTIC_NAME) *.o *.gcda *.gcno *.gcov KeyDB.info lcov-html Makefile.dep
|
||||
rm -f $(DEP)
|
||||
|
||||
.PHONY: clean
|
||||
@@ -468,7 +478,7 @@ bench: $(REDIS_BENCHMARK_NAME)
|
||||
$(MAKE) CXXFLAGS="-m32" CFLAGS="-m32" LDFLAGS="-m32"
|
||||
|
||||
gcov:
|
||||
$(MAKE) REDIS_CXXFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage"
|
||||
$(MAKE) KEYDB_CXXFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" KEYDB_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" KEYDB_LDFLAGS="-fprofile-arcs -ftest-coverage"
|
||||
|
||||
noopt:
|
||||
$(MAKE) OPTIMIZATION="-O0"
|
||||
@@ -477,7 +487,7 @@ valgrind:
|
||||
$(MAKE) OPTIMIZATION="-O0" USEASM="false" MALLOC="libc" CFLAGS="-DSANITIZE" CXXFLAGS="-DSANITIZE"
|
||||
|
||||
helgrind:
|
||||
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" REDIS_CFLAGS="-I/usr/local/include" REDIS_LDFLAGS="-L/usr/local/lib"
|
||||
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" KEYDB_CFLAGS="-I/usr/local/include" KEYDB_LDFLAGS="-L/usr/local/lib"
|
||||
|
||||
src/help.h:
|
||||
@../utils/generate-command-help.rb > help.h
|
||||
@@ -492,4 +502,4 @@ install: all
|
||||
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
|
||||
rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME),$(KEYDB_DIAGNOSTIC_NAME)}
|
||||
+2
-3
@@ -173,12 +173,11 @@ void queueClientForReprocessing(client *c) {
|
||||
/* The client may already be into the unblocked list because of a previous
|
||||
* blocking operation, don't add back it into the list multiple times. */
|
||||
serverAssert(GlobalLocksAcquired());
|
||||
fastlock_lock(&c->lock);
|
||||
std::unique_lock<fastlock> ul(c->lock);
|
||||
if (!(c->flags & CLIENT_UNBLOCKED)) {
|
||||
c->flags |= CLIENT_UNBLOCKED;
|
||||
listAddNodeTail(g_pserver->rgthreadvar[c->iel].unblocked_clients,c);
|
||||
}
|
||||
fastlock_unlock(&c->lock);
|
||||
}
|
||||
|
||||
/* Unblock a client calling the right function depending on the kind
|
||||
@@ -792,4 +791,4 @@ void signalKeyAsReady(redisDb *db, sds key, int type) {
|
||||
redisObjectStack o;
|
||||
initStaticStringObject(o, key);
|
||||
signalKeyAsReady(db, &o, type);
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -561,7 +561,7 @@ void clusterInit(void) {
|
||||
|
||||
serverAssert(serverTL == &g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN]);
|
||||
if (createSocketAcceptHandler(&g_pserver->cfd, clusterAcceptHandler) != C_OK) {
|
||||
serverPanic("Unrecoverable error creating Redis Cluster socket accept handler.");
|
||||
serverPanic("Unrecoverable error creating KeyDB Cluster socket accept handler.");
|
||||
}
|
||||
|
||||
/* The slots -> keys map is a radix tree. Initialize it here. */
|
||||
@@ -5567,9 +5567,10 @@ try_again:
|
||||
if (ttl < 1) ttl = 1;
|
||||
}
|
||||
|
||||
/* Relocate valid (non expired) keys into the array in successive
|
||||
/* Relocate valid (non expired) keys and values into the array in successive
|
||||
* positions to remove holes created by the keys that were present
|
||||
* in the first lookup but are now expired after the second lookup. */
|
||||
ov[non_expired] = ov[j];
|
||||
kv[non_expired++] = kv[j];
|
||||
|
||||
serverAssertWithInfo(c,NULL,
|
||||
|
||||
@@ -437,6 +437,9 @@ void connSetThreadAffinity(connection *conn, int cpu) {
|
||||
{
|
||||
serverLog(LL_WARNING, "Failed to set socket affinity");
|
||||
}
|
||||
#else
|
||||
(void)conn;
|
||||
(void)cpu;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -1403,9 +1403,8 @@ void copyCommand(client *c) {
|
||||
}
|
||||
|
||||
dbAdd(dst,newkey,newobj);
|
||||
if (expire != nullptr) {
|
||||
if (expire != nullptr) setExpire(c, dst, newkey, expire->duplicate());
|
||||
}
|
||||
if (expire != nullptr)
|
||||
setExpire(c, dst, newkey, expire->duplicate());
|
||||
|
||||
/* OK! key copied */
|
||||
signalModifiedKey(c,dst,c->argv[2]);
|
||||
@@ -1771,7 +1770,7 @@ int keyIsExpired(redisDb *db, robj *key) {
|
||||
* script execution, making propagation to slaves / AOF consistent.
|
||||
* See issue #1525 on Github for more information. */
|
||||
if (g_pserver->lua_caller) {
|
||||
now = g_pserver->lua_time_start;
|
||||
now = g_pserver->lua_time_snapshot;
|
||||
}
|
||||
/* If we are in the middle of a command execution, we still want to use
|
||||
* a reference time that does not change: in that case we just use the
|
||||
@@ -1832,14 +1831,17 @@ int expireIfNeeded(redisDb *db, robj *key) {
|
||||
if (checkClientPauseTimeoutAndReturnIfPaused()) return 1;
|
||||
|
||||
/* Delete the key */
|
||||
if (g_pserver->lazyfree_lazy_expire) {
|
||||
dbAsyncDelete(db,key);
|
||||
} else {
|
||||
dbSyncDelete(db,key);
|
||||
}
|
||||
g_pserver->stat_expiredkeys++;
|
||||
propagateExpire(db,key,g_pserver->lazyfree_lazy_expire);
|
||||
notifyKeyspaceEvent(NOTIFY_EXPIRED,
|
||||
"expired",key,db->id);
|
||||
int retval = g_pserver->lazyfree_lazy_expire ? dbAsyncDelete(db,key) :
|
||||
dbSyncDelete(db,key);
|
||||
if (retval) signalModifiedKey(NULL,db,key);
|
||||
return retval;
|
||||
signalModifiedKey(NULL,db,key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
@@ -1038,7 +1038,6 @@ void _serverPanic(const char *file, int line, const char *msg, ...) {
|
||||
vsnprintf(fmtmsg,sizeof(fmtmsg),msg,ap);
|
||||
va_end(ap);
|
||||
|
||||
g_fInCrash = true;
|
||||
bugReportStart();
|
||||
serverLog(LL_WARNING,"------------------------------------------------");
|
||||
serverLog(LL_WARNING,"!!! Software Failure. Press left mouse button to continue");
|
||||
|
||||
+1
-1
@@ -281,7 +281,7 @@ uint32_t intsetLen(const intset *is) {
|
||||
|
||||
/* Return intset blob size in bytes. */
|
||||
size_t intsetBlobLen(intset *is) {
|
||||
return sizeof(intset)+intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
|
||||
return sizeof(intset)+(size_t)intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
|
||||
}
|
||||
|
||||
/* Validate the integrity of the data structure.
|
||||
|
||||
@@ -0,0 +1,967 @@
|
||||
/* KeyDB diagnostic utility.
|
||||
*
|
||||
* Copyright (c) 2009-2021, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2021, EQ Alpha Technology Ltd. <john at eqalpha dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <deque>
|
||||
extern "C" {
|
||||
#include <sds.h> /* Use hiredis sds. */
|
||||
#include <sdscompat.h>
|
||||
#include "hiredis.h"
|
||||
}
|
||||
#include "ae.h"
|
||||
#include "adlist.h"
|
||||
#include "dict.h"
|
||||
#include "zmalloc.h"
|
||||
#include "storage.h"
|
||||
#include "atomicvar.h"
|
||||
#include "crc16_slottable.h"
|
||||
|
||||
#define UNUSED(V) ((void) V)
|
||||
#define RANDPTR_INITIAL_SIZE 8
|
||||
#define MAX_LATENCY_PRECISION 3
|
||||
#define MAX_THREADS 500
|
||||
#define CLUSTER_SLOTS 16384
|
||||
|
||||
#define CLIENT_GET_EVENTLOOP(c) \
|
||||
(c->thread_id >= 0 ? config.threads[c->thread_id]->el : config.el)
|
||||
|
||||
struct benchmarkThread;
|
||||
struct clusterNode;
|
||||
struct redisConfig;
|
||||
|
||||
int g_fTestMode = false;
|
||||
|
||||
static struct config {
|
||||
aeEventLoop *el;
|
||||
const char *hostip;
|
||||
int hostport;
|
||||
const char *hostsocket;
|
||||
int numclients;
|
||||
int liveclients;
|
||||
int period_ms;
|
||||
int requests;
|
||||
int requests_issued;
|
||||
int requests_finished;
|
||||
int keysize;
|
||||
int datasize;
|
||||
int randomkeys;
|
||||
int randomkeys_keyspacelen;
|
||||
int keepalive;
|
||||
int pipeline;
|
||||
int showerrors;
|
||||
long long start;
|
||||
long long totlatency;
|
||||
long long *latency;
|
||||
const char *title;
|
||||
list *clients;
|
||||
int quiet;
|
||||
int csv;
|
||||
int loop;
|
||||
int idlemode;
|
||||
int dbnum;
|
||||
sds dbnumstr;
|
||||
char *tests;
|
||||
char *auth;
|
||||
const char *user;
|
||||
int precision;
|
||||
int max_threads;
|
||||
struct benchmarkThread **threads;
|
||||
int cluster_mode;
|
||||
int cluster_node_count;
|
||||
struct clusterNode **cluster_nodes;
|
||||
struct redisConfig *redis_config;
|
||||
int is_fetching_slots;
|
||||
int is_updating_slots;
|
||||
int slots_last_update;
|
||||
int enable_tracking;
|
||||
/* Thread mutexes to be used as fallbacks by atomicvar.h */
|
||||
pthread_mutex_t requests_issued_mutex;
|
||||
pthread_mutex_t requests_finished_mutex;
|
||||
pthread_mutex_t liveclients_mutex;
|
||||
pthread_mutex_t is_fetching_slots_mutex;
|
||||
pthread_mutex_t is_updating_slots_mutex;
|
||||
pthread_mutex_t updating_slots_mutex;
|
||||
pthread_mutex_t slots_last_update_mutex;
|
||||
} config;
|
||||
|
||||
typedef struct _client {
|
||||
redisContext *context;
|
||||
sds obuf;
|
||||
char **randptr; /* Pointers to :rand: strings inside the command buf */
|
||||
size_t randlen; /* Number of pointers in client->randptr */
|
||||
size_t randfree; /* Number of unused pointers in client->randptr */
|
||||
char **stagptr; /* Pointers to slot hashtags (cluster mode only) */
|
||||
size_t staglen; /* Number of pointers in client->stagptr */
|
||||
size_t stagfree; /* Number of unused pointers in client->stagptr */
|
||||
size_t written; /* Bytes of 'obuf' already written */
|
||||
long long start; /* Start time of a request */
|
||||
long long latency; /* Request latency */
|
||||
int pending; /* Number of pending requests (replies to consume) */
|
||||
int prefix_pending; /* If non-zero, number of pending prefix commands. Commands
|
||||
such as auth and select are prefixed to the pipeline of
|
||||
benchmark commands and discarded after the first send. */
|
||||
int prefixlen; /* Size in bytes of the pending prefix commands */
|
||||
int thread_id;
|
||||
struct clusterNode *cluster_node;
|
||||
int slots_last_update;
|
||||
redisReply *lastReply;
|
||||
} *client;
|
||||
|
||||
/* Threads. */
|
||||
|
||||
typedef struct benchmarkThread {
|
||||
int index;
|
||||
pthread_t thread;
|
||||
aeEventLoop *el;
|
||||
} benchmarkThread;
|
||||
|
||||
/* Cluster. */
|
||||
typedef struct clusterNode {
|
||||
char *ip;
|
||||
int port;
|
||||
sds name;
|
||||
int flags;
|
||||
sds replicate; /* Master ID if node is a replica */
|
||||
int *slots;
|
||||
int slots_count;
|
||||
int current_slot_index;
|
||||
int *updated_slots; /* Used by updateClusterSlotsConfiguration */
|
||||
int updated_slots_count; /* Used by updateClusterSlotsConfiguration */
|
||||
int replicas_count;
|
||||
sds *migrating; /* An array of sds where even strings are slots and odd
|
||||
* strings are the destination node IDs. */
|
||||
sds *importing; /* An array of sds where even strings are slots and odd
|
||||
* strings are the source node IDs. */
|
||||
int migrating_count; /* Length of the migrating array (migrating slots*2) */
|
||||
int importing_count; /* Length of the importing array (importing slots*2) */
|
||||
struct redisConfig *redis_config;
|
||||
} clusterNode;
|
||||
|
||||
typedef struct redisConfig {
|
||||
sds save;
|
||||
sds appendonly;
|
||||
} redisConfig;
|
||||
|
||||
int g_fInCrash = false;
|
||||
|
||||
/* Prototypes */
|
||||
static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask);
|
||||
static benchmarkThread *createBenchmarkThread(int index);
|
||||
static void freeBenchmarkThread(benchmarkThread *thread);
|
||||
static void freeBenchmarkThreads();
|
||||
static redisContext *getRedisContext(const char *ip, int port,
|
||||
const char *hostsocket);
|
||||
|
||||
/* Implementation */
|
||||
static long long ustime(void) {
|
||||
struct timeval tv;
|
||||
long long ust;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ust = ((long)tv.tv_sec)*1000000;
|
||||
ust += tv.tv_usec;
|
||||
return ust;
|
||||
}
|
||||
|
||||
/* _serverAssert is needed by dict */
|
||||
extern "C" void _serverAssert(const char *estr, const char *file, int line) {
|
||||
fprintf(stderr, "=== ASSERTION FAILED ===");
|
||||
fprintf(stderr, "==> %s:%d '%s' is not true",file,line,estr);
|
||||
*((char*)-1) = 'x';
|
||||
}
|
||||
|
||||
static redisContext *getRedisContext(const char *ip, int port,
|
||||
const char *hostsocket)
|
||||
{
|
||||
redisContext *ctx = NULL;
|
||||
redisReply *reply = NULL;
|
||||
if (hostsocket == NULL)
|
||||
ctx = redisConnect(ip, port);
|
||||
else
|
||||
ctx = redisConnectUnix(hostsocket);
|
||||
if (ctx == NULL || ctx->err) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
const char *err = (ctx != NULL ? ctx->errstr : "");
|
||||
if (hostsocket == NULL)
|
||||
fprintf(stderr,"%s:%d: %s\n",ip,port,err);
|
||||
else
|
||||
fprintf(stderr,"%s: %s\n",hostsocket,err);
|
||||
goto cleanup;
|
||||
}
|
||||
if (config.auth == NULL)
|
||||
return ctx;
|
||||
if (config.user == NULL)
|
||||
reply = (redisReply*)redisCommand(ctx,"AUTH %s", config.auth);
|
||||
else
|
||||
reply = (redisReply*)redisCommand(ctx,"AUTH %s %s", config.user, config.auth);
|
||||
if (reply != NULL) {
|
||||
if (reply->type == REDIS_REPLY_ERROR) {
|
||||
if (hostsocket == NULL)
|
||||
fprintf(stderr, "Node %s:%d replied with error:\n%s\n", ip, port, reply->str);
|
||||
else
|
||||
fprintf(stderr, "Node %s replied with error:\n%s\n", hostsocket, reply->str);
|
||||
goto cleanup;
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
return ctx;
|
||||
}
|
||||
fprintf(stderr, "ERROR: failed to fetch reply from ");
|
||||
if (hostsocket == NULL)
|
||||
fprintf(stderr, "%s:%d\n", ip, port);
|
||||
else
|
||||
fprintf(stderr, "%s\n", hostsocket);
|
||||
cleanup:
|
||||
freeReplyObject(reply);
|
||||
redisFree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void freeClient(client c) {
|
||||
aeEventLoop *el = CLIENT_GET_EVENTLOOP(c);
|
||||
listNode *ln;
|
||||
aeDeleteFileEvent(el,c->context->fd,AE_WRITABLE);
|
||||
aeDeleteFileEvent(el,c->context->fd,AE_READABLE);
|
||||
if (c->thread_id >= 0) {
|
||||
int requests_finished = 0;
|
||||
atomicGet(config.requests_finished, requests_finished);
|
||||
if (requests_finished >= config.requests) {
|
||||
aeStop(el);
|
||||
}
|
||||
}
|
||||
redisFree(c->context);
|
||||
sdsfree(c->obuf);
|
||||
zfree(c->randptr);
|
||||
zfree(c->stagptr);
|
||||
zfree(c);
|
||||
if (config.max_threads) pthread_mutex_lock(&(config.liveclients_mutex));
|
||||
config.liveclients--;
|
||||
ln = listSearchKey(config.clients,c);
|
||||
assert(ln != NULL);
|
||||
listDelNode(config.clients,ln);
|
||||
if (config.max_threads) pthread_mutex_unlock(&(config.liveclients_mutex));
|
||||
}
|
||||
|
||||
static void freeAllClients(void) {
|
||||
listNode *ln = config.clients->head, *next;
|
||||
|
||||
while(ln) {
|
||||
next = ln->next;
|
||||
freeClient((client)ln->value);
|
||||
ln = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void resetClient(client c) {
|
||||
aeEventLoop *el = CLIENT_GET_EVENTLOOP(c);
|
||||
aeDeleteFileEvent(el,c->context->fd,AE_WRITABLE);
|
||||
aeDeleteFileEvent(el,c->context->fd,AE_READABLE);
|
||||
aeCreateFileEvent(el,c->context->fd,AE_WRITABLE,writeHandler,c);
|
||||
c->written = 0;
|
||||
c->pending = config.pipeline;
|
||||
}
|
||||
|
||||
static void randomizeClientKey(client c) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < c->randlen; i++) {
|
||||
char *p = c->randptr[i]+11;
|
||||
size_t r = 0;
|
||||
if (config.randomkeys_keyspacelen != 0)
|
||||
r = random() % config.randomkeys_keyspacelen;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < 12; j++) {
|
||||
*p = '0'+r%10;
|
||||
r/=10;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client c = (client)privdata;
|
||||
void *reply = NULL;
|
||||
UNUSED(el);
|
||||
UNUSED(fd);
|
||||
UNUSED(mask);
|
||||
|
||||
/* Calculate latency only for the first read event. This means that the
|
||||
* server already sent the reply and we need to parse it. Parsing overhead
|
||||
* is not part of the latency, so calculate it only once, here. */
|
||||
if (c->latency < 0) c->latency = ustime()-(c->start);
|
||||
|
||||
if (redisBufferRead(c->context) != REDIS_OK) {
|
||||
fprintf(stderr,"Error: %s\n",c->context->errstr);
|
||||
exit(1);
|
||||
} else {
|
||||
while(c->pending) {
|
||||
if (redisGetReply(c->context,&reply) != REDIS_OK) {
|
||||
fprintf(stderr,"Error: %s\n",c->context->errstr);
|
||||
exit(1);
|
||||
}
|
||||
if (reply != NULL) {
|
||||
if (reply == (void*)REDIS_REPLY_ERROR) {
|
||||
fprintf(stderr,"Unexpected error reply, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
redisReply *r = (redisReply*)reply;
|
||||
int is_err = (r->type == REDIS_REPLY_ERROR);
|
||||
|
||||
if (is_err && config.showerrors) {
|
||||
/* TODO: static lasterr_time not thread-safe */
|
||||
static time_t lasterr_time = 0;
|
||||
time_t now = time(NULL);
|
||||
if (lasterr_time != now) {
|
||||
lasterr_time = now;
|
||||
if (c->cluster_node) {
|
||||
printf("Error from server %s:%d: %s\n",
|
||||
c->cluster_node->ip,
|
||||
c->cluster_node->port,
|
||||
r->str);
|
||||
} else printf("Error from server: %s\n", r->str);
|
||||
}
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
/* This is an OK for prefix commands such as auth and select.*/
|
||||
if (c->prefix_pending > 0) {
|
||||
c->prefix_pending--;
|
||||
c->pending--;
|
||||
/* Discard prefix commands on first response.*/
|
||||
if (c->prefixlen > 0) {
|
||||
size_t j;
|
||||
sdsrange(c->obuf, c->prefixlen, -1);
|
||||
/* We also need to fix the pointers to the strings
|
||||
* we need to randomize. */
|
||||
for (j = 0; j < c->randlen; j++)
|
||||
c->randptr[j] -= c->prefixlen;
|
||||
c->prefixlen = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int requests_finished = 0;
|
||||
atomicGetIncr(config.requests_finished, requests_finished, 1);
|
||||
if (requests_finished < config.requests)
|
||||
config.latency[requests_finished] = c->latency;
|
||||
c->pending--;
|
||||
if (c->pending == 0) {
|
||||
resetClient(c);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
client c = (client)privdata;
|
||||
UNUSED(el);
|
||||
UNUSED(fd);
|
||||
UNUSED(mask);
|
||||
|
||||
/* Initialize request when nothing was written. */
|
||||
if (c->written == 0) {
|
||||
/* Really initialize: randomize keys and set start time. */
|
||||
if (config.randomkeys) randomizeClientKey(c);
|
||||
atomicGet(config.slots_last_update, c->slots_last_update);
|
||||
c->start = ustime();
|
||||
c->latency = -1;
|
||||
}
|
||||
if (sdslen(c->obuf) > c->written) {
|
||||
void *ptr = c->obuf+c->written;
|
||||
ssize_t nwritten = write(c->context->fd,ptr,sdslen(c->obuf)-c->written);
|
||||
if (nwritten == -1) {
|
||||
if (errno != EPIPE)
|
||||
fprintf(stderr, "Writing to socket: %s\n", strerror(errno));
|
||||
freeClient(c);
|
||||
return;
|
||||
}
|
||||
c->written += nwritten;
|
||||
if (sdslen(c->obuf) == c->written) {
|
||||
aeDeleteFileEvent(el,c->context->fd,AE_WRITABLE);
|
||||
aeCreateFileEvent(el,c->context->fd,AE_READABLE,readHandler,c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a benchmark client, configured to send the command passed as 'cmd' of
|
||||
* 'len' bytes.
|
||||
*
|
||||
* The command is copied N times in the client output buffer (that is reused
|
||||
* again and again to send the request to the server) accordingly to the configured
|
||||
* pipeline size.
|
||||
*
|
||||
* Also an initial SELECT command is prepended in order to make sure the right
|
||||
* database is selected, if needed. The initial SELECT will be discarded as soon
|
||||
* as the first reply is received.
|
||||
*
|
||||
* To create a client from scratch, the 'from' pointer is set to NULL. If instead
|
||||
* we want to create a client using another client as reference, the 'from' pointer
|
||||
* points to the client to use as reference. In such a case the following
|
||||
* information is take from the 'from' client:
|
||||
*
|
||||
* 1) The command line to use.
|
||||
* 2) The offsets of the __rand_int__ elements inside the command line, used
|
||||
* for arguments randomization.
|
||||
*
|
||||
* Even when cloning another client, prefix commands are applied if needed.*/
|
||||
static client createClient(const char *cmd, size_t len, client from, int thread_id) {
|
||||
int j;
|
||||
int is_cluster_client = (config.cluster_mode && thread_id >= 0);
|
||||
client c = (client)zmalloc(sizeof(struct _client), MALLOC_LOCAL);
|
||||
|
||||
const char *ip = NULL;
|
||||
int port = 0;
|
||||
c->cluster_node = NULL;
|
||||
if (config.hostsocket == NULL || is_cluster_client) {
|
||||
if (!is_cluster_client) {
|
||||
ip = config.hostip;
|
||||
port = config.hostport;
|
||||
} else {
|
||||
int node_idx = 0;
|
||||
if (config.max_threads < config.cluster_node_count)
|
||||
node_idx = config.liveclients % config.cluster_node_count;
|
||||
else
|
||||
node_idx = thread_id % config.cluster_node_count;
|
||||
clusterNode *node = config.cluster_nodes[node_idx];
|
||||
assert(node != NULL);
|
||||
ip = (const char *) node->ip;
|
||||
port = node->port;
|
||||
c->cluster_node = node;
|
||||
}
|
||||
c->context = redisConnectNonBlock(ip,port);
|
||||
} else {
|
||||
c->context = redisConnectUnixNonBlock(config.hostsocket);
|
||||
}
|
||||
if (c->context->err) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
if (config.hostsocket == NULL || is_cluster_client)
|
||||
fprintf(stderr,"%s:%d: %s\n",ip,port,c->context->errstr);
|
||||
else
|
||||
fprintf(stderr,"%s: %s\n",config.hostsocket,c->context->errstr);
|
||||
exit(1);
|
||||
}
|
||||
c->thread_id = thread_id;
|
||||
/* Suppress hiredis cleanup of unused buffers for max speed. */
|
||||
c->context->reader->maxbuf = 0;
|
||||
|
||||
/* Build the request buffer:
|
||||
* Queue N requests accordingly to the pipeline size, or simply clone
|
||||
* the example client buffer. */
|
||||
c->obuf = sdsempty();
|
||||
/* Prefix the request buffer with AUTH and/or SELECT commands, if applicable.
|
||||
* These commands are discarded after the first response, so if the client is
|
||||
* reused the commands will not be used again. */
|
||||
c->prefix_pending = 0;
|
||||
if (config.auth) {
|
||||
char *buf = NULL;
|
||||
int len;
|
||||
if (config.user == NULL)
|
||||
len = redisFormatCommand(&buf, "AUTH %s", config.auth);
|
||||
else
|
||||
len = redisFormatCommand(&buf, "AUTH %s %s",
|
||||
config.user, config.auth);
|
||||
c->obuf = sdscatlen(c->obuf, buf, len);
|
||||
free(buf);
|
||||
c->prefix_pending++;
|
||||
}
|
||||
|
||||
if (config.enable_tracking) {
|
||||
char *buf = NULL;
|
||||
int len = redisFormatCommand(&buf, "CLIENT TRACKING on");
|
||||
c->obuf = sdscatlen(c->obuf, buf, len);
|
||||
free(buf);
|
||||
c->prefix_pending++;
|
||||
}
|
||||
|
||||
/* If a DB number different than zero is selected, prefix our request
|
||||
* buffer with the SELECT command, that will be discarded the first
|
||||
* time the replies are received, so if the client is reused the
|
||||
* SELECT command will not be used again. */
|
||||
if (config.dbnum != 0 && !is_cluster_client) {
|
||||
c->obuf = sdscatprintf(c->obuf,"*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n",
|
||||
(int)sdslen(config.dbnumstr),config.dbnumstr);
|
||||
c->prefix_pending++;
|
||||
}
|
||||
c->prefixlen = sdslen(c->obuf);
|
||||
/* Append the request itself. */
|
||||
if (from) {
|
||||
c->obuf = sdscatlen(c->obuf,
|
||||
from->obuf+from->prefixlen,
|
||||
sdslen(from->obuf)-from->prefixlen);
|
||||
} else {
|
||||
for (j = 0; j < config.pipeline; j++)
|
||||
c->obuf = sdscatlen(c->obuf,cmd,len);
|
||||
}
|
||||
|
||||
c->written = 0;
|
||||
c->pending = config.pipeline+c->prefix_pending;
|
||||
c->randptr = NULL;
|
||||
c->randlen = 0;
|
||||
c->stagptr = NULL;
|
||||
c->staglen = 0;
|
||||
|
||||
/* Find substrings in the output buffer that need to be randomized. */
|
||||
if (config.randomkeys) {
|
||||
if (from) {
|
||||
c->randlen = from->randlen;
|
||||
c->randfree = 0;
|
||||
c->randptr = (char**)zmalloc(sizeof(char*)*c->randlen, MALLOC_LOCAL);
|
||||
/* copy the offsets. */
|
||||
for (j = 0; j < (int)c->randlen; j++) {
|
||||
c->randptr[j] = c->obuf + (from->randptr[j]-from->obuf);
|
||||
/* Adjust for the different select prefix length. */
|
||||
c->randptr[j] += c->prefixlen - from->prefixlen;
|
||||
}
|
||||
} else {
|
||||
char *p = c->obuf;
|
||||
|
||||
c->randlen = 0;
|
||||
c->randfree = RANDPTR_INITIAL_SIZE;
|
||||
c->randptr = (char**)zmalloc(sizeof(char*)*c->randfree, MALLOC_LOCAL);
|
||||
while ((p = strstr(p,"__rand_int__")) != NULL) {
|
||||
if (c->randfree == 0) {
|
||||
c->randptr = (char**)zrealloc(c->randptr,sizeof(char*)*c->randlen*2, MALLOC_LOCAL);
|
||||
c->randfree += c->randlen;
|
||||
}
|
||||
c->randptr[c->randlen++] = p;
|
||||
c->randfree--;
|
||||
p += 12; /* 12 is strlen("__rand_int__). */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If cluster mode is enabled, set slot hashtags pointers. */
|
||||
if (config.cluster_mode) {
|
||||
if (from) {
|
||||
c->staglen = from->staglen;
|
||||
c->stagfree = 0;
|
||||
c->stagptr = (char**)zmalloc(sizeof(char*)*c->staglen, MALLOC_LOCAL);
|
||||
/* copy the offsets. */
|
||||
for (j = 0; j < (int)c->staglen; j++) {
|
||||
c->stagptr[j] = c->obuf + (from->stagptr[j]-from->obuf);
|
||||
/* Adjust for the different select prefix length. */
|
||||
c->stagptr[j] += c->prefixlen - from->prefixlen;
|
||||
}
|
||||
} else {
|
||||
char *p = c->obuf;
|
||||
|
||||
c->staglen = 0;
|
||||
c->stagfree = RANDPTR_INITIAL_SIZE;
|
||||
c->stagptr = (char**)zmalloc(sizeof(char*)*c->stagfree, MALLOC_LOCAL);
|
||||
while ((p = strstr(p,"{tag}")) != NULL) {
|
||||
if (c->stagfree == 0) {
|
||||
c->stagptr = (char**)zrealloc(c->stagptr,
|
||||
sizeof(char*) * c->staglen*2, MALLOC_LOCAL);
|
||||
c->stagfree += c->staglen;
|
||||
}
|
||||
c->stagptr[c->staglen++] = p;
|
||||
c->stagfree--;
|
||||
p += 5; /* 5 is strlen("{tag}"). */
|
||||
}
|
||||
}
|
||||
}
|
||||
aeEventLoop *el = NULL;
|
||||
if (thread_id < 0) el = config.el;
|
||||
else {
|
||||
benchmarkThread *thread = config.threads[thread_id];
|
||||
el = thread->el;
|
||||
}
|
||||
if (config.idlemode == 0)
|
||||
aeCreateFileEvent(el,c->context->fd,AE_WRITABLE,writeHandler,c);
|
||||
listAddNodeTail(config.clients,c);
|
||||
atomicIncr(config.liveclients, 1);
|
||||
atomicGet(config.slots_last_update, c->slots_last_update);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void initBenchmarkThreads() {
|
||||
int i;
|
||||
if (config.threads) freeBenchmarkThreads();
|
||||
config.threads = (benchmarkThread**)zmalloc(config.max_threads * sizeof(benchmarkThread*), MALLOC_LOCAL);
|
||||
for (i = 0; i < config.max_threads; i++) {
|
||||
benchmarkThread *thread = createBenchmarkThread(i);
|
||||
config.threads[i] = thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Thread functions. */
|
||||
|
||||
static benchmarkThread *createBenchmarkThread(int index) {
|
||||
benchmarkThread *thread = (benchmarkThread*)zmalloc(sizeof(*thread), MALLOC_LOCAL);
|
||||
if (thread == NULL) return NULL;
|
||||
thread->index = index;
|
||||
thread->el = aeCreateEventLoop(1024*10);
|
||||
return thread;
|
||||
}
|
||||
|
||||
static void freeBenchmarkThread(benchmarkThread *thread) {
|
||||
if (thread->el) aeDeleteEventLoop(thread->el);
|
||||
zfree(thread);
|
||||
}
|
||||
|
||||
static void freeBenchmarkThreads() {
|
||||
int i = 0;
|
||||
for (; i < config.max_threads; i++) {
|
||||
benchmarkThread *thread = config.threads[i];
|
||||
if (thread) freeBenchmarkThread(thread);
|
||||
}
|
||||
zfree(config.threads);
|
||||
config.threads = NULL;
|
||||
}
|
||||
|
||||
static void *execBenchmarkThread(void *ptr) {
|
||||
benchmarkThread *thread = (benchmarkThread *) ptr;
|
||||
aeMain(thread->el);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void initConfigDefaults() {
|
||||
config.numclients = 50;
|
||||
config.requests = 100000;
|
||||
config.liveclients = 0;
|
||||
config.el = aeCreateEventLoop(1024*10);
|
||||
config.keepalive = 1;
|
||||
config.datasize = 3;
|
||||
config.pipeline = 1;
|
||||
config.period_ms = 5000;
|
||||
config.showerrors = 0;
|
||||
config.randomkeys = 0;
|
||||
config.randomkeys_keyspacelen = 0;
|
||||
config.quiet = 0;
|
||||
config.csv = 0;
|
||||
config.loop = 0;
|
||||
config.idlemode = 0;
|
||||
config.latency = NULL;
|
||||
config.clients = listCreate();
|
||||
config.hostip = "127.0.0.1";
|
||||
config.hostport = 6379;
|
||||
config.hostsocket = NULL;
|
||||
config.tests = NULL;
|
||||
config.dbnum = 0;
|
||||
config.auth = NULL;
|
||||
config.precision = 1;
|
||||
config.max_threads = MAX_THREADS;
|
||||
config.threads = NULL;
|
||||
config.cluster_mode = 0;
|
||||
config.cluster_node_count = 0;
|
||||
config.cluster_nodes = NULL;
|
||||
config.redis_config = NULL;
|
||||
config.is_fetching_slots = 0;
|
||||
config.is_updating_slots = 0;
|
||||
config.slots_last_update = 0;
|
||||
config.enable_tracking = 0;
|
||||
}
|
||||
|
||||
/* Returns number of consumed options. */
|
||||
int parseOptions(int argc, const char **argv) {
|
||||
int i;
|
||||
int lastarg;
|
||||
int exit_status = 1;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
lastarg = (i == (argc-1));
|
||||
|
||||
if (!strcmp(argv[i],"-c") || !strcmp(argv[i],"--clients")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.numclients = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"--time")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.period_ms = atoi(argv[++i]);
|
||||
if (config.period_ms <= 0) {
|
||||
printf("Warning: Invalid value for thread time. Defaulting to 5000ms.\n");
|
||||
config.period_ms = 5000;
|
||||
}
|
||||
} else if (!strcmp(argv[i],"-h") || !strcmp(argv[i],"--host")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.hostip = strdup(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"-p") || !strcmp(argv[i],"--port")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.hostport = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"-s")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.hostsocket = strdup(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"--password") ) {
|
||||
if (lastarg) goto invalid;
|
||||
config.auth = strdup(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"--user")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.user = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--dbnum")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.dbnum = atoi(argv[++i]);
|
||||
config.dbnumstr = sdsfromlonglong(config.dbnum);
|
||||
} else if (!strcmp(argv[i],"-t") || !strcmp(argv[i],"--threads")) {
|
||||
if (lastarg) goto invalid;
|
||||
config.max_threads = atoi(argv[++i]);
|
||||
if (config.max_threads > MAX_THREADS) {
|
||||
printf("Warning: Too many threads, limiting threads to %d.\n", MAX_THREADS);
|
||||
config.max_threads = MAX_THREADS;
|
||||
} else if (config.max_threads <= 0) {
|
||||
printf("Warning: Invalid value for max threads. Defaulting to %d.\n", MAX_THREADS);
|
||||
config.max_threads = MAX_THREADS;
|
||||
}
|
||||
} else if (!strcmp(argv[i],"--help")) {
|
||||
exit_status = 0;
|
||||
goto usage;
|
||||
} else {
|
||||
/* Assume the user meant to provide an option when the arg starts
|
||||
* with a dash. We're done otherwise and should use the remainder
|
||||
* as the command and arguments for running the benchmark. */
|
||||
if (argv[i][0] == '-') goto invalid;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
invalid:
|
||||
printf("Invalid option \"%s\" or option argument missing\n\n",argv[i]);
|
||||
|
||||
usage:
|
||||
printf(
|
||||
"Usage: keydb-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests>] [-k <boolean>]\n\n"
|
||||
" -h, --host <hostname> Server hostname (default 127.0.0.1)\n"
|
||||
" -p, --port <port> Server port (default 6379)\n"
|
||||
" -c <clients> Number of parallel connections (default 50)\n"
|
||||
" -t, --threads <threads> Maximum number of threads to start before ending\n"
|
||||
" --time <time> Time between spinning up new client threads, in milliseconds\n"
|
||||
" --dbnum <db> Select the specified DB number (default 0)\n"
|
||||
" --user <username> Used to send ACL style 'AUTH username pass'. Needs -a.\n"
|
||||
" --password <password> Password for Redis Auth\n\n"
|
||||
);
|
||||
exit(exit_status);
|
||||
}
|
||||
|
||||
int extractPropertyFromInfo(const char *info, const char *key, double &val) {
|
||||
char *line = strstr((char*)info, key);
|
||||
if (line == nullptr) return 1;
|
||||
line += strlen(key) + 1; // Skip past key name and following colon
|
||||
char *newline = strchr(line, '\n');
|
||||
*newline = 0; // Terminate string after relevant line
|
||||
val = strtod(line, nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extractPropertyFromInfo(const char *info, const char *key, unsigned int &val) {
|
||||
char *line = strstr((char*)info, key);
|
||||
if (line == nullptr) return 1;
|
||||
line += strlen(key) + 1; // Skip past key name and following colon
|
||||
char *newline = strchr(line, '\n');
|
||||
*newline = 0; // Terminate string after relevant line
|
||||
val = atoi(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
double getSelfCpuTime(struct rusage *self_ru) {
|
||||
getrusage(RUSAGE_SELF, self_ru);
|
||||
double user_time = self_ru->ru_utime.tv_sec + (self_ru->ru_utime.tv_usec / (double)1000000);
|
||||
double system_time = self_ru->ru_stime.tv_sec + (self_ru->ru_stime.tv_usec / (double)1000000);
|
||||
return user_time + system_time;
|
||||
}
|
||||
|
||||
double getServerCpuTime(redisContext *ctx) {
|
||||
redisReply *reply = (redisReply*)redisCommand(ctx, "INFO CPU");
|
||||
if (reply->type != REDIS_REPLY_STRING) {
|
||||
freeReplyObject(reply);
|
||||
printf("Error executing INFO command. Exiting.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
double used_cpu_user, used_cpu_sys;
|
||||
if (extractPropertyFromInfo(reply->str, "used_cpu_user", used_cpu_user)) {
|
||||
printf("Error reading user CPU usage from INFO command. Exiting.\n");
|
||||
return -1;
|
||||
}
|
||||
if (extractPropertyFromInfo(reply->str, "used_cpu_sys", used_cpu_sys)) {
|
||||
printf("Error reading system CPU usage from INFO command. Exiting.\n");
|
||||
return -1;
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
return used_cpu_user + used_cpu_sys;
|
||||
}
|
||||
|
||||
double getMean(std::deque<double> *q) {
|
||||
double sum = 0;
|
||||
for (long unsigned int i = 0; i < q->size(); i++) {
|
||||
sum += (*q)[i];
|
||||
}
|
||||
return sum / q->size();
|
||||
}
|
||||
|
||||
bool isAtFullLoad(double cpuPercent, unsigned int threads) {
|
||||
return cpuPercent / threads >= 96;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int i;
|
||||
|
||||
storage_init(NULL, 0);
|
||||
|
||||
srandom(time(NULL));
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
initConfigDefaults();
|
||||
|
||||
i = parseOptions(argc,argv);
|
||||
argc -= i;
|
||||
argv += i;
|
||||
|
||||
config.latency = (long long*)zmalloc(sizeof(long long)*config.requests, MALLOC_LOCAL);
|
||||
|
||||
if (config.max_threads > 0) {
|
||||
int err = 0;
|
||||
err |= pthread_mutex_init(&(config.requests_issued_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.requests_finished_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.liveclients_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.is_fetching_slots_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.is_updating_slots_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.updating_slots_mutex), NULL);
|
||||
err |= pthread_mutex_init(&(config.slots_last_update_mutex), NULL);
|
||||
if (err != 0)
|
||||
{
|
||||
perror("Failed to initialize mutex");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
const char *set_value = "abcdefghijklmnopqrstuvwxyz";
|
||||
int self_threads = 0;
|
||||
char command[63];
|
||||
|
||||
initBenchmarkThreads();
|
||||
redisContext *ctx = getRedisContext(config.hostip, config.hostport, config.hostsocket);
|
||||
double server_cpu_time, last_server_cpu_time = getServerCpuTime(ctx);
|
||||
struct rusage self_ru;
|
||||
double self_cpu_time, last_self_cpu_time = getSelfCpuTime(&self_ru);
|
||||
double server_cpu_load, last_server_cpu_load = 0, self_cpu_load, server_cpu_gain;
|
||||
std::deque<double> load_gain_history = {};
|
||||
double current_gain_avg, peak_gain_avg = 0;
|
||||
|
||||
redisReply *reply = (redisReply*)redisCommand(ctx, "INFO CPU");
|
||||
if (reply->type != REDIS_REPLY_STRING) {
|
||||
freeReplyObject(reply);
|
||||
printf("Error executing INFO command. Exiting.\r\n");
|
||||
return 1;
|
||||
}
|
||||
unsigned int server_threads;
|
||||
if (extractPropertyFromInfo(reply->str, "server_threads", server_threads)) {
|
||||
printf("Error reading server threads from INFO command. Exiting.\r\n");
|
||||
return 1;
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
|
||||
printf("Server has %d threads.\nStarting...\n", server_threads);
|
||||
fflush(stdout);
|
||||
|
||||
while (self_threads < config.max_threads) {
|
||||
for (int i = 0; i < config.numclients; i++) {
|
||||
sprintf(command, "SET %d %s\r\n", self_threads * config.numclients + i, set_value);
|
||||
createClient(command, strlen(command), NULL,self_threads);
|
||||
}
|
||||
|
||||
benchmarkThread *t = config.threads[self_threads];
|
||||
if (pthread_create(&(t->thread), NULL, execBenchmarkThread, t)){
|
||||
fprintf(stderr, "FATAL: Failed to start thread %d. Exiting.\n", self_threads);
|
||||
exit(1);
|
||||
}
|
||||
self_threads++;
|
||||
|
||||
usleep(config.period_ms * 1000);
|
||||
|
||||
server_cpu_time = getServerCpuTime(ctx);
|
||||
self_cpu_time = getSelfCpuTime(&self_ru);
|
||||
server_cpu_load = (server_cpu_time - last_server_cpu_time) * 100000 / config.period_ms;
|
||||
self_cpu_load = (self_cpu_time - last_self_cpu_time) * 100000 / config.period_ms;
|
||||
if (server_cpu_time < 0) {
|
||||
break;
|
||||
}
|
||||
printf("%d threads, %d total clients. CPU Usage Self: %.1f%% (%.1f%% per thread), Server: %.1f%% (%.1f%% per thread)\r",
|
||||
self_threads,
|
||||
self_threads * config.numclients,
|
||||
self_cpu_load,
|
||||
self_cpu_load / self_threads,
|
||||
server_cpu_load,
|
||||
server_cpu_load / server_threads);
|
||||
fflush(stdout);
|
||||
server_cpu_gain = server_cpu_load - last_server_cpu_load;
|
||||
load_gain_history.push_back(server_cpu_gain);
|
||||
if (load_gain_history.size() > 5) {
|
||||
load_gain_history.pop_front();
|
||||
}
|
||||
current_gain_avg = getMean(&load_gain_history);
|
||||
if (current_gain_avg > peak_gain_avg) {
|
||||
peak_gain_avg = current_gain_avg;
|
||||
}
|
||||
last_server_cpu_time = server_cpu_time;
|
||||
last_self_cpu_time = self_cpu_time;
|
||||
last_server_cpu_load = server_cpu_load;
|
||||
|
||||
if (isAtFullLoad(server_cpu_load, server_threads)) {
|
||||
printf("\nServer is at full CPU load. If higher performance is expected, check server configuration.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_gain_avg <= 0.05 * peak_gain_avg) {
|
||||
printf("\nServer CPU load appears to have stagnated with increasing clients.\n"
|
||||
"Server does not appear to be at full load. Check network for throughput.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (self_threads * config.numclients > 2000) {
|
||||
printf("\nClient limit of 2000 reached. Server is not at full load and appears to be increasing.\n"
|
||||
"2000 clients should be more than enough to reach a bottleneck. Check all configuration.\n");
|
||||
}
|
||||
}
|
||||
|
||||
printf("Done.\n");
|
||||
|
||||
freeAllClients();
|
||||
freeBenchmarkThreads();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -426,7 +426,7 @@ sds createLatencyReport(void) {
|
||||
}
|
||||
|
||||
if (advise_slowlog_inspect) {
|
||||
report = sdscat(report,"- Check your Slow Log to understand what are the commands you are running which are too slow to execute. Please check https://redis.io/commands/slowlog for more information.\n");
|
||||
report = sdscat(report,"- Check your Slow Log to understand what are the commands you are running which are too slow to execute. Please check https://docs.keydb.dev/docs/commands#slowlog for more information.\n");
|
||||
}
|
||||
|
||||
/* Intrinsic latency. */
|
||||
|
||||
+2
-3
@@ -39,12 +39,11 @@ void lazyfreeFreeSlotsMap(void *args[]) {
|
||||
atomicIncr(lazyfreed_objects,len);
|
||||
}
|
||||
|
||||
/* Release the rax mapping Redis Cluster keys to slots in the
|
||||
* lazyfree thread. */
|
||||
/* Release the key tracking table. */
|
||||
void lazyFreeTrackingTable(void *args[]) {
|
||||
rax *rt = (rax*)args[0];
|
||||
size_t len = rt->numele;
|
||||
raxFree(rt);
|
||||
freeTrackingRadixTree(rt);
|
||||
atomicDecr(lazyfree_objects,len);
|
||||
atomicIncr(lazyfreed_objects,len);
|
||||
}
|
||||
|
||||
+2
-2
@@ -94,8 +94,8 @@ lwCanvas *lwCreateCanvas(int width, int height, int bgcolor) {
|
||||
lwCanvas *canvas = zmalloc(sizeof(*canvas));
|
||||
canvas->width = width;
|
||||
canvas->height = height;
|
||||
canvas->pixels = zmalloc(width*height);
|
||||
memset(canvas->pixels,bgcolor,width*height);
|
||||
canvas->pixels = zmalloc((size_t)width*height);
|
||||
memset(canvas->pixels,bgcolor,(size_t)width*height);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ void memtest_progress_start(char *title, int pass) {
|
||||
printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */
|
||||
printf("%s [%d]\n", title, pass); /* Print title. */
|
||||
progress_printed = 0;
|
||||
progress_full = ws.ws_col*(ws.ws_row-3);
|
||||
progress_full = (size_t)ws.ws_col*(ws.ws_row-3);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -6366,7 +6366,7 @@ int RM_GetClusterNodeInfo(RedisModuleCtx *ctx, const char *id, char *ip, char *m
|
||||
/* If the information is not available, the function will set the
|
||||
* field to zero bytes, so that when the field can't be populated the
|
||||
* function kinda remains predictable. */
|
||||
if (node->flags & CLUSTER_NODE_MASTER && node->slaveof)
|
||||
if (node->flags & CLUSTER_NODE_SLAVE && node->slaveof)
|
||||
memcpy(master_id,node->slaveof->name,REDISMODULE_NODE_ID_LEN);
|
||||
else
|
||||
memset(master_id,0,REDISMODULE_NODE_ID_LEN);
|
||||
@@ -9425,6 +9425,7 @@ long moduleDefragGlobals(void) {
|
||||
module->defrag_cb(&defrag_ctx);
|
||||
defragged += defrag_ctx.defragged;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
|
||||
return defragged;
|
||||
}
|
||||
|
||||
+1
-1
@@ -902,7 +902,7 @@ size_t objectComputeSize(robj *o, size_t sample_size) {
|
||||
if (samples) asize += (double)elesize/samples*dictSize(d);
|
||||
} else if (o->encoding == OBJ_ENCODING_INTSET) {
|
||||
intset *is = (intset*)ptrFromObj(o);
|
||||
asize = sizeof(*o)+sizeof(*is)+is->encoding*is->length;
|
||||
asize = sizeof(*o)+sizeof(*is)+(size_t)is->encoding*is->length;
|
||||
} else {
|
||||
serverPanic("Unknown set encoding");
|
||||
}
|
||||
|
||||
+45
-44
@@ -103,7 +103,6 @@ static struct config {
|
||||
int randomkeys_keyspacelen;
|
||||
int keepalive;
|
||||
int pipeline;
|
||||
int showerrors;
|
||||
long long start;
|
||||
long long totlatency;
|
||||
const char *title;
|
||||
@@ -313,7 +312,9 @@ static redisContext *getRedisContext(const char *ip, int port,
|
||||
fprintf(stderr, "Node %s:%d replied with error:\n%s\n", ip, port, reply->str);
|
||||
else
|
||||
fprintf(stderr, "Node %s replied with error:\n%s\n", hostsocket, reply->str);
|
||||
goto cleanup;
|
||||
freeReplyObject(reply);
|
||||
redisFree(ctx);
|
||||
exit(1);
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
return ctx;
|
||||
@@ -370,9 +371,15 @@ fail:
|
||||
fprintf(stderr, "ERROR: failed to fetch CONFIG from ");
|
||||
if (hostsocket == NULL) fprintf(stderr, "%s:%d\n", ip, port);
|
||||
else fprintf(stderr, "%s\n", hostsocket);
|
||||
int abort_test = 0;
|
||||
if (!strncmp(reply->str,"NOAUTH",5) ||
|
||||
!strncmp(reply->str,"WRONGPASS",9) ||
|
||||
!strncmp(reply->str,"NOPERM",5))
|
||||
abort_test = 1;
|
||||
freeReplyObject(reply);
|
||||
redisFree(c);
|
||||
freeRedisConfig(cfg);
|
||||
if (abort_test) exit(1);
|
||||
return NULL;
|
||||
}
|
||||
static void freeRedisConfig(redisConfig *cfg) {
|
||||
@@ -517,44 +524,39 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
exit(1);
|
||||
}
|
||||
redisReply *r = (redisReply*)reply;
|
||||
int is_err = (r->type == REDIS_REPLY_ERROR);
|
||||
|
||||
if (is_err && config.showerrors) {
|
||||
/* TODO: static lasterr_time not thread-safe */
|
||||
static time_t lasterr_time = 0;
|
||||
time_t now = time(NULL);
|
||||
if (lasterr_time != now) {
|
||||
lasterr_time = now;
|
||||
if (c->cluster_node) {
|
||||
printf("Error from server %s:%d: %s\n",
|
||||
if (r->type == REDIS_REPLY_ERROR) {
|
||||
/* Try to update slots configuration if reply error is
|
||||
* MOVED/ASK/CLUSTERDOWN and the key(s) used by the command
|
||||
* contain(s) the slot hash tag.
|
||||
* If the error is not topology-update related then we
|
||||
* immediately exit to avoid false results. */
|
||||
if (c->cluster_node && c->staglen) {
|
||||
int fetch_slots = 0, do_wait = 0;
|
||||
if (!strncmp(r->str,"MOVED",5) || !strncmp(r->str,"ASK",3))
|
||||
fetch_slots = 1;
|
||||
else if (!strncmp(r->str,"CLUSTERDOWN",11)) {
|
||||
/* Usually the cluster is able to recover itself after
|
||||
* a CLUSTERDOWN error, so try to sleep one second
|
||||
* before requesting the new configuration. */
|
||||
fetch_slots = 1;
|
||||
do_wait = 1;
|
||||
printf("Error from server %s:%d: %s.\n",
|
||||
c->cluster_node->ip,
|
||||
c->cluster_node->port,
|
||||
r->str);
|
||||
}
|
||||
if (do_wait) sleep(1);
|
||||
if (fetch_slots && !fetchClusterSlotsConfiguration(c))
|
||||
exit(1);
|
||||
} else {
|
||||
if (c->cluster_node) {
|
||||
printf("Error from server %s:%d: %s\n",
|
||||
c->cluster_node->ip,
|
||||
c->cluster_node->port,
|
||||
r->str);
|
||||
} else printf("Error from server: %s\n", r->str);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to update slots configuration if reply error is
|
||||
* MOVED/ASK/CLUSTERDOWN and the key(s) used by the command
|
||||
* contain(s) the slot hash tag. */
|
||||
if (is_err && c->cluster_node && c->staglen) {
|
||||
int fetch_slots = 0, do_wait = 0;
|
||||
if (!strncmp(r->str,"MOVED",5) || !strncmp(r->str,"ASK",3))
|
||||
fetch_slots = 1;
|
||||
else if (!strncmp(r->str,"CLUSTERDOWN",11)) {
|
||||
/* Usually the cluster is able to recover itself after
|
||||
* a CLUSTERDOWN error, so try to sleep one second
|
||||
* before requesting the new configuration. */
|
||||
fetch_slots = 1;
|
||||
do_wait = 1;
|
||||
printf("Error from server %s:%d: %s\n",
|
||||
c->cluster_node->ip,
|
||||
c->cluster_node->port,
|
||||
r->str);
|
||||
}
|
||||
if (do_wait) sleep(1);
|
||||
if (fetch_slots && !fetchClusterSlotsConfiguration(c))
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
@@ -1298,8 +1300,7 @@ static int fetchClusterSlotsConfiguration(client c) {
|
||||
atomicGetIncr(config.is_fetching_slots, is_fetching_slots, 1);
|
||||
if (is_fetching_slots) return -1; //TODO: use other codes || errno ?
|
||||
atomicSet(config.is_fetching_slots, 1);
|
||||
if (config.showerrors)
|
||||
printf("Cluster slots configuration changed, fetching new one...\n");
|
||||
printf("WARNING: Cluster slots configuration changed, fetching new one...\n");
|
||||
const char *errmsg = "Failed to update cluster slots configuration";
|
||||
static dictType dtype = {
|
||||
dictSdsHash, /* hash function */
|
||||
@@ -1475,7 +1476,8 @@ int parseOptions(int argc, const char **argv) {
|
||||
} else if (!strcmp(argv[i],"-I")) {
|
||||
config.idlemode = 1;
|
||||
} else if (!strcmp(argv[i],"-e")) {
|
||||
config.showerrors = 1;
|
||||
printf("WARNING: -e option has been deprecated. "
|
||||
"We now immediatly exit on error to avoid false results.\n");
|
||||
} else if (!strcmp(argv[i],"-t")) {
|
||||
if (lastarg) goto invalid;
|
||||
/* We get the list of tests to run as a string in the form
|
||||
@@ -1578,8 +1580,6 @@ usage:
|
||||
" is executed. Default tests use this to hit random keys in the\n"
|
||||
" specified range.\n"
|
||||
" -P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).\n"
|
||||
" -e If server replies with errors, show them on stdout.\n"
|
||||
" (no more than 1 error per second is displayed)\n"
|
||||
" -q Quiet. Just show query/sec values\n"
|
||||
" --precision Number of decimal places to display in latency output (default 0)\n"
|
||||
" --csv Output in CSV format\n"
|
||||
@@ -1707,7 +1707,6 @@ int main(int argc, const char **argv) {
|
||||
config.keepalive = 1;
|
||||
config.datasize = 3;
|
||||
config.pipeline = 1;
|
||||
config.showerrors = 0;
|
||||
config.randomkeys = 0;
|
||||
config.randomkeys_keyspacelen = 0;
|
||||
config.quiet = 0;
|
||||
@@ -1790,8 +1789,9 @@ int main(int argc, const char **argv) {
|
||||
} else {
|
||||
config.redis_config =
|
||||
getRedisConfig(config.hostip, config.hostport, config.hostsocket);
|
||||
if (config.redis_config == NULL)
|
||||
if (config.redis_config == NULL) {
|
||||
fprintf(stderr, "WARN: could not fetch server CONFIG\n");
|
||||
}
|
||||
}
|
||||
if (config.num_threads > 0) {
|
||||
pthread_mutex_init(&(config.liveclients_mutex), NULL);
|
||||
@@ -1954,8 +1954,8 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
|
||||
if (test_is_selected("lrange") || test_is_selected("lrange_500")) {
|
||||
len = redisFormatCommand(&cmd,"LRANGE mylist%s 0 449",tag);
|
||||
benchmark("LRANGE_500 (first 450 elements)",cmd,len);
|
||||
len = redisFormatCommand(&cmd,"LRANGE mylist%s 0 499",tag);
|
||||
benchmark("LRANGE_500 (first 500 elements)",cmd,len);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
@@ -1983,6 +1983,7 @@ int main(int argc, const char **argv) {
|
||||
} while(config.loop);
|
||||
zfree(data);
|
||||
|
||||
zfree(data);
|
||||
if (config.redis_config != NULL) freeRedisConfig(config.redis_config);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -39,12 +39,14 @@
|
||||
|
||||
static char error[1044];
|
||||
static off_t epos;
|
||||
static long long line = 1;
|
||||
|
||||
int consumeNewline(char *buf) {
|
||||
if (strncmp(buf,"\r\n",2) != 0) {
|
||||
ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]);
|
||||
return 0;
|
||||
}
|
||||
line += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -201,8 +203,8 @@ int redis_check_aof_main(int argc, char **argv) {
|
||||
|
||||
off_t pos = process(fp);
|
||||
off_t diff = size-pos;
|
||||
printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",
|
||||
(long long) size, (long long) pos, (long long) diff);
|
||||
printf("AOF analyzed: size=%lld, ok_up_to=%lld, ok_up_to_line=%lld, diff=%lld\n",
|
||||
(long long) size, (long long) pos, line, (long long) diff);
|
||||
if (diff > 0) {
|
||||
if (fix) {
|
||||
char buf[2];
|
||||
|
||||
@@ -250,7 +250,7 @@ int redis_check_rdb(const char *rdbfilename, FILE *fp) {
|
||||
rdbstate.doing = RDB_CHECK_DOING_READ_LEN;
|
||||
if ((dbid = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
|
||||
goto eoferr;
|
||||
rdbCheckInfo("Selecting DB ID %d", dbid);
|
||||
rdbCheckInfo("Selecting DB ID %llu", (unsigned long long)dbid);
|
||||
continue; /* Read type again. */
|
||||
} else if (type == RDB_OPCODE_RESIZEDB) {
|
||||
/* RESIZEDB: Hint about the size of the keys in the currently
|
||||
|
||||
+7
-5
@@ -467,7 +467,7 @@ static void cliOutputHelp(int argc, char **argv) {
|
||||
help = entry->org;
|
||||
if (group == -1) {
|
||||
/* Compare all arguments */
|
||||
if (argc == entry->argc) {
|
||||
if (argc <= entry->argc) {
|
||||
for (j = 0; j < argc; j++) {
|
||||
if (strcasecmp(argv[j],entry->argv[j]) != 0) break;
|
||||
}
|
||||
@@ -648,7 +648,9 @@ static int cliConnect(int flags) {
|
||||
cliRefreshPrompt();
|
||||
}
|
||||
|
||||
if (config.hostsocket == NULL) {
|
||||
/* Do not use hostsocket when we got redirected in cluster mode */
|
||||
if (config.hostsocket == NULL ||
|
||||
(config.cluster_mode && config.cluster_reissue_command)) {
|
||||
context = redisConnect(config.hostip,config.hostport);
|
||||
} else {
|
||||
context = redisConnectUnix(config.hostsocket);
|
||||
@@ -4554,7 +4556,7 @@ static void clusterManagerNodeArrayReset(clusterManagerNodeArray *array) {
|
||||
static void clusterManagerNodeArrayShift(clusterManagerNodeArray *array,
|
||||
clusterManagerNode **nodeptr)
|
||||
{
|
||||
assert(array->nodes < (array->nodes + array->len));
|
||||
assert(array->len > 0);
|
||||
/* If the first node to be shifted is not NULL, decrement count. */
|
||||
if (*array->nodes != NULL) array->count--;
|
||||
/* Store the first node to be shifted into 'nodeptr'. */
|
||||
@@ -4567,7 +4569,7 @@ static void clusterManagerNodeArrayShift(clusterManagerNodeArray *array,
|
||||
static void clusterManagerNodeArrayAdd(clusterManagerNodeArray *array,
|
||||
clusterManagerNode *node)
|
||||
{
|
||||
assert(array->nodes < (array->nodes + array->len));
|
||||
assert(array->len > 0);
|
||||
assert(node != NULL);
|
||||
assert(array->count < array->len);
|
||||
array->nodes[array->count++] = node;
|
||||
@@ -5944,7 +5946,7 @@ void showLatencyDistSamples(struct distsamples *samples, long long tot) {
|
||||
printf("\033[38;5;0m"); /* Set foreground color to black. */
|
||||
for (j = 0; ; j++) {
|
||||
int coloridx =
|
||||
ceil((float) samples[j].count / tot * (spectrum_palette_size-1));
|
||||
ceil((double) samples[j].count / tot * (spectrum_palette_size-1));
|
||||
int color = spectrum_palette[coloridx];
|
||||
printf("\033[48;5;%dm%c", (int)color, samples[j].character);
|
||||
samples[j].count = 0;
|
||||
|
||||
+1
-1
@@ -4803,7 +4803,7 @@ void replicationNotifyLoadedKey(redisDb *db, robj_roptr key, robj_roptr val, lon
|
||||
redisObjectStack objTtl;
|
||||
initStaticStringObject(objTtl, sdscatprintf(sdsempty(), "%lld", expire));
|
||||
redisObjectStack objMvcc;
|
||||
initStaticStringObject(objMvcc, sdscatprintf(sdsempty(), "%lu", mvccFromObj(val)));
|
||||
initStaticStringObject(objMvcc, sdscatprintf(sdsempty(), "%" PRIu64, mvccFromObj(val)));
|
||||
redisObject *argv[5] = {shared.mvccrestore, key.unsafe_robjcast(), &objMvcc, &objTtl, &objPayload};
|
||||
|
||||
replicationFeedSlaves(g_pserver->slaves, db - g_pserver->db, argv, 5);
|
||||
|
||||
+7
-4
@@ -31,6 +31,7 @@
|
||||
#include "sha1.h"
|
||||
#include "rand.h"
|
||||
#include "cluster.h"
|
||||
#include "monotonic.h"
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
@@ -1437,7 +1438,7 @@ sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
|
||||
|
||||
/* This is the Lua script "count" hook that we use to detect scripts timeout. */
|
||||
void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
|
||||
long long elapsed = mstime() - g_pserver->lua_time_start;
|
||||
long long elapsed = elapsedMs(g_pserver->lua_time_start);
|
||||
UNUSED(ar);
|
||||
UNUSED(lua);
|
||||
|
||||
@@ -1588,7 +1589,8 @@ void evalGenericCommand(client *c, int evalsha) {
|
||||
serverTL->in_eval = 1;
|
||||
g_pserver->lua_caller = c;
|
||||
g_pserver->lua_cur_script = funcname + 2;
|
||||
g_pserver->lua_time_start = mstime();
|
||||
g_pserver->lua_time_start = getMonotonicUs();
|
||||
g_pserver->lua_time_snapshot = mstime();
|
||||
g_pserver->lua_kill = 0;
|
||||
if (g_pserver->lua_time_limit > 0 && ldb.active == 0) {
|
||||
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
|
||||
@@ -2747,7 +2749,7 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
|
||||
|
||||
/* Check if a timeout occurred. */
|
||||
if (ar->event == LUA_HOOKCOUNT && ldb.step == 0 && bp == 0) {
|
||||
mstime_t elapsed = mstime() - g_pserver->lua_time_start;
|
||||
mstime_t elapsed = elapsedMs(g_pserver->lua_time_start);
|
||||
mstime_t timelimit = g_pserver->lua_time_limit ?
|
||||
g_pserver->lua_time_limit : 5000;
|
||||
if (elapsed >= timelimit) {
|
||||
@@ -2777,6 +2779,7 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
|
||||
lua_pushstring(lua, "timeout during Lua debugging with client closing connection");
|
||||
lua_error(lua);
|
||||
}
|
||||
g_pserver->lua_time_start = mstime();
|
||||
g_pserver->lua_time_start = getMonotonicUs();
|
||||
g_pserver->lua_time_snapshot = mstime();
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -4131,16 +4131,16 @@ void sentinelSetCommand(client *c) {
|
||||
int numargs = j-old_j+1;
|
||||
switch(numargs) {
|
||||
case 2:
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s %s",ptrFromObj(c->argv[old_j]),
|
||||
ptrFromObj(c->argv[old_j+1]));
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s %s",szFromObj(c->argv[old_j]),
|
||||
szFromObj(c->argv[old_j+1]));
|
||||
break;
|
||||
case 3:
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s %s %s",ptrFromObj(c->argv[old_j]),
|
||||
ptrFromObj(c->argv[old_j+1]),
|
||||
ptrFromObj(c->argv[old_j+2]));
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s %s %s",szFromObj(c->argv[old_j]),
|
||||
szFromObj(c->argv[old_j+1]),
|
||||
szFromObj(c->argv[old_j+2]));
|
||||
break;
|
||||
default:
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s",ptrFromObj(c->argv[old_j]));
|
||||
sentinelEvent(LL_WARNING,"+set",ri,"%@ %s",szFromObj(c->argv[old_j]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-8
@@ -57,7 +57,6 @@
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <locale.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -67,7 +66,6 @@
|
||||
#include "aelocker.h"
|
||||
#include "motd.h"
|
||||
#include "t_nhash.h"
|
||||
#include <sys/resource.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -4301,6 +4299,8 @@ int processCommand(client *c, int callFlags) {
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
int is_read_command = (c->cmd->flags & CMD_READONLY) ||
|
||||
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & CMD_READONLY));
|
||||
int is_write_command = (c->cmd->flags & CMD_WRITE) ||
|
||||
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & CMD_WRITE));
|
||||
int is_denyoom_command = (c->cmd->flags & CMD_DENYOOM) ||
|
||||
@@ -4515,7 +4515,7 @@ int processCommand(client *c, int callFlags) {
|
||||
c->cmd->proc != discardCommand &&
|
||||
c->cmd->proc != watchCommand &&
|
||||
c->cmd->proc != unwatchCommand &&
|
||||
c->cmd->proc != resetCommand &&
|
||||
c->cmd->proc != resetCommand &&
|
||||
!(c->cmd->proc == shutdownCommand &&
|
||||
c->argc == 2 &&
|
||||
tolower(((char*)ptrFromObj(c->argv[1]))[0]) == 'n') &&
|
||||
@@ -4527,6 +4527,14 @@ int processCommand(client *c, int callFlags) {
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
/* Prevent a replica from sending commands that access the keyspace.
|
||||
* The main objective here is to prevent abuse of client pause check
|
||||
* from which replicas are exempt. */
|
||||
if ((c->flags & CLIENT_SLAVE) && (is_may_replicate_command || is_write_command || is_read_command)) {
|
||||
rejectCommandFormat(c, "Replica can't interract with the keyspace");
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
/* If the server is paused, block the client until
|
||||
* the pause has ended. Replicas are never paused. */
|
||||
if (!(c->flags & CLIENT_SLAVE) &&
|
||||
@@ -4635,10 +4643,6 @@ int prepareForShutdown(int flags) {
|
||||
overwrite the synchronous saving did by SHUTDOWN. */
|
||||
if (g_pserver->child_type == CHILD_TYPE_RDB) {
|
||||
serverLog(LL_WARNING,"There is a child saving an .rdb. Killing it!");
|
||||
/* Note that, in killRDBChild, we call rdbRemoveTempFile that will
|
||||
* do close fd(in order to unlink file actully) in background thread.
|
||||
* The temp rdb file fd may won't be closed when redis exits quickly,
|
||||
* but OS will close this fd when process exits. */
|
||||
killRDBChild();
|
||||
/* Note that, in killRDBChild normally has backgroundSaveDoneHandler
|
||||
* doing it's cleanup, but in this case this code will not be reached,
|
||||
@@ -6834,7 +6838,7 @@ int main(int argc, char **argv) {
|
||||
serverLog(LL_WARNING, "Failed to test the kernel for a bug that could lead to data corruption during background save. "
|
||||
"Your system could be affected, please report this error.");
|
||||
if (!checkIgnoreWarning("ARM64-COW-BUG")) {
|
||||
serverLog(LL_WARNING,"Redis will now exit to prevent data corruption. "
|
||||
serverLog(LL_WARNING,"KeyDB will now exit to prevent data corruption. "
|
||||
"Note that it is possible to suppress this warning by setting the following config: ignore-warnings ARM64-COW-BUG");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+3
-1
@@ -1934,7 +1934,8 @@ struct redisServer {
|
||||
::dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */
|
||||
unsigned long long lua_scripts_mem; /* Cached scripts' memory + oh */
|
||||
mstime_t lua_time_limit; /* Script timeout in milliseconds */
|
||||
mstime_t lua_time_start; /* Start time of script, milliseconds time */
|
||||
monotime lua_time_start; /* monotonic timer to detect timed-out script */
|
||||
mstime_t lua_time_snapshot; /* Snapshot of mstime when script is started */
|
||||
int lua_write_dirty; /* True if a write command was called during the
|
||||
execution of the current script. */
|
||||
int lua_random_dirty; /* True if a random command was called during the
|
||||
@@ -2296,6 +2297,7 @@ void disableTracking(client *c);
|
||||
void trackingRememberKeys(client *c);
|
||||
void trackingInvalidateKey(client *c, robj *keyobj);
|
||||
void trackingInvalidateKeysOnFlush(int async);
|
||||
void freeTrackingRadixTree(rax *rt);
|
||||
void freeTrackingRadixTreeAsync(rax *rt);
|
||||
void trackingLimitUsedSlots(void);
|
||||
uint64_t trackingGetTotalItems(void);
|
||||
|
||||
+3
-3
@@ -512,7 +512,7 @@ void spopWithCountCommand(client *c) {
|
||||
const char *sdsele;
|
||||
robj *objele;
|
||||
int encoding;
|
||||
int64_t llele;
|
||||
int64_t llele = 0;
|
||||
unsigned long remaining = size-count; /* Elements left after SPOP. */
|
||||
|
||||
/* If we are here, the number of requested elements is less than the
|
||||
@@ -664,7 +664,7 @@ void srandmemberWithCountCommand(client *c) {
|
||||
int uniq = 1;
|
||||
robj_roptr set;
|
||||
const char *ele;
|
||||
int64_t llele;
|
||||
int64_t llele = 0;
|
||||
int encoding;
|
||||
|
||||
dict *d;
|
||||
@@ -813,7 +813,7 @@ void srandmemberWithCountCommand(client *c) {
|
||||
void srandmemberCommand(client *c) {
|
||||
robj_roptr set;
|
||||
const char *ele;
|
||||
int64_t llele;
|
||||
int64_t llele = 0;
|
||||
int encoding;
|
||||
|
||||
if (c->argc == 3) {
|
||||
|
||||
+3
-3
@@ -813,7 +813,7 @@ int64_t streamTrim(stream *s, streamAddTrimArgs *args) {
|
||||
}
|
||||
deleted += deleted_from_lp;
|
||||
|
||||
/* Now we the entries/deleted counters. */
|
||||
/* Now we update the entries/deleted counters. */
|
||||
p = lpFirst(lp);
|
||||
lp = lpReplaceInteger(lp,&p,entries-deleted_from_lp);
|
||||
p = lpNext(lp,p); /* Skip deleted field. */
|
||||
@@ -842,7 +842,7 @@ int64_t streamTrim(stream *s, streamAddTrimArgs *args) {
|
||||
|
||||
/* Trims a stream by length. Returns the number of deleted items. */
|
||||
int64_t streamTrimByLength(stream *s, long long maxlen, int approx) {
|
||||
streamAddTrimArgs args = {0};
|
||||
streamAddTrimArgs args = {{0}};
|
||||
args.trim_strategy = TRIM_STRATEGY_MAXLEN;
|
||||
args.approx_trim = approx;
|
||||
args.limit = approx ? 100 * g_pserver->stream_node_max_entries : 0;
|
||||
@@ -852,7 +852,7 @@ int64_t streamTrimByLength(stream *s, long long maxlen, int approx) {
|
||||
|
||||
/* Trims a stream by minimum ID. Returns the number of deleted items. */
|
||||
int64_t streamTrimByID(stream *s, streamID minid, int approx) {
|
||||
streamAddTrimArgs args = {0};
|
||||
streamAddTrimArgs args = {{0}};
|
||||
args.trim_strategy = TRIM_STRATEGY_MINID;
|
||||
args.approx_trim = approx;
|
||||
args.limit = approx ? 100 * g_pserver->stream_node_max_entries : 0;
|
||||
|
||||
+1
-1
@@ -810,7 +810,7 @@ void stralgoLCS(client *c) {
|
||||
/* Setup an uint32_t array to store at LCS[i,j] the length of the
|
||||
* LCS A0..i-1, B0..j-1. Note that we have a linear array here, so
|
||||
* we index it as LCS[j+(blen+1)*j] */
|
||||
uint32_t *lcs = (uint32_t*)zmalloc((alen+1)*(blen+1)*sizeof(uint32_t));
|
||||
uint32_t *lcs = (uint32_t*)zmalloc((size_t)(alen+1)*(blen+1)*sizeof(uint32_t));
|
||||
#define LCS(A,B) lcs[(B)+((A)*(blen+1))]
|
||||
|
||||
/* Start building the LCS table. */
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Redis configuration for testing.
|
||||
# KeyDB configuration for testing.
|
||||
|
||||
always-show-logo yes
|
||||
notify-keyspace-events KEA
|
||||
daemonize no
|
||||
pidfile /var/run/redis.pid
|
||||
pidfile /var/run/keydb.pid
|
||||
port 6379
|
||||
timeout 0
|
||||
bind 127.0.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Minimal configuration for testing.
|
||||
always-show-logo yes
|
||||
daemonize no
|
||||
pidfile /var/run/redis.pid
|
||||
pidfile /var/run/keydb.pid
|
||||
loglevel verbose
|
||||
@@ -1,4 +1,4 @@
|
||||
source tests/support/redis.tcl
|
||||
source tests/support/keydb.tcl
|
||||
source tests/support/util.tcl
|
||||
|
||||
set ::tlsdir "tests/tls"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
source tests/support/redis.tcl
|
||||
source tests/support/keydb.tcl
|
||||
source tests/support/util.tcl
|
||||
|
||||
set ::tlsdir "tests/tls"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
source tests/support/redis.tcl
|
||||
source tests/support/keydb.tcl
|
||||
|
||||
set ::tlsdir "tests/tls"
|
||||
|
||||
|
||||
+8
-8
@@ -10,7 +10,7 @@
|
||||
package require Tcl 8.5
|
||||
|
||||
set tcl_precision 17
|
||||
source ../support/redis.tcl
|
||||
source ../support/keydb.tcl
|
||||
source ../support/util.tcl
|
||||
source ../support/server.tcl
|
||||
source ../support/test.tcl
|
||||
@@ -36,7 +36,7 @@ set ::run_matching {} ; # If non empty, only tests matching pattern are run.
|
||||
|
||||
if {[catch {cd tmp}]} {
|
||||
puts "tmp directory not found."
|
||||
puts "Please run this test from the Redis source root."
|
||||
puts "Please run this test from the KeyDB source root."
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ proc spawn_instance {type base_port count {conf {}} {base_conf_file ""}} {
|
||||
puts $cfg [format "tls-key-file %s/../../tls/server.key" [pwd]]
|
||||
puts $cfg [format "tls-client-cert-file %s/../../tls/client.crt" [pwd]]
|
||||
puts $cfg [format "tls-client-key-file %s/../../tls/client.key" [pwd]]
|
||||
puts $cfg [format "tls-dh-params-file %s/../../tls/redis.dh" [pwd]]
|
||||
puts $cfg [format "tls-dh-params-file %s/../../tls/keydb.dh" [pwd]]
|
||||
puts $cfg [format "tls-ca-cert-file %s/../../tls/ca.crt" [pwd]]
|
||||
puts $cfg "loglevel debug"
|
||||
} else {
|
||||
@@ -303,7 +303,7 @@ proc pause_on_error {} {
|
||||
set count 10
|
||||
if {[lindex $argv 1] ne {}} {set count [lindex $argv 1]}
|
||||
foreach_redis_id id {
|
||||
puts "=== REDIS $id ===="
|
||||
puts "=== KeyDB $id ===="
|
||||
puts [exec tail -$count redis_$id/log.txt]
|
||||
puts "---------------------\n"
|
||||
}
|
||||
@@ -317,7 +317,7 @@ proc pause_on_error {} {
|
||||
}
|
||||
} elseif {$cmd eq {ls}} {
|
||||
foreach_redis_id id {
|
||||
puts -nonewline "Redis $id"
|
||||
puts -nonewline "KeyDB $id"
|
||||
set errcode [catch {
|
||||
set str {}
|
||||
append str "@[RI $id tcp_port]: "
|
||||
@@ -348,13 +348,13 @@ proc pause_on_error {} {
|
||||
}
|
||||
}
|
||||
} elseif {$cmd eq {help}} {
|
||||
puts "ls List Sentinel and Redis instances."
|
||||
puts "ls List Sentinel and KeyDB instances."
|
||||
puts "show-sentinel-logs \[N\] Show latest N lines of logs."
|
||||
puts "show-keydb-logs \[N\] Show latest N lines of logs."
|
||||
puts "S <id> cmd ... arg Call command in Sentinel <id>."
|
||||
puts "R <id> cmd ... arg Call command in Redis <id>."
|
||||
puts "R <id> cmd ... arg Call command in KeyDB <id>."
|
||||
puts "SI <id> <field> Show Sentinel <id> INFO <field>."
|
||||
puts "RI <id> <field> Show Redis <id> INFO <field>."
|
||||
puts "RI <id> <field> Show KeyDB <id> INFO <field>."
|
||||
puts "continue Resume test."
|
||||
} else {
|
||||
set errcode [catch {eval $line} retval]
|
||||
|
||||
@@ -158,6 +158,18 @@ tags {"aof"} {
|
||||
assert_match "*not valid*" $result
|
||||
}
|
||||
|
||||
test "Short read: Utility should show the abnormal line num in AOF" {
|
||||
create_aof {
|
||||
append_to_aof [formatCommand set foo hello]
|
||||
append_to_aof "!!!"
|
||||
}
|
||||
|
||||
catch {
|
||||
exec src/keydb-check-aof $aof_path
|
||||
} result
|
||||
assert_match "*ok_up_to_line=8*" $result
|
||||
}
|
||||
|
||||
test "Short read: Utility should be able to fix the AOF" {
|
||||
set result [exec src/keydb-check-aof --fix $aof_path << "y\n"]
|
||||
assert_match "*Successfully truncated AOF*" $result
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,12 +1,10 @@
|
||||
set system_name [string tolower [exec uname -s]]
|
||||
# ldd --version returns 1 under musl for unknown reasons. If this check stops working, that may be why
|
||||
set is_musl [catch {exec ldd --version}]
|
||||
set system_supported 0
|
||||
|
||||
# We only support darwin or Linux with glibc
|
||||
if {$system_name eq {darwin}} {
|
||||
set system_supported 1
|
||||
} elseif {$system_name eq {linux} && $is_musl eq 0} {
|
||||
} elseif {$system_name eq {linux}} {
|
||||
# Avoid the test on libmusl, which does not support backtrace
|
||||
set ldd [exec ldd src/keydb-server]
|
||||
if {![string match {*libc.musl*} $ldd]} {
|
||||
|
||||
@@ -4,7 +4,7 @@ proc show_cluster_status {} {
|
||||
# The following is the regexp we use to match the log line
|
||||
# time info. Logs are in the following form:
|
||||
#
|
||||
# 11296:M 25 May 2020 17:37:14.652 # Server initialized
|
||||
# 11296:11296:M 25 May 2020 17:37:14.652 # Server initialized
|
||||
set log_regexp {^[0-9]+:^[0-9]+:[A-Z] [0-9]+ [A-z]+ [0-9]+ ([0-9:.]+) .*}
|
||||
set repl_regexp {(master|repl|sync|backlog|meaningful|offset)}
|
||||
|
||||
|
||||
File renamed without changes.
@@ -355,7 +355,7 @@ proc start_server {options {code undefined}} {
|
||||
dict set config "tls-key-file" [format "%s/tests/tls/server.key" [pwd]]
|
||||
dict set config "tls-client-cert-file" [format "%s/tests/tls/client.crt" [pwd]]
|
||||
dict set config "tls-client-key-file" [format "%s/tests/tls/client.key" [pwd]]
|
||||
dict set config "tls-dh-params-file" [format "%s/tests/tls/redis.dh" [pwd]]
|
||||
dict set config "tls-dh-params-file" [format "%s/tests/tls/keydb.dh" [pwd]]
|
||||
dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]]
|
||||
dict set config "loglevel" "debug"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package require Tcl 8.5
|
||||
|
||||
set tcl_precision 17
|
||||
source tests/support/redis.tcl
|
||||
source tests/support/keydb.tcl
|
||||
source tests/support/server.tcl
|
||||
source tests/support/tmpfile.tcl
|
||||
source tests/support/test.tcl
|
||||
@@ -57,8 +57,8 @@ set ::all_tests {
|
||||
integration/psync2-reg
|
||||
integration/psync2-pingoff
|
||||
integration/failover
|
||||
integration/redis-cli
|
||||
integration/redis-benchmark
|
||||
integration/keydb-cli
|
||||
integration/keydb-benchmark
|
||||
unit/pubsub
|
||||
unit/slowlog
|
||||
unit/scripting
|
||||
|
||||
@@ -25,7 +25,7 @@ test {CONFIG SET port number} {
|
||||
test {CONFIG SET bind address} {
|
||||
start_server {} {
|
||||
# non-valid address
|
||||
catch {r CONFIG SET bind "some.wrong.bind.address"} e
|
||||
catch {r CONFIG SET bind "999.999.999.999"} e
|
||||
assert_match {*Failed to bind to specified addresses*} $e
|
||||
|
||||
# make sure server still bound to the previous address
|
||||
@@ -33,4 +33,4 @@ test {CONFIG SET bind address} {
|
||||
$rd PING
|
||||
$rd close
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-46
@@ -62,57 +62,55 @@ start_server {overrides {save ""} tags {"other"}} {
|
||||
} {*index is out of range*}
|
||||
|
||||
tags {consistency} {
|
||||
if {true} {
|
||||
if {$::accurate} {set numops 10000} else {set numops 1000}
|
||||
test {Check consistency of different data types after a reload} {
|
||||
r flushdb
|
||||
createComplexDataset r $numops
|
||||
set dump [csvdump r]
|
||||
set sha1 [r debug digest]
|
||||
r debug reload
|
||||
set sha1_after [r debug digest]
|
||||
if {$sha1 eq $sha1_after} {
|
||||
set _ 1
|
||||
} else {
|
||||
set newdump [csvdump r]
|
||||
puts "Consistency test failed!"
|
||||
puts "You can inspect the two dumps in /tmp/repldump*.txt"
|
||||
if {$::accurate} {set numops 10000} else {set numops 1000}
|
||||
test {Check consistency of different data types after a reload} {
|
||||
r flushdb
|
||||
createComplexDataset r $numops
|
||||
set dump [csvdump r]
|
||||
set sha1 [r debug digest]
|
||||
r debug reload
|
||||
set sha1_after [r debug digest]
|
||||
if {$sha1 eq $sha1_after} {
|
||||
set _ 1
|
||||
} else {
|
||||
set newdump [csvdump r]
|
||||
puts "Consistency test failed!"
|
||||
puts "You can inspect the two dumps in /tmp/repldump*.txt"
|
||||
|
||||
set fd [open /tmp/repldump1.txt w]
|
||||
puts $fd $dump
|
||||
close $fd
|
||||
set fd [open /tmp/repldump2.txt w]
|
||||
puts $fd $newdump
|
||||
close $fd
|
||||
set fd [open /tmp/repldump1.txt w]
|
||||
puts $fd $dump
|
||||
close $fd
|
||||
set fd [open /tmp/repldump2.txt w]
|
||||
puts $fd $newdump
|
||||
close $fd
|
||||
|
||||
set _ 0
|
||||
}
|
||||
} {1}
|
||||
set _ 0
|
||||
}
|
||||
} {1}
|
||||
|
||||
test {Same dataset digest if saving/reloading as AOF?} {
|
||||
r config set aof-use-rdb-preamble no
|
||||
r bgrewriteaof
|
||||
waitForBgrewriteaof r
|
||||
r debug loadaof
|
||||
set sha1_after [r debug digest]
|
||||
if {$sha1 eq $sha1_after} {
|
||||
set _ 1
|
||||
} else {
|
||||
set newdump [csvdump r]
|
||||
puts "Consistency test failed!"
|
||||
puts "You can inspect the two dumps in /tmp/aofdump*.txt"
|
||||
test {Same dataset digest if saving/reloading as AOF?} {
|
||||
r config set aof-use-rdb-preamble no
|
||||
r bgrewriteaof
|
||||
waitForBgrewriteaof r
|
||||
r debug loadaof
|
||||
set sha1_after [r debug digest]
|
||||
if {$sha1 eq $sha1_after} {
|
||||
set _ 1
|
||||
} else {
|
||||
set newdump [csvdump r]
|
||||
puts "Consistency test failed!"
|
||||
puts "You can inspect the two dumps in /tmp/aofdump*.txt"
|
||||
|
||||
set fd [open /tmp/aofdump1.txt w]
|
||||
puts $fd $dump
|
||||
close $fd
|
||||
set fd [open /tmp/aofdump2.txt w]
|
||||
puts $fd $newdump
|
||||
close $fd
|
||||
set fd [open /tmp/aofdump1.txt w]
|
||||
puts $fd $dump
|
||||
close $fd
|
||||
set fd [open /tmp/aofdump2.txt w]
|
||||
puts $fd $newdump
|
||||
close $fd
|
||||
|
||||
set _ 0
|
||||
}
|
||||
} {1}
|
||||
}
|
||||
set _ 0
|
||||
}
|
||||
} {1}
|
||||
}
|
||||
|
||||
test {EXPIRES after a reload (snapshot + append only file rewrite)} {
|
||||
|
||||
+2
-2
@@ -100,8 +100,8 @@ start_server {tags {"tls"}} {
|
||||
set master_port [srv 0 port]
|
||||
|
||||
# Use a non-restricted client/server cert for the replica
|
||||
set redis_crt [format "%s/tests/tls/redis.crt" [pwd]]
|
||||
set redis_key [format "%s/tests/tls/redis.key" [pwd]]
|
||||
set redis_crt [format "%s/tests/tls/keydb.crt" [pwd]]
|
||||
set redis_key [format "%s/tests/tls/keydb.key" [pwd]]
|
||||
|
||||
start_server [list overrides [list tls-cert-file $redis_crt tls-key-file $redis_key] \
|
||||
omit [list tls-client-cert-file tls-client-key-file]] {
|
||||
|
||||
@@ -395,6 +395,17 @@ start_server {tags {"tracking network"}} {
|
||||
assert {[lindex msg 2] eq {} }
|
||||
}
|
||||
|
||||
test {Test ASYNC flushall} {
|
||||
clean_all
|
||||
r CLIENT TRACKING on REDIRECT $redir_id
|
||||
r GET key1
|
||||
r GET key2
|
||||
assert_equal [s 0 tracking_total_keys] 2
|
||||
$rd_sg FLUSHALL ASYNC
|
||||
assert_equal [s 0 tracking_total_keys] 0
|
||||
assert_equal [lindex [$rd_redirection read] 2] {}
|
||||
}
|
||||
|
||||
# Keys are defined to be evicted 100 at a time by default.
|
||||
# If after eviction the number of keys still surpasses the limit
|
||||
# defined in tracking-table-max-keys, we increases eviction
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
# Generate some test certificates which are used by the regression test suite:
|
||||
#
|
||||
# tests/tls/ca.{crt,key} Self signed CA certificate.
|
||||
# tests/tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
|
||||
# tests/tls/keydb.{crt,key} A certificate with no key usage/policy restrictions.
|
||||
# tests/tls/client.{crt,key} A certificate restricted for SSL client usage.
|
||||
# tests/tls/server.{crt,key} A certificate restricted fro SSL server usage.
|
||||
# tests/tls/redis.dh DH Params file.
|
||||
# tests/tls/keydb.dh DH Params file.
|
||||
|
||||
generate_cert() {
|
||||
local name=$1
|
||||
@@ -19,7 +19,7 @@ generate_cert() {
|
||||
[ -f $keyfile ] || openssl genrsa -out $keyfile 2048
|
||||
openssl req \
|
||||
-new -sha256 \
|
||||
-subj "/O=Redis Test/CN=$cn" \
|
||||
-subj "/O=KeyDB Test/CN=$cn" \
|
||||
-key $keyfile | \
|
||||
openssl x509 \
|
||||
-req -sha256 \
|
||||
@@ -38,7 +38,7 @@ openssl req \
|
||||
-x509 -new -nodes -sha256 \
|
||||
-key tests/tls/ca.key \
|
||||
-days 3650 \
|
||||
-subj '/O=Redis Test/CN=Certificate Authority' \
|
||||
-subj '/O=KeyDB Test/CN=Certificate Authority' \
|
||||
-out tests/tls/ca.crt
|
||||
|
||||
cat > tests/tls/openssl.cnf <<_END_
|
||||
@@ -53,6 +53,6 @@ _END_
|
||||
|
||||
generate_cert server "Server-only" "-extfile tests/tls/openssl.cnf -extensions server_cert"
|
||||
generate_cert client "Client-only" "-extfile tests/tls/openssl.cnf -extensions client_cert"
|
||||
generate_cert redis "Generic-cert"
|
||||
generate_cert keydb "Generic-cert"
|
||||
|
||||
[ -f tests/tls/redis.dh ] || openssl dhparam -out tests/tls/redis.dh 2048
|
||||
[ -f tests/tls/keydb.dh ] || openssl dhparam -out tests/tls/keydb.dh 2048
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (C) 2011 Salvatore Sanfilippo
|
||||
# Released under the BSD license like Redis itself
|
||||
|
||||
source ../tests/support/redis.tcl
|
||||
source ../tests/support/keydb.tcl
|
||||
set ::port 12123
|
||||
set ::tests {PING,SET,GET,INCR,LPUSH,LPOP,SADD,SPOP,LRANGE_100,LRANGE_600,MSET}
|
||||
set ::datasize 16
|
||||
|
||||
Reference in new issue
Block a user