From c81813148b71cd4be686402ef69f628f67dbb8c4 Mon Sep 17 00:00:00 2001 From: Huang Zhw Date: Wed, 30 Nov 2022 17:56:36 +0800 Subject: Add a special notification unlink available only for modules (#9406) Add a new module event `RedisModule_Event_Key`, this event is fired when a key is removed from the keyspace. The event includes an open key that can be used for reading the key before it is removed. Modules can also extract the key-name, and use RM_Open or RM_Call to access key from within that event, but shouldn't modify anything from within this event. The following sub events are available: - `REDISMODULE_SUBEVENT_KEY_DELETED` - `REDISMODULE_SUBEVENT_KEY_EXPIRED` - `REDISMODULE_SUBEVENT_KEY_EVICTED` - `REDISMODULE_SUBEVENT_KEY_OVERWRITE` The data pointer can be casted to a RedisModuleKeyInfo structure with the following fields: ``` RedisModuleKey *key; // Opened Key ``` ### internals * We also add two dict functions: `dictTwoPhaseUnlinkFind` finds an element from the table, also get the plink of the entry. The entry is returned if the element is found. The user should later call `dictTwoPhaseUnlinkFree` with it in order to unlink and release it. Otherwise if the key is not found, NULL is returned. These two functions should be used in pair. `dictTwoPhaseUnlinkFind` pauses rehash and `dictTwoPhaseUnlinkFree` resumes rehash. * We change `dbOverwrite` to `dbReplaceValue` which just replaces the value of the key and doesn't fire any events. The "overwrite" part (which emits events) is just when called from `setKey`, the other places that called dbOverwrite were ones that just update the value in-place (INCR*, SPOP, and dbUnshareStringValue). This should not have any real impact since `moduleNotifyKeyUnlink` and `signalDeletedKeyAsReady` wouldn't have mattered in these cases anyway (i.e. module keys and stream keys didn't have direct calls to dbOverwrite) * since we allow doing RM_OpenKey from withing these callbacks, we temporarily disable lazy expiry. * We also temporarily disable lazy expiry when we are in unlink/unlink2 callback and keyspace notification callback. * Move special definitions to the top of redismodule.h This is needed to resolve compilation errors with RedisModuleKeyInfoV1 that carries a RedisModuleKey member. Co-authored-by: Oran Agra --- src/redismodule.h | 63 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 19 deletions(-) (limited to 'src/redismodule.h') diff --git a/src/redismodule.h b/src/redismodule.h index 7f04f7ba4..d65687a23 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -6,6 +6,28 @@ #include #include + +typedef struct RedisModuleString RedisModuleString; +typedef struct RedisModuleKey RedisModuleKey; + +/* -------------- Defines NOT common between core and modules ------------- */ + +#if defined REDISMODULE_CORE +/* Things only defined for the modules core (server), not exported to modules + * that include this file. */ + +#define RedisModuleString robj + +#endif /* defined REDISMODULE_CORE */ + +#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE +/* Things defined for modules, but not for core-modules. */ + +typedef long long mstime_t; +typedef long long ustime_t; + +#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */ + /* ---------------- Defines common between core and modules --------------- */ /* Error status return values. */ @@ -458,7 +480,8 @@ typedef void (*RedisModuleEventLoopOneShotFunc)(void *user_data); #define REDISMODULE_EVENT_REPL_ASYNC_LOAD 14 #define REDISMODULE_EVENT_EVENTLOOP 15 #define REDISMODULE_EVENT_CONFIG 16 -#define _REDISMODULE_EVENT_NEXT 17 /* Next event flag, should be updated if a new event added. */ +#define REDISMODULE_EVENT_KEY 17 +#define _REDISMODULE_EVENT_NEXT 18 /* Next event flag, should be updated if a new event added. */ typedef struct RedisModuleEvent { uint64_t id; /* REDISMODULE_EVENT_... defines. */ @@ -565,6 +588,10 @@ static const RedisModuleEvent RedisModuleEvent_Config = { REDISMODULE_EVENT_CONFIG, 1 + }, + RedisModuleEvent_Key = { + REDISMODULE_EVENT_KEY, + 1 }; /* Those are values that are used for the 'subevent' callback argument. */ @@ -633,6 +660,12 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP 1 #define _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT 2 +#define REDISMODULE_SUBEVENT_KEY_DELETED 0 +#define REDISMODULE_SUBEVENT_KEY_EXPIRED 1 +#define REDISMODULE_SUBEVENT_KEY_EVICTED 2 +#define REDISMODULE_SUBEVENT_KEY_OVERWRITTEN 3 +#define _REDISMODULE_SUBEVENT_KEY_NEXT 4 + #define _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT 0 #define _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT 0 #define _REDISMODULE_SUBEVENT_SWAPDB_NEXT 0 @@ -756,6 +789,16 @@ typedef struct RedisModuleSwapDbInfo { #define RedisModuleSwapDbInfo RedisModuleSwapDbInfoV1 +#define REDISMODULE_KEYINFO_VERSION 1 +typedef struct RedisModuleKeyInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + RedisModuleKey *key; /* Opened key. */ +} RedisModuleKeyInfoV1; + +#define RedisModuleKeyInfo RedisModuleKeyInfoV1 + typedef enum { REDISMODULE_ACL_LOG_AUTH = 0, /* Authentication failure */ REDISMODULE_ACL_LOG_CMD, /* Command authorization failure */ @@ -764,7 +807,6 @@ typedef enum { } RedisModuleACLLogEntryReason; /* Incomplete structures needed by both the core and modules. */ -typedef struct RedisModuleString RedisModuleString; typedef struct RedisModuleIO RedisModuleIO; typedef struct RedisModuleDigest RedisModuleDigest; typedef struct RedisModuleInfoCtx RedisModuleInfoCtx; @@ -778,22 +820,6 @@ typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); /* ------------------------- End of common defines ------------------------ */ -#if defined REDISMODULE_CORE -/* Things only defined for the modules core (server), not exported to modules - * that include this file. */ - -#define RedisModuleString robj - -#endif /* defined REDISMODULE_CORE */ - -#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE -/* Things defined for modules, but not for core-modules. */ - -typedef long long mstime_t; -typedef long long ustime_t; - -#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */ - /* ----------- The rest of the defines are only for modules ----------------- */ #if !defined REDISMODULE_CORE || defined REDISMODULE_CORE_MODULE /* Things defined for modules and core-modules. */ @@ -826,7 +852,6 @@ typedef long long ustime_t; /* Incomplete structures for compiler checks but opaque access. */ typedef struct RedisModuleCtx RedisModuleCtx; typedef struct RedisModuleCommand RedisModuleCommand; -typedef struct RedisModuleKey RedisModuleKey; typedef struct RedisModuleCallReply RedisModuleCallReply; typedef struct RedisModuleType RedisModuleType; typedef struct RedisModuleBlockedClient RedisModuleBlockedClient; -- cgit v1.2.1