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
b9394558
Unverified
Commit
b9394558
authored
Nov 21, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Nov 21, 2019
Browse files
Merge pull request #6530 from oranagra/rm_get_server_info
Add module api for looking into INFO fields
parents
f1f259de
64c2508e
Changes
10
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
b9394558
...
...
@@ -41,7 +41,7 @@
typedef
struct
RedisModuleInfoCtx
{
struct
RedisModule
*
module
;
sds
requested_section
;
const
char
*
requested_section
;
sds
info
;
/* info string we collected so far */
int
sections
;
/* number of sections we collected so far */
int
in_section
;
/* indication if we're in an active section or not */
...
...
@@ -93,6 +93,7 @@ struct AutoMemEntry {
#define REDISMODULE_AM_REPLY 2
#define REDISMODULE_AM_FREED 3
/* Explicitly freed by user already. */
#define REDISMODULE_AM_DICT 4
#define REDISMODULE_AM_INFO 5
/* The pool allocator block. Redis Modules can allocate memory via this special
* allocator that will automatically release it all once the callback returns.
...
...
@@ -322,6 +323,10 @@ static struct RedisModuleForkInfo {
void
*
done_handler_user_data
;
}
moduleForkInfo
=
{
0
};
typedef
struct
RedisModuleServerInfoData
{
rax
*
rax
;
/* parsed info data. */
}
RedisModuleServerInfoData
;
/* Flags for moduleCreateArgvFromUserFormat(). */
#define REDISMODULE_ARGV_REPLICATE (1<<0)
#define REDISMODULE_ARGV_NO_AOF (1<<1)
...
...
@@ -361,6 +366,7 @@ void moduleReplicateMultiIfNeeded(RedisModuleCtx *ctx);
void
RM_ZsetRangeStop
(
RedisModuleKey
*
kp
);
static
void
zsetKeyReset
(
RedisModuleKey
*
key
);
void
RM_FreeDict
(
RedisModuleCtx
*
ctx
,
RedisModuleDict
*
d
);
void
RM_FreeServerInfo
(
RedisModuleCtx
*
ctx
,
RedisModuleServerInfoData
*
data
);
/* --------------------------------------------------------------------------
* Heap allocation raw functions
...
...
@@ -947,6 +953,7 @@ void autoMemoryCollect(RedisModuleCtx *ctx) {
case
REDISMODULE_AM_REPLY
:
RM_FreeCallReply
(
ptr
);
break
;
case
REDISMODULE_AM_KEY
:
RM_CloseKey
(
ptr
);
break
;
case
REDISMODULE_AM_DICT
:
RM_FreeDict
(
NULL
,
ptr
);
break
;
case
REDISMODULE_AM_INFO
:
RM_FreeServerInfo
(
NULL
,
ptr
);
break
;
}
}
ctx
->
flags
|=
REDISMODULE_CTX_AUTO_MEMORY
;
...
...
@@ -5634,7 +5641,7 @@ int RM_RegisterInfoFunc(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) {
return
REDISMODULE_OK
;
}
sds
modulesCollectInfo
(
sds
info
,
sds
section
,
int
for_crash_report
,
int
sections
)
{
sds
modulesCollectInfo
(
sds
info
,
const
char
*
section
,
int
for_crash_report
,
int
sections
)
{
dictIterator
*
di
=
dictGetIterator
(
modules
);
dictEntry
*
de
;
...
...
@@ -5654,6 +5661,126 @@ sds modulesCollectInfo(sds info, sds section, int for_crash_report, int sections
return
info
;
}
/* Get information about the server similar to the one that returns from the
* INFO command. This function takes an optional 'section' argument that may
* be NULL. The return value holds the output and can be used with
* RedisModule_ServerInfoGetField and alike to get the individual fields.
* When done, it needs to be freed with RedisModule_FreeServerInfo or with the
* automatic memory management mechanism if enabled. */
RedisModuleServerInfoData
*
RM_GetServerInfo
(
RedisModuleCtx
*
ctx
,
const
char
*
section
)
{
struct
RedisModuleServerInfoData
*
d
=
zmalloc
(
sizeof
(
*
d
));
d
->
rax
=
raxNew
();
if
(
ctx
!=
NULL
)
autoMemoryAdd
(
ctx
,
REDISMODULE_AM_INFO
,
d
);
sds
info
=
genRedisInfoString
(
section
);
int
totlines
,
i
;
sds
*
lines
=
sdssplitlen
(
info
,
sdslen
(
info
),
"
\r\n
"
,
2
,
&
totlines
);
for
(
i
=
0
;
i
<
totlines
;
i
++
)
{
sds
line
=
lines
[
i
];
if
(
line
[
0
]
==
'#'
)
continue
;
char
*
sep
=
strchr
(
line
,
':'
);
if
(
!
sep
)
continue
;
unsigned
char
*
key
=
(
unsigned
char
*
)
line
;
size_t
keylen
=
(
intptr_t
)
sep
-
(
intptr_t
)
line
;
sds
val
=
sdsnewlen
(
sep
+
1
,
sdslen
(
line
)
-
((
intptr_t
)
sep
-
(
intptr_t
)
line
)
-
1
);
if
(
!
raxTryInsert
(
d
->
rax
,
key
,
keylen
,
val
,
NULL
))
sdsfree
(
val
);
}
sdsfree
(
info
);
sdsfreesplitres
(
lines
,
totlines
);
return
d
;
}
/* Free data created with RM_GetServerInfo(). You need to pass the
* context pointer 'ctx' only if the dictionary was created using the
* context instead of passing NULL. */
void
RM_FreeServerInfo
(
RedisModuleCtx
*
ctx
,
RedisModuleServerInfoData
*
data
)
{
if
(
ctx
!=
NULL
)
autoMemoryFreed
(
ctx
,
REDISMODULE_AM_INFO
,
data
);
raxIterator
ri
;
raxStart
(
&
ri
,
data
->
rax
);
while
(
1
)
{
raxSeek
(
&
ri
,
"^"
,
NULL
,
0
);
if
(
!
raxNext
(
&
ri
))
break
;
raxRemove
(
data
->
rax
,(
unsigned
char
*
)
ri
.
key
,
ri
.
key_len
,
NULL
);
sdsfree
(
ri
.
data
);
}
raxStop
(
&
ri
);
raxFree
(
data
->
rax
);
zfree
(
data
);
}
/* Get the value of a field from data collected with RM_GetServerInfo(). You
* need to pass the context pointer 'ctx' only if you want to use auto memory
* mechanism to release the returned string. Return value will be NULL if the
* field was not found. */
RedisModuleString
*
RM_ServerInfoGetField
(
RedisModuleCtx
*
ctx
,
RedisModuleServerInfoData
*
data
,
const
char
*
field
)
{
sds
val
=
raxFind
(
data
->
rax
,
(
unsigned
char
*
)
field
,
strlen
(
field
));
if
(
val
==
raxNotFound
)
return
NULL
;
RedisModuleString
*
o
=
createStringObject
(
val
,
sdslen
(
val
));
if
(
ctx
!=
NULL
)
autoMemoryAdd
(
ctx
,
REDISMODULE_AM_STRING
,
o
);
return
o
;
}
/* Similar to RM_ServerInfoGetField, but returns a char* which should not be freed but the caller. */
const
char
*
RM_ServerInfoGetFieldC
(
RedisModuleServerInfoData
*
data
,
const
char
*
field
)
{
sds
val
=
raxFind
(
data
->
rax
,
(
unsigned
char
*
)
field
,
strlen
(
field
));
if
(
val
==
raxNotFound
)
return
NULL
;
return
val
;
}
/* Get the value of a field from data collected with RM_GetServerInfo(). If the
* field is not found, or is not numerical or out of range, return value will be
* 0, and the optional out_err argument will be set to REDISMODULE_ERR. */
long
long
RM_ServerInfoGetFieldSigned
(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
)
{
long
long
ll
;
sds
val
=
raxFind
(
data
->
rax
,
(
unsigned
char
*
)
field
,
strlen
(
field
));
if
(
val
==
raxNotFound
)
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
!
string2ll
(
val
,
sdslen
(
val
),
&
ll
))
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
out_err
)
*
out_err
=
REDISMODULE_OK
;
return
ll
;
}
/* Get the value of a field from data collected with RM_GetServerInfo(). If the
* field is not found, or is not numerical or out of range, return value will be
* 0, and the optional out_err argument will be set to REDISMODULE_ERR. */
unsigned
long
long
RM_ServerInfoGetFieldUnsigned
(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
)
{
unsigned
long
long
ll
;
sds
val
=
raxFind
(
data
->
rax
,
(
unsigned
char
*
)
field
,
strlen
(
field
));
if
(
val
==
raxNotFound
)
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
!
string2ull
(
val
,
&
ll
))
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
out_err
)
*
out_err
=
REDISMODULE_OK
;
return
ll
;
}
/* Get the value of a field from data collected with RM_GetServerInfo(). If the
* field is not found, or is not a double, return value will be 0, and the
* optional out_err argument will be set to REDISMODULE_ERR. */
double
RM_ServerInfoGetFieldDouble
(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
)
{
double
dbl
;
sds
val
=
raxFind
(
data
->
rax
,
(
unsigned
char
*
)
field
,
strlen
(
field
));
if
(
val
==
raxNotFound
)
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
!
string2d
(
val
,
sdslen
(
val
),
&
dbl
))
{
if
(
out_err
)
*
out_err
=
REDISMODULE_ERR
;
return
0
;
}
if
(
out_err
)
*
out_err
=
REDISMODULE_OK
;
return
dbl
;
}
/* --------------------------------------------------------------------------
* Modules utility APIs
* -------------------------------------------------------------------------- */
...
...
@@ -7377,6 +7504,13 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API
(
InfoAddFieldDouble
);
REGISTER_API
(
InfoAddFieldLongLong
);
REGISTER_API
(
InfoAddFieldULongLong
);
REGISTER_API
(
GetServerInfo
);
REGISTER_API
(
FreeServerInfo
);
REGISTER_API
(
ServerInfoGetField
);
REGISTER_API
(
ServerInfoGetFieldC
);
REGISTER_API
(
ServerInfoGetFieldSigned
);
REGISTER_API
(
ServerInfoGetFieldUnsigned
);
REGISTER_API
(
ServerInfoGetFieldDouble
);
REGISTER_API
(
GetClientInfoById
);
REGISTER_API
(
PublishMessage
);
REGISTER_API
(
SubscribeToServerEvent
);
...
...
src/object.c
View file @
b9394558
...
...
@@ -606,21 +606,13 @@ size_t stringObjectLen(robj *o) {
int
getDoubleFromObject
(
const
robj
*
o
,
double
*
target
)
{
double
value
;
char
*
eptr
;
if
(
o
==
NULL
)
{
value
=
0
;
}
else
{
serverAssertWithInfo
(
NULL
,
o
,
o
->
type
==
OBJ_STRING
);
if
(
sdsEncodedObject
(
o
))
{
errno
=
0
;
value
=
strtod
(
o
->
ptr
,
&
eptr
);
if
(
sdslen
(
o
->
ptr
)
==
0
||
isspace
(((
const
char
*
)
o
->
ptr
)[
0
])
||
(
size_t
)(
eptr
-
(
char
*
)
o
->
ptr
)
!=
sdslen
(
o
->
ptr
)
||
(
errno
==
ERANGE
&&
(
value
==
HUGE_VAL
||
value
==
-
HUGE_VAL
||
value
==
0
))
||
isnan
(
value
))
if
(
!
string2d
(
o
->
ptr
,
sdslen
(
o
->
ptr
),
&
value
))
return
C_ERR
;
}
else
if
(
o
->
encoding
==
OBJ_ENCODING_INT
)
{
value
=
(
long
)
o
->
ptr
;
...
...
src/redismodule.h
View file @
b9394558
...
...
@@ -393,6 +393,7 @@ typedef struct RedisModuleDictIter RedisModuleDictIter;
typedef
struct
RedisModuleCommandFilterCtx
RedisModuleCommandFilterCtx
;
typedef
struct
RedisModuleCommandFilter
RedisModuleCommandFilter
;
typedef
struct
RedisModuleInfoCtx
RedisModuleInfoCtx
;
typedef
struct
RedisModuleServerInfoData
RedisModuleServerInfoData
;
typedef
struct
RedisModuleScanCursor
RedisModuleScanCursor
;
typedef
int
(
*
RedisModuleCmdFunc
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
);
...
...
@@ -592,6 +593,13 @@ int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ct
int
REDISMODULE_API_FUNC
(
RedisModule_InfoAddFieldDouble
)(
RedisModuleInfoCtx
*
ctx
,
char
*
field
,
double
value
);
int
REDISMODULE_API_FUNC
(
RedisModule_InfoAddFieldLongLong
)(
RedisModuleInfoCtx
*
ctx
,
char
*
field
,
long
long
value
);
int
REDISMODULE_API_FUNC
(
RedisModule_InfoAddFieldULongLong
)(
RedisModuleInfoCtx
*
ctx
,
char
*
field
,
unsigned
long
long
value
);
RedisModuleServerInfoData
*
REDISMODULE_API_FUNC
(
RedisModule_GetServerInfo
)(
RedisModuleCtx
*
ctx
,
const
char
*
section
);
void
REDISMODULE_API_FUNC
(
RedisModule_FreeServerInfo
)(
RedisModuleCtx
*
ctx
,
RedisModuleServerInfoData
*
data
);
RedisModuleString
*
REDISMODULE_API_FUNC
(
RedisModule_ServerInfoGetField
)(
RedisModuleCtx
*
ctx
,
RedisModuleServerInfoData
*
data
,
const
char
*
field
);
const
char
*
REDISMODULE_API_FUNC
(
RedisModule_ServerInfoGetFieldC
)(
RedisModuleServerInfoData
*
data
,
const
char
*
field
);
long
long
REDISMODULE_API_FUNC
(
RedisModule_ServerInfoGetFieldSigned
)(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
);
unsigned
long
long
REDISMODULE_API_FUNC
(
RedisModule_ServerInfoGetFieldUnsigned
)(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
);
double
REDISMODULE_API_FUNC
(
RedisModule_ServerInfoGetFieldDouble
)(
RedisModuleServerInfoData
*
data
,
const
char
*
field
,
int
*
out_err
);
int
REDISMODULE_API_FUNC
(
RedisModule_SubscribeToServerEvent
)(
RedisModuleCtx
*
ctx
,
RedisModuleEvent
event
,
RedisModuleEventCallback
callback
);
int
REDISMODULE_API_FUNC
(
RedisModule_SetLRU
)(
RedisModuleKey
*
key
,
mstime_t
lru_idle
);
int
REDISMODULE_API_FUNC
(
RedisModule_GetLRU
)(
RedisModuleKey
*
key
,
mstime_t
*
lru_idle
);
...
...
@@ -816,6 +824,13 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
InfoAddFieldDouble
);
REDISMODULE_GET_API
(
InfoAddFieldLongLong
);
REDISMODULE_GET_API
(
InfoAddFieldULongLong
);
REDISMODULE_GET_API
(
GetServerInfo
);
REDISMODULE_GET_API
(
FreeServerInfo
);
REDISMODULE_GET_API
(
ServerInfoGetField
);
REDISMODULE_GET_API
(
ServerInfoGetFieldC
);
REDISMODULE_GET_API
(
ServerInfoGetFieldSigned
);
REDISMODULE_GET_API
(
ServerInfoGetFieldUnsigned
);
REDISMODULE_GET_API
(
ServerInfoGetFieldDouble
);
REDISMODULE_GET_API
(
GetClientInfoById
);
REDISMODULE_GET_API
(
PublishMessage
);
REDISMODULE_GET_API
(
SubscribeToServerEvent
);
...
...
src/server.c
View file @
b9394558
...
...
@@ -3936,7 +3936,7 @@ void bytesToHuman(char *s, unsigned long long n) {
/* Create the string returned by the INFO command. This is decoupled
* by the INFO command itself as we need to report the same information
* on memory corruption problems. */
sds
genRedisInfoString
(
char
*
section
)
{
sds
genRedisInfoString
(
const
char
*
section
)
{
sds
info
=
sdsempty
();
time_t
uptime
=
server
.
unixtime
-
server
.
stat_starttime
;
int
j
;
...
...
src/server.h
View file @
b9394558
...
...
@@ -1604,7 +1604,7 @@ void ModuleForkDoneHandler(int exitcode, int bysignal);
int
TerminateModuleForkChild
(
int
child_pid
,
int
wait
);
ssize_t
rdbSaveModulesAux
(
rio
*
rdb
,
int
when
);
int
moduleAllDatatypesHandleErrors
();
sds
modulesCollectInfo
(
sds
info
,
sds
section
,
int
for_crash_report
,
int
sections
);
sds
modulesCollectInfo
(
sds
info
,
const
char
*
section
,
int
for_crash_report
,
int
sections
);
void
moduleFireServerEvent
(
uint64_t
eid
,
int
subid
,
void
*
data
);
void
processModuleLoadingProgressEvent
(
int
is_aof
);
int
moduleTryServeClientBlockedOnKey
(
client
*
c
,
robj
*
key
);
...
...
@@ -2418,7 +2418,7 @@ void _serverPanic(const char *file, int line, const char *msg, ...);
void
bugReportStart
(
void
);
void
serverLogObjectDebugInfo
(
const
robj
*
o
);
void
sigsegvHandler
(
int
sig
,
siginfo_t
*
info
,
void
*
secret
);
sds
genRedisInfoString
(
char
*
section
);
sds
genRedisInfoString
(
const
char
*
section
);
sds
genModulesInfoString
(
sds
info
);
void
enableWatchdog
(
int
period
);
void
disableWatchdog
(
void
);
...
...
src/t_stream.c
View file @
b9394558
...
...
@@ -1079,26 +1079,6 @@ robj *streamTypeLookupWriteOrCreate(client *c, robj *key) {
return
o
;
}
/* Helper function to convert a string to an unsigned long long value.
* The function attempts to use the faster string2ll() function inside
* Redis: if it fails, strtoull() is used instead. The function returns
* 1 if the conversion happened successfully or 0 if the number is
* invalid or out of range. */
int
string2ull
(
const
char
*
s
,
unsigned
long
long
*
value
)
{
long
long
ll
;
if
(
string2ll
(
s
,
strlen
(
s
),
&
ll
))
{
if
(
ll
<
0
)
return
0
;
/* Negative values are out of range. */
*
value
=
ll
;
return
1
;
}
errno
=
0
;
char
*
endptr
=
NULL
;
*
value
=
strtoull
(
s
,
&
endptr
,
10
);
if
(
errno
==
EINVAL
||
errno
==
ERANGE
||
!
(
*
s
!=
'\0'
&&
*
endptr
==
'\0'
))
return
0
;
/* strtoull() failed. */
return
1
;
/* Conversion done! */
}
/* Parse a stream ID in the format given by clients to Redis, that is
* <ms>-<seq>, and converts it into a streamID structure. If
* the specified ID is invalid C_ERR is returned and an error is reported
...
...
src/util.c
View file @
b9394558
...
...
@@ -423,6 +423,26 @@ int string2ll(const char *s, size_t slen, long long *value) {
return
1
;
}
/* Helper function to convert a string to an unsigned long long value.
* The function attempts to use the faster string2ll() function inside
* Redis: if it fails, strtoull() is used instead. The function returns
* 1 if the conversion happened successfully or 0 if the number is
* invalid or out of range. */
int
string2ull
(
const
char
*
s
,
unsigned
long
long
*
value
)
{
long
long
ll
;
if
(
string2ll
(
s
,
strlen
(
s
),
&
ll
))
{
if
(
ll
<
0
)
return
0
;
/* Negative values are out of range. */
*
value
=
ll
;
return
1
;
}
errno
=
0
;
char
*
endptr
=
NULL
;
*
value
=
strtoull
(
s
,
&
endptr
,
10
);
if
(
errno
==
EINVAL
||
errno
==
ERANGE
||
!
(
*
s
!=
'\0'
&&
*
endptr
==
'\0'
))
return
0
;
/* strtoull() failed. */
return
1
;
/* Conversion done! */
}
/* Convert a string into a long. Returns 1 if the string could be parsed into a
* (non-overflowing) long, 0 otherwise. The value will be set to the parsed
* value when appropriate. */
...
...
@@ -468,6 +488,27 @@ int string2ld(const char *s, size_t slen, long double *dp) {
return
1
;
}
/* Convert a string into a double. Returns 1 if the string could be parsed
* into a (non-overflowing) double, 0 otherwise. The value will be set to
* the parsed value when appropriate.
*
* Note that this function demands that the string strictly represents
* a double: no spaces or other characters before or after the string
* representing the number are accepted. */
int
string2d
(
const
char
*
s
,
size_t
slen
,
double
*
dp
)
{
errno
=
0
;
char
*
eptr
;
*
dp
=
strtod
(
s
,
&
eptr
);
if
(
slen
==
0
||
isspace
(((
const
char
*
)
s
)[
0
])
||
(
size_t
)(
eptr
-
(
char
*
)
s
)
!=
slen
||
(
errno
==
ERANGE
&&
(
*
dp
==
HUGE_VAL
||
*
dp
==
-
HUGE_VAL
||
*
dp
==
0
))
||
isnan
(
*
dp
))
return
0
;
return
1
;
}
/* Convert a double to a string representation. Returns the number of bytes
* required. The representation should always be parsable by strtod(3).
* This function does not support human-friendly formatting like ld2string
...
...
src/util.h
View file @
b9394558
...
...
@@ -53,8 +53,10 @@ uint32_t digits10(uint64_t v);
uint32_t
sdigits10
(
int64_t
v
);
int
ll2string
(
char
*
s
,
size_t
len
,
long
long
value
);
int
string2ll
(
const
char
*
s
,
size_t
slen
,
long
long
*
value
);
int
string2ull
(
const
char
*
s
,
unsigned
long
long
*
value
);
int
string2l
(
const
char
*
s
,
size_t
slen
,
long
*
value
);
int
string2ld
(
const
char
*
s
,
size_t
slen
,
long
double
*
dp
);
int
string2d
(
const
char
*
s
,
size_t
slen
,
double
*
dp
);
int
d2string
(
char
*
buf
,
size_t
len
,
double
value
);
int
ld2string
(
char
*
buf
,
size_t
len
,
long
double
value
,
ld2string_mode
mode
);
sds
getAbsolutePath
(
char
*
filename
);
...
...
tests/modules/infotest.c
View file @
b9394558
...
...
@@ -5,6 +5,7 @@
void
InfoFunc
(
RedisModuleInfoCtx
*
ctx
,
int
for_crash_report
)
{
RedisModule_InfoAddSection
(
ctx
,
""
);
RedisModule_InfoAddFieldLongLong
(
ctx
,
"global"
,
-
2
);
RedisModule_InfoAddFieldULongLong
(
ctx
,
"uglobal"
,
(
unsigned
long
long
)
-
2
);
RedisModule_InfoAddSection
(
ctx
,
"Spanish"
);
RedisModule_InfoAddFieldCString
(
ctx
,
"uno"
,
"one"
);
...
...
@@ -29,6 +30,67 @@ void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) {
}
int
info_get
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
,
char
field_type
)
{
if
(
argc
!=
3
&&
argc
!=
4
)
{
RedisModule_WrongArity
(
ctx
);
return
REDISMODULE_OK
;
}
int
err
=
REDISMODULE_OK
;
const
char
*
section
,
*
field
;
section
=
RedisModule_StringPtrLen
(
argv
[
1
],
NULL
);
field
=
RedisModule_StringPtrLen
(
argv
[
2
],
NULL
);
RedisModuleServerInfoData
*
info
=
RedisModule_GetServerInfo
(
ctx
,
section
);
if
(
field_type
==
'i'
)
{
long
long
ll
=
RedisModule_ServerInfoGetFieldSigned
(
info
,
field
,
&
err
);
if
(
err
==
REDISMODULE_OK
)
RedisModule_ReplyWithLongLong
(
ctx
,
ll
);
}
else
if
(
field_type
==
'u'
)
{
unsigned
long
long
ll
=
(
unsigned
long
long
)
RedisModule_ServerInfoGetFieldUnsigned
(
info
,
field
,
&
err
);
if
(
err
==
REDISMODULE_OK
)
RedisModule_ReplyWithLongLong
(
ctx
,
ll
);
}
else
if
(
field_type
==
'd'
)
{
double
d
=
RedisModule_ServerInfoGetFieldDouble
(
info
,
field
,
&
err
);
if
(
err
==
REDISMODULE_OK
)
RedisModule_ReplyWithDouble
(
ctx
,
d
);
}
else
if
(
field_type
==
'c'
)
{
const
char
*
str
=
RedisModule_ServerInfoGetFieldC
(
info
,
field
);
if
(
str
)
RedisModule_ReplyWithCString
(
ctx
,
str
);
}
else
{
RedisModuleString
*
str
=
RedisModule_ServerInfoGetField
(
ctx
,
info
,
field
);
if
(
str
)
{
RedisModule_ReplyWithString
(
ctx
,
str
);
RedisModule_FreeString
(
ctx
,
str
);
}
else
err
=
REDISMODULE_ERR
;
}
if
(
err
!=
REDISMODULE_OK
)
RedisModule_ReplyWithError
(
ctx
,
"not found"
);
RedisModule_FreeServerInfo
(
ctx
,
info
);
return
REDISMODULE_OK
;
}
int
info_gets
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
return
info_get
(
ctx
,
argv
,
argc
,
's'
);
}
int
info_getc
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
return
info_get
(
ctx
,
argv
,
argc
,
'c'
);
}
int
info_geti
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
return
info_get
(
ctx
,
argv
,
argc
,
'i'
);
}
int
info_getu
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
return
info_get
(
ctx
,
argv
,
argc
,
'u'
);
}
int
info_getd
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
return
info_get
(
ctx
,
argv
,
argc
,
'd'
);
}
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
REDISMODULE_NOT_USED
(
argv
);
REDISMODULE_NOT_USED
(
argc
);
...
...
@@ -37,5 +99,16 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
if
(
RedisModule_RegisterInfoFunc
(
ctx
,
InfoFunc
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"info.gets"
,
info_gets
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"info.getc"
,
info_getc
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"info.geti"
,
info_geti
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"info.getu"
,
info_getu
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"info.getd"
,
info_getd
,
""
,
0
,
0
,
0
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
}
tests/unit/moduleapi/infotest.tcl
View file @
b9394558
...
...
@@ -10,6 +10,32 @@ proc field {info property} {
start_server
{
tags
{
"modules"
}}
{
r module load $testmodule log-key 0
test
{
module reading info
}
{
# check string, integer and float fields
assert_equal
[
r info.gets replication role
]
"master"
assert_equal
[
r info.getc replication role
]
"master"
assert_equal
[
r info.geti stats expired_keys
]
0
assert_equal
[
r info.getd stats expired_stale_perc
]
0
# check signed and unsigned
assert_equal
[
r info.geti infotest infotest_global
]
-2
assert_equal
[
r info.getu infotest infotest_uglobal
]
-2
# the above are always 0, try module info that is non-zero
assert_equal
[
r info.geti infotest_italian infotest_due
]
2
set tre
[
r info.getd infotest_italian infotest_tre
]
assert
{
$tre
> 3.2 && $tre < 3.4
}
# search using the wrong section
catch
{
[
r info.gets badname redis_version
]
}
e
assert_match
{
*not found*
}
$e
# check that section filter works
assert
{
[
string match
"*usec_per_call*"
[
r info.gets all cmdstat_info.gets
]
]
}
catch
{
[
r info.gets default cmdstat_info.gets
]
]
}
e
assert_match
{
*not found*
}
$e
}
test
{
module info all
}
{
set info
[
r info all
]
# info all does not contain modules
...
...
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