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
61297585
Unverified
Commit
61297585
authored
Sep 27, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Sep 27, 2019
Browse files
Merge branch 'unstable' into modules_fork
parents
83e87bac
fddc4757
Changes
82
Expand all
Hide whitespace changes
Inline
Side-by-side
src/cluster.c
View file @
61297585
...
...
@@ -138,6 +138,7 @@ int clusterLoadConfig(char *filename) {
/* Handle the special "vars" line. Don't pretend it is the last
* line even if it actually is when generated by Redis. */
if
(
strcasecmp
(
argv
[
0
],
"vars"
)
==
0
)
{
if
(
!
(
argc
%
2
))
goto
fmterr
;
for
(
j
=
1
;
j
<
argc
;
j
+=
2
)
{
if
(
strcasecmp
(
argv
[
j
],
"currentEpoch"
)
==
0
)
{
server
.
cluster
->
currentEpoch
=
...
...
@@ -4251,12 +4252,9 @@ NULL
}
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"nodes"
)
&&
c
->
argc
==
2
)
{
/* CLUSTER NODES */
robj
*
o
;
sds
ci
=
clusterGenNodesDescription
(
0
);
o
=
createObject
(
OBJ_STRING
,
ci
);
addReplyBulk
(
c
,
o
);
decrRefCount
(
o
);
sds
nodes
=
clusterGenNodesDescription
(
0
);
addReplyVerbatim
(
c
,
nodes
,
sdslen
(
nodes
),
"txt"
);
sdsfree
(
nodes
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"myid"
)
&&
c
->
argc
==
2
)
{
/* CLUSTER MYID */
addReplyBulkCBuffer
(
c
,
myself
->
name
,
CLUSTER_NAMELEN
);
...
...
@@ -4498,10 +4496,8 @@ NULL
"cluster_stats_messages_received:%lld
\r\n
"
,
tot_msg_received
);
/* Produce the reply protocol. */
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"$%lu
\r\n
"
,
(
unsigned
long
)
sdslen
(
info
)));
addReplySds
(
c
,
info
);
addReply
(
c
,
shared
.
crlf
);
addReplyVerbatim
(
c
,
info
,
sdslen
(
info
),
"txt"
);
sdsfree
(
info
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"saveconfig"
)
&&
c
->
argc
==
2
)
{
int
retval
=
clusterSaveConfig
(
1
);
...
...
@@ -4832,7 +4828,7 @@ int verifyDumpPayload(unsigned char *p, size_t len) {
* DUMP is actually not used by Redis Cluster but it is the obvious
* complement of RESTORE and can be useful for different applications. */
void
dumpCommand
(
client
*
c
)
{
robj
*
o
,
*
dumpobj
;
robj
*
o
;
rio
payload
;
/* Check if the key is here. */
...
...
@@ -4845,9 +4841,7 @@ void dumpCommand(client *c) {
createDumpPayload
(
&
payload
,
o
,
c
->
argv
[
1
]);
/* Transfer to the client */
dumpobj
=
createObject
(
OBJ_STRING
,
payload
.
io
.
buffer
.
ptr
);
addReplyBulk
(
c
,
dumpobj
);
decrRefCount
(
dumpobj
);
addReplyBulkSds
(
c
,
payload
.
io
.
buffer
.
ptr
);
return
;
}
...
...
src/config.c
View file @
61297585
...
...
@@ -672,6 +672,10 @@ void loadServerConfigFromString(char *config) {
server
.
lua_time_limit
=
strtoll
(
argv
[
1
],
NULL
,
10
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"lua-replicate-commands"
)
&&
argc
==
2
)
{
server
.
lua_always_replicate_commands
=
yesnotoi
(
argv
[
1
]);
if
(
server
.
lua_always_replicate_commands
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"slowlog-log-slower-than"
)
&&
argc
==
2
)
{
...
...
@@ -686,6 +690,17 @@ void loadServerConfigFromString(char *config) {
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"slowlog-max-len"
)
&&
argc
==
2
)
{
server
.
slowlog_max_len
=
strtoll
(
argv
[
1
],
NULL
,
10
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"tracking-table-max-fill"
)
&&
argc
==
2
)
{
server
.
tracking_table_max_fill
=
strtoll
(
argv
[
1
],
NULL
,
10
);
if
(
server
.
tracking_table_max_fill
>
100
||
server
.
tracking_table_max_fill
<
0
)
{
err
=
"The tracking table fill percentage must be an "
"integer between 0 and 100"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"client-output-buffer-limit"
)
&&
argc
==
5
)
{
...
...
@@ -1133,6 +1148,8 @@ void configSetCommand(client *c) {
"slowlog-max-len"
,
ll
,
0
,
LONG_MAX
)
{
/* Cast to unsigned. */
server
.
slowlog_max_len
=
(
unsigned
long
)
ll
;
}
config_set_numerical_field
(
"tracking-table-max-fill"
,
server
.
tracking_table_max_fill
,
0
,
100
)
{
}
config_set_numerical_field
(
"latency-monitor-threshold"
,
server
.
latency_monitor_threshold
,
0
,
LLONG_MAX
){
}
config_set_numerical_field
(
...
...
@@ -1338,8 +1355,8 @@ void configGetCommand(client *c) {
server
.
slowlog_log_slower_than
);
config_get_numerical_field
(
"latency-monitor-threshold"
,
server
.
latency_monitor_threshold
);
config_get_numerical_field
(
"slowlog-max-len"
,
server
.
slowlog
_max_
len
);
config_get_numerical_field
(
"slowlog-max-len"
,
server
.
slowlog_max_len
);
config_get_numerical_field
(
"tracking-table-max-fill"
,
server
.
tracking_table
_max_
fill
);
config_get_numerical_field
(
"port"
,
server
.
port
);
config_get_numerical_field
(
"cluster-announce-port"
,
server
.
cluster_announce_port
);
config_get_numerical_field
(
"cluster-announce-bus-port"
,
server
.
cluster_announce_bus_port
);
...
...
@@ -1470,12 +1487,10 @@ void configGetCommand(client *c) {
matches
++
;
}
if
(
stringmatch
(
pattern
,
"notify-keyspace-events"
,
1
))
{
robj
*
flagsobj
=
createObject
(
OBJ_STRING
,
keyspaceEventsFlagsToString
(
server
.
notify_keyspace_events
));
sds
flags
=
keyspaceEventsFlagsToString
(
server
.
notify_keyspace_events
);
addReplyBulkCString
(
c
,
"notify-keyspace-events"
);
addReplyBulk
(
c
,
flagsobj
);
decrRefCount
(
flagsobj
);
addReplyBulkSds
(
c
,
flags
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"bind"
,
1
))
{
...
...
@@ -2167,6 +2182,7 @@ int rewriteConfig(char *path) {
rewriteConfigNumericalOption
(
state
,
"slowlog-log-slower-than"
,
server
.
slowlog_log_slower_than
,
CONFIG_DEFAULT_SLOWLOG_LOG_SLOWER_THAN
);
rewriteConfigNumericalOption
(
state
,
"latency-monitor-threshold"
,
server
.
latency_monitor_threshold
,
CONFIG_DEFAULT_LATENCY_MONITOR_THRESHOLD
);
rewriteConfigNumericalOption
(
state
,
"slowlog-max-len"
,
server
.
slowlog_max_len
,
CONFIG_DEFAULT_SLOWLOG_MAX_LEN
);
rewriteConfigNumericalOption
(
state
,
"tracking-table-max-fill"
,
server
.
tracking_table_max_fill
,
CONFIG_DEFAULT_TRACKING_TABLE_MAX_FILL
);
rewriteConfigNotifykeyspaceeventsOption
(
state
);
rewriteConfigNumericalOption
(
state
,
"hash-max-ziplist-entries"
,
server
.
hash_max_ziplist_entries
,
OBJ_HASH_MAX_ZIPLIST_ENTRIES
);
rewriteConfigNumericalOption
(
state
,
"hash-max-ziplist-value"
,
server
.
hash_max_ziplist_value
,
OBJ_HASH_MAX_ZIPLIST_VALUE
);
...
...
src/db.c
View file @
61297585
...
...
@@ -350,6 +350,11 @@ long long emptyDbGeneric(redisDb *dbarray, int dbnum, int flags, void(callback)(
return
-
1
;
}
/* Make sure the WATCHed keys are affected by the FLUSH* commands.
* Note that we need to call the function while the keys are still
* there. */
signalFlushedDb
(
dbnum
);
int
startdb
,
enddb
;
if
(
dbnum
==
-
1
)
{
startdb
=
0
;
...
...
@@ -409,11 +414,12 @@ long long dbTotalServerKeyCount() {
void
signalModifiedKey
(
redisDb
*
db
,
robj
*
key
)
{
touchWatchedKey
(
db
,
key
);
if
(
server
.
tracking_clients
)
trackingInvalidateKey
(
key
);
trackingInvalidateKey
(
key
);
}
void
signalFlushedDb
(
int
dbid
)
{
touchWatchedKeysOnFlush
(
dbid
);
trackingInvalidateKeysOnFlush
(
dbid
);
}
/*-----------------------------------------------------------------------------
...
...
@@ -449,7 +455,6 @@ void flushdbCommand(client *c) {
int
flags
;
if
(
getFlushCommandFlags
(
c
,
&
flags
)
==
C_ERR
)
return
;
signalFlushedDb
(
c
->
db
->
id
);
server
.
dirty
+=
emptyDb
(
c
->
db
->
id
,
flags
,
NULL
);
addReply
(
c
,
shared
.
ok
);
}
...
...
@@ -461,7 +466,6 @@ void flushallCommand(client *c) {
int
flags
;
if
(
getFlushCommandFlags
(
c
,
&
flags
)
==
C_ERR
)
return
;
signalFlushedDb
(
-
1
);
server
.
dirty
+=
emptyDb
(
-
1
,
flags
,
NULL
);
addReply
(
c
,
shared
.
ok
);
if
(
server
.
rdb_child_pid
!=
-
1
)
killRDBChild
();
...
...
src/debug.c
View file @
61297585
...
...
@@ -638,7 +638,8 @@ NULL
dictGetStats
(
buf
,
sizeof
(
buf
),
server
.
db
[
dbid
].
expires
);
stats
=
sdscat
(
stats
,
buf
);
addReplyBulkSds
(
c
,
stats
);
addReplyVerbatim
(
c
,
stats
,
sdslen
(
stats
),
"txt"
);
sdsfree
(
stats
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"htstats-key"
)
&&
c
->
argc
==
3
)
{
robj
*
o
;
dict
*
ht
=
NULL
;
...
...
@@ -665,7 +666,7 @@ NULL
}
else
{
char
buf
[
4096
];
dictGetStats
(
buf
,
sizeof
(
buf
),
ht
);
addReply
BulkCString
(
c
,
buf
);
addReply
Verbatim
(
c
,
buf
,
strlen
(
buf
),
"txt"
);
}
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"change-repl-id"
)
&&
c
->
argc
==
2
)
{
serverLog
(
LL_WARNING
,
"Changing replication IDs after receiving DEBUG change-repl-id"
);
...
...
@@ -1110,6 +1111,33 @@ void logRegisters(ucontext_t *uc) {
(
unsigned
long
)
uc
->
uc_mcontext
.
mc_cs
);
logStackContent
((
void
**
)
uc
->
uc_mcontext
.
mc_rsp
);
#elif defined(__aarch64__)
/* Linux AArch64 */
serverLog
(
LL_WARNING
,
"
\n
"
"X18:%016lx X19:%016lx
\n
X20:%016lx X21:%016lx
\n
"
"X22:%016lx X23:%016lx
\n
X24:%016lx X25:%016lx
\n
"
"X26:%016lx X27:%016lx
\n
X28:%016lx X29:%016lx
\n
"
"X30:%016lx
\n
"
"pc:%016lx sp:%016lx
\n
pstate:%016lx fault_address:%016lx
\n
"
,
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
18
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
19
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
20
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
21
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
22
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
23
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
24
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
25
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
26
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
27
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
28
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
29
],
(
unsigned
long
)
uc
->
uc_mcontext
.
regs
[
30
],
(
unsigned
long
)
uc
->
uc_mcontext
.
pc
,
(
unsigned
long
)
uc
->
uc_mcontext
.
sp
,
(
unsigned
long
)
uc
->
uc_mcontext
.
pstate
,
(
unsigned
long
)
uc
->
uc_mcontext
.
fault_address
);
logStackContent
((
void
**
)
uc
->
uc_mcontext
.
sp
);
#else
serverLog
(
LL_WARNING
,
" Dumping of registers not supported for this OS/arch"
);
...
...
src/expire.c
View file @
61297585
...
...
@@ -64,7 +64,7 @@ int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
dbSyncDelete
(
db
,
keyobj
);
notifyKeyspaceEvent
(
NOTIFY_EXPIRED
,
"expired"
,
keyobj
,
db
->
id
);
if
(
server
.
tracking_clients
)
trackingInvalidateKey
(
keyobj
);
trackingInvalidateKey
(
keyobj
);
decrRefCount
(
keyobj
);
server
.
stat_expiredkeys
++
;
return
1
;
...
...
src/hyperloglog.c
View file @
61297585
...
...
@@ -700,7 +700,7 @@ int hllSparseSet(robj *o, long index, uint8_t count) {
p
+=
oplen
;
first
+=
span
;
}
if
(
span
==
0
)
return
-
1
;
/* Invalid format. */
if
(
span
==
0
||
p
>=
end
)
return
-
1
;
/* Invalid format. */
next
=
HLL_SPARSE_IS_XZERO
(
p
)
?
p
+
2
:
p
+
1
;
if
(
next
>=
end
)
next
=
NULL
;
...
...
@@ -1242,7 +1242,7 @@ void pfcountCommand(client *c) {
if
(
o
==
NULL
)
continue
;
/* Assume empty HLL for non existing var.*/
if
(
isHLLObjectOrReply
(
c
,
o
)
!=
C_OK
)
return
;
/* Merge with this HLL with our 'max' H
H
L by setting max[i]
/* Merge with this HLL with our 'max' H
L
L by setting max[i]
* to MAX(max[i],hll[i]). */
if
(
hllMerge
(
registers
,
o
)
==
C_ERR
)
{
addReplySds
(
c
,
sdsnew
(
invalid_hll_err
));
...
...
@@ -1329,7 +1329,7 @@ void pfmergeCommand(client *c) {
hdr
=
o
->
ptr
;
if
(
hdr
->
encoding
==
HLL_DENSE
)
use_dense
=
1
;
/* Merge with this HLL with our 'max' H
H
L by setting max[i]
/* Merge with this HLL with our 'max' H
L
L by setting max[i]
* to MAX(max[i],hll[i]). */
if
(
hllMerge
(
max
,
o
)
==
C_ERR
)
{
addReplySds
(
c
,
sdsnew
(
invalid_hll_err
));
...
...
src/latency.c
View file @
61297585
...
...
@@ -599,7 +599,7 @@ NULL
event
=
dictGetKey
(
de
);
graph
=
latencyCommandGenSparkeline
(
event
,
ts
);
addReply
BulkCString
(
c
,
graph
);
addReply
Verbatim
(
c
,
graph
,
sdslen
(
graph
),
"txt"
);
sdsfree
(
graph
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"latest"
)
&&
c
->
argc
==
2
)
{
/* LATENCY LATEST */
...
...
@@ -608,7 +608,7 @@ NULL
/* LATENCY DOCTOR */
sds
report
=
createLatencyReport
();
addReply
BulkCBuffer
(
c
,
report
,
sdslen
(
report
));
addReply
Verbatim
(
c
,
report
,
sdslen
(
report
)
,
"txt"
);
sdsfree
(
report
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"reset"
)
&&
c
->
argc
>=
2
)
{
/* LATENCY RESET */
...
...
src/lolwut.c
View file @
61297585
...
...
@@ -43,7 +43,8 @@ void lolwutUnstableCommand(client *c) {
sds
rendered
=
sdsnew
(
"Redis ver. "
);
rendered
=
sdscat
(
rendered
,
REDIS_VERSION
);
rendered
=
sdscatlen
(
rendered
,
"
\n
"
,
1
);
addReplyBulkSds
(
c
,
rendered
);
addReplyVerbatim
(
c
,
rendered
,
sdslen
(
rendered
),
"txt"
);
sdsfree
(
rendered
);
}
void
lolwutCommand
(
client
*
c
)
{
...
...
src/lolwut5.c
View file @
61297585
...
...
@@ -277,6 +277,7 @@ void lolwut5Command(client *c) {
"
\n
Georg Nees - schotter, plotter on paper, 1968. Redis ver. "
);
rendered
=
sdscat
(
rendered
,
REDIS_VERSION
);
rendered
=
sdscatlen
(
rendered
,
"
\n
"
,
1
);
addReplyBulkSds
(
c
,
rendered
);
addReplyVerbatim
(
c
,
rendered
,
sdslen
(
rendered
),
"txt"
);
sdsfree
(
rendered
);
lwFreeCanvas
(
canvas
);
}
src/module.c
View file @
61297585
...
...
@@ -29,6 +29,7 @@
#include "server.h"
#include "cluster.h"
#include "rdb.h"
#include <dlfcn.h>
#include <wait.h>
...
...
@@ -52,6 +53,7 @@ struct RedisModule {
list
*
using
;
/* List of modules we use some APIs of. */
list
*
filters
;
/* List of filters the module has registered. */
int
in_call
;
/* RM_Call() nesting level */
int
options
;
/* Module options and capabilities. */
};
typedef
struct
RedisModule
RedisModule
;
...
...
@@ -780,6 +782,19 @@ long long RM_Milliseconds(void) {
return
mstime
();
}
/* Set flags defining capabilities or behavior bit flags.
*
* REDISMODULE_OPTIONS_HANDLE_IO_ERRORS:
* Generally, modules don't need to bother with this, as the process will just
* terminate if a read error happens, however, setting this flag would allow
* repl-diskless-load to work if enabled.
* The module should use RedisModule_IsIOError after reads, before using the
* data that was read, and in case of error, propagate it upwards, and also be
* able to release the partially populated value and all it's allocations. */
void
RM_SetModuleOptions
(
RedisModuleCtx
*
ctx
,
int
options
)
{
ctx
->
module
->
options
=
options
;
}
/* --------------------------------------------------------------------------
* Automatic memory management for modules
* -------------------------------------------------------------------------- */
...
...
@@ -2397,7 +2412,7 @@ int RM_HashSet(RedisModuleKey *key, int flags, ...) {
*
* REDISMODULE_HASH_EXISTS: instead of setting the value of the field
* expecting a RedisModuleString pointer to pointer, the function just
* reports if the field e
s
ists or not and expects an integer pointer
* reports if the field e
x
ists or not and expects an integer pointer
* as the second element of each pair.
*
* Example of REDISMODULE_HASH_CFIELD:
...
...
@@ -3087,6 +3102,11 @@ moduleType *RM_CreateDataType(RedisModuleCtx *ctx, const char *name, int encver,
moduleTypeMemUsageFunc
mem_usage
;
moduleTypeDigestFunc
digest
;
moduleTypeFreeFunc
free
;
struct
{
moduleTypeAuxLoadFunc
aux_load
;
moduleTypeAuxSaveFunc
aux_save
;
int
aux_save_triggers
;
}
v2
;
}
*
tms
=
(
struct
typemethods
*
)
typemethods_ptr
;
moduleType
*
mt
=
zcalloc
(
sizeof
(
*
mt
));
...
...
@@ -3098,6 +3118,11 @@ moduleType *RM_CreateDataType(RedisModuleCtx *ctx, const char *name, int encver,
mt
->
mem_usage
=
tms
->
mem_usage
;
mt
->
digest
=
tms
->
digest
;
mt
->
free
=
tms
->
free
;
if
(
tms
->
version
>=
2
)
{
mt
->
aux_load
=
tms
->
v2
.
aux_load
;
mt
->
aux_save
=
tms
->
v2
.
aux_save
;
mt
->
aux_save_triggers
=
tms
->
v2
.
aux_save_triggers
;
}
memcpy
(
mt
->
name
,
name
,
sizeof
(
mt
->
name
));
listAddNodeTail
(
ctx
->
module
->
types
,
mt
);
return
mt
;
...
...
@@ -3148,9 +3173,14 @@ void *RM_ModuleTypeGetValue(RedisModuleKey *key) {
* RDB loading and saving functions
* -------------------------------------------------------------------------- */
/* Called when there is a load error in the context of a module. This cannot
* be recovered like for the built-in types. */
/* Called when there is a load error in the context of a module. On some
* modules this cannot be recovered, but if the module declared capability
* to handle errors, we'll raise a flag rather than exiting. */
void
moduleRDBLoadError
(
RedisModuleIO
*
io
)
{
if
(
io
->
ctx
->
module
->
options
&
REDISMODULE_OPTIONS_HANDLE_IO_ERRORS
)
{
io
->
error
=
1
;
return
;
}
serverLog
(
LL_WARNING
,
"Error loading data from RDB (short read or EOF). "
"Read performed by module '%s' about type '%s' "
...
...
@@ -3161,6 +3191,33 @@ void moduleRDBLoadError(RedisModuleIO *io) {
exit
(
1
);
}
/* Returns 0 if there's at least one registered data type that did not declare
* REDISMODULE_OPTIONS_HANDLE_IO_ERRORS, in which case diskless loading should
* be avoided since it could cause data loss. */
int
moduleAllDatatypesHandleErrors
()
{
dictIterator
*
di
=
dictGetIterator
(
modules
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
struct
RedisModule
*
module
=
dictGetVal
(
de
);
if
(
listLength
(
module
->
types
)
&&
!
(
module
->
options
&
REDISMODULE_OPTIONS_HANDLE_IO_ERRORS
))
{
dictReleaseIterator
(
di
);
return
0
;
}
}
dictReleaseIterator
(
di
);
return
1
;
}
/* Returns true if any previous IO API failed.
* for Load* APIs the REDISMODULE_OPTIONS_HANDLE_IO_ERRORS flag must be set with
* RediModule_SetModuleOptions first. */
int
RM_IsIOError
(
RedisModuleIO
*
io
)
{
return
io
->
error
;
}
/* Save an unsigned 64 bit value into the RDB file. This function should only
* be called in the context of the rdb_save method of modules implementing new
* data types. */
...
...
@@ -3184,6 +3241,7 @@ saveerr:
* be called in the context of the rdb_load method of modules implementing
* new data types. */
uint64_t
RM_LoadUnsigned
(
RedisModuleIO
*
io
)
{
if
(
io
->
error
)
return
0
;
if
(
io
->
ver
==
2
)
{
uint64_t
opcode
=
rdbLoadLen
(
io
->
rio
,
NULL
);
if
(
opcode
!=
RDB_MODULE_OPCODE_UINT
)
goto
loaderr
;
...
...
@@ -3195,7 +3253,7 @@ uint64_t RM_LoadUnsigned(RedisModuleIO *io) {
loaderr:
moduleRDBLoadError
(
io
);
return
0
;
/* Never reached. */
return
0
;
}
/* Like RedisModule_SaveUnsigned() but for signed 64 bit values. */
...
...
@@ -3254,6 +3312,7 @@ saveerr:
/* Implements RM_LoadString() and RM_LoadStringBuffer() */
void
*
moduleLoadString
(
RedisModuleIO
*
io
,
int
plain
,
size_t
*
lenptr
)
{
if
(
io
->
error
)
return
NULL
;
if
(
io
->
ver
==
2
)
{
uint64_t
opcode
=
rdbLoadLen
(
io
->
rio
,
NULL
);
if
(
opcode
!=
RDB_MODULE_OPCODE_STRING
)
goto
loaderr
;
...
...
@@ -3265,7 +3324,7 @@ void *moduleLoadString(RedisModuleIO *io, int plain, size_t *lenptr) {
loaderr:
moduleRDBLoadError
(
io
);
return
NULL
;
/* Never reached. */
return
NULL
;
}
/* In the context of the rdb_load method of a module data type, loads a string
...
...
@@ -3286,7 +3345,7 @@ RedisModuleString *RM_LoadString(RedisModuleIO *io) {
* RedisModule_Realloc() or RedisModule_Free().
*
* The size of the string is stored at '*lenptr' if not NULL.
* The returned string is not automatically NULL termi
a
nted, it is loaded
* The returned string is not automatically NULL termin
a
ted, it is loaded
* exactly as it was stored inisde the RDB file. */
char
*
RM_LoadStringBuffer
(
RedisModuleIO
*
io
,
size_t
*
lenptr
)
{
return
moduleLoadString
(
io
,
1
,
lenptr
);
...
...
@@ -3314,6 +3373,7 @@ saveerr:
/* In the context of the rdb_save method of a module data type, loads back the
* double value saved by RedisModule_SaveDouble(). */
double
RM_LoadDouble
(
RedisModuleIO
*
io
)
{
if
(
io
->
error
)
return
0
;
if
(
io
->
ver
==
2
)
{
uint64_t
opcode
=
rdbLoadLen
(
io
->
rio
,
NULL
);
if
(
opcode
!=
RDB_MODULE_OPCODE_DOUBLE
)
goto
loaderr
;
...
...
@@ -3325,7 +3385,7 @@ double RM_LoadDouble(RedisModuleIO *io) {
loaderr:
moduleRDBLoadError
(
io
);
return
0
;
/* Never reached. */
return
0
;
}
/* In the context of the rdb_save method of a module data type, saves a float
...
...
@@ -3350,6 +3410,7 @@ saveerr:
/* In the context of the rdb_save method of a module data type, loads back the
* float value saved by RedisModule_SaveFloat(). */
float
RM_LoadFloat
(
RedisModuleIO
*
io
)
{
if
(
io
->
error
)
return
0
;
if
(
io
->
ver
==
2
)
{
uint64_t
opcode
=
rdbLoadLen
(
io
->
rio
,
NULL
);
if
(
opcode
!=
RDB_MODULE_OPCODE_FLOAT
)
goto
loaderr
;
...
...
@@ -3361,7 +3422,37 @@ float RM_LoadFloat(RedisModuleIO *io) {
loaderr:
moduleRDBLoadError
(
io
);
return
0
;
/* Never reached. */
return
0
;
}
/* Iterate over modules, and trigger rdb aux saving for the ones modules types
* who asked for it. */
ssize_t
rdbSaveModulesAux
(
rio
*
rdb
,
int
when
)
{
size_t
total_written
=
0
;
dictIterator
*
di
=
dictGetIterator
(
modules
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
struct
RedisModule
*
module
=
dictGetVal
(
de
);
listIter
li
;
listNode
*
ln
;
listRewind
(
module
->
types
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
moduleType
*
mt
=
ln
->
value
;
if
(
!
mt
->
aux_save
||
!
(
mt
->
aux_save_triggers
&
when
))
continue
;
ssize_t
ret
=
rdbSaveSingleModuleAux
(
rdb
,
when
,
mt
);
if
(
ret
==-
1
)
{
dictReleaseIterator
(
di
);
return
-
1
;
}
total_written
+=
ret
;
}
}
dictReleaseIterator
(
di
);
return
total_written
;
}
/* --------------------------------------------------------------------------
...
...
@@ -3524,7 +3615,7 @@ void RM_LogRaw(RedisModule *module, const char *levelstr, const char *fmt, va_li
if
(
level
<
server
.
verbosity
)
return
;
name_len
=
snprintf
(
msg
,
sizeof
(
msg
),
"<%s> "
,
module
->
name
);
name_len
=
snprintf
(
msg
,
sizeof
(
msg
),
"<%s> "
,
module
?
module
->
name
:
"module"
);
vsnprintf
(
msg
+
name_len
,
sizeof
(
msg
)
-
name_len
,
fmt
,
ap
);
serverLogRaw
(
level
,
msg
);
}
...
...
@@ -3542,13 +3633,15 @@ void RM_LogRaw(RedisModule *module, const char *levelstr, const char *fmt, va_li
* There is a fixed limit to the length of the log line this function is able
* to emit, this limit is not specified but is guaranteed to be more than
* a few lines of text.
*
* The ctx argument may be NULL if cannot be provided in the context of the
* caller for instance threads or callbacks, in which case a generic "module"
* will be used instead of the module name.
*/
void
RM_Log
(
RedisModuleCtx
*
ctx
,
const
char
*
levelstr
,
const
char
*
fmt
,
...)
{
if
(
!
ctx
->
module
)
return
;
/* Can only log if module is initialized */
va_list
ap
;
va_start
(
ap
,
fmt
);
RM_LogRaw
(
ctx
->
module
,
levelstr
,
fmt
,
ap
);
RM_LogRaw
(
ctx
?
ctx
->
module
:
NULL
,
levelstr
,
fmt
,
ap
);
va_end
(
ap
);
}
...
...
@@ -3564,6 +3657,15 @@ void RM_LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...
va_end
(
ap
);
}
/* Redis-like assert function.
*
* A failed assertion will shut down the server and produce logging information
* that looks identical to information generated by Redis itself.
*/
void
RM__Assert
(
const
char
*
estr
,
const
char
*
file
,
int
line
)
{
_serverAssert
(
estr
,
file
,
line
);
}
/* --------------------------------------------------------------------------
* Blocking clients from modules
* -------------------------------------------------------------------------- */
...
...
@@ -5362,6 +5464,62 @@ void addReplyLoadedModules(client *c) {
dictReleaseIterator
(
di
);
}
/* Helper for genModulesInfoString(): given a list of modules, return
* am SDS string in the form "[modulename|modulename2|...]" */
sds
genModulesInfoStringRenderModulesList
(
list
*
l
)
{
listIter
li
;
listNode
*
ln
;
listRewind
(
l
,
&
li
);
sds
output
=
sdsnew
(
"["
);
while
((
ln
=
listNext
(
&
li
)))
{
RedisModule
*
module
=
ln
->
value
;
output
=
sdscat
(
output
,
module
->
name
);
}
output
=
sdstrim
(
output
,
"|"
);
output
=
sdscat
(
output
,
"]"
);
return
output
;
}
/* Helper for genModulesInfoString(): render module options as an SDS string. */
sds
genModulesInfoStringRenderModuleOptions
(
struct
RedisModule
*
module
)
{
sds
output
=
sdsnew
(
"["
);
if
(
module
->
options
&
REDISMODULE_OPTIONS_HANDLE_IO_ERRORS
)
output
=
sdscat
(
output
,
"handle-io-errors|"
);
output
=
sdstrim
(
output
,
"|"
);
output
=
sdscat
(
output
,
"]"
);
return
output
;
}
/* Helper function for the INFO command: adds loaded modules as to info's
* output.
*
* After the call, the passed sds info string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds
genModulesInfoString
(
sds
info
)
{
dictIterator
*
di
=
dictGetIterator
(
modules
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
sds
name
=
dictGetKey
(
de
);
struct
RedisModule
*
module
=
dictGetVal
(
de
);
sds
usedby
=
genModulesInfoStringRenderModulesList
(
module
->
usedby
);
sds
using
=
genModulesInfoStringRenderModulesList
(
module
->
using
);
sds
options
=
genModulesInfoStringRenderModuleOptions
(
module
);
info
=
sdscatprintf
(
info
,
"module:name=%s,ver=%d,api=%d,filters=%d,"
"usedby=%s,using=%s,options=%s
\r\n
"
,
name
,
module
->
ver
,
module
->
apiver
,
(
int
)
listLength
(
module
->
filters
),
usedby
,
using
,
options
);
sdsfree
(
usedby
);
sdsfree
(
using
);
sdsfree
(
options
);
}
dictReleaseIterator
(
di
);
return
info
;
}
/* Redis MODULE command.
*
* MODULE LOAD <path> [args...] */
...
...
@@ -5447,6 +5605,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
ReplySetArrayLength
);
REGISTER_API
(
ReplyWithString
);
REGISTER_API
(
ReplyWithStringBuffer
);
REGISTER_API
(
ReplyWithCString
);
REGISTER_API
(
ReplyWithNull
);
REGISTER_API
(
ReplyWithCallReply
);
REGISTER_API
(
ReplyWithDouble
);
...
...
@@ -5509,6 +5668,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
ModuleTypeSetValue
);
REGISTER_API
(
ModuleTypeGetType
);
REGISTER_API
(
ModuleTypeGetValue
);
REGISTER_API
(
IsIOError
);
REGISTER_API
(
SetModuleOptions
);
REGISTER_API
(
SaveUnsigned
);
REGISTER_API
(
LoadUnsigned
);
REGISTER_API
(
SaveSigned
);
...
...
@@ -5524,6 +5685,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
EmitAOF
);
REGISTER_API
(
Log
);
REGISTER_API
(
LogIOError
);
REGISTER_API
(
_Assert
);
REGISTER_API
(
StringAppendBuffer
);
REGISTER_API
(
RetainString
);
REGISTER_API
(
StringCompare
);
...
...
src/multi.c
View file @
61297585
...
...
@@ -175,7 +175,19 @@ void execCommand(client *c) {
must_propagate
=
1
;
}
call
(
c
,
server
.
loading
?
CMD_CALL_NONE
:
CMD_CALL_FULL
);
int
acl_retval
=
ACLCheckCommandPerm
(
c
);
if
(
acl_retval
!=
ACL_OK
)
{
addReplyErrorFormat
(
c
,
"-NOPERM ACLs rules changed between the moment the "
"transaction was accumulated and the EXEC call. "
"This command is no longer allowed for the "
"following reason: %s"
,
(
acl_retval
==
ACL_DENIED_CMD
)
?
"no permission to execute the command or subcommand"
:
"no permission to touch the specified keys"
);
}
else
{
call
(
c
,
server
.
loading
?
CMD_CALL_NONE
:
CMD_CALL_FULL
);
}
/* Commands may alter argc/argv, restore mstate. */
c
->
mstate
.
commands
[
j
].
argc
=
c
->
argc
;
...
...
src/networking.c
View file @
61297585
...
...
@@ -1990,7 +1990,7 @@ NULL
return
;
}
sds
o
=
getAllClientsInfoString
(
type
);
addReply
BulkCBuffer
(
c
,
o
,
sdslen
(
o
));
addReply
Verbatim
(
c
,
o
,
sdslen
(
o
)
,
"txt"
);
sdsfree
(
o
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"reply"
)
&&
c
->
argc
==
3
)
{
/* CLIENT REPLY ON|OFF|SKIP */
...
...
@@ -2468,17 +2468,27 @@ void flushSlavesOutputBuffers(void) {
listRewind
(
server
.
slaves
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
client
*
slave
=
listNodeValue
(
ln
);
int
events
;
/* Note that the following will not flush output buffers of slaves
* in STATE_ONLINE but having put_online_on_ack set to true: in this
* case the writable event is never installed, since the purpose
* of put_online_on_ack is to postpone the moment it is installed.
* This is what we want since slaves in this state should not receive
* writes before the first ACK. */
events
=
aeGetFileEvents
(
server
.
el
,
slave
->
fd
);
if
(
events
&
AE_WRITABLE
&&
slave
->
replstate
==
SLAVE_STATE_ONLINE
&&
int
events
=
aeGetFileEvents
(
server
.
el
,
slave
->
fd
);
int
can_receive_writes
=
(
events
&
AE_WRITABLE
)
||
(
slave
->
flags
&
CLIENT_PENDING_WRITE
);
/* We don't want to send the pending data to the replica in a few
* cases:
*
* 1. For some reason there is neither the write handler installed
* nor the client is flagged as to have pending writes: for some
* reason this replica may not be set to receive data. This is
* just for the sake of defensive programming.
*
* 2. The put_online_on_ack flag is true. To know why we don't want
* to send data to the replica in this case, please grep for the
* flag for this flag.
*
* 3. Obviously if the slave is not ONLINE.
*/
if
(
slave
->
replstate
==
SLAVE_STATE_ONLINE
&&
can_receive_writes
&&
!
slave
->
repl_put_online_on_ack
&&
clientHasPendingReplies
(
slave
))
{
writeToClient
(
slave
->
fd
,
slave
,
0
);
...
...
src/object.c
View file @
61297585
...
...
@@ -467,10 +467,15 @@ robj *tryObjectEncoding(robj *o) {
incrRefCount
(
shared
.
integers
[
value
]);
return
shared
.
integers
[
value
];
}
else
{
if
(
o
->
encoding
==
OBJ_ENCODING_RAW
)
sdsfree
(
o
->
ptr
);
o
->
encoding
=
OBJ_ENCODING_INT
;
o
->
ptr
=
(
void
*
)
value
;
return
o
;
if
(
o
->
encoding
==
OBJ_ENCODING_RAW
)
{
sdsfree
(
o
->
ptr
);
o
->
encoding
=
OBJ_ENCODING_INT
;
o
->
ptr
=
(
void
*
)
value
;
return
o
;
}
else
if
(
o
->
encoding
==
OBJ_ENCODING_EMBSTR
)
{
decrRefCount
(
o
);
return
createStringObjectFromLongLongForValue
(
value
);
}
}
}
...
...
@@ -1435,13 +1440,15 @@ NULL
#if defined(USE_JEMALLOC)
sds
info
=
sdsempty
();
je_malloc_stats_print
(
inputCatSds
,
&
info
,
NULL
);
addReplyBulkSds
(
c
,
info
);
addReplyVerbatim
(
c
,
info
,
sdslen
(
info
),
"txt"
);
sdsfree
(
info
);
#else
addReplyBulkCString
(
c
,
"Stats not supported for the current allocator"
);
#endif
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"doctor"
)
&&
c
->
argc
==
2
)
{
sds
report
=
getMemoryDoctorReport
();
addReplyBulkSds
(
c
,
report
);
addReplyVerbatim
(
c
,
report
,
sdslen
(
report
),
"txt"
);
sdsfree
(
report
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"purge"
)
&&
c
->
argc
==
2
)
{
#if defined(USE_JEMALLOC)
char
tmp
[
32
];
...
...
src/rdb.c
View file @
61297585
This diff is collapsed.
Click to expand it.
src/rdb.h
View file @
61297585
...
...
@@ -145,6 +145,7 @@ size_t rdbSavedObjectLen(robj *o);
robj
*
rdbLoadObject
(
int
type
,
rio
*
rdb
,
robj
*
key
);
void
backgroundSaveDoneHandler
(
int
exitcode
,
int
bysignal
);
int
rdbSaveKeyValuePair
(
rio
*
rdb
,
robj
*
key
,
robj
*
val
,
long
long
expiretime
);
ssize_t
rdbSaveSingleModuleAux
(
rio
*
rdb
,
int
when
,
moduleType
*
mt
);
robj
*
rdbLoadStringObject
(
rio
*
rdb
);
ssize_t
rdbSaveStringObject
(
rio
*
rdb
,
robj
*
obj
);
ssize_t
rdbSaveRawString
(
rio
*
rdb
,
unsigned
char
*
s
,
size_t
len
);
...
...
src/redis-benchmark.c
View file @
61297585
...
...
@@ -104,6 +104,7 @@ static struct 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
;
...
...
@@ -255,7 +256,7 @@ static redisConfig *getRedisConfig(const char *ip, int port,
goto
fail
;
}
if
(
config
.
auth
){
if
(
config
.
auth
)
{
void
*
authReply
=
NULL
;
redisAppendCommand
(
c
,
"AUTH %s"
,
config
.
auth
);
if
(
REDIS_OK
!=
redisGetReply
(
c
,
&
authReply
))
goto
fail
;
...
...
@@ -633,6 +634,14 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) {
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
...
...
@@ -1350,6 +1359,8 @@ int parseOptions(int argc, const char **argv) {
}
else
if
(
config
.
num_threads
<
0
)
config
.
num_threads
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--cluster"
))
{
config
.
cluster_mode
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--enable-tracking"
))
{
config
.
enable_tracking
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--help"
))
{
exit_status
=
0
;
goto
usage
;
...
...
@@ -1380,6 +1391,7 @@ usage:
" --dbnum <db> SELECT the specified db number (default 0)
\n
"
" --threads <num> Enable multi-thread mode.
\n
"
" --cluster Enable cluster mode.
\n
"
" --enable-tracking Send CLIENT TRACKING on before starting benchmark.
\n
"
" -k <boolean> 1=keep alive 0=reconnect (default 1)
\n
"
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
\n
"
" Using this option the benchmark will expand the string __rand_int__
\n
"
...
...
@@ -1504,6 +1516,7 @@ int main(int argc, const char **argv) {
config
.
is_fetching_slots
=
0
;
config
.
is_updating_slots
=
0
;
config
.
slots_last_update
=
0
;
config
.
enable_tracking
=
0
;
i
=
parseOptions
(
argc
,
argv
);
argc
-=
i
;
...
...
src/redis-check-rdb.c
View file @
61297585
...
...
@@ -216,14 +216,16 @@ int redis_check_rdb(char *rdbfilename, FILE *fp) {
/* EXPIRETIME: load an expire associated with the next key
* to load. Note that after loading an expire we need to
* load the actual type, and continue. */
if
((
expiretime
=
rdbLoadTime
(
&
rdb
)
)
==
-
1
)
goto
eoferr
;
expiretime
=
rdbLoadTime
(
&
rdb
);
expiretime
*=
1000
;
if
(
rioGetReadError
(
&
rdb
))
goto
eoferr
;
continue
;
/* Read next opcode. */
}
else
if
(
type
==
RDB_OPCODE_EXPIRETIME_MS
)
{
/* EXPIRETIME_MS: milliseconds precision expire times introduced
* with RDB v3. Like EXPIRETIME but no with more precision. */
rdbstate
.
doing
=
RDB_CHECK_DOING_READ_EXPIRE
;
if
((
expiretime
=
rdbLoadMillisecondTime
(
&
rdb
,
rdbver
))
==
-
1
)
goto
eoferr
;
expiretime
=
rdbLoadMillisecondTime
(
&
rdb
,
rdbver
);
if
(
rioGetReadError
(
&
rdb
))
goto
eoferr
;
continue
;
/* Read next opcode. */
}
else
if
(
type
==
RDB_OPCODE_FREQ
)
{
/* FREQ: LFU frequency. */
...
...
src/redis-cli.c
View file @
61297585
This diff is collapsed.
Click to expand it.
src/redismodule.h
View file @
61297585
This diff is collapsed.
Click to expand it.
src/replication.c
View file @
61297585
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment