mirror of
http://github.com/valkey-io/valkey
synced 2024-11-23 11:51:01 +00:00
Merge branch 'unstable' of github.com:/antirez/redis into unstable
This commit is contained in:
commit
1ee195d255
28
.github/workflows/ci.yml
vendored
Normal file
28
.github/workflows/ci.yml
vendored
Normal 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
|
@ -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 \
|
||||
"${@}"
|
||||
|
46
src/module.c
46
src/module.c
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -17,6 +17,7 @@ TEST_MODULES = \
|
||||
fork.so \
|
||||
infotest.so \
|
||||
propagate.so \
|
||||
misc.so \
|
||||
hooks.so
|
||||
|
||||
.PHONY: all
|
||||
|
@ -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
55
tests/modules/misc.c
Normal 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;
|
||||
}
|
19
tests/unit/moduleapi/misc.tcl
Normal file
19
tests/unit/moduleapi/misc.tcl
Normal 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] }
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user