Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
20618c71
Commit
20618c71
authored
Apr 27, 2022
by
Oran Agra
Browse files
Merge remote-tracking branch 'origin/unstable' into 7.0
parents
fb4e0d40
89772ed8
Changes
122
Expand all
Hide whitespace changes
Inline
Side-by-side
src/anet.h
View file @
20618c71
...
...
@@ -73,5 +73,6 @@ int anetKeepAlive(char *err, int fd, int interval);
int
anetFormatAddr
(
char
*
fmt
,
size_t
fmt_len
,
char
*
ip
,
int
port
);
int
anetFormatFdAddr
(
int
fd
,
char
*
buf
,
size_t
buf_len
,
int
fd_to_str_type
);
int
anetPipe
(
int
fds
[
2
],
int
read_flags
,
int
write_flags
);
int
anetSetSockMarkId
(
char
*
err
,
int
fd
,
uint32_t
id
);
#endif
src/aof.c
View file @
20618c71
...
...
@@ -87,7 +87,7 @@ void aofManifestFreeAndUpdate(aofManifest *am);
#define RDB_FORMAT_SUFFIX ".rdb"
#define AOF_FORMAT_SUFFIX ".aof"
#define MANIFEST_NAME_SUFFIX ".manifest"
#define
MANIFEST_TEMP
_NAME_PREFIX "temp
_
"
#define
TEMP_FILE
_NAME_PREFIX
"temp
-
"
/* AOF manifest key. */
#define AOF_MANIFEST_KEY_FILE_NAME "file"
...
...
@@ -169,7 +169,7 @@ sds getAofManifestFileName() {
}
sds
getTempAofManifestFileName
()
{
return
sdscatprintf
(
sdsempty
(),
"%s%s%s"
,
MANIFEST_TEMP
_NAME_PREFIX
,
return
sdscatprintf
(
sdsempty
(),
"%s%s%s"
,
TEMP_FILE
_NAME_PREFIX
,
server
.
aof_filename
,
MANIFEST_NAME_SUFFIX
);
}
...
...
@@ -462,6 +462,12 @@ sds getNewIncrAofName(aofManifest *am) {
return
ai
->
file_name
;
}
/* Get temp INCR type AOF name. */
sds
getTempIncrAofName
()
{
return
sdscatprintf
(
sdsempty
(),
"%s%s%s"
,
TEMP_FILE_NAME_PREFIX
,
server
.
aof_filename
,
INCR_FILE_SUFFIX
);
}
/* Get the last INCR AOF name or create a new one. */
sds
getLastIncrAofName
(
aofManifest
*
am
)
{
serverAssert
(
am
!=
NULL
);
...
...
@@ -674,6 +680,17 @@ int aofDelHistoryFiles(void) {
return
persistAofManifest
(
server
.
aof_manifest
);
}
/* Used to clean up temp INCR AOF when AOFRW fails. */
void
aofDelTempIncrAofFile
()
{
sds
aof_filename
=
getTempIncrAofName
();
sds
aof_filepath
=
makePath
(
server
.
aof_dirname
,
aof_filename
);
serverLog
(
LL_NOTICE
,
"Removing the temp incr aof file %s in the background"
,
aof_filename
);
bg_unlink
(
aof_filepath
);
sdsfree
(
aof_filepath
);
sdsfree
(
aof_filename
);
return
;
}
/* Called after `loadDataFromDisk` when redis start. If `server.aof_state` is
* 'AOF_ON', It will do three things:
* 1. Force create a BASE file when redis starts with an empty dataset
...
...
@@ -739,44 +756,52 @@ int aofFileExist(char *filename) {
}
/* Called in `rewriteAppendOnlyFileBackground`. If `server.aof_state`
* is 'AOF_ON'
or 'AOF_WAIT_REWRITE'
, It will do two things:
* is 'AOF_ON', It will do two things:
* 1. Open a new INCR type AOF for writing
* 2. Synchronously update the manifest file to the disk
*
* The above two steps of modification are atomic, that is, if
* any step fails, the entire operation will rollback and returns
* C_ERR, and if all succeeds, it returns C_OK.
*
* If `server.aof_state` is 'AOF_WAIT_REWRITE', It will open a temporary INCR AOF
* file to accumulate data during AOF_WAIT_REWRITE, and it will eventually be
* renamed in the `backgroundRewriteDoneHandler` and written to the manifest file.
* */
int
openNewIncrAofForAppend
(
void
)
{
serverAssert
(
server
.
aof_manifest
!=
NULL
);
int
newfd
;
int
newfd
=
-
1
;
aofManifest
*
temp_am
=
NULL
;
sds
new_aof_name
=
NULL
;
/* Only open new INCR AOF when AOF enabled. */
if
(
server
.
aof_state
==
AOF_OFF
)
return
C_OK
;
/* Dup a temp aof_manifest to modify. */
aofManifest
*
temp_am
=
aofManifestDup
(
server
.
aof_manifest
);
/* Open new AOF. */
sds
new_aof_name
=
getNewIncrAofName
(
temp_am
);
if
(
server
.
aof_state
==
AOF_WAIT_REWRITE
)
{
/* Use a temporary INCR AOF file to accumulate data during AOF_WAIT_REWRITE. */
new_aof_name
=
getTempIncrAofName
();
}
else
{
/* Dup a temp aof_manifest to modify. */
temp_am
=
aofManifestDup
(
server
.
aof_manifest
);
new_aof_name
=
sdsdup
(
getNewIncrAofName
(
temp_am
));
}
sds
new_aof_filepath
=
makePath
(
server
.
aof_dirname
,
new_aof_name
);
newfd
=
open
(
new_aof_filepath
,
O_WRONLY
|
O_TRUNC
|
O_CREAT
,
0644
);
sdsfree
(
new_aof_filepath
);
if
(
newfd
==
-
1
)
{
serverLog
(
LL_WARNING
,
"Can't open the append-only file %s: %s"
,
new_aof_name
,
strerror
(
errno
));
aofManifestFree
(
temp_am
);
return
C_ERR
;
goto
cleanup
;
}
/* Persist AOF Manifest. */
int
ret
=
persistAofManifest
(
temp_am
);
if
(
ret
==
C_ERR
)
{
close
(
newfd
);
aofManifestFree
(
temp_am
);
return
C_ERR
;
if
(
temp_am
)
{
/* Persist AOF Manifest. */
if
(
persistAofManifest
(
temp_am
)
==
C_ERR
)
{
goto
cleanup
;
}
}
sdsfree
(
new_aof_name
);
/* If reaches here, we can safely modify the `server.aof_manifest`
* and `server.aof_fd`. */
...
...
@@ -788,8 +813,14 @@ int openNewIncrAofForAppend(void) {
/* Reset the aof_last_incr_size. */
server
.
aof_last_incr_size
=
0
;
/* Update `server.aof_manifest`. */
aofManifestFreeAndUpdate
(
temp_am
);
if
(
temp_am
)
aofManifestFreeAndUpdate
(
temp_am
);
return
C_OK
;
cleanup:
if
(
new_aof_name
)
sdsfree
(
new_aof_name
);
if
(
newfd
!=
-
1
)
close
(
newfd
);
if
(
temp_am
)
aofManifestFree
(
temp_am
);
return
C_ERR
;
}
/* Whether to limit the execution of Background AOF rewrite.
...
...
@@ -815,38 +846,35 @@ int openNewIncrAofForAppend(void) {
#define AOF_REWRITE_LIMITE_THRESHOLD 3
#define AOF_REWRITE_LIMITE_MAX_MINUTES 60
/* 1 hour */
int
aofRewriteLimited
(
void
)
{
int
limit
=
0
;
static
int
limit_delay_minutes
=
0
;
static
int
next_delay_minutes
=
0
;
static
time_t
next_rewrite_time
=
0
;
unsigned
long
incr_aof_num
=
listLength
(
server
.
aof_manifest
->
incr_aof_list
);
if
(
incr_aof_num
>=
AOF_REWRITE_LIMITE_THRESHOLD
)
{
if
(
server
.
stat_aofrw_consecutive_failures
<
AOF_REWRITE_LIMITE_THRESHOLD
)
{
/* We may be recovering from limited state, so reset all states. */
next_delay_minutes
=
0
;
next_rewrite_time
=
0
;
return
0
;
}
/* if it is in the limiting state, then check if the next_rewrite_time is reached */
if
(
next_rewrite_time
!=
0
)
{
if
(
server
.
unixtime
<
next_rewrite_time
)
{
limit
=
1
;
return
1
;
}
else
{
if
(
limit_delay_minutes
==
0
)
{
limit
=
1
;
limit_delay_minutes
=
1
;
}
else
{
limit_delay_minutes
*=
2
;
}
if
(
limit_delay_minutes
>
AOF_REWRITE_LIMITE_MAX_MINUTES
)
{
limit_delay_minutes
=
AOF_REWRITE_LIMITE_MAX_MINUTES
;
}
next_rewrite_time
=
server
.
unixtime
+
limit_delay_minutes
*
60
;
serverLog
(
LL_WARNING
,
"Background AOF rewrite has repeatedly failed %ld times and triggered the limit, will retry in %d minutes"
,
incr_aof_num
,
limit_delay_minutes
);
next_rewrite_time
=
0
;
return
0
;
}
}
else
{
limit_delay_minutes
=
0
;
next_rewrite_time
=
0
;
}
return
limit
;
next_delay_minutes
=
(
next_delay_minutes
==
0
)
?
1
:
(
next_delay_minutes
*
2
);
if
(
next_delay_minutes
>
AOF_REWRITE_LIMITE_MAX_MINUTES
)
{
next_delay_minutes
=
AOF_REWRITE_LIMITE_MAX_MINUTES
;
}
next_rewrite_time
=
server
.
unixtime
+
next_delay_minutes
*
60
;
serverLog
(
LL_WARNING
,
"Background AOF rewrite has repeatedly failed and triggered the limit, will retry in %d minutes"
,
next_delay_minutes
);
return
1
;
}
/* ----------------------------------------------------------------------------
...
...
@@ -1265,7 +1293,7 @@ void feedAppendOnlyFile(int dictid, robj **argv, int argc) {
* of re-entering the event loop, so before the client will get a
* positive reply about the operation performed. */
if
(
server
.
aof_state
==
AOF_ON
||
server
.
child_type
==
CHILD_TYPE_AOF
)
(
server
.
aof_state
==
AOF_WAIT_REWRITE
&&
server
.
child_type
==
CHILD_TYPE_AOF
)
)
{
server
.
aof_buf
=
sdscatlen
(
server
.
aof_buf
,
buf
,
sdslen
(
buf
));
}
...
...
@@ -1558,7 +1586,7 @@ int loadAppendOnlyFiles(aofManifest *am) {
serverAssert
(
am
!=
NULL
);
int
status
,
ret
=
C_OK
;
long
long
start
;
off_t
total_size
=
0
;
off_t
total_size
=
0
,
base_size
=
0
;
sds
aof_name
;
int
total_num
,
aof_num
=
0
,
last_file
;
...
...
@@ -1607,6 +1635,7 @@ int loadAppendOnlyFiles(aofManifest *am) {
serverAssert
(
am
->
base_aof_info
->
file_type
==
AOF_FILE_TYPE_BASE
);
aof_name
=
(
char
*
)
am
->
base_aof_info
->
file_name
;
updateLoadingFileName
(
aof_name
);
base_size
=
getAppendOnlyFileSize
(
aof_name
,
NULL
);
last_file
=
++
aof_num
==
total_num
;
start
=
ustime
();
ret
=
loadSingleAppendOnlyFile
(
aof_name
);
...
...
@@ -1659,7 +1688,16 @@ int loadAppendOnlyFiles(aofManifest *am) {
}
server
.
aof_current_size
=
total_size
;
server
.
aof_rewrite_base_size
=
server
.
aof_current_size
;
/* Ideally, the aof_rewrite_base_size variable should hold the size of the
* AOF when the last rewrite ended, this should include the size of the
* incremental file that was created during the rewrite since otherwise we
* risk the next automatic rewrite to happen too soon (or immediately if
* auto-aof-rewrite-percentage is low). However, since we do not persist
* aof_rewrite_base_size information anywhere, we initialize it on restart
* to the size of BASE AOF file. This might cause the first AOFRW to be
* executed early, but that shouldn't be a problem since everything will be
* fine after the first AOFRW. */
server
.
aof_rewrite_base_size
=
base_size
;
server
.
aof_fsync_offset
=
server
.
aof_current_size
;
cleanup:
...
...
@@ -2393,6 +2431,9 @@ void bgrewriteaofCommand(client *c) {
addReplyError
(
c
,
"Background append only file rewriting already in progress"
);
}
else
if
(
hasActiveChildProcess
()
||
server
.
in_exec
)
{
server
.
aof_rewrite_scheduled
=
1
;
/* When manually triggering AOFRW we reset the count
* so that it can be executed immediately. */
server
.
stat_aofrw_consecutive_failures
=
0
;
addReplyStatus
(
c
,
"Background append only file rewriting scheduled"
);
}
else
if
(
rewriteAppendOnlyFileBackground
()
==
C_OK
)
{
addReplyStatus
(
c
,
"Background append only file rewriting started"
);
...
...
@@ -2476,7 +2517,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
if
(
!
bysignal
&&
exitcode
==
0
)
{
char
tmpfile
[
256
];
long
long
now
=
ustime
();
sds
new_base_filename
;
sds
new_base_filepath
=
NULL
;
sds
new_incr_filepath
=
NULL
;
aofManifest
*
temp_am
;
mstime_t
latency
;
...
...
@@ -2493,9 +2535,9 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
/* Get a new BASE file name and mark the previous (if we have)
* as the HISTORY type. */
new_base_filename
=
getNewBaseFileNameAndMarkPreAsHistory
(
temp_am
);
sds
new_base_filename
=
getNewBaseFileNameAndMarkPreAsHistory
(
temp_am
);
serverAssert
(
new_base_filename
!=
NULL
);
sds
new_base_filepath
=
makePath
(
server
.
aof_dirname
,
new_base_filename
);
new_base_filepath
=
makePath
(
server
.
aof_dirname
,
new_base_filename
);
/* Rename the temporary aof file to 'new_base_filename'. */
latencyStartMonitor
(
latency
);
...
...
@@ -2503,7 +2545,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
serverLog
(
LL_WARNING
,
"Error trying to rename the temporary AOF file %s into %s: %s"
,
tmpfile
,
new_base_file
name
,
new_base_file
path
,
strerror
(
errno
));
aofManifestFree
(
temp_am
);
sdsfree
(
new_base_filepath
);
...
...
@@ -2512,6 +2554,34 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
latencyEndMonitor
(
latency
);
latencyAddSampleIfNeeded
(
"aof-rename"
,
latency
);
/* Rename the temporary incr aof file to 'new_incr_filename'. */
if
(
server
.
aof_state
==
AOF_WAIT_REWRITE
)
{
/* Get temporary incr aof name. */
sds
temp_incr_aof_name
=
getTempIncrAofName
();
sds
temp_incr_filepath
=
makePath
(
server
.
aof_dirname
,
temp_incr_aof_name
);
sdsfree
(
temp_incr_aof_name
);
/* Get next new incr aof name. */
sds
new_incr_filename
=
getNewIncrAofName
(
temp_am
);
new_incr_filepath
=
makePath
(
server
.
aof_dirname
,
new_incr_filename
);
latencyStartMonitor
(
latency
);
if
(
rename
(
temp_incr_filepath
,
new_incr_filepath
)
==
-
1
)
{
serverLog
(
LL_WARNING
,
"Error trying to rename the temporary incr AOF file %s into %s: %s"
,
temp_incr_filepath
,
new_incr_filepath
,
strerror
(
errno
));
bg_unlink
(
new_base_filepath
);
sdsfree
(
new_base_filepath
);
aofManifestFree
(
temp_am
);
sdsfree
(
temp_incr_filepath
);
sdsfree
(
new_incr_filepath
);
goto
cleanup
;
}
latencyEndMonitor
(
latency
);
latencyAddSampleIfNeeded
(
"aof-rename"
,
latency
);
sdsfree
(
temp_incr_filepath
);
}
/* Change the AOF file type in 'incr_aof_list' from AOF_FILE_TYPE_INCR
* to AOF_FILE_TYPE_HIST, and move them to the 'history_aof_list'. */
markRewrittenIncrAofAsHistory
(
temp_am
);
...
...
@@ -2521,9 +2591,14 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
bg_unlink
(
new_base_filepath
);
aofManifestFree
(
temp_am
);
sdsfree
(
new_base_filepath
);
if
(
new_incr_filepath
)
{
bg_unlink
(
new_incr_filepath
);
sdsfree
(
new_incr_filepath
);
}
goto
cleanup
;
}
sdsfree
(
new_base_filepath
);
if
(
new_incr_filepath
)
sdsfree
(
new_incr_filepath
);
/* We can safely let `server.aof_manifest` point to 'temp_am' and free the previous one. */
aofManifestFreeAndUpdate
(
temp_am
);
...
...
@@ -2542,6 +2617,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
aofDelHistoryFiles
();
server
.
aof_lastbgrewrite_status
=
C_OK
;
server
.
stat_aofrw_consecutive_failures
=
0
;
serverLog
(
LL_NOTICE
,
"Background AOF rewrite finished successfully"
);
/* Change state from WAIT_REWRITE to ON if needed */
...
...
@@ -2552,14 +2628,17 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
"Background AOF rewrite signal handler took %lldus"
,
ustime
()
-
now
);
}
else
if
(
!
bysignal
&&
exitcode
!=
0
)
{
server
.
aof_lastbgrewrite_status
=
C_ERR
;
server
.
stat_aofrw_consecutive_failures
++
;
serverLog
(
LL_WARNING
,
"Background AOF rewrite terminated with error"
);
}
else
{
/* SIGUSR1 is whitelisted, so we have a way to kill a child without
* triggering an error condition. */
if
(
bysignal
!=
SIGUSR1
)
if
(
bysignal
!=
SIGUSR1
)
{
server
.
aof_lastbgrewrite_status
=
C_ERR
;
server
.
stat_aofrw_consecutive_failures
++
;
}
serverLog
(
LL_WARNING
,
"Background AOF rewrite terminated by signal %d"
,
bysignal
);
...
...
@@ -2567,6 +2646,12 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
cleanup:
aofRemoveTempFile
(
server
.
child_pid
);
/* Clear AOF buffer and delete temp incr aof for next rewrite. */
if
(
server
.
aof_state
==
AOF_WAIT_REWRITE
)
{
sdsfree
(
server
.
aof_buf
);
server
.
aof_buf
=
sdsempty
();
aofDelTempIncrAofFile
();
}
server
.
aof_rewrite_time_last
=
time
(
NULL
)
-
server
.
aof_rewrite_time_start
;
server
.
aof_rewrite_time_start
=
-
1
;
/* Schedule a new rewrite if we are waiting for it to switch the AOF ON. */
...
...
src/bitops.c
View file @
20618c71
...
...
@@ -430,7 +430,7 @@ int getBitOffsetFromArgument(client *c, robj *o, uint64_t *offset, int hash, int
if
(
usehash
)
loffset
*=
bits
;
/* Limit offset to server.proto_max_bulk_len (512MB in bytes by default) */
if
(
loffset
<
0
||
(
!
(
c
->
flags
&
CLIENT_MASTER
)
&&
(
loffset
>>
3
)
>=
server
.
proto_max_bulk_len
))
if
(
loffset
<
0
||
(
!
mustObeyClient
(
c
)
&&
(
loffset
>>
3
)
>=
server
.
proto_max_bulk_len
))
{
addReplyError
(
c
,
err
);
return
C_ERR
;
...
...
@@ -1002,7 +1002,7 @@ void bitposCommand(client *c) {
}
}
/* BITFIELD key subcomm
m
and-1 arg ... subcommand-2 arg ... subcommand-N ...
/* BITFIELD key subcommand-1 arg ... subcommand-2 arg ... subcommand-N ...
*
* Supported subcommands:
*
...
...
src/cli_common.c
View file @
20618c71
...
...
@@ -390,7 +390,7 @@ sds escapeJsonString(sds s, const char *p, size_t len) {
case
'\t'
:
s
=
sdscatlen
(
s
,
"
\\
t"
,
2
);
break
;
case
'\b'
:
s
=
sdscatlen
(
s
,
"
\\
b"
,
2
);
break
;
default:
s
=
sdscatprintf
(
s
,
(
*
p
>=
0
&&
*
p
<=
0x1f
)
?
"
\\
u%04x"
:
"%c"
,
*
p
);
s
=
sdscatprintf
(
s
,
*
(
unsigned
char
*
)
p
<=
0x1f
?
"
\\
u%04x"
:
"%c"
,
*
p
);
}
p
++
;
}
...
...
src/cluster.c
View file @
20618c71
...
...
@@ -960,7 +960,6 @@ clusterNode *createClusterNode(char *nodename, int flags) {
memset
(
node
->
slots
,
0
,
sizeof
(
node
->
slots
));
node
->
slot_info_pairs
=
NULL
;
node
->
slot_info_pairs_count
=
0
;
node
->
slot_info_pairs_alloc
=
0
;
node
->
numslots
=
0
;
node
->
numslaves
=
0
;
node
->
slaves
=
NULL
;
...
...
@@ -2507,11 +2506,7 @@ int clusterProcessPacket(clusterLink *link) {
message
=
createStringObject
(
(
char
*
)
hdr
->
data
.
publish
.
msg
.
bulk_data
+
channel_len
,
message_len
);
if
(
type
==
CLUSTERMSG_TYPE_PUBLISHSHARD
)
{
pubsubPublishMessageShard
(
channel
,
message
);
}
else
{
pubsubPublishMessage
(
channel
,
message
);
}
pubsubPublishMessage
(
channel
,
message
,
type
==
CLUSTERMSG_TYPE_PUBLISHSHARD
);
decrRefCount
(
channel
);
decrRefCount
(
message
);
}
...
...
@@ -3200,20 +3195,19 @@ int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uin
/* -----------------------------------------------------------------------------
* CLUSTER Pub/Sub support
*
* For now we do very little, just propagating PUBLISH messages across the whole
* If `sharded` is 0:
* For now we do very little, just propagating [S]PUBLISH messages across the whole
* cluster. In the future we'll try to get smarter and avoiding propagating those
* messages to hosts without receives for a given channel.
* -------------------------------------------------------------------------- */
void
clusterPropagatePublish
(
robj
*
channel
,
robj
*
message
)
{
clusterSendPublish
(
NULL
,
channel
,
message
,
CLUSTERMSG_TYPE_PUBLISH
);
}
/* -----------------------------------------------------------------------------
* CLUSTER Pub/Sub shard support
*
* Otherwise:
* Publish this message across the slot (primary/replica).
* -------------------------------------------------------------------------- */
void
clusterPropagatePublishShard
(
robj
*
channel
,
robj
*
message
)
{
void
clusterPropagatePublish
(
robj
*
channel
,
robj
*
message
,
int
sharded
)
{
if
(
!
sharded
)
{
clusterSendPublish
(
NULL
,
channel
,
message
,
CLUSTERMSG_TYPE_PUBLISH
);
return
;
}
list
*
nodes_for_slot
=
clusterGetNodesServingMySlots
(
server
.
cluster
->
myself
);
if
(
listLength
(
nodes_for_slot
)
!=
0
)
{
listIter
li
;
...
...
@@ -4726,13 +4720,10 @@ void clusterGenNodesSlotsInfo(int filter) {
* or end of slot. */
if
(
i
==
CLUSTER_SLOTS
||
n
!=
server
.
cluster
->
slots
[
i
])
{
if
(
!
(
n
->
flags
&
filter
))
{
if
(
n
->
slot_info_pairs_count
+
2
>
n
->
slot_info_pairs_alloc
)
{
if
(
n
->
slot_info_pairs_alloc
==
0
)
n
->
slot_info_pairs_alloc
=
8
;
else
n
->
slot_info_pairs_alloc
*=
2
;
n
->
slot_info_pairs
=
zrealloc
(
n
->
slot_info_pairs
,
n
->
slot_info_pairs_alloc
*
sizeof
(
uint16_t
));
if
(
!
n
->
slot_info_pairs
)
{
n
->
slot_info_pairs
=
zmalloc
(
2
*
n
->
numslots
*
sizeof
(
uint16_t
));
}
serverAssert
((
n
->
slot_info_pairs_count
+
1
)
<
(
2
*
n
->
numslots
));
n
->
slot_info_pairs
[
n
->
slot_info_pairs_count
++
]
=
start
;
n
->
slot_info_pairs
[
n
->
slot_info_pairs_count
++
]
=
i
-
1
;
}
...
...
@@ -4747,7 +4738,6 @@ void clusterFreeNodesSlotsInfo(clusterNode *n) {
zfree
(
n
->
slot_info_pairs
);
n
->
slot_info_pairs
=
NULL
;
n
->
slot_info_pairs_count
=
0
;
n
->
slot_info_pairs_alloc
=
0
;
}
/* Generate a csv-alike representation of the nodes we are aware of,
...
...
src/cluster.h
View file @
20618c71
...
...
@@ -120,7 +120,6 @@ typedef struct clusterNode {
unsigned
char
slots
[
CLUSTER_SLOTS
/
8
];
/* slots handled by this node */
uint16_t
*
slot_info_pairs
;
/* Slots info represented as (start/end) pair (consecutive index). */
int
slot_info_pairs_count
;
/* Used number of slots in slot_info_pairs */
int
slot_info_pairs_alloc
;
/* Allocated number of slots in slot_info_pairs */
int
numslots
;
/* Number of slots handled by this node */
int
numslaves
;
/* Number of slave nodes, if this is a master */
struct
clusterNode
**
slaves
;
/* pointers to slave nodes */
...
...
@@ -385,8 +384,7 @@ void migrateCloseTimedoutSockets(void);
int
verifyClusterConfigWithData
(
void
);
unsigned
long
getClusterConnectionsCount
(
void
);
int
clusterSendModuleMessageToTarget
(
const
char
*
target
,
uint64_t
module_id
,
uint8_t
type
,
const
char
*
payload
,
uint32_t
len
);
void
clusterPropagatePublish
(
robj
*
channel
,
robj
*
message
);
void
clusterPropagatePublishShard
(
robj
*
channel
,
robj
*
message
);
void
clusterPropagatePublish
(
robj
*
channel
,
robj
*
message
,
int
sharded
);
unsigned
int
keyHashSlot
(
char
*
key
,
int
keylen
);
void
slotToKeyAddEntry
(
dictEntry
*
entry
,
redisDb
*
db
);
void
slotToKeyDelEntry
(
dictEntry
*
entry
,
redisDb
*
db
);
...
...
src/commands.c
View file @
20618c71
This diff is collapsed.
Click to expand it.
src/commands/bitfield.json
View file @
20618c71
...
...
@@ -44,84 +44,100 @@
"key_spec_index"
:
0
},
{
"token"
:
"GET"
,
"name"
:
"encoding_offset"
,
"type"
:
"block"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
}
]
},
{
"token"
:
"SET"
,
"name"
:
"encoding_offset_value"
,
"type"
:
"block"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
},
{
"name"
:
"value"
,
"type"
:
"integer"
}
]
},
{
"token"
:
"INCRBY"
,
"name"
:
"encoding_offset_increment"
,
"type"
:
"block"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
},
{
"name"
:
"increment"
,
"type"
:
"integer"
}
]
},
{
"token"
:
"OVERFLOW"
,
"name"
:
"wrap_sat_fail"
,
"name"
:
"operation"
,
"type"
:
"oneof"
,
"
optional
"
:
true
,
"
multiple
"
:
"
true
"
,
"arguments"
:
[
{
"name"
:
"wrap"
,
"type"
:
"pure-token"
,
"token"
:
"WRAP"
},
{
"name"
:
"sat"
,
"type"
:
"pure-token"
,
"token"
:
"SAT"
"token"
:
"GET"
,
"name"
:
"encoding_offset"
,
"type"
:
"block"
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
}
]
},
{
"name"
:
"fail"
,
"type"
:
"pure-token"
,
"token"
:
"FAIL"
"name"
:
"write"
,
"type"
:
"block"
,
"arguments"
:
[
{
"token"
:
"OVERFLOW"
,
"name"
:
"wrap_sat_fail"
,
"type"
:
"oneof"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"wrap"
,
"type"
:
"pure-token"
,
"token"
:
"WRAP"
},
{
"name"
:
"sat"
,
"type"
:
"pure-token"
,
"token"
:
"SAT"
},
{
"name"
:
"fail"
,
"type"
:
"pure-token"
,
"token"
:
"FAIL"
}
]
},
{
"name"
:
"write_operation"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"token"
:
"SET"
,
"name"
:
"encoding_offset_value"
,
"type"
:
"block"
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
},
{
"name"
:
"value"
,
"type"
:
"integer"
}
]
},
{
"token"
:
"INCRBY"
,
"name"
:
"encoding_offset_increment"
,
"type"
:
"block"
,
"arguments"
:
[
{
"name"
:
"encoding"
,
"type"
:
"string"
},
{
"name"
:
"offset"
,
"type"
:
"integer"
},
{
"name"
:
"increment"
,
"type"
:
"integer"
}
]
}
]
}
]
}
]
}
]
}
}
}
\ No newline at end of file
src/commands/bitfield_ro.json
View file @
20618c71
...
...
@@ -43,6 +43,7 @@
"token"
:
"GET"
,
"name"
:
"encoding_offset"
,
"type"
:
"block"
,
"multiple"
:
"true"
,
"arguments"
:
[
{
"name"
:
"encoding"
,
...
...
src/commands/geosearch.json
View file @
20618c71
...
...
@@ -39,102 +39,110 @@
"key_spec_index"
:
0
},
{
"token"
:
"FROMMEMBER"
,
"name"
:
"member"
,
"type"
:
"string"
,
"optional"
:
true
},
{
"token"
:
"FROMLONLAT"
,
"name"
:
"longitude_latitude"
,
"type"
:
"block"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"longitude"
,
"type"
:
"double"
},
{
"name"
:
"latitude"
,
"type"
:
"double"
}
]
},
{
"name"
:
"circle"
,
"type"
:
"block"
,
"optional"
:
true
,
"name"
:
"from"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"token"
:
"
BYRADIUS
"
,
"name"
:
"
radius
"
,
"type"
:
"
double
"
"token"
:
"
FROMMEMBER
"
,
"name"
:
"
member
"
,
"type"
:
"
string
"
},
{
"name"
:
"unit"
,
"type"
:
"oneof"
,
"token"
:
"FROMLONLAT"
,
"name"
:
"longitude_latitude"
,
"type"
:
"block"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
"name"
:
"longitude"
,
"type"
:
"double"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
"name"
:
"latitude"
,
"type"
:
"double"
}
]
}
]
},
{
"name"
:
"box"
,
"type"
:
"block"
,
"optional"
:
true
,
"name"
:
"by"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"token"
:
"BYBOX"
,
"name"
:
"width"
,
"type"
:
"double"
},
{
"name"
:
"height"
,
"type"
:
"double"
},
{
"name"
:
"unit"
,
"type"
:
"oneof"
,
"name"
:
"circle"
,
"type"
:
"block"
,
"arguments"
:
[
{
"
name"
:
"m
"
,
"
typ
e"
:
"
pure-token
"
,
"t
oken"
:
"m
"
"
token"
:
"BYRADIUS
"
,
"
nam
e"
:
"
radius
"
,
"t
ype"
:
"double
"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
"name"
:
"unit"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
}
]
}
]
},
{
"name"
:
"box"
,
"type"
:
"block"
,
"arguments"
:
[
{
"token"
:
"BYBOX"
,
"name"
:
"width"
,
"type"
:
"double"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
"name"
:
"height"
,
"type"
:
"double"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
"name"
:
"unit"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
}
]
}
]
}
...
...
@@ -195,4 +203,4 @@
}
]
}
}
}
\ No newline at end of file
src/commands/geosearchstore.json
View file @
20618c71
...
...
@@ -63,102 +63,110 @@
"key_spec_index"
:
1
},
{
"token"
:
"FROMMEMBER"
,
"name"
:
"member"
,
"type"
:
"string"
,
"optional"
:
true
},
{
"token"
:
"FROMLONLAT"
,
"name"
:
"longitude_latitude"
,
"type"
:
"block"
,
"optional"
:
true
,
"arguments"
:
[
{
"name"
:
"longitude"
,
"type"
:
"double"
},
{
"name"
:
"latitude"
,
"type"
:
"double"
}
]
},
{
"name"
:
"circle"
,
"type"
:
"block"
,
"optional"
:
true
,
"name"
:
"from"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"token"
:
"
BYRADIUS
"
,
"name"
:
"
radius
"
,
"type"
:
"
double
"
"token"
:
"
FROMMEMBER
"
,
"name"
:
"
member
"
,
"type"
:
"
string
"
},
{
"name"
:
"unit"
,
"type"
:
"oneof"
,
"token"
:
"FROMLONLAT"
,
"name"
:
"longitude_latitude"
,
"type"
:
"block"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
"name"
:
"longitude"
,
"type"
:
"double"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
"name"
:
"latitude"
,
"type"
:
"double"
}
]
}
]
},
{
"name"
:
"box"
,
"type"
:
"block"
,
"optional"
:
true
,
"name"
:
"by"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"token"
:
"BYBOX"
,
"name"
:
"width"
,
"type"
:
"double"
},
{
"name"
:
"height"
,
"type"
:
"double"
},
{
"name"
:
"unit"
,
"type"
:
"oneof"
,
"name"
:
"circle"
,
"type"
:
"block"
,
"arguments"
:
[
{
"
name"
:
"m
"
,
"
typ
e"
:
"
pure-token
"
,
"t
oken"
:
"m
"
"
token"
:
"BYRADIUS
"
,
"
nam
e"
:
"
radius
"
,
"t
ype"
:
"double
"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
"name"
:
"unit"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
}
]
}
]
},
{
"name"
:
"box"
,
"type"
:
"block"
,
"arguments"
:
[
{
"token"
:
"BYBOX"
,
"name"
:
"width"
,
"type"
:
"double"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
"name"
:
"height"
,
"type"
:
"double"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
"name"
:
"unit"
,
"type"
:
"oneof"
,
"arguments"
:
[
{
"name"
:
"m"
,
"type"
:
"pure-token"
,
"token"
:
"m"
},
{
"name"
:
"km"
,
"type"
:
"pure-token"
,
"token"
:
"km"
},
{
"name"
:
"ft"
,
"type"
:
"pure-token"
,
"token"
:
"ft"
},
{
"name"
:
"mi"
,
"type"
:
"pure-token"
,
"token"
:
"mi"
}
]
}
]
}
...
...
@@ -207,4 +215,4 @@
}
]
}
}
}
\ No newline at end of file
src/commands/migrate.json
View file @
20618c71
...
...
@@ -125,27 +125,33 @@
"since"
:
"3.0.0"
},
{
"token"
:
"AUTH"
,
"name"
:
"password"
,
"type"
:
"string"
,
"optional"
:
true
,
"since"
:
"4.0.7"
},
{
"token"
:
"AUTH2"
,
"name"
:
"username_password"
,
"type"
:
"block"
,
"name"
:
"authentication"
,
"type"
:
"oneof"
,
"optional"
:
true
,
"since"
:
"6.0.0"
,
"arguments"
:
[
{
"name"
:
"username"
,
"type"
:
"string"
"token"
:
"AUTH"
,
"name"
:
"password"
,
"type"
:
"string"
,
"optional"
:
true
,
"since"
:
"4.0.7"
},
{
"name"
:
"password"
,
"type"
:
"string"
"token"
:
"AUTH2"
,
"name"
:
"username_password"
,
"type"
:
"block"
,
"optional"
:
true
,
"since"
:
"6.0.0"
,
"arguments"
:
[
{
"name"
:
"username"
,
"type"
:
"string"
},
{
"name"
:
"password"
,
"type"
:
"string"
}
]
}
]
},
...
...
@@ -160,4 +166,4 @@
}
]
}
}
}
\ No newline at end of file
src/commands/module-loadex.json
View file @
20618c71
...
...
@@ -23,6 +23,7 @@
"token"
:
"CONFIG"
,
"type"
:
"block"
,
"multiple"
:
true
,
"multiple_token"
:
true
,
"optional"
:
true
,
"arguments"
:
[
{
...
...
src/commands/set.json
View file @
20618c71
...
...
@@ -65,6 +65,31 @@
"name"
:
"value"
,
"type"
:
"string"
},
{
"name"
:
"condition"
,
"type"
:
"oneof"
,
"optional"
:
true
,
"since"
:
"2.6.12"
,
"arguments"
:
[
{
"name"
:
"nx"
,
"type"
:
"pure-token"
,
"token"
:
"NX"
},
{
"name"
:
"xx"
,
"type"
:
"pure-token"
,
"token"
:
"XX"
}
]
},
{
"name"
:
"get"
,
"token"
:
"GET"
,
"type"
:
"pure-token"
,
"optional"
:
true
,
"since"
:
"6.2.0"
},
{
"name"
:
"expiration"
,
"type"
:
"oneof"
,
...
...
@@ -101,31 +126,6 @@
"since"
:
"6.0.0"
}
]
},
{
"name"
:
"condition"
,
"type"
:
"oneof"
,
"optional"
:
true
,
"since"
:
"2.6.12"
,
"arguments"
:
[
{
"name"
:
"nx"
,
"type"
:
"pure-token"
,
"token"
:
"NX"
},
{
"name"
:
"xx"
,
"type"
:
"pure-token"
,
"token"
:
"XX"
}
]
},
{
"name"
:
"get"
,
"token"
:
"GET"
,
"type"
:
"pure-token"
,
"optional"
:
true
,
"since"
:
"6.2.0"
}
]
}
...
...
src/commands/zrangebylex.json
View file @
20618c71
...
...
@@ -7,7 +7,7 @@
"arity"
:
-4
,
"function"
:
"zrangebylexCommand"
,
"deprecated_since"
:
"6.2.0"
,
"replaced_by"
:
"`ZRANGE` with the `BY
SCORE
` argument"
,
"replaced_by"
:
"`ZRANGE` with the `BY
LEX
` argument"
,
"doc_flags"
:
[
"DEPRECATED"
],
...
...
src/config.c
View file @
20618c71
...
...
@@ -94,6 +94,15 @@ configEnum aof_fsync_enum[] = {
{
NULL
,
0
}
};
configEnum
shutdown_on_sig_enum
[]
=
{
{
"default"
,
0
},
{
"save"
,
SHUTDOWN_SAVE
},
{
"nosave"
,
SHUTDOWN_NOSAVE
},
{
"now"
,
SHUTDOWN_NOW
},
{
"force"
,
SHUTDOWN_FORCE
},
{
NULL
,
0
}
};
configEnum
repl_diskless_load_enum
[]
=
{
{
"disabled"
,
REPL_DISKLESS_LOAD_DISABLED
},
{
"on-empty-db"
,
REPL_DISKLESS_LOAD_WHEN_DB_EMPTY
},
...
...
@@ -143,6 +152,13 @@ configEnum cluster_preferred_endpoint_type_enum[] = {
{
NULL
,
0
}
};
configEnum
propagation_error_behavior_enum
[]
=
{
{
"ignore"
,
PROPAGATION_ERR_BEHAVIOR_IGNORE
},
{
"panic"
,
PROPAGATION_ERR_BEHAVIOR_PANIC
},
{
"panic-on-replicas"
,
PROPAGATION_ERR_BEHAVIOR_PANIC_ON_REPLICAS
},
{
NULL
,
0
}
};
/* Output buffer limits presets. */
clientBufferLimitsConfig
clientBufferLimitsDefaults
[
CLIENT_TYPE_OBUF_COUNT
]
=
{
{
0
,
0
,
0
},
/* normal */
...
...
@@ -276,33 +292,50 @@ static standardConfig *lookupConfig(sds name) {
*----------------------------------------------------------------------------*/
/* Get enum value from name. If there is no match INT_MIN is returned. */
int
configEnumGetValue
(
configEnum
*
ce
,
char
*
name
)
{
while
(
ce
->
name
!=
NULL
)
{
if
(
!
strcasecmp
(
ce
->
name
,
name
))
return
ce
->
val
;
ce
++
;
int
configEnumGetValue
(
configEnum
*
ce
,
sds
*
argv
,
int
argc
,
int
bitflags
)
{
if
(
argc
==
0
||
(
!
bitflags
&&
argc
!=
1
))
return
INT_MIN
;
int
values
=
0
;
for
(
int
i
=
0
;
i
<
argc
;
i
++
)
{
int
matched
=
0
;
for
(
configEnum
*
ceItem
=
ce
;
ceItem
->
name
!=
NULL
;
ceItem
++
)
{
if
(
!
strcasecmp
(
argv
[
i
],
ceItem
->
name
))
{
values
|=
ceItem
->
val
;
matched
=
1
;
}
}
if
(
!
matched
)
return
INT_MIN
;
}
return
INT_MIN
;
return
values
;
}
/* Get enum name from value. If no match is found NULL is returned. */
const
char
*
configEnumGetName
(
configEnum
*
ce
,
int
val
)
{
while
(
ce
->
name
!=
NULL
)
{
if
(
ce
->
val
==
val
)
return
ce
->
name
;
ce
++
;
/* Get enum name/s from value. If no matches are found "unknown" is returned. */
static
sds
configEnumGetName
(
configEnum
*
ce
,
int
values
,
int
bitflags
)
{
sds
names
=
NULL
;
int
matches
=
0
;
for
(
;
ce
->
name
!=
NULL
;
ce
++
)
{
if
(
values
==
ce
->
val
)
{
/* Short path for perfect match */
sdsfree
(
names
);
return
sdsnew
(
ce
->
name
);
}
if
(
bitflags
&&
(
values
&
ce
->
val
))
{
names
=
names
?
sdscatfmt
(
names
,
" %s"
,
ce
->
name
)
:
sdsnew
(
ce
->
name
);
matches
|=
ce
->
val
;
}
}
return
NULL
;
}
/* Wrapper for configEnumGetName() returning "unknown" instead of NULL if
* there is no match. */
const
char
*
configEnumGetNameOrUnknown
(
configEnum
*
ce
,
int
val
)
{
const
char
*
name
=
configEnumGetName
(
ce
,
val
);
return
name
?
name
:
"unknown"
;
if
(
!
names
||
values
!=
matches
)
{
sdsfree
(
names
);
return
sdsnew
(
"unknown"
);
}
return
names
;
}
/* Used for INFO generation. */
const
char
*
evictPolicyToString
(
void
)
{
return
configEnumGetNameOrUnknown
(
maxmemory_policy_enum
,
server
.
maxmemory_policy
);
for
(
configEnum
*
ce
=
maxmemory_policy_enum
;
ce
->
name
!=
NULL
;
ce
++
)
{
if
(
server
.
maxmemory_policy
==
ce
->
val
)
return
ce
->
name
;
}
serverPanic
(
"unknown eviction policy"
);
}
/*-----------------------------------------------------------------------------
...
...
@@ -514,12 +547,15 @@ void loadServerConfigFromString(char *config) {
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"loadmodule"
)
&&
argc
>=
2
)
{
queueLoadModule
(
argv
[
1
],
&
argv
[
2
],
argc
-
2
);
}
else
if
(
strchr
(
argv
[
0
],
'.'
))
{
if
(
argc
!=
2
)
{
if
(
argc
<
2
)
{
err
=
"Module config specified without value"
;
goto
loaderr
;
}
sds
name
=
sdsdup
(
argv
[
0
]);
if
(
!
dictReplace
(
server
.
module_configs_queue
,
name
,
sdsdup
(
argv
[
1
])))
sdsfree
(
name
);
sds
val
=
sdsdup
(
argv
[
1
]);
for
(
int
i
=
2
;
i
<
argc
;
i
++
)
val
=
sdscatfmt
(
val
,
" %S"
,
argv
[
i
]);
if
(
!
dictReplace
(
server
.
module_configs_queue
,
name
,
val
))
sdsfree
(
name
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"sentinel"
))
{
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
...
...
@@ -1297,12 +1333,13 @@ void rewriteConfigOctalOption(struct rewriteConfigState *state, const char *opti
/* Rewrite an enumeration option. It takes as usually state and option name,
* and in addition the enumeration array and the default value for the
* option. */
void
rewriteConfigEnumOption
(
struct
rewriteConfigState
*
state
,
const
char
*
option
,
int
value
,
configEnum
*
ce
,
int
defval
)
{
sds
line
;
const
char
*
name
=
configEnumGetNameOrUnknown
(
ce
,
value
);
int
force
=
value
!=
defval
;
void
rewriteConfigEnumOption
(
struct
rewriteConfigState
*
state
,
const
char
*
option
,
int
value
,
standardConfig
*
config
)
{
int
multiarg
=
config
->
flags
&
MULTI_ARG_CONFIG
;
sds
names
=
configEnumGetName
(
config
->
data
.
enumd
.
enum_value
,
value
,
multiarg
);
sds
line
=
sdscatfmt
(
sdsempty
(),
"%s %s"
,
option
,
names
);
sdsfree
(
names
);
int
force
=
value
!=
config
->
data
.
enumd
.
default_value
;
line
=
sdscatprintf
(
sdsempty
(),
"%s %s"
,
option
,
name
);
rewriteConfigRewriteLine
(
state
,
option
,
line
,
force
);
}
...
...
@@ -1821,10 +1858,16 @@ static int sdsConfigSet(standardConfig *config, sds *argv, int argc, const char
UNUSED
(
argc
);
if
(
config
->
data
.
sds
.
is_valid_fn
&&
!
config
->
data
.
sds
.
is_valid_fn
(
argv
[
0
],
err
))
return
0
;
sds
prev
=
config
->
flags
&
MODULE_CONFIG
?
getModuleStringConfig
(
config
->
privdata
)
:
*
config
->
data
.
sds
.
config
;
sds
new
=
(
config
->
data
.
string
.
convert_empty_to_null
&&
(
sdslen
(
argv
[
0
])
==
0
))
?
NULL
:
argv
[
0
];
/* if prev and new configuration are not equal, set the new one */
if
(
new
!=
prev
&&
(
new
==
NULL
||
prev
==
NULL
||
sdscmp
(
prev
,
new
)))
{
/* If MODULE_CONFIG flag is set, then free temporary prev getModuleStringConfig returned.
* Otherwise, free the actual previous config value Redis held (Same action, different reasons) */
sdsfree
(
prev
);
if
(
config
->
flags
&
MODULE_CONFIG
)
{
return
setModuleStringConfig
(
config
->
privdata
,
new
,
err
);
}
...
...
@@ -1848,7 +1891,7 @@ static sds sdsConfigGet(standardConfig *config) {
static
void
sdsConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
sds
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleStringConfig
(
config
->
privdata
)
:
*
config
->
data
.
sds
.
config
;
rewriteConfigSdsOption
(
state
,
name
,
val
,
config
->
data
.
sds
.
default_value
);
if
(
val
)
sdsfree
(
val
);
if
(
(
val
)
&&
(
config
->
flags
&
MODULE_CONFIG
))
sdsfree
(
val
);
}
...
...
@@ -1885,10 +1928,12 @@ static void enumConfigInit(standardConfig *config) {
}
static
int
enumConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
int
enumval
=
configEnumGetValue
(
config
->
data
.
enumd
.
enum_value
,
argv
[
0
]);
int
enumval
;
int
bitflags
=
!!
(
config
->
flags
&
MULTI_ARG_CONFIG
);
enumval
=
configEnumGetValue
(
config
->
data
.
enumd
.
enum_value
,
argv
,
argc
,
bitflags
);
if
(
enumval
==
INT_MIN
)
{
sds
enumerr
=
sdsnew
(
"argument must be one of the following: "
);
sds
enumerr
=
sdsnew
(
"argument
(s)
must be one of the following: "
);
configEnum
*
enumNode
=
config
->
data
.
enumd
.
enum_value
;
while
(
enumNode
->
name
!=
NULL
)
{
enumerr
=
sdscatlen
(
enumerr
,
enumNode
->
name
,
...
...
@@ -1919,12 +1964,13 @@ static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char
static
sds
enumConfigGet
(
standardConfig
*
config
)
{
int
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleEnumConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
enumd
.
config
);
return
sdsnew
(
configEnumGetNameOrUnknown
(
config
->
data
.
enumd
.
enum_value
,
val
));
int
bitflags
=
!!
(
config
->
flags
&
MULTI_ARG_CONFIG
);
return
configEnumGetName
(
config
->
data
.
enumd
.
enum_value
,
val
,
bitflags
);
}
static
void
enumConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
int
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleEnumConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
enumd
.
config
);
rewriteConfigEnumOption
(
state
,
name
,
val
,
config
->
data
.
enumd
.
enum_value
,
config
->
data
.
enumd
.
default_value
);
rewriteConfigEnumOption
(
state
,
name
,
val
,
config
);
}
#define createEnumConfig(name, alias, flags, enum, config_addr, default, is_valid, apply) { \
...
...
@@ -2284,6 +2330,16 @@ static int isValidAOFdirname(char *val, const char **err) {
return
1
;
}
static
int
isValidShutdownOnSigFlags
(
int
val
,
const
char
**
err
)
{
/* Individual arguments are validated by createEnumConfig logic.
* We just need to ensure valid combinations here. */
if
(
val
&
SHUTDOWN_NOSAVE
&&
val
&
SHUTDOWN_SAVE
)
{
*
err
=
"shutdown options SAVE and NOSAVE can't be used simultaneously"
;
return
0
;
}
return
1
;
}
static
int
isValidAnnouncedHostname
(
char
*
val
,
const
char
**
err
)
{
if
(
strlen
(
val
)
>=
NET_HOST_STR_LEN
)
{
*
err
=
"Hostnames must be less than "
...
...
@@ -2641,7 +2697,7 @@ static int setConfigOOMScoreAdjValuesOption(standardConfig *config, sds *argv, i
if
(
*
eptr
!=
'\0'
||
val
<
-
2000
||
val
>
2000
)
{
if
(
err
)
*
err
=
"Invalid oom-score-adj-values, elements must be between -2000 and 2000."
;
return
-
1
;
return
0
;
}
values
[
i
]
=
val
;
...
...
@@ -2691,7 +2747,7 @@ static int setConfigNotifyKeyspaceEventsOption(standardConfig *config, sds *argv
}
int
flags
=
keyspaceEventsStringToFlags
(
argv
[
0
]);
if
(
flags
==
-
1
)
{
*
err
=
"Invalid event class character. Use 'Ag$lshzxeKEtmd'."
;
*
err
=
"Invalid event class character. Use 'Ag$lshzxeKEtmd
n
'."
;
return
0
;
}
server
.
notify_keyspace_events
=
flags
;
...
...
@@ -2887,7 +2943,8 @@ standardConfig static_configs[] = {
createBoolConfig
(
"replica-announced"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
replica_announced
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"latency-tracking"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
latency_tracking_enabled
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"aof-disable-auto-gc"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
aof_disable_auto_gc
,
0
,
NULL
,
updateAofAutoGCEnabled
),
createBoolConfig
(
"replica-ignore-disk-write-errors"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
repl_ignore_disk_write_error
,
0
,
NULL
,
NULL
),
/* String Configs */
createStringConfig
(
"aclfile"
,
NULL
,
IMMUTABLE_CONFIG
,
ALLOW_EMPTY_STRING
,
server
.
acl_filename
,
""
,
NULL
,
NULL
),
createStringConfig
(
"unixsocket"
,
NULL
,
IMMUTABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
unixsocket
,
NULL
,
NULL
,
NULL
),
...
...
@@ -2928,6 +2985,9 @@ standardConfig static_configs[] = {
createEnumConfig
(
"enable-debug-command"
,
NULL
,
IMMUTABLE_CONFIG
,
protected_action_enum
,
server
.
enable_debug_cmd
,
PROTECTED_ACTION_ALLOWED_NO
,
NULL
,
NULL
),
createEnumConfig
(
"enable-module-command"
,
NULL
,
IMMUTABLE_CONFIG
,
protected_action_enum
,
server
.
enable_module_cmd
,
PROTECTED_ACTION_ALLOWED_NO
,
NULL
,
NULL
),
createEnumConfig
(
"cluster-preferred-endpoint-type"
,
NULL
,
MODIFIABLE_CONFIG
,
cluster_preferred_endpoint_type_enum
,
server
.
cluster_preferred_endpoint_type
,
CLUSTER_ENDPOINT_TYPE_IP
,
NULL
,
NULL
),
createEnumConfig
(
"propagation-error-behavior"
,
NULL
,
MODIFIABLE_CONFIG
,
propagation_error_behavior_enum
,
server
.
propagation_error_behavior
,
PROPAGATION_ERR_BEHAVIOR_IGNORE
,
NULL
,
NULL
),
createEnumConfig
(
"shutdown-on-sigint"
,
NULL
,
MODIFIABLE_CONFIG
|
MULTI_ARG_CONFIG
,
shutdown_on_sig_enum
,
server
.
shutdown_on_sigint
,
0
,
isValidShutdownOnSigFlags
,
NULL
),
createEnumConfig
(
"shutdown-on-sigterm"
,
NULL
,
MODIFIABLE_CONFIG
|
MULTI_ARG_CONFIG
,
shutdown_on_sig_enum
,
server
.
shutdown_on_sigterm
,
0
,
isValidShutdownOnSigFlags
,
NULL
),
/* Integer configs */
createIntConfig
(
"databases"
,
NULL
,
IMMUTABLE_CONFIG
,
1
,
INT_MAX
,
server
.
dbnum
,
16
,
INTEGER_CONFIG
,
NULL
,
NULL
),
...
...
@@ -2971,6 +3031,7 @@ standardConfig static_configs[] = {
/* Unsigned int configs */
createUIntConfig
(
"maxclients"
,
NULL
,
MODIFIABLE_CONFIG
,
1
,
UINT_MAX
,
server
.
maxclients
,
10000
,
INTEGER_CONFIG
,
NULL
,
updateMaxclients
),
createUIntConfig
(
"unixsocketperm"
,
NULL
,
IMMUTABLE_CONFIG
,
0
,
0777
,
server
.
unixsocketperm
,
0
,
OCTAL_CONFIG
,
NULL
,
NULL
),
createUIntConfig
(
"socket-mark-id"
,
NULL
,
IMMUTABLE_CONFIG
,
0
,
UINT_MAX
,
server
.
socket_mark_id
,
0
,
INTEGER_CONFIG
,
NULL
,
NULL
),
/* Unsigned Long configs */
createULongConfig
(
"active-defrag-max-scan-fields"
,
NULL
,
MODIFIABLE_CONFIG
,
1
,
LONG_MAX
,
server
.
active_defrag_max_scan_fields
,
1000
,
INTEGER_CONFIG
,
NULL
,
NULL
),
/* Default: keys with more than 1000 fields will be processed separately */
...
...
src/config.h
View file @
20618c71
...
...
@@ -80,6 +80,10 @@
/* MSG_NOSIGNAL. */
#ifdef __linux__
#define HAVE_MSG_NOSIGNAL 1
#if defined(SO_MARK)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_MARK
#endif
#endif
/* Test for polling API */
...
...
@@ -113,6 +117,20 @@
#define redis_fsync(fd) fsync(fd)
#endif
#if defined(__FreeBSD__)
#if defined(SO_USER_COOKIE)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_USER_COOKIE
#endif
#endif
#if defined(__OpenBSD__)
#if defined(SO_RTABLE)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_RTABLE
#endif
#endif
#if __GNUC__ >= 4
#define redis_unreachable __builtin_unreachable
#else
...
...
src/db.c
View file @
20618c71
...
...
@@ -182,6 +182,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
dictSetVal
(
db
->
dict
,
de
,
val
);
signalKeyAsReady
(
db
,
key
,
val
->
type
);
if
(
server
.
cluster_enabled
)
slotToKeyAddEntry
(
de
,
db
);
notifyKeyspaceEvent
(
NOTIFY_NEW
,
"new"
,
key
,
db
->
id
);
}
/* This is a special version of dbAdd() that is used only when loading
...
...
src/debug.c
View file @
20618c71
...
...
@@ -416,6 +416,8 @@ void debugCommand(client *c) {
" Like HTSTATS but for the hash table stored at <key>'s value."
,
"LOADAOF"
,
" Flush the AOF buffers on disk and reload the AOF in memory."
,
"REPLICATE <string>"
,
" Replicates the provided string to replicas, allowing data divergence."
,
#ifdef USE_JEMALLOC
"MALLCTL <key> [<val>]"
,
" Get or set a malloc tuning integer."
,
...
...
@@ -849,6 +851,10 @@ NULL
{
server
.
aof_flush_sleep
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
addReply
(
c
,
shared
.
ok
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"replicate"
)
&&
c
->
argc
>=
3
)
{
replicationFeedSlaves
(
server
.
slaves
,
server
.
slaveseldb
,
c
->
argv
+
2
,
c
->
argc
-
2
);
addReply
(
c
,
shared
.
ok
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"error"
)
&&
c
->
argc
==
3
)
{
sds
errstr
=
sdsnewlen
(
"-"
,
1
);
...
...
src/eval.c
View file @
20618c71
...
...
@@ -218,31 +218,20 @@ void scriptingInit(int setup) {
lua_setglobal
(
lua
,
"redis"
);
/* Add a helper function that we use to sort the multi bulk output of non
* deterministic commands, when containing 'false' elements. */
{
char
*
compare_func
=
"function __redis__compare_helper(a,b)
\n
"
" if a == false then a = '' end
\n
"
" if b == false then b = '' end
\n
"
" return a<b
\n
"
"end
\n
"
;
luaL_loadbuffer
(
lua
,
compare_func
,
strlen
(
compare_func
),
"@cmp_func_def"
);
lua_pcall
(
lua
,
0
,
0
,
0
);
}
/* Add a helper function we use for pcall error reporting.
* Note that when the error is in the C function we want to report the
* information about the caller, that's what makes sense from the point
* of view of the user debugging a script. */
{
char
*
errh_func
=
"local dbg = debug
\n
"
"debug = nil
\n
"
"function __redis__err__handler(err)
\n
"
" local i = dbg.getinfo(2,'nSl')
\n
"
" if i and i.what == 'C' then
\n
"
" i = dbg.getinfo(3,'nSl')
\n
"
" end
\n
"
" if type(err) ~= 'table' then
\n
"
" err = {err='ERR' .. tostring(err)}"
" err = {err='ERR
' .. tostring(err)}"
" end"
" if i then
\n
"
" err['source'] = i.source
\n
"
...
...
@@ -266,10 +255,12 @@ void scriptingInit(int setup) {
lctx
.
lua_client
->
flags
|=
CLIENT_DENY_BLOCKING
;
}
/* Lua beginners often don't use "local", this is likely to introduce
* subtle bugs in their code. To prevent problems we protect accesses
* to global variables. */
luaEnableGlobalsProtection
(
lua
,
1
);
/* Lock the global table from any changes */
lua_pushvalue
(
lua
,
LUA_GLOBALSINDEX
);
luaSetErrorMetatable
(
lua
);
/* Recursively lock all tables that can be reached from the global table */
luaSetTableProtectionRecursively
(
lua
);
lua_pop
(
lua
,
1
);
lctx
.
lua
=
lua
;
}
...
...
@@ -378,35 +369,20 @@ sds luaCreateFunction(client *c, robj *body) {
sdsfreesplitres
(
parts
,
numparts
);
}
/* Build the lua function to be loaded */
sds
funcdef
=
sdsempty
();
funcdef
=
sdscat
(
funcdef
,
"function "
);
funcdef
=
sdscatlen
(
funcdef
,
funcname
,
42
);
funcdef
=
sdscatlen
(
funcdef
,
"() "
,
3
);
/* Note that in case of a shebang line we skip it but keep the line feed to conserve the user's line numbers */
funcdef
=
sdscatlen
(
funcdef
,(
char
*
)
body
->
ptr
+
shebang_len
,
sdslen
(
body
->
ptr
)
-
shebang_len
);
funcdef
=
sdscatlen
(
funcdef
,
"
\n
end"
,
4
);
if
(
luaL_loadbuffer
(
lctx
.
lua
,
funcdef
,
sdslen
(
funcdef
),
"@user_script"
))
{
if
(
luaL_loadbuffer
(
lctx
.
lua
,(
char
*
)
body
->
ptr
+
shebang_len
,
sdslen
(
body
->
ptr
)
-
shebang_len
,
"@user_script"
))
{
if
(
c
!=
NULL
)
{
addReplyErrorFormat
(
c
,
"Error compiling script (new function): %s"
,
lua_tostring
(
lctx
.
lua
,
-
1
));
}
lua_pop
(
lctx
.
lua
,
1
);
sdsfree
(
funcdef
);
return
NULL
;
}
sdsfree
(
funcdef
);
if
(
lua_pcall
(
lctx
.
lua
,
0
,
0
,
0
))
{
if
(
c
!=
NULL
)
{
addReplyErrorFormat
(
c
,
"Error running script (new function): %s"
,
lua_tostring
(
lctx
.
lua
,
-
1
));
}
lua_pop
(
lctx
.
lua
,
1
);
return
NULL
;
}
serverAssert
(
lua_isfunction
(
lctx
.
lua
,
-
1
));
lua_setfield
(
lctx
.
lua
,
LUA_REGISTRYINDEX
,
funcname
);
/* We also save a SHA1 -> Original script map in a dictionary
* so that we can replicate / write in the AOF all the
...
...
@@ -479,7 +455,7 @@ void evalGenericCommand(client *c, int evalsha) {
lua_getglobal
(
lua
,
"__redis__err__handler"
);
/* Try to lookup the Lua function */
lua_get
global
(
lua
,
funcname
);
lua_get
field
(
lua
,
LUA_REGISTRYINDEX
,
funcname
);
if
(
lua_isnil
(
lua
,
-
1
))
{
lua_pop
(
lua
,
1
);
/* remove the nil from the stack */
/* Function not defined... let's define it if we have the
...
...
@@ -497,7 +473,7 @@ void evalGenericCommand(client *c, int evalsha) {
return
;
}
/* Now the following is guaranteed to return non nil */
lua_get
global
(
lua
,
funcname
);
lua_get
field
(
lua
,
LUA_REGISTRYINDEX
,
funcname
);
serverAssert
(
!
lua_isnil
(
lua
,
-
1
));
}
...
...
Prev
1
2
3
4
5
6
7
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment