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
a5d2df34
Commit
a5d2df34
authored
Jun 08, 2022
by
Oran Agra
Browse files
Merge remote-tracking branch 'origin/unstable' into 7.0
parents
d375595d
f22bfe86
Changes
108
Hide whitespace changes
Inline
Side-by-side
src/commands/lcs.json
View file @
a5d2df34
...
...
@@ -41,7 +41,7 @@
{
"name"
:
"key2"
,
"type"
:
"key"
,
"key_spec_index"
:
1
"key_spec_index"
:
0
},
{
"name"
:
"len"
,
...
...
src/commands/pfdebug.json
View file @
a5d2df34
...
...
@@ -4,7 +4,7 @@
"complexity"
:
"N/A"
,
"group"
:
"hyperloglog"
,
"since"
:
"2.8.9"
,
"arity"
:
-
3
,
"arity"
:
3
,
"function"
:
"pfdebugCommand"
,
"doc_flags"
:
[
"SYSCMD"
...
...
@@ -36,6 +36,17 @@
}
}
}
],
"arguments"
:
[
{
"name"
:
"subcommand"
,
"type"
:
"string"
},
{
"name"
:
"key"
,
"type"
:
"key"
,
"key_spec_index"
:
0
}
]
}
}
src/commands/pubsub-shardchannels.json
View file @
a5d2df34
{
"SHARDCHANNELS"
:
{
"summary"
:
"List active shard channels"
,
"complexity"
:
"O(N) where N is the number of active shard channels, and assuming constant time pattern matching (relatively short channels)."
,
"complexity"
:
"O(N) where N is the number of active shard channels, and assuming constant time pattern matching (relatively short
shard
channels)."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-2
,
...
...
src/commands/pubsub-shardnumsub.json
View file @
a5d2df34
{
"SHARDNUMSUB"
:
{
"summary"
:
"Get the count of subscribers for shard channels"
,
"complexity"
:
"O(N) for the SHARDNUMSUB subcommand, where N is the number of requested channels"
,
"complexity"
:
"O(N) for the SHARDNUMSUB subcommand, where N is the number of requested
shard
channels"
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-2
,
...
...
@@ -14,7 +14,7 @@
],
"arguments"
:
[
{
"name"
:
"channel"
,
"name"
:
"
shard
channel"
,
"type"
:
"string"
,
"optional"
:
true
,
"multiple"
:
true
...
...
src/commands/rename.json
View file @
a5d2df34
...
...
@@ -62,7 +62,7 @@
{
"name"
:
"newkey"
,
"type"
:
"key"
,
"key_spec_index"
:
0
"key_spec_index"
:
1
}
]
}
...
...
src/commands/renamenx.json
View file @
a5d2df34
...
...
@@ -67,7 +67,7 @@
{
"name"
:
"newkey"
,
"type"
:
"key"
,
"key_spec_index"
:
0
"key_spec_index"
:
1
}
]
}
...
...
src/commands/restore-asking.json
View file @
a5d2df34
...
...
@@ -6,6 +6,20 @@
"since"
:
"3.0.0"
,
"arity"
:
-4
,
"function"
:
"restoreCommand"
,
"history"
:
[
[
"3.0.0"
,
"Added the `REPLACE` modifier."
],
[
"5.0.0"
,
"Added the `ABSTTL` modifier."
],
[
"5.0.0"
,
"Added the `IDLETIME` and `FREQ` options."
]
],
"doc_flags"
:
[
"SYSCMD"
],
...
...
@@ -37,6 +51,49 @@
}
}
}
],
"arguments"
:
[
{
"name"
:
"key"
,
"type"
:
"key"
,
"key_spec_index"
:
0
},
{
"name"
:
"ttl"
,
"type"
:
"integer"
},
{
"name"
:
"serialized-value"
,
"type"
:
"string"
},
{
"name"
:
"replace"
,
"token"
:
"REPLACE"
,
"type"
:
"pure-token"
,
"optional"
:
true
,
"since"
:
"3.0.0"
},
{
"name"
:
"absttl"
,
"token"
:
"ABSTTL"
,
"type"
:
"pure-token"
,
"optional"
:
true
,
"since"
:
"5.0.0"
},
{
"token"
:
"IDLETIME"
,
"name"
:
"seconds"
,
"type"
:
"integer"
,
"optional"
:
true
,
"since"
:
"5.0.0"
},
{
"token"
:
"FREQ"
,
"name"
:
"frequency"
,
"type"
:
"integer"
,
"optional"
:
true
,
"since"
:
"5.0.0"
}
]
}
}
src/commands/sentinel-slaves.json
0 → 100644
View file @
a5d2df34
{
"SLAVES"
:
{
"summary"
:
"List the monitored slaves"
,
"complexity"
:
"O(N) where N is the number of slaves"
,
"group"
:
"sentinel"
,
"since"
:
"2.8.0"
,
"arity"
:
3
,
"container"
:
"SENTINEL"
,
"function"
:
"sentinelCommand"
,
"deprecated_since"
:
"5.0.0"
,
"replaced_by"
:
"`SENTINEL REPLICAS`"
,
"doc_flags"
:
[
"DEPRECATED"
],
"command_flags"
:
[
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/spublish.json
View file @
a5d2df34
...
...
@@ -15,7 +15,7 @@
],
"arguments"
:
[
{
"name"
:
"channel"
,
"name"
:
"
shard
channel"
,
"type"
:
"string"
},
{
...
...
src/commands/ssubscribe.json
View file @
a5d2df34
...
...
@@ -14,7 +14,7 @@
],
"arguments"
:
[
{
"name"
:
"channel"
,
"name"
:
"
shard
channel"
,
"type"
:
"string"
,
"multiple"
:
true
}
...
...
src/commands/sunsubscribe.json
View file @
a5d2df34
{
"SUNSUBSCRIBE"
:
{
"summary"
:
"Stop listening for messages posted to the given shard channels"
,
"complexity"
:
"O(N) where N is the number of clients already subscribed to a channel."
,
"complexity"
:
"O(N) where N is the number of clients already subscribed to a
shard
channel."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-1
,
...
...
@@ -14,7 +14,7 @@
],
"arguments"
:
[
{
"name"
:
"channel"
,
"name"
:
"
shard
channel"
,
"type"
:
"string"
,
"optional"
:
true
,
"multiple"
:
true
...
...
src/commands/watch.json
View file @
a5d2df34
...
...
@@ -18,6 +18,9 @@
],
"key_specs"
:
[
{
"flags"
:
[
"RO"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
...
...
src/commands/xinfo-stream.json
View file @
a5d2df34
...
...
@@ -7,6 +7,10 @@
"arity"
:
-3
,
"container"
:
"XINFO"
,
"history"
:
[
[
"6.0.0"
,
"Added the `FULL` modifier."
],
[
"7.0.0"
,
"Added the `max-deleted-entry-id`, `entries-added`, `recorded-first-entry-id`, `entries-read` and `lag` fields"
...
...
src/config.c
View file @
a5d2df34
...
...
@@ -311,18 +311,21 @@ int configEnumGetValue(configEnum *ce, sds *argv, int argc, int bitflags) {
/* 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
matche
s
=
0
;
int
un
matche
d
=
values
;
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
))
{
/* Note: for bitflags, we want them sorted from high to low, so that if there are several / partially
* overlapping entries, we'll prefer the ones matching more bits. */
if
(
bitflags
&&
ce
->
val
&&
ce
->
val
==
(
unmatched
&
ce
->
val
))
{
names
=
names
?
sdscatfmt
(
names
,
" %s"
,
ce
->
name
)
:
sdsnew
(
ce
->
name
);
matche
s
|
=
ce
->
val
;
un
matche
d
&
=
~
ce
->
val
;
}
}
if
(
!
names
||
values
!=
matche
s
)
{
if
(
!
names
||
un
matche
d
)
{
sdsfree
(
names
);
return
sdsnew
(
"unknown"
);
}
...
...
@@ -484,9 +487,23 @@ void loadServerConfigFromString(char *config) {
err
=
"wrong number of arguments"
;
goto
loaderr
;
}
/* Set config using all arguments that follows */
if
(
!
config
->
interface
.
set
(
config
,
&
argv
[
1
],
argc
-
1
,
&
err
))
{
goto
loaderr
;
if
((
config
->
flags
&
MULTI_ARG_CONFIG
)
&&
argc
==
2
&&
sdslen
(
argv
[
1
]))
{
/* For MULTI_ARG_CONFIGs, if we only have one argument, try to split it by spaces.
* Only if the argument is not empty, otherwise something like --save "" will fail.
* So that we can support something like --config "arg1 arg2 arg3". */
sds
*
new_argv
;
int
new_argc
;
new_argv
=
sdssplitargs
(
argv
[
1
],
&
new_argc
);
if
(
!
config
->
interface
.
set
(
config
,
new_argv
,
new_argc
,
&
err
))
{
goto
loaderr
;
}
sdsfreesplitres
(
new_argv
,
new_argc
);
}
else
{
/* Set config using all arguments that follows */
if
(
!
config
->
interface
.
set
(
config
,
&
argv
[
1
],
argc
-
1
,
&
err
))
{
goto
loaderr
;
}
}
sdsfreesplitres
(
argv
,
argc
);
...
...
@@ -1125,10 +1142,21 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
/* Not a comment, split into arguments. */
argv
=
sdssplitargs
(
line
,
&
argc
);
if
(
argv
==
NULL
||
(
!
server
.
sentinel_mode
&&
!
lookupConfig
(
argv
[
0
])))
{
/* Apparently the line is unparsable for some reason, for
* instance it may have unbalanced quotes, or may contain a
* config that doesn't exist anymore. Load it as a comment. */
if
(
argv
==
NULL
||
(
!
lookupConfig
(
argv
[
0
])
&&
/* The following is a list of config features that are only supported in
* config file parsing and are not recognized by lookupConfig */
strcasecmp
(
argv
[
0
],
"include"
)
&&
strcasecmp
(
argv
[
0
],
"rename-command"
)
&&
strcasecmp
(
argv
[
0
],
"user"
)
&&
strcasecmp
(
argv
[
0
],
"loadmodule"
)
&&
strcasecmp
(
argv
[
0
],
"sentinel"
)))
{
/* The line is either unparsable for some reason, for
* instance it may have unbalanced quotes, may contain a
* config that doesn't exist anymore, for instance a module that got
* unloaded. Load it as a comment. */
sds
aux
=
sdsnew
(
"# ??? "
);
aux
=
sdscatsds
(
aux
,
line
);
if
(
argv
)
sdsfreesplitres
(
argv
,
argc
);
...
...
@@ -1143,18 +1171,13 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
* Append the line and populate the option -> line numbers map. */
rewriteConfigAppendLine
(
state
,
line
);
/* Translate options using the word "slave" to the corresponding name
* "replica", before adding such option to the config name -> lines
* mapping. */
char
*
p
=
strstr
(
argv
[
0
],
"slave"
);
if
(
p
)
{
sds
alt
=
sdsempty
();
alt
=
sdscatlen
(
alt
,
argv
[
0
],
p
-
argv
[
0
]);
alt
=
sdscatlen
(
alt
,
"replica"
,
7
);
alt
=
sdscatlen
(
alt
,
p
+
5
,
strlen
(
p
+
5
));
/* If this is a alias config, replace it with the original name. */
standardConfig
*
s_conf
=
lookupConfig
(
argv
[
0
]);
if
(
s_conf
&&
s_conf
->
flags
&
ALIAS_CONFIG
)
{
sdsfree
(
argv
[
0
]);
argv
[
0
]
=
alt
;
argv
[
0
]
=
sdsnew
(
s_conf
->
alias
)
;
}
/* If this is sentinel config, we use sentinel "sentinel <config>" as option
to avoid messing up the sequence. */
if
(
server
.
sentinel_mode
&&
argc
>
1
&&
!
strcasecmp
(
argv
[
0
],
"sentinel"
))
{
...
...
@@ -1796,7 +1819,7 @@ static int boolConfigSet(standardConfig *config, sds *argv, int argc, const char
*
(
config
->
data
.
yesno
.
config
)
=
yn
;
return
1
;
}
return
2
;
return
(
config
->
flags
&
VOLATILE_CONFIG
)
?
1
:
2
;
}
static
sds
boolConfigGet
(
standardConfig
*
config
)
{
...
...
@@ -1838,7 +1861,7 @@ static int stringConfigSet(standardConfig *config, sds *argv, int argc, const ch
zfree
(
prev
);
return
1
;
}
return
2
;
return
(
config
->
flags
&
VOLATILE_CONFIG
)
?
1
:
2
;
}
static
sds
stringConfigGet
(
standardConfig
*
config
)
{
...
...
@@ -1875,7 +1898,7 @@ static int sdsConfigSet(standardConfig *config, sds *argv, int argc, const char
return
1
;
}
if
(
config
->
flags
&
MODULE_CONFIG
&&
prev
)
sdsfree
(
prev
);
return
2
;
return
(
config
->
flags
&
VOLATILE_CONFIG
)
?
1
:
2
;
}
static
sds
sdsConfigGet
(
standardConfig
*
config
)
{
...
...
@@ -1959,7 +1982,7 @@ static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char
*
(
config
->
data
.
enumd
.
config
)
=
enumval
;
return
1
;
}
return
2
;
return
(
config
->
flags
&
VOLATILE_CONFIG
)
?
1
:
2
;
}
static
sds
enumConfigGet
(
standardConfig
*
config
)
{
...
...
@@ -2155,7 +2178,7 @@ static int numericConfigSet(standardConfig *config, sds *argv, int argc, const c
return
setNumericType
(
config
,
ll
,
err
);
}
return
2
;
return
(
config
->
flags
&
VOLATILE_CONFIG
)
?
1
:
2
;
}
static
sds
numericConfigGet
(
standardConfig
*
config
)
{
...
...
@@ -2592,8 +2615,10 @@ static int setConfigSaveOption(standardConfig *config, sds *argv, int argc, cons
int
j
;
/* Special case: treat single arg "" as zero args indicating empty save configuration */
if
(
argc
==
1
&&
!
strcasecmp
(
argv
[
0
],
""
))
if
(
argc
==
1
&&
!
strcasecmp
(
argv
[
0
],
""
))
{
resetServerSaveParams
();
argc
=
0
;
}
/* Perform sanity check before setting the new config:
* - Even number of args
...
...
@@ -3078,15 +3103,15 @@ standardConfig static_configs[] = {
createEnumConfig
(
"tls-auth-clients"
,
NULL
,
MODIFIABLE_CONFIG
,
tls_auth_clients_enum
,
server
.
tls_auth_clients
,
TLS_CLIENT_AUTH_YES
,
NULL
,
NULL
),
createBoolConfig
(
"tls-prefer-server-ciphers"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
tls_ctx_config
.
prefer_server_ciphers
,
0
,
NULL
,
applyTlsCfg
),
createBoolConfig
(
"tls-session-caching"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
tls_ctx_config
.
session_caching
,
1
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-cert-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-key-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
key_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-cert-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-key-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
key_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-key-file-pass"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
key_file_pass
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-client-cert-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
client_cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-client-key-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
client_key_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-client-cert-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
client_cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-client-key-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
client_key_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-client-key-file-pass"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
client_key_file_pass
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-dh-params-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
dh_params_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ca-cert-file"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ca_cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ca-cert-dir"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ca_cert_dir
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-dh-params-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
dh_params_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ca-cert-file"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ca_cert_file
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ca-cert-dir"
,
NULL
,
VOLATILE_CONFIG
|
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ca_cert_dir
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-protocols"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
protocols
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ciphers"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ciphers
,
NULL
,
NULL
,
applyTlsCfg
),
createStringConfig
(
"tls-ciphersuites"
,
NULL
,
MODIFIABLE_CONFIG
,
EMPTY_STRING_IS_NULL
,
server
.
tls_ctx_config
.
ciphersuites
,
NULL
,
NULL
,
applyTlsCfg
),
...
...
src/db.c
View file @
a5d2df34
...
...
@@ -602,18 +602,11 @@ void flushAllDataAndResetRDB(int flags) {
server
.
dirty
+=
emptyData
(
-
1
,
flags
,
NULL
);
if
(
server
.
child_type
==
CHILD_TYPE_RDB
)
killRDBChild
();
if
(
server
.
saveparamslen
>
0
)
{
/* Normally rdbSave() will reset dirty, but we don't want this here
* as otherwise FLUSHALL will not be replicated nor put into the AOF. */
int
saved_dirty
=
server
.
dirty
;
rdbSaveInfo
rsi
,
*
rsiptr
;
rsiptr
=
rdbPopulateSaveInfo
(
&
rsi
);
rdbSave
(
SLAVE_REQ_NONE
,
server
.
rdb_filename
,
rsiptr
);
server
.
dirty
=
saved_dirty
;
}
/* Without that extra dirty++, when db was already empty, FLUSHALL will
* not be replicated nor put into the AOF. */
server
.
dirty
++
;
#if defined(USE_JEMALLOC)
/* jemalloc 5 doesn't release pages back to the OS when there's no traffic.
* for large databases, flushdb blocks for long anyway, so a bit more won't
...
...
@@ -632,7 +625,13 @@ void flushdbCommand(client *c) {
if
(
getFlushCommandFlags
(
c
,
&
flags
)
==
C_ERR
)
return
;
/* flushdb should not flush the functions */
server
.
dirty
+=
emptyData
(
c
->
db
->
id
,
flags
|
EMPTYDB_NOFUNCTIONS
,
NULL
);
/* Without the forceCommandPropagation, when DB was already empty,
* FLUSHDB will not be replicated nor put into the AOF. */
forceCommandPropagation
(
c
,
PROPAGATE_REPL
|
PROPAGATE_AOF
);
addReply
(
c
,
shared
.
ok
);
#if defined(USE_JEMALLOC)
/* jemalloc 5 doesn't release pages back to the OS when there's no traffic.
* for large databases, flushdb blocks for long anyway, so a bit more won't
...
...
@@ -650,6 +649,11 @@ void flushallCommand(client *c) {
if
(
getFlushCommandFlags
(
c
,
&
flags
)
==
C_ERR
)
return
;
/* flushall should not flush the functions */
flushAllDataAndResetRDB
(
flags
|
EMPTYDB_NOFUNCTIONS
);
/* Without the forceCommandPropagation, when DBs were already empty,
* FLUSHALL will not be replicated nor put into the AOF. */
forceCommandPropagation
(
c
,
PROPAGATE_REPL
|
PROPAGATE_AOF
);
addReply
(
c
,
shared
.
ok
);
}
...
...
@@ -1080,7 +1084,7 @@ void shutdownCommand(client *c) {
return
;
}
if
(
!
(
flags
&
SHUTDOWN_NOSAVE
)
&&
scriptIsTimedout
())
{
if
(
!
(
flags
&
SHUTDOWN_NOSAVE
)
&&
isInsideYieldingLongCommand
())
{
/* Script timed out. Shutdown allowed only with the NOSAVE flag. See
* also processCommand where these errors are returned. */
if
(
server
.
busy_module_yield_flags
&&
server
.
busy_module_yield_reply
)
{
...
...
@@ -1878,7 +1882,6 @@ int getKeysFromCommandWithSpecs(struct redisCommand *cmd, robj **argv, int argc,
/* Flags indicating that we have a getkeys callback */
int
has_module_getkeys
=
cmd
->
flags
&
CMD_MODULE_GETKEYS
;
int
has_native_getkeys
=
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
;
/* The key-spec that's auto generated by RM_CreateCommand sets VARIABLE_FLAGS since no flags are given.
* If the module provides getkeys callback, we'll prefer it, but if it didn't, we'll use key-spec anyway. */
...
...
@@ -1900,14 +1903,14 @@ int getKeysFromCommandWithSpecs(struct redisCommand *cmd, robj **argv, int argc,
/* We use native getkeys as a last resort, since not all these native getkeys provide
* flags properly (only the ones that correspond to INVALID, INCOMPLETE or VARIABLE_FLAGS do.*/
if
(
has_native_
getkeys
)
if
(
cmd
->
getkeys
_proc
)
return
cmd
->
getkeys_proc
(
cmd
,
argv
,
argc
,
result
);
return
0
;
}
/* This function returns a sanity check if the command may have keys. */
int
doesCommandHaveKeys
(
struct
redisCommand
*
cmd
)
{
return
(
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
)
||
/* has getkeys_proc (non modules) */
return
cmd
->
getkeys_proc
||
/* has getkeys_proc (non modules) */
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
)
||
/* module with GETKEYS */
(
getAllKeySpecsFlags
(
cmd
,
1
)
&
CMD_KEY_NOT_KEY
);
/* has at least one key-spec not marked as NOT_KEY */
}
...
...
@@ -2056,7 +2059,7 @@ int getKeysUsingLegacyRangeSpec(struct redisCommand *cmd, robj **argv, int argc,
int
getKeysFromCommand
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
getKeysResult
*
result
)
{
if
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
)
{
return
moduleGetCommandKeysViaAPI
(
cmd
,
argv
,
argc
,
result
);
}
else
if
(
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
)
{
}
else
if
(
cmd
->
getkeys_proc
)
{
return
cmd
->
getkeys_proc
(
cmd
,
argv
,
argc
,
result
);
}
else
{
return
getKeysUsingLegacyRangeSpec
(
cmd
,
argv
,
argc
,
result
);
...
...
src/debug.c
View file @
a5d2df34
...
...
@@ -2014,7 +2014,9 @@ void bugReportEnd(int killViaSignal, int sig) {
"
\n
=== REDIS BUG REPORT END. Make sure to include from START to END. ===
\n\n
"
" Please report the crash by opening an issue on github:
\n\n
"
" http://github.com/redis/redis/issues
\n\n
"
" If a Redis module was involved, please open in the module's repo instead.
\n\n
"
" Suspect RAM error? Use redis-server --test-memory to verify it.
\n\n
"
" Some other issues could be detected by redis-server --check-system
\n
"
);
/* free(messages); Don't call free() with possibly corrupted memory. */
...
...
src/eval.c
View file @
a5d2df34
...
...
@@ -285,59 +285,61 @@ void scriptingReset(int async) {
* EVAL and SCRIPT commands implementation
* ------------------------------------------------------------------------- */
/* Define a Lua function with the specified body.
* The function name will be generated in the following form:
*
* f_<hex sha1 sum>
*
* The function increments the reference count of the 'body' object as a
* side effect of a successful call.
*
* On success a pointer to an SDS string representing the function SHA1 of the
* just added function is returned (and will be valid until the next call
* to scriptingReset() function), otherwise NULL is returned.
*
* The function handles the fact of being called with a script that already
* exists, and in such a case, it behaves like in the success case.
*
* If 'c' is not NULL, on error the client is informed with an appropriate
* error describing the nature of the problem and the Lua interpreter error. */
sds
luaCreateFunction
(
client
*
c
,
robj
*
body
)
{
char
funcname
[
43
];
dictEntry
*
de
;
uint64_t
script_flags
=
SCRIPT_FLAG_EVAL_COMPAT_MODE
;
funcname
[
0
]
=
'f'
;
funcname
[
1
]
=
'_'
;
sha1hex
(
funcname
+
2
,
body
->
ptr
,
sdslen
(
body
->
ptr
));
static
void
evalCalcFunctionName
(
int
evalsha
,
sds
script
,
char
*
out_funcname
)
{
/* We obtain the script SHA1, then check if this function is already
* defined into the Lua state */
out_funcname
[
0
]
=
'f'
;
out_funcname
[
1
]
=
'_'
;
if
(
!
evalsha
)
{
/* Hash the code if this is an EVAL call */
sha1hex
(
out_funcname
+
2
,
script
,
sdslen
(
script
));
}
else
{
/* We already have the SHA if it is an EVALSHA */
int
j
;
char
*
sha
=
script
;
if
((
de
=
dictFind
(
lctx
.
lua_scripts
,
funcname
+
2
))
!=
NULL
)
{
return
dictGetKey
(
de
);
/* Convert to lowercase. We don't use tolower since the function
* managed to always show up in the profiler output consuming
* a non trivial amount of time. */
for
(
j
=
0
;
j
<
40
;
j
++
)
out_funcname
[
j
+
2
]
=
(
sha
[
j
]
>=
'A'
&&
sha
[
j
]
<=
'Z'
)
?
sha
[
j
]
+
(
'a'
-
'A'
)
:
sha
[
j
];
out_funcname
[
42
]
=
'\0'
;
}
}
/* Handle shebang header in script code */
/* Helper function to try and extract shebang flags from the script body.
* If no shebang is found, return with success and COMPAT mode flag.
* The err arg is optional, can be used to get a detailed error string.
* The out_shebang_len arg is optional, can be used to trim the shebang from the script.
* Returns C_OK on success, and C_ERR on error. */
int
evalExtractShebangFlags
(
sds
body
,
uint64_t
*
out_flags
,
ssize_t
*
out_shebang_len
,
sds
*
err
)
{
ssize_t
shebang_len
=
0
;
if
(
!
strncmp
(
body
->
ptr
,
"#!"
,
2
))
{
uint64_t
script_flags
=
SCRIPT_FLAG_EVAL_COMPAT_MODE
;
if
(
!
strncmp
(
body
,
"#!"
,
2
))
{
int
numparts
,
j
;
char
*
shebang_end
=
strchr
(
body
->
ptr
,
'\n'
);
char
*
shebang_end
=
strchr
(
body
,
'\n'
);
if
(
shebang_end
==
NULL
)
{
addReplyError
(
c
,
"Invalid script shebang"
);
return
NULL
;
if
(
err
)
*
err
=
sdsnew
(
"Invalid script shebang"
);
return
C_ERR
;
}
shebang_len
=
shebang_end
-
(
char
*
)
body
->
ptr
;
sds
shebang
=
sdsnewlen
(
body
->
ptr
,
shebang_len
);
shebang_len
=
shebang_end
-
body
;
sds
shebang
=
sdsnewlen
(
body
,
shebang_len
);
sds
*
parts
=
sdssplitargs
(
shebang
,
&
numparts
);
sdsfree
(
shebang
);
if
(
!
parts
||
numparts
==
0
)
{
addReplyError
(
c
,
"Invalid engine in script shebang"
);
if
(
err
)
*
err
=
sdsnew
(
"Invalid engine in script shebang"
);
sdsfreesplitres
(
parts
,
numparts
);
return
NULL
;
return
C_ERR
;
}
/* Verify lua interpreter was specified */
if
(
strcmp
(
parts
[
0
],
"#!lua"
))
{
addReplyErrorFormat
(
c
,
"Unexpected engine in script shebang: %s"
,
parts
[
0
]);
if
(
err
)
*
err
=
sdscatfmt
(
sdsempty
(),
"Unexpected engine in script shebang: %s"
,
parts
[
0
]);
sdsfreesplitres
(
parts
,
numparts
);
return
NULL
;
return
C_ERR
;
}
script_flags
&=
~
SCRIPT_FLAG_EVAL_COMPAT_MODE
;
for
(
j
=
1
;
j
<
numparts
;
j
++
)
{
...
...
@@ -351,23 +353,93 @@ sds luaCreateFunction(client *c, robj *body) {
if
(
!
strcmp
(
flags
[
jj
],
sf
->
str
))
break
;
}
if
(
!
sf
->
flag
)
{
addReplyErrorFormat
(
c
,
"Unexpected flag in script shebang: %s"
,
flags
[
jj
]);
if
(
err
)
*
err
=
sdscatfmt
(
sdsempty
(),
"Unexpected flag in script shebang: %s"
,
flags
[
jj
]);
sdsfreesplitres
(
flags
,
numflags
);
sdsfreesplitres
(
parts
,
numparts
);
return
NULL
;
return
C_ERR
;
}
script_flags
|=
sf
->
flag
;
}
sdsfreesplitres
(
flags
,
numflags
);
}
else
{
/* We only support function flags options for lua scripts */
addReplyErrorFormat
(
c
,
"Unknown lua shebang option: %s"
,
parts
[
j
]);
if
(
err
)
*
err
=
sdscatfmt
(
sdsempty
(),
"Unknown lua shebang option: %s"
,
parts
[
j
]);
sdsfreesplitres
(
parts
,
numparts
);
return
NULL
;
return
C_ERR
;
}
}
sdsfreesplitres
(
parts
,
numparts
);
}
if
(
out_shebang_len
)
*
out_shebang_len
=
shebang_len
;
*
out_flags
=
script_flags
;
return
C_OK
;
}
/* Try to extract command flags if we can, returns the modified flags.
* Note that it does not guarantee the command arguments are right. */
uint64_t
evalGetCommandFlags
(
client
*
c
,
uint64_t
cmd_flags
)
{
char
funcname
[
43
];
int
evalsha
=
c
->
cmd
->
proc
==
evalShaCommand
||
c
->
cmd
->
proc
==
evalShaRoCommand
;
if
(
evalsha
&&
sdslen
(
c
->
argv
[
1
]
->
ptr
)
!=
40
)
return
cmd_flags
;
evalCalcFunctionName
(
evalsha
,
c
->
argv
[
1
]
->
ptr
,
funcname
);
char
*
lua_cur_script
=
funcname
+
2
;
dictEntry
*
de
=
dictFind
(
lctx
.
lua_scripts
,
lua_cur_script
);
uint64_t
script_flags
;
if
(
!
de
)
{
if
(
evalsha
)
return
cmd_flags
;
if
(
evalExtractShebangFlags
(
c
->
argv
[
1
]
->
ptr
,
&
script_flags
,
NULL
,
NULL
)
==
C_ERR
)
return
cmd_flags
;
}
else
{
luaScript
*
l
=
dictGetVal
(
de
);
script_flags
=
l
->
flags
;
}
if
(
script_flags
&
SCRIPT_FLAG_EVAL_COMPAT_MODE
)
return
cmd_flags
;
return
scriptFlagsToCmdFlags
(
cmd_flags
,
script_flags
);
}
/* Define a Lua function with the specified body.
* The function name will be generated in the following form:
*
* f_<hex sha1 sum>
*
* The function increments the reference count of the 'body' object as a
* side effect of a successful call.
*
* On success a pointer to an SDS string representing the function SHA1 of the
* just added function is returned (and will be valid until the next call
* to scriptingReset() function), otherwise NULL is returned.
*
* The function handles the fact of being called with a script that already
* exists, and in such a case, it behaves like in the success case.
*
* If 'c' is not NULL, on error the client is informed with an appropriate
* error describing the nature of the problem and the Lua interpreter error. */
sds
luaCreateFunction
(
client
*
c
,
robj
*
body
)
{
char
funcname
[
43
];
dictEntry
*
de
;
uint64_t
script_flags
;
funcname
[
0
]
=
'f'
;
funcname
[
1
]
=
'_'
;
sha1hex
(
funcname
+
2
,
body
->
ptr
,
sdslen
(
body
->
ptr
));
if
((
de
=
dictFind
(
lctx
.
lua_scripts
,
funcname
+
2
))
!=
NULL
)
{
return
dictGetKey
(
de
);
}
/* Handle shebang header in script code */
ssize_t
shebang_len
=
0
;
sds
err
=
NULL
;
if
(
evalExtractShebangFlags
(
body
->
ptr
,
&
script_flags
,
&
shebang_len
,
&
err
)
==
C_ERR
)
{
addReplyErrorSds
(
c
,
err
);
return
NULL
;
}
/* Note that in case of a shebang line we skip it but keep the line feed to conserve the user's line numbers */
if
(
luaL_loadbuffer
(
lctx
.
lua
,(
char
*
)
body
->
ptr
+
shebang_len
,
sdslen
(
body
->
ptr
)
-
shebang_len
,
"@user_script"
))
{
...
...
@@ -430,26 +502,7 @@ void evalGenericCommand(client *c, int evalsha) {
return
;
}
/* We obtain the script SHA1, then check if this function is already
* defined into the Lua state */
funcname
[
0
]
=
'f'
;
funcname
[
1
]
=
'_'
;
if
(
!
evalsha
)
{
/* Hash the code if this is an EVAL call */
sha1hex
(
funcname
+
2
,
c
->
argv
[
1
]
->
ptr
,
sdslen
(
c
->
argv
[
1
]
->
ptr
));
}
else
{
/* We already have the SHA if it is an EVALSHA */
int
j
;
char
*
sha
=
c
->
argv
[
1
]
->
ptr
;
/* Convert to lowercase. We don't use tolower since the function
* managed to always show up in the profiler output consuming
* a non trivial amount of time. */
for
(
j
=
0
;
j
<
40
;
j
++
)
funcname
[
j
+
2
]
=
(
sha
[
j
]
>=
'A'
&&
sha
[
j
]
<=
'Z'
)
?
sha
[
j
]
+
(
'a'
-
'A'
)
:
sha
[
j
];
funcname
[
42
]
=
'\0'
;
}
evalCalcFunctionName
(
evalsha
,
c
->
argv
[
1
]
->
ptr
,
funcname
);
/* Push the pcall error handler function on the stack. */
lua_getglobal
(
lua
,
"__redis__err__handler"
);
...
...
src/evict.c
View file @
a5d2df34
...
...
@@ -481,7 +481,7 @@ void startEvictionTimeProc(void) {
static
int
isSafeToPerformEvictions
(
void
)
{
/* - There must be no script in timeout condition.
* - Nor we are loading data right now. */
if
(
scriptIsTimedout
()
||
server
.
loading
)
return
0
;
if
(
isInsideYieldingLongCommand
()
||
server
.
loading
)
return
0
;
/* By default replicas should ignore maxmemory
* and just be masters exact copies. */
...
...
src/expire.c
View file @
a5d2df34
...
...
@@ -662,22 +662,22 @@ void expireGenericCommand(client *c, long long basetime, int unit) {
}
}
/* EXPIRE key seconds */
/* EXPIRE key seconds
[ NX | XX | GT | LT]
*/
void
expireCommand
(
client
*
c
)
{
expireGenericCommand
(
c
,
mstime
(),
UNIT_SECONDS
);
}
/* EXPIREAT key
time
*/
/* EXPIREAT key
unix-time-seconds [ NX | XX | GT | LT]
*/
void
expireatCommand
(
client
*
c
)
{
expireGenericCommand
(
c
,
0
,
UNIT_SECONDS
);
}
/* PEXPIRE key milliseconds */
/* PEXPIRE key milliseconds
[ NX | XX | GT | LT]
*/
void
pexpireCommand
(
client
*
c
)
{
expireGenericCommand
(
c
,
mstime
(),
UNIT_MILLISECONDS
);
}
/* PEXPIREAT key
ms_time
*/
/* PEXPIREAT key
unix-time-milliseconds [ NX | XX | GT | LT]
*/
void
pexpireatCommand
(
client
*
c
)
{
expireGenericCommand
(
c
,
0
,
UNIT_MILLISECONDS
);
}
...
...
src/functions.c
View file @
a5d2df34
...
...
@@ -293,7 +293,7 @@ static void libraryUnlink(functionsLibCtx *lib_ctx, functionLibInfo* li) {
entry
=
dictUnlink
(
lib_ctx
->
libraries
,
li
->
name
);
dictSetVal
(
lib_ctx
->
libraries
,
entry
,
NULL
);
dictFreeUnlinkedEntry
(
lib_ctx
->
libraries
,
entry
);
lib_ctx
->
cache_memory
+
=
libraryMallocSize
(
li
);
lib_ctx
->
cache_memory
-
=
libraryMallocSize
(
li
);
/* update stats */
functionsLibEngineStats
*
stats
=
dictFetchValue
(
lib_ctx
->
engines_stats
,
li
->
ei
->
name
);
...
...
@@ -325,7 +325,7 @@ static void libraryLink(functionsLibCtx *lib_ctx, functionLibInfo* li) {
/* Takes all libraries from lib_ctx_src and add to lib_ctx_dst.
* On collision, if 'replace' argument is true, replace the existing library with the new one.
* Otherwise abort and leave 'lib_ctx_dst' and 'lib_ctx_src' untouched.
* Return C_OK on success and C_ERR if aborted. If C_ERR is retu
n
red, set a relevant
* Return C_OK on success and C_ERR if aborted. If C_ERR is retur
n
ed, set a relevant
* error message on the 'err' out parameter.
* */
static
int
libraryJoin
(
functionsLibCtx
*
functions_lib_ctx_dst
,
functionsLibCtx
*
functions_lib_ctx_src
,
int
replace
,
sds
*
err
)
{
...
...
@@ -599,10 +599,22 @@ void functionDeleteCommand(client *c) {
addReply
(
c
,
shared
.
ok
);
}
/* FUNCTION KILL */
void
functionKillCommand
(
client
*
c
)
{
scriptKill
(
c
,
0
);
}
/* Try to extract command flags if we can, returns the modified flags.
* Note that it does not guarantee the command arguments are right. */
uint64_t
fcallGetCommandFlags
(
client
*
c
,
uint64_t
cmd_flags
)
{
robj
*
function_name
=
c
->
argv
[
1
];
functionInfo
*
fi
=
dictFetchValue
(
curr_functions_lib_ctx
->
functions
,
function_name
->
ptr
);
if
(
!
fi
)
return
cmd_flags
;
uint64_t
script_flags
=
fi
->
f_flags
;
return
scriptFlagsToCmdFlags
(
cmd_flags
,
script_flags
);
}
static
void
fcallCommandGeneric
(
client
*
c
,
int
ro
)
{
robj
*
function_name
=
c
->
argv
[
1
];
functionInfo
*
fi
=
dictFetchValue
(
curr_functions_lib_ctx
->
functions
,
function_name
->
ptr
);
...
...
@@ -778,6 +790,7 @@ load_error:
}
}
/* FUNCTION FLUSH [ASYNC | SYNC] */
void
functionFlushCommand
(
client
*
c
)
{
if
(
c
->
argc
>
3
)
{
addReplySubcommandSyntaxError
(
c
);
...
...
@@ -803,6 +816,7 @@ void functionFlushCommand(client *c) {
addReply
(
c
,
shared
.
ok
);
}
/* FUNCTION HELP */
void
functionHelpCommand
(
client
*
c
)
{
const
char
*
help
[]
=
{
"LOAD <ENGINE NAME> <LIBRARY NAME> [REPLACE] [DESCRIPTION <LIBRARY DESCRIPTION>] <LIBRARY CODE>"
,
...
...
@@ -960,6 +974,7 @@ sds functionsCreateWithLibraryCtx(sds code, int replace, sds* err, functionsLibC
old_li
=
dictFetchValue
(
lib_ctx
->
libraries
,
md
.
name
);
if
(
old_li
&&
!
replace
)
{
old_li
=
NULL
;
*
err
=
sdscatfmt
(
sdsempty
(),
"Library '%S' already exists"
,
md
.
name
);
goto
error
;
}
...
...
Prev
1
2
3
4
5
6
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