Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
d5c14c70
Commit
d5c14c70
authored
Sep 30, 2019
by
Oran Agra
Browse files
Merge remote-tracking branch 'antirez/unstable' into modules_info
parents
61853ad8
a9628142
Changes
84
Expand all
Show whitespace changes
Inline
Side-by-side
src/cluster.c
View file @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -60,10 +60,7 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
/* Update the access time for the ageing algorithm.
* Don't do it if we have a saving child, as this will trigger
* a copy on write madness. */
if
(
server
.
rdb_child_pid
==
-
1
&&
server
.
aof_child_pid
==
-
1
&&
!
(
flags
&
LOOKUP_NOTOUCH
))
{
if
(
!
hasActiveChildProcess
()
&&
!
(
flags
&
LOOKUP_NOTOUCH
)){
if
(
server
.
maxmemory_policy
&
MAXMEMORY_FLAG_LFU
)
{
updateLFU
(
val
);
}
else
{
...
...
@@ -353,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
;
...
...
@@ -412,12 +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
);
if
(
server
.
tracking_clients
)
trackingInvalidateKeysOnFlush
(
dbid
);
trackingInvalidateKeysOnFlush
(
dbid
);
}
/*-----------------------------------------------------------------------------
...
...
@@ -453,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
);
}
...
...
@@ -465,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 @
d5c14c70
...
...
@@ -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/defrag.c
View file @
d5c14c70
...
...
@@ -1039,7 +1039,7 @@ void activeDefragCycle(void) {
mstime_t
latency
;
int
quit
=
0
;
if
(
server
.
aof_child_pid
!=-
1
||
server
.
rdb_child_pid
!=-
1
)
if
(
hasActiveChildProcess
()
)
return
;
/* Defragging memory while there's a fork will just do damage. */
/* Once a second, check if we the fragmentation justfies starting a scan
...
...
src/expire.c
View file @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -29,7 +29,9 @@
#include "server.h"
#include "cluster.h"
#include "rdb.h"
#include <dlfcn.h>
#include <sys/wait.h>
#define REDISMODULE_CORE 1
#include "redismodule.h"
...
...
@@ -62,6 +64,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. */
RedisModuleInfoFunc
info_cb
;
/* callback for module to add INFO fields. */
};
typedef
struct
RedisModule
RedisModule
;
...
...
@@ -303,6 +306,14 @@ typedef struct RedisModuleCommandFilter {
/* Registered filters */
static
list
*
moduleCommandFilters
;
typedef
void
(
*
RedisModuleForkDoneHandler
)
(
int
exitcode
,
int
bysignal
,
void
*
user_data
);
static
struct
RedisModuleForkInfo
{
RedisModuleForkDoneHandler
done_handler
;
void
*
done_handler_user_data
;
}
moduleForkInfo
=
{
0
};
/* --------------------------------------------------------------------------
* Prototypes
* -------------------------------------------------------------------------- */
...
...
@@ -783,6 +794,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
* -------------------------------------------------------------------------- */
...
...
@@ -1137,10 +1161,9 @@ int RM_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll) {
int
replyWithStatus
(
RedisModuleCtx
*
ctx
,
const
char
*
msg
,
char
*
prefix
)
{
client
*
c
=
moduleGetReplyClient
(
ctx
);
if
(
c
==
NULL
)
return
REDISMODULE_OK
;
sds
strmsg
=
sdsnewlen
(
prefix
,
1
);
strmsg
=
sdscat
(
strmsg
,
msg
);
strmsg
=
sdscatlen
(
strmsg
,
"
\r\n
"
,
2
);
addReplySds
(
c
,
strmsg
);
addReplyProto
(
c
,
prefix
,
strlen
(
prefix
));
addReplyProto
(
c
,
msg
,
strlen
(
msg
));
addReplyProto
(
c
,
"
\r\n
"
,
2
);
return
REDISMODULE_OK
;
}
...
...
@@ -2400,7 +2423,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:
...
...
@@ -3090,6 +3113,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
));
...
...
@@ -3101,6 +3129,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
;
...
...
@@ -3151,9 +3184,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
->
type
->
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' "
...
...
@@ -3164,6 +3202,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. */
...
...
@@ -3187,6 +3252,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
;
...
...
@@ -3198,7 +3264,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. */
...
...
@@ -3257,6 +3323,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
;
...
...
@@ -3268,7 +3335,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
...
...
@@ -3289,7 +3356,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
);
...
...
@@ -3317,6 +3384,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
;
...
...
@@ -3328,7 +3396,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
...
...
@@ -3353,6 +3421,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
;
...
...
@@ -3364,7 +3433,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
;
}
/* --------------------------------------------------------------------------
...
...
@@ -3527,7 +3626,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
);
}
...
...
@@ -3545,13 +3644,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
);
}
...
...
@@ -3567,6 +3668,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
* -------------------------------------------------------------------------- */
...
...
@@ -5125,6 +5235,8 @@ int RM_UnregisterCommandFilter(RedisModuleCtx *ctx, RedisModuleCommandFilter *fi
if
(
!
ln
)
return
REDISMODULE_ERR
;
/* Shouldn't happen */
listDelNode
(
ctx
->
module
->
filters
,
ln
);
zfree
(
filter
);
return
REDISMODULE_OK
;
}
...
...
@@ -5228,6 +5340,100 @@ int RM_CommandFilterArgDelete(RedisModuleCommandFilterCtx *fctx, int pos)
return
REDISMODULE_OK
;
}
/* --------------------------------------------------------------------------
* Module fork API
* -------------------------------------------------------------------------- */
/* Create a background child process with the current frozen snaphost of the
* main process where you can do some processing in the background without
* affecting / freezing the traffic and no need for threads and GIL locking.
* Note that Redis allows for only one concurrent fork.
* When the child wants to exit, it should call RedisModule_ExitFromChild.
* If the parent wants to kill the child it should call RedisModule_KillForkChild
* The done handler callback will be executed on the parent process when the
* child existed (but not when killed)
* Return: -1 on failure, on success the parent process will get a positive PID
* of the child, and the child process will get 0.
*/
int
RM_Fork
(
RedisModuleForkDoneHandler
cb
,
void
*
user_data
)
{
pid_t
childpid
;
if
(
hasActiveChildProcess
())
{
return
-
1
;
}
openChildInfoPipe
();
if
((
childpid
=
redisFork
())
==
0
)
{
/* Child */
redisSetProcTitle
(
"redis-module-fork"
);
}
else
if
(
childpid
==
-
1
)
{
closeChildInfoPipe
();
serverLog
(
LL_WARNING
,
"Can't fork for module: %s"
,
strerror
(
errno
));
}
else
{
/* Parent */
server
.
module_child_pid
=
childpid
;
moduleForkInfo
.
done_handler
=
cb
;
moduleForkInfo
.
done_handler_user_data
=
user_data
;
serverLog
(
LL_NOTICE
,
"Module fork started pid: %d "
,
childpid
);
}
return
childpid
;
}
/* Call from the child process when you want to terminate it.
* retcode will be provided to the done handler executed on the parent process.
*/
int
RM_ExitFromChild
(
int
retcode
)
{
sendChildCOWInfo
(
CHILD_INFO_TYPE_MODULE
,
"Module fork"
);
exitFromChild
(
retcode
);
return
REDISMODULE_OK
;
}
/* Kill the active module forked child, if there is one active and the
* pid matches, and returns C_OK. Otherwise if there is no active module
* child or the pid does not match, return C_ERR without doing anything. */
int
TerminateModuleForkChild
(
int
child_pid
,
int
wait
)
{
/* Module child should be active and pid should match. */
if
(
server
.
module_child_pid
==
-
1
||
server
.
module_child_pid
!=
child_pid
)
return
C_ERR
;
int
statloc
;
serverLog
(
LL_NOTICE
,
"Killing running module fork child: %ld"
,
(
long
)
server
.
module_child_pid
);
if
(
kill
(
server
.
module_child_pid
,
SIGUSR1
)
!=
-
1
&&
wait
)
{
while
(
wait4
(
server
.
module_child_pid
,
&
statloc
,
0
,
NULL
)
!=
server
.
module_child_pid
);
}
/* Reset the buffer accumulating changes while the child saves. */
server
.
module_child_pid
=
-
1
;
moduleForkInfo
.
done_handler
=
NULL
;
moduleForkInfo
.
done_handler_user_data
=
NULL
;
closeChildInfoPipe
();
updateDictResizePolicy
();
return
C_OK
;
}
/* Can be used to kill the forked child process from the parent process.
* child_pid whould be the return value of RedisModule_Fork. */
int
RM_KillForkChild
(
int
child_pid
)
{
/* Kill module child, wait for child exit. */
if
(
TerminateModuleForkChild
(
child_pid
,
1
)
==
C_OK
)
return
REDISMODULE_OK
;
else
return
REDISMODULE_ERR
;
}
void
ModuleForkDoneHandler
(
int
exitcode
,
int
bysignal
)
{
serverLog
(
LL_NOTICE
,
"Module fork exited pid: %d, retcode: %d, bysignal: %d"
,
server
.
module_child_pid
,
exitcode
,
bysignal
);
if
(
moduleForkInfo
.
done_handler
)
{
moduleForkInfo
.
done_handler
(
exitcode
,
bysignal
,
moduleForkInfo
.
done_handler_user_data
);
}
server
.
module_child_pid
=
-
1
;
moduleForkInfo
.
done_handler
=
NULL
;
moduleForkInfo
.
done_handler_user_data
=
NULL
;
}
/* --------------------------------------------------------------------------
* Modules API internals
* -------------------------------------------------------------------------- */
...
...
@@ -5327,6 +5533,8 @@ void moduleLoadFromQueue(void) {
void
moduleFreeModuleStructure
(
struct
RedisModule
*
module
)
{
listRelease
(
module
->
types
);
listRelease
(
module
->
filters
);
listRelease
(
module
->
usedby
);
listRelease
(
module
->
using
);
sdsfree
(
module
->
name
);
zfree
(
module
);
}
...
...
@@ -5461,6 +5669,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...] */
...
...
@@ -5546,6 +5810,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
);
...
...
@@ -5608,6 +5873,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
);
...
...
@@ -5623,6 +5890,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
);
...
...
@@ -5690,6 +5958,9 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
CommandFilterArgInsert
);
REGISTER_API
(
CommandFilterArgReplace
);
REGISTER_API
(
CommandFilterArgDelete
);
REGISTER_API
(
Fork
);
REGISTER_API
(
ExitFromChild
);
REGISTER_API
(
KillForkChild
);
REGISTER_API
(
RegisterInfoFunc
);
REGISTER_API
(
InfoAddSection
);
REGISTER_API
(
InfoBeginDictField
);
...
...
src/multi.c
View file @
d5c14c70
...
...
@@ -175,7 +175,19 @@ void execCommand(client *c) {
must_propagate
=
1
;
}
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 @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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
);
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 @
d5c14c70
This diff is collapsed.
Click to expand it.
src/rdb.h
View file @
d5c14c70
...
...
@@ -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 @
d5c14c70
...
...
@@ -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-cli.c
View file @
d5c14c70
This diff is collapsed.
Click to expand it.
src/redismodule.h
View file @
d5c14c70
...
...
@@ -129,6 +129,10 @@
#define REDISMODULE_NOT_USED(V) ((void) V)
/* Bit flags for aux_save_triggers and the aux_load and aux_save callbacks */
#define REDISMODULE_AUX_BEFORE_RDB (1<<0)
#define REDISMODULE_AUX_AFTER_RDB (1<<1)
/* This type represents a timer handle, and is returned when a timer is
* registered and used in order to invalidate a timer. It's just a 64 bit
* number, because this is how each timer is represented inside the radix tree
...
...
@@ -140,6 +144,9 @@ typedef uint64_t RedisModuleTimerID;
/* Do filter RedisModule_Call() commands initiated by module itself. */
#define REDISMODULE_CMDFILTER_NOSELF (1<<0)
/* Declare that the module can handle errors with RedisModule_SetModuleOptions. */
#define REDISMODULE_OPTIONS_HANDLE_IO_ERRORS (1<<0)
/* ------------------------- End of common defines ------------------------ */
#ifndef REDISMODULE_CORE
...
...
@@ -167,6 +174,8 @@ typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlocke
typedef
int
(
*
RedisModuleNotificationFunc
)(
RedisModuleCtx
*
ctx
,
int
type
,
const
char
*
event
,
RedisModuleString
*
key
);
typedef
void
*
(
*
RedisModuleTypeLoadFunc
)(
RedisModuleIO
*
rdb
,
int
encver
);
typedef
void
(
*
RedisModuleTypeSaveFunc
)(
RedisModuleIO
*
rdb
,
void
*
value
);
typedef
int
(
*
RedisModuleTypeAuxLoadFunc
)(
RedisModuleIO
*
rdb
,
int
encver
,
int
when
);
typedef
void
(
*
RedisModuleTypeAuxSaveFunc
)(
RedisModuleIO
*
rdb
,
int
when
);
typedef
void
(
*
RedisModuleTypeRewriteFunc
)(
RedisModuleIO
*
aof
,
RedisModuleString
*
key
,
void
*
value
);
typedef
size_t
(
*
RedisModuleTypeMemUsageFunc
)(
const
void
*
value
);
typedef
void
(
*
RedisModuleTypeDigestFunc
)(
RedisModuleDigest
*
digest
,
void
*
value
);
...
...
@@ -174,9 +183,10 @@ typedef void (*RedisModuleTypeFreeFunc)(void *value);
typedef
void
(
*
RedisModuleClusterMessageReceiver
)(
RedisModuleCtx
*
ctx
,
const
char
*
sender_id
,
uint8_t
type
,
const
unsigned
char
*
payload
,
uint32_t
len
);
typedef
void
(
*
RedisModuleTimerProc
)(
RedisModuleCtx
*
ctx
,
void
*
data
);
typedef
void
(
*
RedisModuleCommandFilterFunc
)
(
RedisModuleCommandFilterCtx
*
filter
);
typedef
void
(
*
RedisModuleForkDoneHandler
)
(
int
exitcode
,
int
bysignal
,
void
*
user_data
);
typedef
void
(
*
RedisModuleInfoFunc
)(
RedisModuleInfoCtx
*
ctx
,
int
for_crash_report
);
#define REDISMODULE_TYPE_METHOD_VERSION
1
#define REDISMODULE_TYPE_METHOD_VERSION
2
typedef
struct
RedisModuleTypeMethods
{
uint64_t
version
;
RedisModuleTypeLoadFunc
rdb_load
;
...
...
@@ -185,6 +195,9 @@ typedef struct RedisModuleTypeMethods {
RedisModuleTypeMemUsageFunc
mem_usage
;
RedisModuleTypeDigestFunc
digest
;
RedisModuleTypeFreeFunc
free
;
RedisModuleTypeAuxLoadFunc
aux_load
;
RedisModuleTypeAuxSaveFunc
aux_save
;
int
aux_save_triggers
;
}
RedisModuleTypeMethods
;
#define REDISMODULE_GET_API(name) \
...
...
@@ -273,6 +286,8 @@ RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx
int
REDISMODULE_API_FUNC
(
RedisModule_ModuleTypeSetValue
)(
RedisModuleKey
*
key
,
RedisModuleType
*
mt
,
void
*
value
);
RedisModuleType
*
REDISMODULE_API_FUNC
(
RedisModule_ModuleTypeGetType
)(
RedisModuleKey
*
key
);
void
*
REDISMODULE_API_FUNC
(
RedisModule_ModuleTypeGetValue
)(
RedisModuleKey
*
key
);
int
REDISMODULE_API_FUNC
(
RedisModule_IsIOError
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_SetModuleOptions
)(
RedisModuleCtx
*
ctx
,
int
options
);
void
REDISMODULE_API_FUNC
(
RedisModule_SaveUnsigned
)(
RedisModuleIO
*
io
,
uint64_t
value
);
uint64_t
REDISMODULE_API_FUNC
(
RedisModule_LoadUnsigned
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_SaveSigned
)(
RedisModuleIO
*
io
,
int64_t
value
);
...
...
@@ -288,6 +303,7 @@ void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value)
float
REDISMODULE_API_FUNC
(
RedisModule_LoadFloat
)(
RedisModuleIO
*
io
);
void
REDISMODULE_API_FUNC
(
RedisModule_Log
)(
RedisModuleCtx
*
ctx
,
const
char
*
level
,
const
char
*
fmt
,
...);
void
REDISMODULE_API_FUNC
(
RedisModule_LogIOError
)(
RedisModuleIO
*
io
,
const
char
*
levelstr
,
const
char
*
fmt
,
...);
void
REDISMODULE_API_FUNC
(
RedisModule__Assert
)(
const
char
*
estr
,
const
char
*
file
,
int
line
);
int
REDISMODULE_API_FUNC
(
RedisModule_StringAppendBuffer
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
,
const
char
*
buf
,
size_t
len
);
void
REDISMODULE_API_FUNC
(
RedisModule_RetainString
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
);
int
REDISMODULE_API_FUNC
(
RedisModule_StringCompare
)(
RedisModuleString
*
a
,
RedisModuleString
*
b
);
...
...
@@ -368,6 +384,9 @@ const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CommandFilterArgGet)(R
int
REDISMODULE_API_FUNC
(
RedisModule_CommandFilterArgInsert
)(
RedisModuleCommandFilterCtx
*
fctx
,
int
pos
,
RedisModuleString
*
arg
);
int
REDISMODULE_API_FUNC
(
RedisModule_CommandFilterArgReplace
)(
RedisModuleCommandFilterCtx
*
fctx
,
int
pos
,
RedisModuleString
*
arg
);
int
REDISMODULE_API_FUNC
(
RedisModule_CommandFilterArgDelete
)(
RedisModuleCommandFilterCtx
*
fctx
,
int
pos
);
int
REDISMODULE_API_FUNC
(
RedisModule_Fork
)(
RedisModuleForkDoneHandler
cb
,
void
*
user_data
);
int
REDISMODULE_API_FUNC
(
RedisModule_ExitFromChild
)(
int
retcode
);
int
REDISMODULE_API_FUNC
(
RedisModule_KillForkChild
)(
int
child_pid
);
#endif
/* This is included inline inside each Redis module. */
...
...
@@ -455,6 +474,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
ModuleTypeSetValue
);
REDISMODULE_GET_API
(
ModuleTypeGetType
);
REDISMODULE_GET_API
(
ModuleTypeGetValue
);
REDISMODULE_GET_API
(
IsIOError
);
REDISMODULE_GET_API
(
SetModuleOptions
);
REDISMODULE_GET_API
(
SaveUnsigned
);
REDISMODULE_GET_API
(
LoadUnsigned
);
REDISMODULE_GET_API
(
SaveSigned
);
...
...
@@ -470,6 +491,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
EmitAOF
);
REDISMODULE_GET_API
(
Log
);
REDISMODULE_GET_API
(
LogIOError
);
REDISMODULE_GET_API
(
_Assert
);
REDISMODULE_GET_API
(
StringAppendBuffer
);
REDISMODULE_GET_API
(
RetainString
);
REDISMODULE_GET_API
(
StringCompare
);
...
...
@@ -548,6 +570,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
CommandFilterArgInsert
);
REDISMODULE_GET_API
(
CommandFilterArgReplace
);
REDISMODULE_GET_API
(
CommandFilterArgDelete
);
REDISMODULE_GET_API
(
Fork
);
REDISMODULE_GET_API
(
ExitFromChild
);
REDISMODULE_GET_API
(
KillForkChild
);
#endif
if
(
RedisModule_IsModuleNameBusy
&&
RedisModule_IsModuleNameBusy
(
name
))
return
REDISMODULE_ERR
;
...
...
@@ -555,6 +580,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
return
REDISMODULE_OK
;
}
#define RedisModule_Assert(_e) ((_e)?(void)0 : (RedisModule__Assert(#_e,__FILE__,__LINE__),exit(1)))
#else
/* Things only defined for the modules core, not exported to modules
...
...
src/replication.c
View file @
d5c14c70
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