Merge branch 'unstable' of github.com:/antirez/redis into unstable

This commit is contained in:
antirez 2019-10-31 17:55:18 +01:00
commit 1ee195d255
8 changed files with 179 additions and 5 deletions

28
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: CI
on: [push, pull_request]
jobs:
build-ubuntu:
strategy:
matrix:
platform: [ubuntu-latest, ubuntu-16.04]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- name: make
run: make
- name: test
run: |
sudo apt-get install tcl8.5
make test
build-macos-latest:
strategy:
matrix:
platform: [macos-latest, macOS-10.14]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- name: make
run: make

View File

@ -13,4 +13,12 @@ then
fi
make -C tests/modules && \
$TCLSH tests/test_helper.tcl --single unit/moduleapi/commandfilter --single unit/moduleapi/fork --single unit/moduleapi/testrdb --single unit/moduleapi/infotest --single unit/moduleapi/propagate --single unit/moduleapi/hooks "${@}"
$TCLSH tests/test_helper.tcl \
--single unit/moduleapi/commandfilter \
--single unit/moduleapi/fork \
--single unit/moduleapi/testrdb \
--single unit/moduleapi/infotest \
--single unit/moduleapi/propagate \
--single unit/moduleapi/hooks \
--single unit/moduleapi/misc \
"${@}"

View File

@ -327,6 +327,13 @@ static struct RedisModuleForkInfo {
#define REDISMODULE_ARGV_NO_AOF (1<<1)
#define REDISMODULE_ARGV_NO_REPLICAS (1<<2)
/* Determine whether Redis should signalModifiedKey implicitly.
* In case 'ctx' has no 'module' member (and therefore no module->options),
* we assume default behavior, that is, Redis signals.
* (see RM_GetThreadSafeContext) */
#define SHOULD_SIGNAL_MODIFIED_KEYS(ctx) \
ctx->module? !(ctx->module->options & REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED) : 1
/* Server events hooks data structures and defines: this modules API
* allow modules to subscribe to certain events in Redis, such as
* the start and end of an RDB or AOF save, the change of role in replication,
@ -827,6 +834,7 @@ void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int api
module->filters = listCreate();
module->in_call = 0;
module->in_hook = 0;
module->options = 0;
ctx->module = module;
}
@ -857,6 +865,12 @@ void RM_SetModuleOptions(RedisModuleCtx *ctx, int options) {
ctx->module->options = options;
}
/* Signals that the key is modified from user's perspective (i.e. invalidate WATCH). */
int RM_SignalModifiedKey(RedisModuleCtx *ctx, RedisModuleString *keyname) {
signalModifiedKey(ctx->client->db,keyname);
return REDISMODULE_OK;
}
/* --------------------------------------------------------------------------
* Automatic memory management for modules
* -------------------------------------------------------------------------- */
@ -1848,7 +1862,9 @@ void *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) {
/* Close a key handle. */
void RM_CloseKey(RedisModuleKey *key) {
if (key == NULL) return;
if (key->mode & REDISMODULE_WRITE) signalModifiedKey(key->db,key->key);
int signal = SHOULD_SIGNAL_MODIFIED_KEYS(key->ctx);
if ((key->mode & REDISMODULE_WRITE) && signal)
signalModifiedKey(key->db,key->key);
/* TODO: if (key->iter) RM_KeyIteratorStop(kp); */
RM_ZsetRangeStop(key);
decrRefCount(key->key);
@ -3072,7 +3088,10 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch
/* We handle the above format error only when the client is setup so that
* we can free it normally. */
if (argv == NULL) goto cleanup;
if (argv == NULL) {
errno = EINVAL;
goto cleanup;
}
/* Call command filters */
moduleCallCommandFilters(c);
@ -3864,6 +3883,11 @@ const RedisModuleString *RM_GetKeyNameFromIO(RedisModuleIO *io) {
return io->key;
}
/* Returns a RedisModuleString with the name of the key from RedisModuleKey */
const RedisModuleString *RM_GetKeyNameFromModuleKey(RedisModuleKey *key) {
return key ? key->key : NULL;
}
/* --------------------------------------------------------------------------
* Logging
* -------------------------------------------------------------------------- */
@ -4537,6 +4561,20 @@ int RM_SubscribeToKeyspaceEvents(RedisModuleCtx *ctx, int types, RedisModuleNoti
return REDISMODULE_OK;
}
/* Get the configured bitmap of notify-keyspace-events (Could be used
* for additional filtering in RedisModuleNotificationFunc) */
int RM_GetNotifyKeyspaceEvents() {
return server.notify_keyspace_events;
}
/* Expose notifyKeyspaceEvent to modules */
int RM_NotifyKeyspaceEvent(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) {
if (!ctx || !ctx->client)
return REDISMODULE_ERR;
notifyKeyspaceEvent(type, (char *)event, key, ctx->client->db->id);
return REDISMODULE_OK;
}
/* Dispatcher for keyspace notifications to module subscriber functions.
* This gets called only if at least one module requested to be notified on
* keyspace notifications */
@ -6618,6 +6656,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(ModuleTypeGetValue);
REGISTER_API(IsIOError);
REGISTER_API(SetModuleOptions);
REGISTER_API(SignalModifiedKey);
REGISTER_API(SaveUnsigned);
REGISTER_API(LoadUnsigned);
REGISTER_API(SaveSigned);
@ -6640,6 +6679,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(StringCompare);
REGISTER_API(GetContextFromIO);
REGISTER_API(GetKeyNameFromIO);
REGISTER_API(GetKeyNameFromModuleKey);
REGISTER_API(BlockClient);
REGISTER_API(UnblockClient);
REGISTER_API(IsBlockedReplyRequest);
@ -6654,6 +6694,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(DigestAddStringBuffer);
REGISTER_API(DigestAddLongLong);
REGISTER_API(DigestEndSequence);
REGISTER_API(NotifyKeyspaceEvent);
REGISTER_API(GetNotifyKeyspaceEvents);
REGISTER_API(SubscribeToKeyspaceEvents);
REGISTER_API(RegisterClusterMessageReceiver);
REGISTER_API(SendClusterMessage);

View File

@ -106,6 +106,11 @@
/* There is currently some background process active. */
#define REDISMODULE_CTX_FLAGS_ACTIVE_CHILD (1<<18)
/* Keyspace changes notification classes. Every class is associated with a
* character for configuration purposes.
* NOTE: These have to be in sync with NOTIFY_* in server.h */
#define REDISMODULE_NOTIFY_KEYSPACE (1<<0) /* K */
#define REDISMODULE_NOTIFY_KEYEVENT (1<<1) /* E */
#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
@ -161,6 +166,10 @@ typedef uint64_t RedisModuleTimerID;
/* Declare that the module can handle errors with RedisModule_SetModuleOptions. */
#define REDISMODULE_OPTIONS_HANDLE_IO_ERRORS (1<<0)
/* When set, Redis will not call RedisModule_SignalModifiedKey(), implicitly in
* RedisModule_CloseKey, and the module needs to do that when manually when keys
* are modified from the user's sperspective, to invalidate WATCH. */
#define REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED (1<<1)
/* Server events definitions. */
#define REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED 0
@ -181,7 +190,7 @@ typedef struct RedisModuleEvent {
struct RedisModuleCtx;
typedef void (*RedisModuleEventCallback)(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data);
static RedisModuleEvent
static const RedisModuleEvent
RedisModuleEvent_ReplicationRoleChanged = {
REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED,
1
@ -434,6 +443,7 @@ RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModule
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);
int REDISMODULE_API_FUNC(RedisModule_SignalModifiedKey)(RedisModuleCtx *ctx, RedisModuleString *keyname);
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);
@ -456,6 +466,7 @@ void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisMo
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetKeyNameFromIO)(RedisModuleIO *io);
const RedisModuleString *REDISMODULE_API_FUNC(RedisModule_GetKeyNameFromModuleKey)(RedisModuleKey *key);
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
@ -511,6 +522,8 @@ void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
int REDISMODULE_API_FUNC(RedisModule_NotifyKeyspaceEvent)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
int REDISMODULE_API_FUNC(RedisModule_GetNotifyKeyspaceEvents)();
int REDISMODULE_API_FUNC(RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx);
void REDISMODULE_API_FUNC(RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback);
int REDISMODULE_API_FUNC(RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len);
@ -632,6 +645,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(ModuleTypeGetValue);
REDISMODULE_GET_API(IsIOError);
REDISMODULE_GET_API(SetModuleOptions);
REDISMODULE_GET_API(SignalModifiedKey);
REDISMODULE_GET_API(SaveUnsigned);
REDISMODULE_GET_API(LoadUnsigned);
REDISMODULE_GET_API(SaveSigned);
@ -654,6 +668,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(StringCompare);
REDISMODULE_GET_API(GetContextFromIO);
REDISMODULE_GET_API(GetKeyNameFromIO);
REDISMODULE_GET_API(GetKeyNameFromModuleKey);
REDISMODULE_GET_API(Milliseconds);
REDISMODULE_GET_API(DigestAddStringBuffer);
REDISMODULE_GET_API(DigestAddLongLong);
@ -709,6 +724,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(AbortBlock);
REDISMODULE_GET_API(SetDisconnectCallback);
REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
REDISMODULE_GET_API(NotifyKeyspaceEvent);
REDISMODULE_GET_API(GetNotifyKeyspaceEvents);
REDISMODULE_GET_API(BlockedClientDisconnected);
REDISMODULE_GET_API(RegisterClusterMessageReceiver);
REDISMODULE_GET_API(SendClusterMessage);

View File

@ -17,6 +17,7 @@ TEST_MODULES = \
fork.so \
infotest.so \
propagate.so \
misc.so \
hooks.so
.PHONY: all

View File

@ -1,6 +1,10 @@
#define REDISMODULE_EXPERIMENTAL_API
#include "redismodule.h"
/* define macros for having usleep */
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include "redismodule.h"
#include <string.h>
#include <assert.h>
#include <unistd.h>

55
tests/modules/misc.c Normal file
View File

@ -0,0 +1,55 @@
#define REDISMODULE_EXPERIMENTAL_API
#include "redismodule.h"
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
int test_call_generic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
if (argc<2) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
const char* cmdname = RedisModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply *reply = RedisModule_Call(ctx, cmdname, "v", argv+2, argc-2);
if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply);
} else {
RedisModule_ReplyWithError(ctx, strerror(errno));
}
return REDISMODULE_OK;
}
int test_call_info(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
RedisModuleCallReply *reply;
if (argc>1)
reply = RedisModule_Call(ctx, "info", "s", argv[1]);
else
reply = RedisModule_Call(ctx, "info", "");
if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply);
} else {
RedisModule_ReplyWithError(ctx, strerror(errno));
}
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"misc",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.call_generic", test_call_generic,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.call_info", test_call_info,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}

View File

@ -0,0 +1,19 @@
set testmodule [file normalize tests/modules/misc.so]
start_server {tags {"modules"}} {
r module load $testmodule
test {test RM_Call} {
set info [r test.call_info commandstats]
# cmdstat is not in a default section, so we also test an argument was passed
assert { [string match "*cmdstat_module*" $info] }
}
test {test RM_Call args array} {
set info [r test.call_generic info commandstats]
# cmdstat is not in a default section, so we also test an argument was passed
assert { [string match "*cmdstat_module*" $info] }
}
}