1 | /* |
2 | * Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com> |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: |
7 | * |
8 | * * Redistributions of source code must retain the above copyright notice, |
9 | * this list of conditions and the following disclaimer. |
10 | * * Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * * Neither the name of Redis nor the names of its contributors may be used |
14 | * to endorse or promote products derived from this software without |
15 | * specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | /* -------------------------------------------------------------------------- |
31 | * Modules API documentation information |
32 | * |
33 | * The comments in this file are used to generate the API documentation on the |
34 | * Redis website. |
35 | * |
36 | * Each function starting with RM_ and preceded by a block comment is included |
37 | * in the API documentation. To hide an RM_ function, put a blank line between |
38 | * the comment and the function definition or put the comment inside the |
39 | * function body. |
40 | * |
41 | * The functions are divided into sections. Each section is preceded by a |
42 | * documentation block, which is comment block starting with a markdown level 2 |
43 | * heading, i.e. a line starting with ##, on the first line of the comment block |
44 | * (with the exception of a ----- line which can appear first). Other comment |
45 | * blocks, which are not intended for the modules API user, such as this comment |
46 | * block, do NOT start with a markdown level 2 heading, so they are included in |
47 | * the generated a API documentation. |
48 | * |
49 | * The documentation comments may contain markdown formatting. Some automatic |
50 | * replacements are done, such as the replacement of RM with RedisModule in |
51 | * function names. For details, see the script src/modules/gendoc.rb. |
52 | * -------------------------------------------------------------------------- */ |
53 | |
54 | #include "server.h" |
55 | #include "cluster.h" |
56 | #include "slowlog.h" |
57 | #include "rdb.h" |
58 | #include "monotonic.h" |
59 | #include "script.h" |
60 | #include "call_reply.h" |
61 | #include <dlfcn.h> |
62 | #include <sys/stat.h> |
63 | #include <sys/wait.h> |
64 | #include <fcntl.h> |
65 | |
66 | /* -------------------------------------------------------------------------- |
67 | * Private data structures used by the modules system. Those are data |
68 | * structures that are never exposed to Redis Modules, if not as void |
69 | * pointers that have an API the module can call with them) |
70 | * -------------------------------------------------------------------------- */ |
71 | |
72 | typedef struct RedisModuleInfoCtx { |
73 | struct RedisModule *module; |
74 | dict *requested_sections; |
75 | sds info; /* info string we collected so far */ |
76 | int sections; /* number of sections we collected so far */ |
77 | int in_section; /* indication if we're in an active section or not */ |
78 | int in_dict_field; /* indication that we're currently appending to a dict */ |
79 | } RedisModuleInfoCtx; |
80 | |
81 | /* This represents a shared API. Shared APIs will be used to populate |
82 | * the server.sharedapi dictionary, mapping names of APIs exported by |
83 | * modules for other modules to use, to their structure specifying the |
84 | * function pointer that can be called. */ |
85 | struct RedisModuleSharedAPI { |
86 | void *func; |
87 | RedisModule *module; |
88 | }; |
89 | typedef struct RedisModuleSharedAPI RedisModuleSharedAPI; |
90 | |
91 | dict *modules; /* Hash table of modules. SDS -> RedisModule ptr.*/ |
92 | |
93 | /* Entries in the context->amqueue array, representing objects to free |
94 | * when the callback returns. */ |
95 | struct AutoMemEntry { |
96 | void *ptr; |
97 | int type; |
98 | }; |
99 | |
100 | /* AutoMemEntry type field values. */ |
101 | #define REDISMODULE_AM_KEY 0 |
102 | #define REDISMODULE_AM_STRING 1 |
103 | #define REDISMODULE_AM_REPLY 2 |
104 | #define REDISMODULE_AM_FREED 3 /* Explicitly freed by user already. */ |
105 | #define REDISMODULE_AM_DICT 4 |
106 | #define REDISMODULE_AM_INFO 5 |
107 | |
108 | /* The pool allocator block. Redis Modules can allocate memory via this special |
109 | * allocator that will automatically release it all once the callback returns. |
110 | * This means that it can only be used for ephemeral allocations. However |
111 | * there are two advantages for modules to use this API: |
112 | * |
113 | * 1) The memory is automatically released when the callback returns. |
114 | * 2) This allocator is faster for many small allocations since whole blocks |
115 | * are allocated, and small pieces returned to the caller just advancing |
116 | * the index of the allocation. |
117 | * |
118 | * Allocations are always rounded to the size of the void pointer in order |
119 | * to always return aligned memory chunks. */ |
120 | |
121 | #define REDISMODULE_POOL_ALLOC_MIN_SIZE (1024*8) |
122 | #define REDISMODULE_POOL_ALLOC_ALIGN (sizeof(void*)) |
123 | |
124 | typedef struct RedisModulePoolAllocBlock { |
125 | uint32_t size; |
126 | uint32_t used; |
127 | struct RedisModulePoolAllocBlock *next; |
128 | char memory[]; |
129 | } RedisModulePoolAllocBlock; |
130 | |
131 | /* This structure represents the context in which Redis modules operate. |
132 | * Most APIs module can access, get a pointer to the context, so that the API |
133 | * implementation can hold state across calls, or remember what to free after |
134 | * the call and so forth. |
135 | * |
136 | * Note that not all the context structure is always filled with actual values |
137 | * but only the fields needed in a given context. */ |
138 | |
139 | struct RedisModuleBlockedClient; |
140 | |
141 | struct RedisModuleCtx { |
142 | void *getapifuncptr; /* NOTE: Must be the first field. */ |
143 | struct RedisModule *module; /* Module reference. */ |
144 | client *client; /* Client calling a command. */ |
145 | struct RedisModuleBlockedClient *blocked_client; /* Blocked client for |
146 | thread safe context. */ |
147 | struct AutoMemEntry *amqueue; /* Auto memory queue of objects to free. */ |
148 | int amqueue_len; /* Number of slots in amqueue. */ |
149 | int amqueue_used; /* Number of used slots in amqueue. */ |
150 | int flags; /* REDISMODULE_CTX_... flags. */ |
151 | void **postponed_arrays; /* To set with RM_ReplySetArrayLength(). */ |
152 | int postponed_arrays_count; /* Number of entries in postponed_arrays. */ |
153 | void *blocked_privdata; /* Privdata set when unblocking a client. */ |
154 | RedisModuleString *blocked_ready_key; /* Key ready when the reply callback |
155 | gets called for clients blocked |
156 | on keys. */ |
157 | |
158 | /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST or |
159 | * REDISMODULE_CTX_CHANNEL_POS_REQUEST flag set. */ |
160 | getKeysResult *keys_result; |
161 | |
162 | struct RedisModulePoolAllocBlock *pa_head; |
163 | long long next_yield_time; |
164 | }; |
165 | typedef struct RedisModuleCtx RedisModuleCtx; |
166 | |
167 | #define REDISMODULE_CTX_NONE (0) |
168 | #define REDISMODULE_CTX_AUTO_MEMORY (1<<0) |
169 | #define REDISMODULE_CTX_KEYS_POS_REQUEST (1<<1) |
170 | #define REDISMODULE_CTX_BLOCKED_REPLY (1<<2) |
171 | #define REDISMODULE_CTX_BLOCKED_TIMEOUT (1<<3) |
172 | #define REDISMODULE_CTX_THREAD_SAFE (1<<4) |
173 | #define REDISMODULE_CTX_BLOCKED_DISCONNECTED (1<<5) |
174 | #define REDISMODULE_CTX_TEMP_CLIENT (1<<6) /* Return client object to the pool |
175 | when the context is destroyed */ |
176 | #define REDISMODULE_CTX_NEW_CLIENT (1<<7) /* Free client object when the |
177 | context is destroyed */ |
178 | #define REDISMODULE_CTX_CHANNELS_POS_REQUEST (1<<8) |
179 | |
180 | /* This represents a Redis key opened with RM_OpenKey(). */ |
181 | struct RedisModuleKey { |
182 | RedisModuleCtx *ctx; |
183 | redisDb *db; |
184 | robj *key; /* Key name object. */ |
185 | robj *value; /* Value object, or NULL if the key was not found. */ |
186 | void *iter; /* Iterator. */ |
187 | int mode; /* Opening mode. */ |
188 | |
189 | union { |
190 | struct { |
191 | /* List, use only if value->type == OBJ_LIST */ |
192 | listTypeEntry entry; /* Current entry in iteration. */ |
193 | long index; /* Current 0-based index in iteration. */ |
194 | } list; |
195 | struct { |
196 | /* Zset iterator, use only if value->type == OBJ_ZSET */ |
197 | uint32_t type; /* REDISMODULE_ZSET_RANGE_* */ |
198 | zrangespec rs; /* Score range. */ |
199 | zlexrangespec lrs; /* Lex range. */ |
200 | uint32_t start; /* Start pos for positional ranges. */ |
201 | uint32_t end; /* End pos for positional ranges. */ |
202 | void *current; /* Zset iterator current node. */ |
203 | int er; /* Zset iterator end reached flag |
204 | (true if end was reached). */ |
205 | } zset; |
206 | struct { |
207 | /* Stream, use only if value->type == OBJ_STREAM */ |
208 | streamID currentid; /* Current entry while iterating. */ |
209 | int64_t numfieldsleft; /* Fields left to fetch for current entry. */ |
210 | int signalready; /* Flag that signalKeyAsReady() is needed. */ |
211 | } stream; |
212 | } u; |
213 | }; |
214 | typedef struct RedisModuleKey RedisModuleKey; |
215 | |
216 | /* RedisModuleKey 'ztype' values. */ |
217 | #define REDISMODULE_ZSET_RANGE_NONE 0 /* This must always be 0. */ |
218 | #define REDISMODULE_ZSET_RANGE_LEX 1 |
219 | #define REDISMODULE_ZSET_RANGE_SCORE 2 |
220 | #define REDISMODULE_ZSET_RANGE_POS 3 |
221 | |
222 | /* Function pointer type of a function representing a command inside |
223 | * a Redis module. */ |
224 | struct RedisModuleBlockedClient; |
225 | typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, void **argv, int argc); |
226 | typedef void (*RedisModuleDisconnectFunc) (RedisModuleCtx *ctx, struct RedisModuleBlockedClient *bc); |
227 | |
228 | /* This struct holds the information about a command registered by a module.*/ |
229 | struct RedisModuleCommand { |
230 | struct RedisModule *module; |
231 | RedisModuleCmdFunc func; |
232 | struct redisCommand *rediscmd; |
233 | }; |
234 | typedef struct RedisModuleCommand RedisModuleCommand; |
235 | |
236 | #define REDISMODULE_REPLYFLAG_NONE 0 |
237 | #define REDISMODULE_REPLYFLAG_TOPARSE (1<<0) /* Protocol must be parsed. */ |
238 | #define REDISMODULE_REPLYFLAG_NESTED (1<<1) /* Nested reply object. No proto |
239 | or struct free. */ |
240 | |
241 | /* Reply of RM_Call() function. The function is filled in a lazy |
242 | * way depending on the function called on the reply structure. By default |
243 | * only the type, proto and protolen are filled. */ |
244 | typedef struct CallReply RedisModuleCallReply; |
245 | |
246 | /* Structure representing a blocked client. We get a pointer to such |
247 | * an object when blocking from modules. */ |
248 | typedef struct RedisModuleBlockedClient { |
249 | client *client; /* Pointer to the blocked client. or NULL if the client |
250 | was destroyed during the life of this object. */ |
251 | RedisModule *module; /* Module blocking the client. */ |
252 | RedisModuleCmdFunc reply_callback; /* Reply callback on normal completion.*/ |
253 | RedisModuleCmdFunc timeout_callback; /* Reply callback on timeout. */ |
254 | RedisModuleDisconnectFunc disconnect_callback; /* Called on disconnection.*/ |
255 | void (*free_privdata)(RedisModuleCtx*,void*);/* privdata cleanup callback.*/ |
256 | void *privdata; /* Module private data that may be used by the reply |
257 | or timeout callback. It is set via the |
258 | RedisModule_UnblockClient() API. */ |
259 | client *thread_safe_ctx_client; /* Fake client to be used for thread safe |
260 | context so that no lock is required. */ |
261 | client *reply_client; /* Fake client used to accumulate replies |
262 | in thread safe contexts. */ |
263 | int dbid; /* Database number selected by the original client. */ |
264 | int blocked_on_keys; /* If blocked via RM_BlockClientOnKeys(). */ |
265 | int unblocked; /* Already on the moduleUnblocked list. */ |
266 | monotime background_timer; /* Timer tracking the start of background work */ |
267 | uint64_t background_duration; /* Current command background time duration. |
268 | Used for measuring latency of blocking cmds */ |
269 | } RedisModuleBlockedClient; |
270 | |
271 | static pthread_mutex_t moduleUnblockedClientsMutex = PTHREAD_MUTEX_INITIALIZER; |
272 | static list *moduleUnblockedClients; |
273 | |
274 | /* Pool for temporary client objects. Creating and destroying a client object is |
275 | * costly. We manage a pool of clients to avoid this cost. Pool expands when |
276 | * more clients are needed and shrinks when unused. Please see modulesCron() |
277 | * for more details. */ |
278 | static client **moduleTempClients; |
279 | static size_t moduleTempClientCap = 0; |
280 | static size_t moduleTempClientCount = 0; /* Client count in pool */ |
281 | static size_t moduleTempClientMinCount = 0; /* Min client count in pool since |
282 | the last cron. */ |
283 | |
284 | /* We need a mutex that is unlocked / relocked in beforeSleep() in order to |
285 | * allow thread safe contexts to execute commands at a safe moment. */ |
286 | static pthread_mutex_t moduleGIL = PTHREAD_MUTEX_INITIALIZER; |
287 | |
288 | |
289 | /* Function pointer type for keyspace event notification subscriptions from modules. */ |
290 | typedef int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key); |
291 | |
292 | /* Keyspace notification subscriber information. |
293 | * See RM_SubscribeToKeyspaceEvents() for more information. */ |
294 | typedef struct RedisModuleKeyspaceSubscriber { |
295 | /* The module subscribed to the event */ |
296 | RedisModule *module; |
297 | /* Notification callback in the module*/ |
298 | RedisModuleNotificationFunc notify_callback; |
299 | /* A bit mask of the events the module is interested in */ |
300 | int event_mask; |
301 | /* Active flag set on entry, to avoid reentrant subscribers |
302 | * calling themselves */ |
303 | int active; |
304 | } RedisModuleKeyspaceSubscriber; |
305 | |
306 | /* The module keyspace notification subscribers list */ |
307 | static list *moduleKeyspaceSubscribers; |
308 | |
309 | /* Data structures related to the exported dictionary data structure. */ |
310 | typedef struct RedisModuleDict { |
311 | rax *rax; /* The radix tree. */ |
312 | } RedisModuleDict; |
313 | |
314 | typedef struct RedisModuleDictIter { |
315 | RedisModuleDict *dict; |
316 | raxIterator ri; |
317 | } RedisModuleDictIter; |
318 | |
319 | typedef struct RedisModuleCommandFilterCtx { |
320 | RedisModuleString **argv; |
321 | int argc; |
322 | } RedisModuleCommandFilterCtx; |
323 | |
324 | typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter); |
325 | |
326 | typedef struct RedisModuleCommandFilter { |
327 | /* The module that registered the filter */ |
328 | RedisModule *module; |
329 | /* Filter callback function */ |
330 | RedisModuleCommandFilterFunc callback; |
331 | /* REDISMODULE_CMDFILTER_* flags */ |
332 | int flags; |
333 | } RedisModuleCommandFilter; |
334 | |
335 | /* Registered filters */ |
336 | static list *moduleCommandFilters; |
337 | |
338 | typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data); |
339 | |
340 | static struct RedisModuleForkInfo { |
341 | RedisModuleForkDoneHandler done_handler; |
342 | void* done_handler_user_data; |
343 | } moduleForkInfo = {0}; |
344 | |
345 | typedef struct RedisModuleServerInfoData { |
346 | rax *rax; /* parsed info data. */ |
347 | } RedisModuleServerInfoData; |
348 | |
349 | /* Flags for moduleCreateArgvFromUserFormat(). */ |
350 | #define REDISMODULE_ARGV_REPLICATE (1<<0) |
351 | #define REDISMODULE_ARGV_NO_AOF (1<<1) |
352 | #define REDISMODULE_ARGV_NO_REPLICAS (1<<2) |
353 | #define REDISMODULE_ARGV_RESP_3 (1<<3) |
354 | #define REDISMODULE_ARGV_RESP_AUTO (1<<4) |
355 | #define REDISMODULE_ARGV_CHECK_ACL (1<<5) |
356 | #define REDISMODULE_ARGV_SCRIPT_MODE (1<<6) |
357 | #define REDISMODULE_ARGV_NO_WRITES (1<<7) |
358 | #define REDISMODULE_ARGV_CALL_REPLIES_AS_ERRORS (1<<8) |
359 | #define REDISMODULE_ARGV_RESPECT_DENY_OOM (1<<9) |
360 | |
361 | /* Determine whether Redis should signalModifiedKey implicitly. |
362 | * In case 'ctx' has no 'module' member (and therefore no module->options), |
363 | * we assume default behavior, that is, Redis signals. |
364 | * (see RM_GetThreadSafeContext) */ |
365 | #define SHOULD_SIGNAL_MODIFIED_KEYS(ctx) \ |
366 | ctx->module? !(ctx->module->options & REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED) : 1 |
367 | |
368 | /* Server events hooks data structures and defines: this modules API |
369 | * allow modules to subscribe to certain events in Redis, such as |
370 | * the start and end of an RDB or AOF save, the change of role in replication, |
371 | * and similar other events. */ |
372 | |
373 | typedef struct RedisModuleEventListener { |
374 | RedisModule *module; |
375 | RedisModuleEvent event; |
376 | RedisModuleEventCallback callback; |
377 | } RedisModuleEventListener; |
378 | |
379 | list *RedisModule_EventListeners; /* Global list of all the active events. */ |
380 | |
381 | /* Data structures related to the redis module users */ |
382 | |
383 | /* This is the object returned by RM_CreateModuleUser(). The module API is |
384 | * able to create users, set ACLs to such users, and later authenticate |
385 | * clients using such newly created users. */ |
386 | typedef struct RedisModuleUser { |
387 | user *user; /* Reference to the real redis user */ |
388 | int free_user; /* Indicates that user should also be freed when this object is freed */ |
389 | } RedisModuleUser; |
390 | |
391 | /* This is a structure used to export some meta-information such as dbid to the module. */ |
392 | typedef struct RedisModuleKeyOptCtx { |
393 | struct redisObject *from_key, *to_key; /* Optional name of key processed, NULL when unknown. |
394 | In most cases, only 'from_key' is valid, but in callbacks |
395 | such as `copy2`, both 'from_key' and 'to_key' are valid. */ |
396 | int from_dbid, to_dbid; /* The dbid of the key being processed, -1 when unknown. |
397 | In most cases, only 'from_dbid' is valid, but in callbacks such |
398 | as `copy2`, 'from_dbid' and 'to_dbid' are both valid. */ |
399 | } RedisModuleKeyOptCtx; |
400 | |
401 | /* Data structures related to redis module configurations */ |
402 | /* The function signatures for module config get callbacks. These are identical to the ones exposed in redismodule.h. */ |
403 | typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata); |
404 | typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata); |
405 | typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata); |
406 | typedef int (*RedisModuleConfigGetEnumFunc)(const char *name, void *privdata); |
407 | /* The function signatures for module config set callbacks. These are identical to the ones exposed in redismodule.h. */ |
408 | typedef int (*RedisModuleConfigSetStringFunc)(const char *name, RedisModuleString *val, void *privdata, RedisModuleString **err); |
409 | typedef int (*RedisModuleConfigSetNumericFunc)(const char *name, long long val, void *privdata, RedisModuleString **err); |
410 | typedef int (*RedisModuleConfigSetBoolFunc)(const char *name, int val, void *privdata, RedisModuleString **err); |
411 | typedef int (*RedisModuleConfigSetEnumFunc)(const char *name, int val, void *privdata, RedisModuleString **err); |
412 | /* Apply signature, identical to redismodule.h */ |
413 | typedef int (*RedisModuleConfigApplyFunc)(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err); |
414 | |
415 | /* Struct representing a module config. These are stored in a list in the module struct */ |
416 | struct ModuleConfig { |
417 | sds name; /* Name of config without the module name appended to the front */ |
418 | void *privdata; /* Optional data passed into the module config callbacks */ |
419 | union get_fn { /* The get callback specified by the module */ |
420 | RedisModuleConfigGetStringFunc get_string; |
421 | RedisModuleConfigGetNumericFunc get_numeric; |
422 | RedisModuleConfigGetBoolFunc get_bool; |
423 | RedisModuleConfigGetEnumFunc get_enum; |
424 | } get_fn; |
425 | union set_fn { /* The set callback specified by the module */ |
426 | RedisModuleConfigSetStringFunc set_string; |
427 | RedisModuleConfigSetNumericFunc set_numeric; |
428 | RedisModuleConfigSetBoolFunc set_bool; |
429 | RedisModuleConfigSetEnumFunc set_enum; |
430 | } set_fn; |
431 | RedisModuleConfigApplyFunc apply_fn; |
432 | RedisModule *module; |
433 | }; |
434 | |
435 | /* -------------------------------------------------------------------------- |
436 | * Prototypes |
437 | * -------------------------------------------------------------------------- */ |
438 | |
439 | void RM_FreeCallReply(RedisModuleCallReply *reply); |
440 | void RM_CloseKey(RedisModuleKey *key); |
441 | void autoMemoryCollect(RedisModuleCtx *ctx); |
442 | robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int *argcp, int *argvlenp, int *flags, va_list ap); |
443 | void RM_ZsetRangeStop(RedisModuleKey *kp); |
444 | static void zsetKeyReset(RedisModuleKey *key); |
445 | static void moduleInitKeyTypeSpecific(RedisModuleKey *key); |
446 | void RM_FreeDict(RedisModuleCtx *ctx, RedisModuleDict *d); |
447 | void RM_FreeServerInfo(RedisModuleCtx *ctx, RedisModuleServerInfoData *data); |
448 | |
449 | /* Helpers for RM_SetCommandInfo. */ |
450 | static int moduleValidateCommandInfo(const RedisModuleCommandInfo *info); |
451 | static int64_t moduleConvertKeySpecsFlags(int64_t flags, int from_api); |
452 | static int moduleValidateCommandArgs(RedisModuleCommandArg *args, |
453 | const RedisModuleCommandInfoVersion *version); |
454 | static struct redisCommandArg *moduleCopyCommandArgs(RedisModuleCommandArg *args, |
455 | const RedisModuleCommandInfoVersion *version); |
456 | static redisCommandArgType moduleConvertArgType(RedisModuleCommandArgType type, int *error); |
457 | static int moduleConvertArgFlags(int flags); |
458 | |
459 | /* -------------------------------------------------------------------------- |
460 | * ## Heap allocation raw functions |
461 | * |
462 | * Memory allocated with these functions are taken into account by Redis key |
463 | * eviction algorithms and are reported in Redis memory usage information. |
464 | * -------------------------------------------------------------------------- */ |
465 | |
466 | /* Use like malloc(). Memory allocated with this function is reported in |
467 | * Redis INFO memory, used for keys eviction according to maxmemory settings |
468 | * and in general is taken into account as memory allocated by Redis. |
469 | * You should avoid using malloc(). |
470 | * This function panics if unable to allocate enough memory. */ |
471 | void *RM_Alloc(size_t bytes) { |
472 | return zmalloc(bytes); |
473 | } |
474 | |
475 | /* Similar to RM_Alloc, but returns NULL in case of allocation failure, instead |
476 | * of panicking. */ |
477 | void *RM_TryAlloc(size_t bytes) { |
478 | return ztrymalloc(bytes); |
479 | } |
480 | |
481 | /* Use like calloc(). Memory allocated with this function is reported in |
482 | * Redis INFO memory, used for keys eviction according to maxmemory settings |
483 | * and in general is taken into account as memory allocated by Redis. |
484 | * You should avoid using calloc() directly. */ |
485 | void *RM_Calloc(size_t nmemb, size_t size) { |
486 | return zcalloc(nmemb*size); |
487 | } |
488 | |
489 | /* Use like realloc() for memory obtained with RedisModule_Alloc(). */ |
490 | void* RM_Realloc(void *ptr, size_t bytes) { |
491 | return zrealloc(ptr,bytes); |
492 | } |
493 | |
494 | /* Use like free() for memory obtained by RedisModule_Alloc() and |
495 | * RedisModule_Realloc(). However you should never try to free with |
496 | * RedisModule_Free() memory allocated with malloc() inside your module. */ |
497 | void RM_Free(void *ptr) { |
498 | zfree(ptr); |
499 | } |
500 | |
501 | /* Like strdup() but returns memory allocated with RedisModule_Alloc(). */ |
502 | char *RM_Strdup(const char *str) { |
503 | return zstrdup(str); |
504 | } |
505 | |
506 | /* -------------------------------------------------------------------------- |
507 | * Pool allocator |
508 | * -------------------------------------------------------------------------- */ |
509 | |
510 | /* Release the chain of blocks used for pool allocations. */ |
511 | void poolAllocRelease(RedisModuleCtx *ctx) { |
512 | RedisModulePoolAllocBlock *head = ctx->pa_head, *next; |
513 | |
514 | while(head != NULL) { |
515 | next = head->next; |
516 | zfree(head); |
517 | head = next; |
518 | } |
519 | ctx->pa_head = NULL; |
520 | } |
521 | |
522 | /* Return heap allocated memory that will be freed automatically when the |
523 | * module callback function returns. Mostly suitable for small allocations |
524 | * that are short living and must be released when the callback returns |
525 | * anyway. The returned memory is aligned to the architecture word size |
526 | * if at least word size bytes are requested, otherwise it is just |
527 | * aligned to the next power of two, so for example a 3 bytes request is |
528 | * 4 bytes aligned while a 2 bytes request is 2 bytes aligned. |
529 | * |
530 | * There is no realloc style function since when this is needed to use the |
531 | * pool allocator is not a good idea. |
532 | * |
533 | * The function returns NULL if `bytes` is 0. */ |
534 | void *RM_PoolAlloc(RedisModuleCtx *ctx, size_t bytes) { |
535 | if (bytes == 0) return NULL; |
536 | RedisModulePoolAllocBlock *b = ctx->pa_head; |
537 | size_t left = b ? b->size - b->used : 0; |
538 | |
539 | /* Fix alignment. */ |
540 | if (left >= bytes) { |
541 | size_t alignment = REDISMODULE_POOL_ALLOC_ALIGN; |
542 | while (bytes < alignment && alignment/2 >= bytes) alignment /= 2; |
543 | if (b->used % alignment) |
544 | b->used += alignment - (b->used % alignment); |
545 | left = (b->used > b->size) ? 0 : b->size - b->used; |
546 | } |
547 | |
548 | /* Create a new block if needed. */ |
549 | if (left < bytes) { |
550 | size_t blocksize = REDISMODULE_POOL_ALLOC_MIN_SIZE; |
551 | if (blocksize < bytes) blocksize = bytes; |
552 | b = zmalloc(sizeof(*b) + blocksize); |
553 | b->size = blocksize; |
554 | b->used = 0; |
555 | b->next = ctx->pa_head; |
556 | ctx->pa_head = b; |
557 | } |
558 | |
559 | char *retval = b->memory + b->used; |
560 | b->used += bytes; |
561 | return retval; |
562 | } |
563 | |
564 | /* -------------------------------------------------------------------------- |
565 | * Helpers for modules API implementation |
566 | * -------------------------------------------------------------------------- */ |
567 | |
568 | client *moduleAllocTempClient() { |
569 | client *c = NULL; |
570 | |
571 | if (moduleTempClientCount > 0) { |
572 | c = moduleTempClients[--moduleTempClientCount]; |
573 | if (moduleTempClientCount < moduleTempClientMinCount) |
574 | moduleTempClientMinCount = moduleTempClientCount; |
575 | } else { |
576 | c = createClient(NULL); |
577 | c->flags |= CLIENT_MODULE; |
578 | c->user = NULL; /* Root user */ |
579 | } |
580 | return c; |
581 | } |
582 | |
583 | void moduleReleaseTempClient(client *c) { |
584 | if (moduleTempClientCount == moduleTempClientCap) { |
585 | moduleTempClientCap = moduleTempClientCap ? moduleTempClientCap*2 : 32; |
586 | moduleTempClients = zrealloc(moduleTempClients, sizeof(c)*moduleTempClientCap); |
587 | } |
588 | clearClientConnectionState(c); |
589 | listEmpty(c->reply); |
590 | c->reply_bytes = 0; |
591 | resetClient(c); |
592 | c->bufpos = 0; |
593 | c->flags = CLIENT_MODULE; |
594 | c->user = NULL; /* Root user */ |
595 | moduleTempClients[moduleTempClientCount++] = c; |
596 | } |
597 | |
598 | /* Create an empty key of the specified type. `key` must point to a key object |
599 | * opened for writing where the `.value` member is set to NULL because the |
600 | * key was found to be non existing. |
601 | * |
602 | * On success REDISMODULE_OK is returned and the key is populated with |
603 | * the value of the specified type. The function fails and returns |
604 | * REDISMODULE_ERR if: |
605 | * |
606 | * 1. The key is not open for writing. |
607 | * 2. The key is not empty. |
608 | * 3. The specified type is unknown. |
609 | */ |
610 | int moduleCreateEmptyKey(RedisModuleKey *key, int type) { |
611 | robj *obj; |
612 | |
613 | /* The key must be open for writing and non existing to proceed. */ |
614 | if (!(key->mode & REDISMODULE_WRITE) || key->value) |
615 | return REDISMODULE_ERR; |
616 | |
617 | switch(type) { |
618 | case REDISMODULE_KEYTYPE_LIST: |
619 | obj = createQuicklistObject(); |
620 | quicklistSetOptions(obj->ptr, server.list_max_listpack_size, |
621 | server.list_compress_depth); |
622 | break; |
623 | case REDISMODULE_KEYTYPE_ZSET: |
624 | obj = createZsetListpackObject(); |
625 | break; |
626 | case REDISMODULE_KEYTYPE_HASH: |
627 | obj = createHashObject(); |
628 | break; |
629 | case REDISMODULE_KEYTYPE_STREAM: |
630 | obj = createStreamObject(); |
631 | break; |
632 | default: return REDISMODULE_ERR; |
633 | } |
634 | dbAdd(key->db,key->key,obj); |
635 | key->value = obj; |
636 | moduleInitKeyTypeSpecific(key); |
637 | return REDISMODULE_OK; |
638 | } |
639 | |
640 | /* Frees key->iter and sets it to NULL. */ |
641 | static void moduleFreeKeyIterator(RedisModuleKey *key) { |
642 | serverAssert(key->iter != NULL); |
643 | switch (key->value->type) { |
644 | case OBJ_LIST: listTypeReleaseIterator(key->iter); break; |
645 | case OBJ_STREAM: |
646 | streamIteratorStop(key->iter); |
647 | zfree(key->iter); |
648 | break; |
649 | default: serverAssert(0); /* No key->iter for other types. */ |
650 | } |
651 | key->iter = NULL; |
652 | } |
653 | |
654 | /* This function is called in low-level API implementation functions in order |
655 | * to check if the value associated with the key remained empty after an |
656 | * operation that removed elements from an aggregate data type. |
657 | * |
658 | * If this happens, the key is deleted from the DB and the key object state |
659 | * is set to the right one in order to be targeted again by write operations |
660 | * possibly recreating the key if needed. |
661 | * |
662 | * The function returns 1 if the key value object is found empty and is |
663 | * deleted, otherwise 0 is returned. */ |
664 | int moduleDelKeyIfEmpty(RedisModuleKey *key) { |
665 | if (!(key->mode & REDISMODULE_WRITE) || key->value == NULL) return 0; |
666 | int isempty; |
667 | robj *o = key->value; |
668 | |
669 | switch(o->type) { |
670 | case OBJ_LIST: isempty = listTypeLength(o) == 0; break; |
671 | case OBJ_SET: isempty = setTypeSize(o) == 0; break; |
672 | case OBJ_ZSET: isempty = zsetLength(o) == 0; break; |
673 | case OBJ_HASH: isempty = hashTypeLength(o) == 0; break; |
674 | case OBJ_STREAM: isempty = streamLength(o) == 0; break; |
675 | default: isempty = 0; |
676 | } |
677 | |
678 | if (isempty) { |
679 | if (key->iter) moduleFreeKeyIterator(key); |
680 | dbDelete(key->db,key->key); |
681 | key->value = NULL; |
682 | return 1; |
683 | } else { |
684 | return 0; |
685 | } |
686 | } |
687 | |
688 | /* -------------------------------------------------------------------------- |
689 | * Service API exported to modules |
690 | * |
691 | * Note that all the exported APIs are called RM_<funcname> in the core |
692 | * and RedisModule_<funcname> in the module side (defined as function |
693 | * pointers in redismodule.h). In this way the dynamic linker does not |
694 | * mess with our global function pointers, overriding it with the symbols |
695 | * defined in the main executable having the same names. |
696 | * -------------------------------------------------------------------------- */ |
697 | |
698 | int RM_GetApi(const char *funcname, void **targetPtrPtr) { |
699 | /* Lookup the requested module API and store the function pointer into the |
700 | * target pointer. The function returns REDISMODULE_ERR if there is no such |
701 | * named API, otherwise REDISMODULE_OK. |
702 | * |
703 | * This function is not meant to be used by modules developer, it is only |
704 | * used implicitly by including redismodule.h. */ |
705 | dictEntry *he = dictFind(server.moduleapi, funcname); |
706 | if (!he) return REDISMODULE_ERR; |
707 | *targetPtrPtr = dictGetVal(he); |
708 | return REDISMODULE_OK; |
709 | } |
710 | |
711 | /* Free the context after the user function was called. */ |
712 | void moduleFreeContext(RedisModuleCtx *ctx) { |
713 | if (!(ctx->flags & REDISMODULE_CTX_THREAD_SAFE)) { |
714 | /* Modules take care of their own propagation, when we are |
715 | * outside of call() context (timers, events, etc.). */ |
716 | if (--server.module_ctx_nesting == 0) { |
717 | if (!server.core_propagates) |
718 | propagatePendingCommands(); |
719 | if (server.busy_module_yield_flags) { |
720 | blockingOperationEnds(); |
721 | server.busy_module_yield_flags = BUSY_MODULE_YIELD_NONE; |
722 | if (server.current_client) |
723 | unprotectClient(server.current_client); |
724 | unblockPostponedClients(); |
725 | } |
726 | } |
727 | } |
728 | autoMemoryCollect(ctx); |
729 | poolAllocRelease(ctx); |
730 | if (ctx->postponed_arrays) { |
731 | zfree(ctx->postponed_arrays); |
732 | ctx->postponed_arrays_count = 0; |
733 | serverLog(LL_WARNING, |
734 | "API misuse detected in module %s: " |
735 | "RedisModule_ReplyWith*(REDISMODULE_POSTPONED_LEN) " |
736 | "not matched by the same number of RedisModule_SetReply*Len() " |
737 | "calls." , |
738 | ctx->module->name); |
739 | } |
740 | /* If this context has a temp client, we return it back to the pool. |
741 | * If this context created a new client (e.g detached context), we free it. |
742 | * If the client is assigned manually, e.g ctx->client = someClientInstance, |
743 | * none of these flags will be set and we do not attempt to free it. */ |
744 | if (ctx->flags & REDISMODULE_CTX_TEMP_CLIENT) |
745 | moduleReleaseTempClient(ctx->client); |
746 | else if (ctx->flags & REDISMODULE_CTX_NEW_CLIENT) |
747 | freeClient(ctx->client); |
748 | } |
749 | |
750 | /* Create a module ctx and keep track of the nesting level. |
751 | * |
752 | * Note: When creating ctx for threads (RM_GetThreadSafeContext and |
753 | * RM_GetDetachedThreadSafeContext) we do not bump up the nesting level |
754 | * because we only need to track of nesting level in the main thread |
755 | * (only the main thread uses propagatePendingCommands) */ |
756 | void moduleCreateContext(RedisModuleCtx *out_ctx, RedisModule *module, int ctx_flags) { |
757 | memset(out_ctx, 0 ,sizeof(RedisModuleCtx)); |
758 | out_ctx->getapifuncptr = (void*)(unsigned long)&RM_GetApi; |
759 | out_ctx->module = module; |
760 | out_ctx->flags = ctx_flags; |
761 | if (ctx_flags & REDISMODULE_CTX_TEMP_CLIENT) |
762 | out_ctx->client = moduleAllocTempClient(); |
763 | else if (ctx_flags & REDISMODULE_CTX_NEW_CLIENT) |
764 | out_ctx->client = createClient(NULL); |
765 | |
766 | /* Calculate the initial yield time for long blocked contexts. |
767 | * in loading we depend on the server hz, but in other cases we also wait |
768 | * for busy_reply_threshold. |
769 | * Note that in theory we could have started processing BUSY_MODULE_YIELD_EVENTS |
770 | * sooner, and only delay the processing for clients till the busy_reply_threshold, |
771 | * but this carries some overheads of frequently marking clients with BLOCKED_POSTPONE |
772 | * and releasing them, i.e. if modules only block for short periods. */ |
773 | if (server.loading) |
774 | out_ctx->next_yield_time = getMonotonicUs() + 1000000 / server.hz; |
775 | else |
776 | out_ctx->next_yield_time = getMonotonicUs() + server.busy_reply_threshold * 1000; |
777 | |
778 | if (!(ctx_flags & REDISMODULE_CTX_THREAD_SAFE)) { |
779 | server.module_ctx_nesting++; |
780 | } |
781 | } |
782 | |
783 | /* This Redis command binds the normal Redis command invocation with commands |
784 | * exported by modules. */ |
785 | void RedisModuleCommandDispatcher(client *c) { |
786 | RedisModuleCommand *cp = c->cmd->module_cmd; |
787 | RedisModuleCtx ctx; |
788 | moduleCreateContext(&ctx, cp->module, REDISMODULE_CTX_NONE); |
789 | |
790 | ctx.client = c; |
791 | cp->func(&ctx,(void**)c->argv,c->argc); |
792 | moduleFreeContext(&ctx); |
793 | |
794 | /* In some cases processMultibulkBuffer uses sdsMakeRoomFor to |
795 | * expand the query buffer, and in order to avoid a big object copy |
796 | * the query buffer SDS may be used directly as the SDS string backing |
797 | * the client argument vectors: sometimes this will result in the SDS |
798 | * string having unused space at the end. Later if a module takes ownership |
799 | * of the RedisString, such space will be wasted forever. Inside the |
800 | * Redis core this is not a problem because tryObjectEncoding() is called |
801 | * before storing strings in the key space. Here we need to do it |
802 | * for the module. */ |
803 | for (int i = 0; i < c->argc; i++) { |
804 | /* Only do the work if the module took ownership of the object: |
805 | * in that case the refcount is no longer 1. */ |
806 | if (c->argv[i]->refcount > 1) |
807 | trimStringObjectIfNeeded(c->argv[i]); |
808 | } |
809 | } |
810 | |
811 | /* This function returns the list of keys, with the same interface as the |
812 | * 'getkeys' function of the native commands, for module commands that exported |
813 | * the "getkeys-api" flag during the registration. This is done when the |
814 | * list of keys are not at fixed positions, so that first/last/step cannot |
815 | * be used. |
816 | * |
817 | * In order to accomplish its work, the module command is called, flagging |
818 | * the context in a way that the command can recognize this is a special |
819 | * "get keys" call by calling RedisModule_IsKeysPositionRequest(ctx). */ |
820 | int moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { |
821 | RedisModuleCommand *cp = cmd->module_cmd; |
822 | RedisModuleCtx ctx; |
823 | moduleCreateContext(&ctx, cp->module, REDISMODULE_CTX_KEYS_POS_REQUEST); |
824 | |
825 | /* Initialize getKeysResult */ |
826 | getKeysPrepareResult(result, MAX_KEYS_BUFFER); |
827 | ctx.keys_result = result; |
828 | |
829 | cp->func(&ctx,(void**)argv,argc); |
830 | /* We currently always use the array allocated by RM_KeyAtPos() and don't try |
831 | * to optimize for the pre-allocated buffer. |
832 | */ |
833 | moduleFreeContext(&ctx); |
834 | return result->numkeys; |
835 | } |
836 | |
837 | /* This function returns the list of channels, with the same interface as |
838 | * moduleGetCommandKeysViaAPI, for modules that declare "getchannels-api" |
839 | * during registration. Unlike keys, this is the only way to declare channels. */ |
840 | int moduleGetCommandChannelsViaAPI(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { |
841 | RedisModuleCommand *cp = cmd->module_cmd; |
842 | RedisModuleCtx ctx; |
843 | moduleCreateContext(&ctx, cp->module, REDISMODULE_CTX_CHANNELS_POS_REQUEST); |
844 | |
845 | /* Initialize getKeysResult */ |
846 | getKeysPrepareResult(result, MAX_KEYS_BUFFER); |
847 | ctx.keys_result = result; |
848 | |
849 | cp->func(&ctx,(void**)argv,argc); |
850 | /* We currently always use the array allocated by RM_RM_ChannelAtPosWithFlags() and don't try |
851 | * to optimize for the pre-allocated buffer. */ |
852 | moduleFreeContext(&ctx); |
853 | return result->numkeys; |
854 | } |
855 | |
856 | /* -------------------------------------------------------------------------- |
857 | * ## Commands API |
858 | * |
859 | * These functions are used to implement custom Redis commands. |
860 | * |
861 | * For examples, see https://redis.io/topics/modules-intro. |
862 | * -------------------------------------------------------------------------- */ |
863 | |
864 | /* Return non-zero if a module command, that was declared with the |
865 | * flag "getkeys-api", is called in a special way to get the keys positions |
866 | * and not to get executed. Otherwise zero is returned. */ |
867 | int RM_IsKeysPositionRequest(RedisModuleCtx *ctx) { |
868 | return (ctx->flags & REDISMODULE_CTX_KEYS_POS_REQUEST) != 0; |
869 | } |
870 | |
871 | /* When a module command is called in order to obtain the position of |
872 | * keys, since it was flagged as "getkeys-api" during the registration, |
873 | * the command implementation checks for this special call using the |
874 | * RedisModule_IsKeysPositionRequest() API and uses this function in |
875 | * order to report keys. |
876 | * |
877 | * The supported flags are the ones used by RM_SetCommandInfo, see REDISMODULE_CMD_KEY_*. |
878 | * |
879 | * |
880 | * The following is an example of how it could be used: |
881 | * |
882 | * if (RedisModule_IsKeysPositionRequest(ctx)) { |
883 | * RedisModule_KeyAtPosWithFlags(ctx, 2, REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS); |
884 | * RedisModule_KeyAtPosWithFlags(ctx, 1, REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE | REDISMODULE_CMD_KEY_ACCESS); |
885 | * } |
886 | * |
887 | * Note: in the example above the get keys API could have been handled by key-specs (preferred). |
888 | * Implementing the getkeys-api is required only when is it not possible to declare key-specs that cover all keys. |
889 | * |
890 | */ |
891 | void RM_KeyAtPosWithFlags(RedisModuleCtx *ctx, int pos, int flags) { |
892 | if (!(ctx->flags & REDISMODULE_CTX_KEYS_POS_REQUEST) || !ctx->keys_result) return; |
893 | if (pos <= 0) return; |
894 | |
895 | getKeysResult *res = ctx->keys_result; |
896 | |
897 | /* Check overflow */ |
898 | if (res->numkeys == res->size) { |
899 | int newsize = res->size + (res->size > 8192 ? 8192 : res->size); |
900 | getKeysPrepareResult(res, newsize); |
901 | } |
902 | |
903 | res->keys[res->numkeys].pos = pos; |
904 | res->keys[res->numkeys].flags = moduleConvertKeySpecsFlags(flags, 1); |
905 | res->numkeys++; |
906 | } |
907 | |
908 | /* This API existed before RM_KeyAtPosWithFlags was added, now deprecated and |
909 | * can be used for compatibility with older versions, before key-specs and flags |
910 | * were introduced. */ |
911 | void RM_KeyAtPos(RedisModuleCtx *ctx, int pos) { |
912 | /* Default flags require full access */ |
913 | int flags = moduleConvertKeySpecsFlags(CMD_KEY_FULL_ACCESS, 0); |
914 | RM_KeyAtPosWithFlags(ctx, pos, flags); |
915 | } |
916 | |
917 | /* Return non-zero if a module command, that was declared with the |
918 | * flag "getchannels-api", is called in a special way to get the channel positions |
919 | * and not to get executed. Otherwise zero is returned. */ |
920 | int RM_IsChannelsPositionRequest(RedisModuleCtx *ctx) { |
921 | return (ctx->flags & REDISMODULE_CTX_CHANNELS_POS_REQUEST) != 0; |
922 | } |
923 | |
924 | /* When a module command is called in order to obtain the position of |
925 | * channels, since it was flagged as "getchannels-api" during the |
926 | * registration, the command implementation checks for this special call |
927 | * using the RedisModule_IsChannelsPositionRequest() API and uses this |
928 | * function in order to report the channels. |
929 | * |
930 | * The supported flags are: |
931 | * * REDISMODULE_CMD_CHANNEL_SUBSCRIBE: This command will subscribe to the channel. |
932 | * * REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE: This command will unsubscribe from this channel. |
933 | * * REDISMODULE_CMD_CHANNEL_PUBLISH: This command will publish to this channel. |
934 | * * REDISMODULE_CMD_CHANNEL_PATTERN: Instead of acting on a specific channel, will act on any |
935 | * channel specified by the pattern. This is the same access |
936 | * used by the PSUBSCRIBE and PUNSUBSCRIBE commands available |
937 | * in Redis. Not intended to be used with PUBLISH permissions. |
938 | * |
939 | * The following is an example of how it could be used: |
940 | * |
941 | * if (RedisModule_IsChannelsPositionRequest(ctx)) { |
942 | * RedisModule_ChannelAtPosWithFlags(ctx, 1, REDISMODULE_CMD_CHANNEL_SUBSCRIBE | REDISMODULE_CMD_CHANNEL_PATTERN); |
943 | * RedisModule_ChannelAtPosWithFlags(ctx, 1, REDISMODULE_CMD_CHANNEL_PUBLISH); |
944 | * } |
945 | * |
946 | * Note: One usage of declaring channels is for evaluating ACL permissions. In this context, |
947 | * unsubscribing is always allowed, so commands will only be checked against subscribe and |
948 | * publish permissions. This is preferred over using RM_ACLCheckChannelPermissions, since |
949 | * it allows the ACLs to be checked before the command is executed. */ |
950 | void RM_ChannelAtPosWithFlags(RedisModuleCtx *ctx, int pos, int flags) { |
951 | if (!(ctx->flags & REDISMODULE_CTX_CHANNELS_POS_REQUEST) || !ctx->keys_result) return; |
952 | if (pos <= 0) return; |
953 | |
954 | getKeysResult *res = ctx->keys_result; |
955 | |
956 | /* Check overflow */ |
957 | if (res->numkeys == res->size) { |
958 | int newsize = res->size + (res->size > 8192 ? 8192 : res->size); |
959 | getKeysPrepareResult(res, newsize); |
960 | } |
961 | |
962 | int new_flags = 0; |
963 | if (flags & REDISMODULE_CMD_CHANNEL_SUBSCRIBE) new_flags |= CMD_CHANNEL_SUBSCRIBE; |
964 | if (flags & REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE) new_flags |= CMD_CHANNEL_UNSUBSCRIBE; |
965 | if (flags & REDISMODULE_CMD_CHANNEL_PUBLISH) new_flags |= CMD_CHANNEL_PUBLISH; |
966 | if (flags & REDISMODULE_CMD_CHANNEL_PATTERN) new_flags |= CMD_CHANNEL_PATTERN; |
967 | |
968 | res->keys[res->numkeys].pos = pos; |
969 | res->keys[res->numkeys].flags = new_flags; |
970 | res->numkeys++; |
971 | } |
972 | |
973 | /* Helper for RM_CreateCommand(). Turns a string representing command |
974 | * flags into the command flags used by the Redis core. |
975 | * |
976 | * It returns the set of flags, or -1 if unknown flags are found. */ |
977 | int64_t commandFlagsFromString(char *s) { |
978 | int count, j; |
979 | int64_t flags = 0; |
980 | sds *tokens = sdssplitlen(s,strlen(s)," " ,1,&count); |
981 | for (j = 0; j < count; j++) { |
982 | char *t = tokens[j]; |
983 | if (!strcasecmp(t,"write" )) flags |= CMD_WRITE; |
984 | else if (!strcasecmp(t,"readonly" )) flags |= CMD_READONLY; |
985 | else if (!strcasecmp(t,"admin" )) flags |= CMD_ADMIN; |
986 | else if (!strcasecmp(t,"deny-oom" )) flags |= CMD_DENYOOM; |
987 | else if (!strcasecmp(t,"deny-script" )) flags |= CMD_NOSCRIPT; |
988 | else if (!strcasecmp(t,"allow-loading" )) flags |= CMD_LOADING; |
989 | else if (!strcasecmp(t,"pubsub" )) flags |= CMD_PUBSUB; |
990 | else if (!strcasecmp(t,"random" )) { /* Deprecated. Silently ignore. */ } |
991 | else if (!strcasecmp(t,"blocking" )) flags |= CMD_BLOCKING; |
992 | else if (!strcasecmp(t,"allow-stale" )) flags |= CMD_STALE; |
993 | else if (!strcasecmp(t,"no-monitor" )) flags |= CMD_SKIP_MONITOR; |
994 | else if (!strcasecmp(t,"no-slowlog" )) flags |= CMD_SKIP_SLOWLOG; |
995 | else if (!strcasecmp(t,"fast" )) flags |= CMD_FAST; |
996 | else if (!strcasecmp(t,"no-auth" )) flags |= CMD_NO_AUTH; |
997 | else if (!strcasecmp(t,"may-replicate" )) flags |= CMD_MAY_REPLICATE; |
998 | else if (!strcasecmp(t,"getkeys-api" )) flags |= CMD_MODULE_GETKEYS; |
999 | else if (!strcasecmp(t,"getchannels-api" )) flags |= CMD_MODULE_GETCHANNELS; |
1000 | else if (!strcasecmp(t,"no-cluster" )) flags |= CMD_MODULE_NO_CLUSTER; |
1001 | else if (!strcasecmp(t,"no-mandatory-keys" )) flags |= CMD_NO_MANDATORY_KEYS; |
1002 | else if (!strcasecmp(t,"allow-busy" )) flags |= CMD_ALLOW_BUSY; |
1003 | else break; |
1004 | } |
1005 | sdsfreesplitres(tokens,count); |
1006 | if (j != count) return -1; /* Some token not processed correctly. */ |
1007 | return flags; |
1008 | } |
1009 | |
1010 | RedisModuleCommand *moduleCreateCommandProxy(struct RedisModule *module, sds declared_name, sds fullname, RedisModuleCmdFunc cmdfunc, int64_t flags, int firstkey, int lastkey, int keystep); |
1011 | |
1012 | /* Register a new command in the Redis server, that will be handled by |
1013 | * calling the function pointer 'cmdfunc' using the RedisModule calling |
1014 | * convention. The function returns REDISMODULE_ERR if the specified command |
1015 | * name is already busy or a set of invalid flags were passed, otherwise |
1016 | * REDISMODULE_OK is returned and the new command is registered. |
1017 | * |
1018 | * This function must be called during the initialization of the module |
1019 | * inside the RedisModule_OnLoad() function. Calling this function outside |
1020 | * of the initialization function is not defined. |
1021 | * |
1022 | * The command function type is the following: |
1023 | * |
1024 | * int MyCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); |
1025 | * |
1026 | * And is supposed to always return REDISMODULE_OK. |
1027 | * |
1028 | * The set of flags 'strflags' specify the behavior of the command, and should |
1029 | * be passed as a C string composed of space separated words, like for |
1030 | * example "write deny-oom". The set of flags are: |
1031 | * |
1032 | * * **"write"**: The command may modify the data set (it may also read |
1033 | * from it). |
1034 | * * **"readonly"**: The command returns data from keys but never writes. |
1035 | * * **"admin"**: The command is an administrative command (may change |
1036 | * replication or perform similar tasks). |
1037 | * * **"deny-oom"**: The command may use additional memory and should be |
1038 | * denied during out of memory conditions. |
1039 | * * **"deny-script"**: Don't allow this command in Lua scripts. |
1040 | * * **"allow-loading"**: Allow this command while the server is loading data. |
1041 | * Only commands not interacting with the data set |
1042 | * should be allowed to run in this mode. If not sure |
1043 | * don't use this flag. |
1044 | * * **"pubsub"**: The command publishes things on Pub/Sub channels. |
1045 | * * **"random"**: The command may have different outputs even starting |
1046 | * from the same input arguments and key values. |
1047 | * Starting from Redis 7.0 this flag has been deprecated. |
1048 | * Declaring a command as "random" can be done using |
1049 | * command tips, see https://redis.io/topics/command-tips. |
1050 | * * **"allow-stale"**: The command is allowed to run on slaves that don't |
1051 | * serve stale data. Don't use if you don't know what |
1052 | * this means. |
1053 | * * **"no-monitor"**: Don't propagate the command on monitor. Use this if |
1054 | * the command has sensitive data among the arguments. |
1055 | * * **"no-slowlog"**: Don't log this command in the slowlog. Use this if |
1056 | * the command has sensitive data among the arguments. |
1057 | * * **"fast"**: The command time complexity is not greater |
1058 | * than O(log(N)) where N is the size of the collection or |
1059 | * anything else representing the normal scalability |
1060 | * issue with the command. |
1061 | * * **"getkeys-api"**: The command implements the interface to return |
1062 | * the arguments that are keys. Used when start/stop/step |
1063 | * is not enough because of the command syntax. |
1064 | * * **"no-cluster"**: The command should not register in Redis Cluster |
1065 | * since is not designed to work with it because, for |
1066 | * example, is unable to report the position of the |
1067 | * keys, programmatically creates key names, or any |
1068 | * other reason. |
1069 | * * **"no-auth"**: This command can be run by an un-authenticated client. |
1070 | * Normally this is used by a command that is used |
1071 | * to authenticate a client. |
1072 | * * **"may-replicate"**: This command may generate replication traffic, even |
1073 | * though it's not a write command. |
1074 | * * **"no-mandatory-keys"**: All the keys this command may take are optional |
1075 | * * **"blocking"**: The command has the potential to block the client. |
1076 | * * **"allow-busy"**: Permit the command while the server is blocked either by |
1077 | * a script or by a slow module command, see |
1078 | * RM_Yield. |
1079 | * * **"getchannels-api"**: The command implements the interface to return |
1080 | * the arguments that are channels. |
1081 | * |
1082 | * The last three parameters specify which arguments of the new command are |
1083 | * Redis keys. See https://redis.io/commands/command for more information. |
1084 | * |
1085 | * * `firstkey`: One-based index of the first argument that's a key. |
1086 | * Position 0 is always the command name itself. |
1087 | * 0 for commands with no keys. |
1088 | * * `lastkey`: One-based index of the last argument that's a key. |
1089 | * Negative numbers refer to counting backwards from the last |
1090 | * argument (-1 means the last argument provided) |
1091 | * 0 for commands with no keys. |
1092 | * * `keystep`: Step between first and last key indexes. |
1093 | * 0 for commands with no keys. |
1094 | * |
1095 | * This information is used by ACL, Cluster and the `COMMAND` command. |
1096 | * |
1097 | * NOTE: The scheme described above serves a limited purpose and can |
1098 | * only be used to find keys that exist at constant indices. |
1099 | * For non-trivial key arguments, you may pass 0,0,0 and use |
1100 | * RedisModule_SetCommandInfo to set key specs using a more advanced scheme. */ |
1101 | int RM_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) { |
1102 | int64_t flags = strflags ? commandFlagsFromString((char*)strflags) : 0; |
1103 | if (flags == -1) return REDISMODULE_ERR; |
1104 | if ((flags & CMD_MODULE_NO_CLUSTER) && server.cluster_enabled) |
1105 | return REDISMODULE_ERR; |
1106 | |
1107 | /* Check if the command name is busy. */ |
1108 | if (lookupCommandByCString(name) != NULL) |
1109 | return REDISMODULE_ERR; |
1110 | |
1111 | sds declared_name = sdsnew(name); |
1112 | RedisModuleCommand *cp = moduleCreateCommandProxy(ctx->module, declared_name, sdsdup(declared_name), cmdfunc, flags, firstkey, lastkey, keystep); |
1113 | cp->rediscmd->arity = cmdfunc ? -1 : -2; /* Default value, can be changed later via dedicated API */ |
1114 | |
1115 | serverAssert(dictAdd(server.commands, sdsdup(declared_name), cp->rediscmd) == DICT_OK); |
1116 | serverAssert(dictAdd(server.orig_commands, sdsdup(declared_name), cp->rediscmd) == DICT_OK); |
1117 | cp->rediscmd->id = ACLGetCommandID(declared_name); /* ID used for ACL. */ |
1118 | return REDISMODULE_OK; |
1119 | } |
1120 | |
1121 | /* A proxy that help create a module command / subcommand. |
1122 | * |
1123 | * 'declared_name': it contains the sub_name, which is just the fullname for non-subcommands. |
1124 | * 'fullname': sds string representing the command fullname. |
1125 | * |
1126 | * Function will take the ownership of both 'declared_name' and 'fullname' SDS. |
1127 | */ |
1128 | RedisModuleCommand *moduleCreateCommandProxy(struct RedisModule *module, sds declared_name, sds fullname, RedisModuleCmdFunc cmdfunc, int64_t flags, int firstkey, int lastkey, int keystep) { |
1129 | struct redisCommand *rediscmd; |
1130 | RedisModuleCommand *cp; |
1131 | |
1132 | /* Create a command "proxy", which is a structure that is referenced |
1133 | * in the command table, so that the generic command that works as |
1134 | * binding between modules and Redis, can know what function to call |
1135 | * and what the module is. */ |
1136 | cp = zcalloc(sizeof(*cp)); |
1137 | cp->module = module; |
1138 | cp->func = cmdfunc; |
1139 | cp->rediscmd = zcalloc(sizeof(*rediscmd)); |
1140 | cp->rediscmd->declared_name = declared_name; /* SDS for module commands */ |
1141 | cp->rediscmd->fullname = fullname; |
1142 | cp->rediscmd->group = COMMAND_GROUP_MODULE; |
1143 | cp->rediscmd->proc = RedisModuleCommandDispatcher; |
1144 | cp->rediscmd->flags = flags | CMD_MODULE; |
1145 | cp->rediscmd->module_cmd = cp; |
1146 | cp->rediscmd->key_specs_max = STATIC_KEY_SPECS_NUM; |
1147 | cp->rediscmd->key_specs = cp->rediscmd->key_specs_static; |
1148 | if (firstkey != 0) { |
1149 | cp->rediscmd->key_specs_num = 1; |
1150 | cp->rediscmd->key_specs[0].flags = CMD_KEY_FULL_ACCESS | CMD_KEY_VARIABLE_FLAGS; |
1151 | cp->rediscmd->key_specs[0].begin_search_type = KSPEC_BS_INDEX; |
1152 | cp->rediscmd->key_specs[0].bs.index.pos = firstkey; |
1153 | cp->rediscmd->key_specs[0].find_keys_type = KSPEC_FK_RANGE; |
1154 | cp->rediscmd->key_specs[0].fk.range.lastkey = lastkey < 0 ? lastkey : (lastkey-firstkey); |
1155 | cp->rediscmd->key_specs[0].fk.range.keystep = keystep; |
1156 | cp->rediscmd->key_specs[0].fk.range.limit = 0; |
1157 | } else { |
1158 | cp->rediscmd->key_specs_num = 0; |
1159 | } |
1160 | populateCommandLegacyRangeSpec(cp->rediscmd); |
1161 | cp->rediscmd->microseconds = 0; |
1162 | cp->rediscmd->calls = 0; |
1163 | cp->rediscmd->rejected_calls = 0; |
1164 | cp->rediscmd->failed_calls = 0; |
1165 | return cp; |
1166 | } |
1167 | |
1168 | /* Get an opaque structure, representing a module command, by command name. |
1169 | * This structure is used in some of the command-related APIs. |
1170 | * |
1171 | * NULL is returned in case of the following errors: |
1172 | * |
1173 | * * Command not found |
1174 | * * The command is not a module command |
1175 | * * The command doesn't belong to the calling module |
1176 | */ |
1177 | RedisModuleCommand *RM_GetCommand(RedisModuleCtx *ctx, const char *name) { |
1178 | struct redisCommand *cmd = lookupCommandByCString(name); |
1179 | |
1180 | if (!cmd || !(cmd->flags & CMD_MODULE)) |
1181 | return NULL; |
1182 | |
1183 | RedisModuleCommand *cp = cmd->module_cmd; |
1184 | if (cp->module != ctx->module) |
1185 | return NULL; |
1186 | |
1187 | return cp; |
1188 | } |
1189 | |
1190 | /* Very similar to RedisModule_CreateCommand except that it is used to create |
1191 | * a subcommand, associated with another, container, command. |
1192 | * |
1193 | * Example: If a module has a configuration command, MODULE.CONFIG, then |
1194 | * GET and SET should be individual subcommands, while MODULE.CONFIG is |
1195 | * a command, but should not be registered with a valid `funcptr`: |
1196 | * |
1197 | * if (RedisModule_CreateCommand(ctx,"module.config",NULL,"",0,0,0) == REDISMODULE_ERR) |
1198 | * return REDISMODULE_ERR; |
1199 | * |
1200 | * RedisModuleCommand *parent = RedisModule_GetCommand(ctx,,"module.config"); |
1201 | * |
1202 | * if (RedisModule_CreateSubcommand(parent,"set",cmd_config_set,"",0,0,0) == REDISMODULE_ERR) |
1203 | * return REDISMODULE_ERR; |
1204 | * |
1205 | * if (RedisModule_CreateSubcommand(parent,"get",cmd_config_get,"",0,0,0) == REDISMODULE_ERR) |
1206 | * return REDISMODULE_ERR; |
1207 | * |
1208 | * Returns REDISMODULE_OK on success and REDISMODULE_ERR in case of the following errors: |
1209 | * |
1210 | * * Error while parsing `strflags` |
1211 | * * Command is marked as `no-cluster` but cluster mode is enabled |
1212 | * * `parent` is already a subcommand (we do not allow more than one level of command nesting) |
1213 | * * `parent` is a command with an implementation (RedisModuleCmdFunc) (A parent command should be a pure container of subcommands) |
1214 | * * `parent` already has a subcommand called `name` |
1215 | */ |
1216 | int RM_CreateSubcommand(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) { |
1217 | int64_t flags = strflags ? commandFlagsFromString((char*)strflags) : 0; |
1218 | if (flags == -1) return REDISMODULE_ERR; |
1219 | if ((flags & CMD_MODULE_NO_CLUSTER) && server.cluster_enabled) |
1220 | return REDISMODULE_ERR; |
1221 | |
1222 | struct redisCommand *parent_cmd = parent->rediscmd; |
1223 | |
1224 | if (parent_cmd->parent) |
1225 | return REDISMODULE_ERR; /* We don't allow more than one level of subcommands */ |
1226 | |
1227 | RedisModuleCommand *parent_cp = parent_cmd->module_cmd; |
1228 | if (parent_cp->func) |
1229 | return REDISMODULE_ERR; /* A parent command should be a pure container of subcommands */ |
1230 | |
1231 | /* Check if the command name is busy within the parent command. */ |
1232 | sds declared_name = sdsnew(name); |
1233 | if (parent_cmd->subcommands_dict && lookupSubcommand(parent_cmd, declared_name) != NULL) { |
1234 | sdsfree(declared_name); |
1235 | return REDISMODULE_ERR; |
1236 | } |
1237 | |
1238 | sds fullname = catSubCommandFullname(parent_cmd->fullname, name); |
1239 | RedisModuleCommand *cp = moduleCreateCommandProxy(parent->module, declared_name, fullname, cmdfunc, flags, firstkey, lastkey, keystep); |
1240 | cp->rediscmd->arity = -2; |
1241 | |
1242 | commandAddSubcommand(parent_cmd, cp->rediscmd, name); |
1243 | return REDISMODULE_OK; |
1244 | } |
1245 | |
1246 | /* Accessors of array elements of structs where the element size is stored |
1247 | * separately in the version struct. */ |
1248 | static RedisModuleCommandHistoryEntry * |
1249 | moduleCmdHistoryEntryAt(const RedisModuleCommandInfoVersion *version, |
1250 | RedisModuleCommandHistoryEntry *entries, int index) { |
1251 | off_t offset = index * version->sizeof_historyentry; |
1252 | return (RedisModuleCommandHistoryEntry *)((char *)(entries) + offset); |
1253 | } |
1254 | static RedisModuleCommandKeySpec * |
1255 | moduleCmdKeySpecAt(const RedisModuleCommandInfoVersion *version, |
1256 | RedisModuleCommandKeySpec *keyspecs, int index) { |
1257 | off_t offset = index * version->sizeof_keyspec; |
1258 | return (RedisModuleCommandKeySpec *)((char *)(keyspecs) + offset); |
1259 | } |
1260 | static RedisModuleCommandArg * |
1261 | moduleCmdArgAt(const RedisModuleCommandInfoVersion *version, |
1262 | const RedisModuleCommandArg *args, int index) { |
1263 | off_t offset = index * version->sizeof_arg; |
1264 | return (RedisModuleCommandArg *)((char *)(args) + offset); |
1265 | } |
1266 | |
1267 | /* Set additional command information. |
1268 | * |
1269 | * Affects the output of `COMMAND`, `COMMAND INFO` and `COMMAND DOCS`, Cluster, |
1270 | * ACL and is used to filter commands with the wrong number of arguments before |
1271 | * the call reaches the module code. |
1272 | * |
1273 | * This function can be called after creating a command using RM_CreateCommand |
1274 | * and fetching the command pointer using RM_GetCommand. The information can |
1275 | * only be set once for each command and has the following structure: |
1276 | * |
1277 | * typedef struct RedisModuleCommandInfo { |
1278 | * const RedisModuleCommandInfoVersion *version; |
1279 | * const char *summary; |
1280 | * const char *complexity; |
1281 | * const char *since; |
1282 | * RedisModuleCommandHistoryEntry *history; |
1283 | * const char *tips; |
1284 | * int arity; |
1285 | * RedisModuleCommandKeySpec *key_specs; |
1286 | * RedisModuleCommandArg *args; |
1287 | * } RedisModuleCommandInfo; |
1288 | * |
1289 | * All fields except `version` are optional. Explanation of the fields: |
1290 | * |
1291 | * - `version`: This field enables compatibility with different Redis versions. |
1292 | * Always set this field to REDISMODULE_COMMAND_INFO_VERSION. |
1293 | * |
1294 | * - `summary`: A short description of the command (optional). |
1295 | * |
1296 | * - `complexity`: Complexity description (optional). |
1297 | * |
1298 | * - `since`: The version where the command was introduced (optional). |
1299 | * Note: The version specified should be the module's, not Redis version. |
1300 | * |
1301 | * - `history`: An array of RedisModuleCommandHistoryEntry (optional), which is |
1302 | * a struct with the following fields: |
1303 | * |
1304 | * const char *since; |
1305 | * const char *changes; |
1306 | * |
1307 | * `since` is a version string and `changes` is a string describing the |
1308 | * changes. The array is terminated by a zeroed entry, i.e. an entry with |
1309 | * both strings set to NULL. |
1310 | * |
1311 | * - `tips`: A string of space-separated tips regarding this command, meant for |
1312 | * clients and proxies. See https://redis.io/topics/command-tips. |
1313 | * |
1314 | * - `arity`: Number of arguments, including the command name itself. A positive |
1315 | * number specifies an exact number of arguments and a negative number |
1316 | * specifies a minimum number of arguments, so use -N to say >= N. Redis |
1317 | * validates a call before passing it to a module, so this can replace an |
1318 | * arity check inside the module command implementation. A value of 0 (or an |
1319 | * omitted arity field) is equivalent to -2 if the command has sub commands |
1320 | * and -1 otherwise. |
1321 | * |
1322 | * - `key_specs`: An array of RedisModuleCommandKeySpec, terminated by an |
1323 | * element memset to zero. This is a scheme that tries to describe the |
1324 | * positions of key arguments better than the old RM_CreateCommand arguments |
1325 | * `firstkey`, `lastkey`, `keystep` and is needed if those three are not |
1326 | * enough to describe the key positions. There are two steps to retrieve key |
1327 | * positions: *begin search* (BS) in which index should find the first key and |
1328 | * *find keys* (FK) which, relative to the output of BS, describes how can we |
1329 | * will which arguments are keys. Additionally, there are key specific flags. |
1330 | * |
1331 | * Key-specs cause the triplet (firstkey, lastkey, keystep) given in |
1332 | * RM_CreateCommand to be recomputed, but it is still useful to provide |
1333 | * these three parameters in RM_CreateCommand, to better support old Redis |
1334 | * versions where RM_SetCommandInfo is not available. |
1335 | * |
1336 | * Note that key-specs don't fully replace the "getkeys-api" (see |
1337 | * RM_CreateCommand, RM_IsKeysPositionRequest and RM_KeyAtPosWithFlags) so |
1338 | * it may be a good idea to supply both key-specs and implement the |
1339 | * getkeys-api. |
1340 | * |
1341 | * A key-spec has the following structure: |
1342 | * |
1343 | * typedef struct RedisModuleCommandKeySpec { |
1344 | * const char *notes; |
1345 | * uint64_t flags; |
1346 | * RedisModuleKeySpecBeginSearchType begin_search_type; |
1347 | * union { |
1348 | * struct { |
1349 | * int pos; |
1350 | * } index; |
1351 | * struct { |
1352 | * const char *keyword; |
1353 | * int startfrom; |
1354 | * } keyword; |
1355 | * } bs; |
1356 | * RedisModuleKeySpecFindKeysType find_keys_type; |
1357 | * union { |
1358 | * struct { |
1359 | * int lastkey; |
1360 | * int keystep; |
1361 | * int limit; |
1362 | * } range; |
1363 | * struct { |
1364 | * int keynumidx; |
1365 | * int firstkey; |
1366 | * int keystep; |
1367 | * } keynum; |
1368 | * } fk; |
1369 | * } RedisModuleCommandKeySpec; |
1370 | * |
1371 | * Explanation of the fields of RedisModuleCommandKeySpec: |
1372 | * |
1373 | * * `notes`: Optional notes or clarifications about this key spec. |
1374 | * |
1375 | * * `flags`: A bitwise or of key-spec flags described below. |
1376 | * |
1377 | * * `begin_search_type`: This describes how the first key is discovered. |
1378 | * There are two ways to determine the first key: |
1379 | * |
1380 | * * `REDISMODULE_KSPEC_BS_UNKNOWN`: There is no way to tell where the |
1381 | * key args start. |
1382 | * * `REDISMODULE_KSPEC_BS_INDEX`: Key args start at a constant index. |
1383 | * * `REDISMODULE_KSPEC_BS_KEYWORD`: Key args start just after a |
1384 | * specific keyword. |
1385 | * |
1386 | * * `bs`: This is a union in which the `index` or `keyword` branch is used |
1387 | * depending on the value of the `begin_search_type` field. |
1388 | * |
1389 | * * `bs.index.pos`: The index from which we start the search for keys. |
1390 | * (`REDISMODULE_KSPEC_BS_INDEX` only.) |
1391 | * |
1392 | * * `bs.keyword.keyword`: The keyword (string) that indicates the |
1393 | * beginning of key arguments. (`REDISMODULE_KSPEC_BS_KEYWORD` only.) |
1394 | * |
1395 | * * `bs.keyword.startfrom`: An index in argv from which to start |
1396 | * searching. Can be negative, which means start search from the end, |
1397 | * in reverse. Example: -2 means to start in reverse from the |
1398 | * penultimate argument. (`REDISMODULE_KSPEC_BS_KEYWORD` only.) |
1399 | * |
1400 | * * `find_keys_type`: After the "begin search", this describes which |
1401 | * arguments are keys. The strategies are: |
1402 | * |
1403 | * * `REDISMODULE_KSPEC_BS_UNKNOWN`: There is no way to tell where the |
1404 | * key args are located. |
1405 | * * `REDISMODULE_KSPEC_FK_RANGE`: Keys end at a specific index (or |
1406 | * relative to the last argument). |
1407 | * * `REDISMODULE_KSPEC_FK_KEYNUM`: There's an argument that contains |
1408 | * the number of key args somewhere before the keys themselves. |
1409 | * |
1410 | * `find_keys_type` and `fk` can be omitted if this keyspec describes |
1411 | * exactly one key. |
1412 | * |
1413 | * * `fk`: This is a union in which the `range` or `keynum` branch is used |
1414 | * depending on the value of the `find_keys_type` field. |
1415 | * |
1416 | * * `fk.range` (for `REDISMODULE_KSPEC_FK_RANGE`): A struct with the |
1417 | * following fields: |
1418 | * |
1419 | * * `lastkey`: Index of the last key relative to the result of the |
1420 | * begin search step. Can be negative, in which case it's not |
1421 | * relative. -1 indicates the last argument, -2 one before the |
1422 | * last and so on. |
1423 | * |
1424 | * * `keystep`: How many arguments should we skip after finding a |
1425 | * key, in order to find the next one? |
1426 | * |
1427 | * * `limit`: If `lastkey` is -1, we use `limit` to stop the search |
1428 | * by a factor. 0 and 1 mean no limit. 2 means 1/2 of the |
1429 | * remaining args, 3 means 1/3, and so on. |
1430 | * |
1431 | * * `fk.keynum` (for `REDISMODULE_KSPEC_FK_KEYNUM`): A struct with the |
1432 | * following fields: |
1433 | * |
1434 | * * `keynumidx`: Index of the argument containing the number of |
1435 | * keys to come, relative to the result of the begin search step. |
1436 | * |
1437 | * * `firstkey`: Index of the fist key relative to the result of the |
1438 | * begin search step. (Usually it's just after `keynumidx`, in |
1439 | * which case it should be set to `keynumidx + 1`.) |
1440 | * |
1441 | * * `keystep`: How many arguments should we skip after finding a |
1442 | * key, in order to find the next one? |
1443 | * |
1444 | * Key-spec flags: |
1445 | * |
1446 | * The first four refer to what the command actually does with the *value or |
1447 | * metadata of the key*, and not necessarily the user data or how it affects |
1448 | * it. Each key-spec may must have exactly one of these. Any operation |
1449 | * that's not distinctly deletion, overwrite or read-only would be marked as |
1450 | * RW. |
1451 | * |
1452 | * * `REDISMODULE_CMD_KEY_RO`: Read-Only. Reads the value of the key, but |
1453 | * doesn't necessarily return it. |
1454 | * |
1455 | * * `REDISMODULE_CMD_KEY_RW`: Read-Write. Modifies the data stored in the |
1456 | * value of the key or its metadata. |
1457 | * |
1458 | * * `REDISMODULE_CMD_KEY_OW`: Overwrite. Overwrites the data stored in the |
1459 | * value of the key. |
1460 | * |
1461 | * * `REDISMODULE_CMD_KEY_RM`: Deletes the key. |
1462 | * |
1463 | * The next four refer to *user data inside the value of the key*, not the |
1464 | * metadata like LRU, type, cardinality. It refers to the logical operation |
1465 | * on the user's data (actual input strings or TTL), being |
1466 | * used/returned/copied/changed. It doesn't refer to modification or |
1467 | * returning of metadata (like type, count, presence of data). ACCESS can be |
1468 | * combined with one of the write operations INSERT, DELETE or UPDATE. Any |
1469 | * write that's not an INSERT or a DELETE would be UPDATE. |
1470 | * |
1471 | * * `REDISMODULE_CMD_KEY_ACCESS`: Returns, copies or uses the user data |
1472 | * from the value of the key. |
1473 | * |
1474 | * * `REDISMODULE_CMD_KEY_UPDATE`: Updates data to the value, new value may |
1475 | * depend on the old value. |
1476 | * |
1477 | * * `REDISMODULE_CMD_KEY_INSERT`: Adds data to the value with no chance of |
1478 | * modification or deletion of existing data. |
1479 | * |
1480 | * * `REDISMODULE_CMD_KEY_DELETE`: Explicitly deletes some content from the |
1481 | * value of the key. |
1482 | * |
1483 | * Other flags: |
1484 | * |
1485 | * * `REDISMODULE_CMD_KEY_NOT_KEY`: The key is not actually a key, but |
1486 | * should be routed in cluster mode as if it was a key. |
1487 | * |
1488 | * * `REDISMODULE_CMD_KEY_INCOMPLETE`: The keyspec might not point out all |
1489 | * the keys it should cover. |
1490 | * |
1491 | * * `REDISMODULE_CMD_KEY_VARIABLE_FLAGS`: Some keys might have different |
1492 | * flags depending on arguments. |
1493 | * |
1494 | * - `args`: An array of RedisModuleCommandArg, terminated by an element memset |
1495 | * to zero. RedisModuleCommandArg is a structure with at the fields described |
1496 | * below. |
1497 | * |
1498 | * typedef struct RedisModuleCommandArg { |
1499 | * const char *name; |
1500 | * RedisModuleCommandArgType type; |
1501 | * int key_spec_index; |
1502 | * const char *token; |
1503 | * const char *summary; |
1504 | * const char *since; |
1505 | * int flags; |
1506 | * struct RedisModuleCommandArg *subargs; |
1507 | * } RedisModuleCommandArg; |
1508 | * |
1509 | * Explanation of the fields: |
1510 | * |
1511 | * * `name`: Name of the argument. |
1512 | * |
1513 | * * `type`: The type of the argument. See below for details. The types |
1514 | * `REDISMODULE_ARG_TYPE_ONEOF` and `REDISMODULE_ARG_TYPE_BLOCK` require |
1515 | * an argument to have sub-arguments, i.e. `subargs`. |
1516 | * |
1517 | * * `key_spec_index`: If the `type` is `REDISMODULE_ARG_TYPE_KEY` you must |
1518 | * provide the index of the key-spec associated with this argument. See |
1519 | * `key_specs` above. If the argument is not a key, you may specify -1. |
1520 | * |
1521 | * * `token`: The token preceding the argument (optional). Example: the |
1522 | * argument `seconds` in `SET` has a token `EX`. If the argument consists |
1523 | * of only a token (for example `NX` in `SET`) the type should be |
1524 | * `REDISMODULE_ARG_TYPE_PURE_TOKEN` and `value` should be NULL. |
1525 | * |
1526 | * * `summary`: A short description of the argument (optional). |
1527 | * |
1528 | * * `since`: The first version which included this argument (optional). |
1529 | * |
1530 | * * `flags`: A bitwise or of the macros `REDISMODULE_CMD_ARG_*`. See below. |
1531 | * |
1532 | * * `value`: The display-value of the argument. This string is what should |
1533 | * be displayed when creating the command syntax from the output of |
1534 | * `COMMAND`. If `token` is not NULL, it should also be displayed. |
1535 | * |
1536 | * Explanation of `RedisModuleCommandArgType`: |
1537 | * |
1538 | * * `REDISMODULE_ARG_TYPE_STRING`: String argument. |
1539 | * * `REDISMODULE_ARG_TYPE_INTEGER`: Integer argument. |
1540 | * * `REDISMODULE_ARG_TYPE_DOUBLE`: Double-precision float argument. |
1541 | * * `REDISMODULE_ARG_TYPE_KEY`: String argument representing a keyname. |
1542 | * * `REDISMODULE_ARG_TYPE_PATTERN`: String, but regex pattern. |
1543 | * * `REDISMODULE_ARG_TYPE_UNIX_TIME`: Integer, but Unix timestamp. |
1544 | * * `REDISMODULE_ARG_TYPE_PURE_TOKEN`: Argument doesn't have a placeholder. |
1545 | * It's just a token without a value. Example: the `KEEPTTL` option of the |
1546 | * `SET` command. |
1547 | * * `REDISMODULE_ARG_TYPE_ONEOF`: Used when the user can choose only one of |
1548 | * a few sub-arguments. Requires `subargs`. Example: the `NX` and `XX` |
1549 | * options of `SET`. |
1550 | * * `REDISMODULE_ARG_TYPE_BLOCK`: Used when one wants to group together |
1551 | * several sub-arguments, usually to apply something on all of them, like |
1552 | * making the entire group "optional". Requires `subargs`. Example: the |
1553 | * `LIMIT offset count` parameters in `ZRANGE`. |
1554 | * |
1555 | * Explanation of the command argument flags: |
1556 | * |
1557 | * * `REDISMODULE_CMD_ARG_OPTIONAL`: The argument is optional (like GET in |
1558 | * the SET command). |
1559 | * * `REDISMODULE_CMD_ARG_MULTIPLE`: The argument may repeat itself (like |
1560 | * key in DEL). |
1561 | * * `REDISMODULE_CMD_ARG_MULTIPLE_TOKEN`: The argument may repeat itself, |
1562 | * and so does its token (like `GET pattern` in SORT). |
1563 | * |
1564 | * On success REDISMODULE_OK is returned. On error REDISMODULE_ERR is returned |
1565 | * and `errno` is set to EINVAL if invalid info was provided or EEXIST if info |
1566 | * has already been set. If the info is invalid, a warning is logged explaining |
1567 | * which part of the info is invalid and why. */ |
1568 | int RM_SetCommandInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info) { |
1569 | if (!moduleValidateCommandInfo(info)) { |
1570 | errno = EINVAL; |
1571 | return REDISMODULE_ERR; |
1572 | } |
1573 | |
1574 | struct redisCommand *cmd = command->rediscmd; |
1575 | |
1576 | /* Check if any info has already been set. Overwriting info involves freeing |
1577 | * the old info, which is not implemented. */ |
1578 | if (cmd->summary || cmd->complexity || cmd->since || cmd->history || |
1579 | cmd->tips || cmd->args || |
1580 | !(cmd->key_specs_num == 0 || |
1581 | /* Allow key spec populated from legacy (first,last,step) to exist. */ |
1582 | (cmd->key_specs_num == 1 && cmd->key_specs == cmd->key_specs_static && |
1583 | cmd->key_specs[0].begin_search_type == KSPEC_BS_INDEX && |
1584 | cmd->key_specs[0].find_keys_type == KSPEC_FK_RANGE))) { |
1585 | errno = EEXIST; |
1586 | return REDISMODULE_ERR; |
1587 | } |
1588 | |
1589 | if (info->summary) cmd->summary = zstrdup(info->summary); |
1590 | if (info->complexity) cmd->complexity = zstrdup(info->complexity); |
1591 | if (info->since) cmd->since = zstrdup(info->since); |
1592 | |
1593 | const RedisModuleCommandInfoVersion *version = info->version; |
1594 | if (info->history) { |
1595 | size_t count = 0; |
1596 | while (moduleCmdHistoryEntryAt(version, info->history, count)->since) |
1597 | count++; |
1598 | serverAssert(count < SIZE_MAX / sizeof(commandHistory)); |
1599 | cmd->history = zmalloc(sizeof(commandHistory) * (count + 1)); |
1600 | for (size_t j = 0; j < count; j++) { |
1601 | RedisModuleCommandHistoryEntry *entry = |
1602 | moduleCmdHistoryEntryAt(version, info->history, j); |
1603 | cmd->history[j].since = zstrdup(entry->since); |
1604 | cmd->history[j].changes = zstrdup(entry->changes); |
1605 | } |
1606 | cmd->history[count].since = NULL; |
1607 | cmd->history[count].changes = NULL; |
1608 | cmd->num_history = count; |
1609 | } |
1610 | |
1611 | if (info->tips) { |
1612 | int count; |
1613 | sds *tokens = sdssplitlen(info->tips, strlen(info->tips), " " , 1, &count); |
1614 | if (tokens) { |
1615 | cmd->tips = zmalloc(sizeof(char *) * (count + 1)); |
1616 | for (int j = 0; j < count; j++) { |
1617 | cmd->tips[j] = zstrdup(tokens[j]); |
1618 | } |
1619 | cmd->tips[count] = NULL; |
1620 | cmd->num_tips = count; |
1621 | sdsfreesplitres(tokens, count); |
1622 | } |
1623 | } |
1624 | |
1625 | if (info->arity) cmd->arity = info->arity; |
1626 | |
1627 | if (info->key_specs) { |
1628 | /* Count and allocate the key specs. */ |
1629 | size_t count = 0; |
1630 | while (moduleCmdKeySpecAt(version, info->key_specs, count)->begin_search_type) |
1631 | count++; |
1632 | serverAssert(count < INT_MAX); |
1633 | if (count <= STATIC_KEY_SPECS_NUM) { |
1634 | cmd->key_specs_max = STATIC_KEY_SPECS_NUM; |
1635 | cmd->key_specs = cmd->key_specs_static; |
1636 | } else { |
1637 | cmd->key_specs_max = count; |
1638 | cmd->key_specs = zmalloc(sizeof(keySpec) * count); |
1639 | } |
1640 | |
1641 | /* Copy the contents of the RedisModuleCommandKeySpec array. */ |
1642 | cmd->key_specs_num = count; |
1643 | for (size_t j = 0; j < count; j++) { |
1644 | RedisModuleCommandKeySpec *spec = |
1645 | moduleCmdKeySpecAt(version, info->key_specs, j); |
1646 | cmd->key_specs[j].notes = spec->notes ? zstrdup(spec->notes) : NULL; |
1647 | cmd->key_specs[j].flags = moduleConvertKeySpecsFlags(spec->flags, 1); |
1648 | switch (spec->begin_search_type) { |
1649 | case REDISMODULE_KSPEC_BS_UNKNOWN: |
1650 | cmd->key_specs[j].begin_search_type = KSPEC_BS_UNKNOWN; |
1651 | break; |
1652 | case REDISMODULE_KSPEC_BS_INDEX: |
1653 | cmd->key_specs[j].begin_search_type = KSPEC_BS_INDEX; |
1654 | cmd->key_specs[j].bs.index.pos = spec->bs.index.pos; |
1655 | break; |
1656 | case REDISMODULE_KSPEC_BS_KEYWORD: |
1657 | cmd->key_specs[j].begin_search_type = KSPEC_BS_KEYWORD; |
1658 | cmd->key_specs[j].bs.keyword.keyword = zstrdup(spec->bs.keyword.keyword); |
1659 | cmd->key_specs[j].bs.keyword.startfrom = spec->bs.keyword.startfrom; |
1660 | break; |
1661 | default: |
1662 | /* Can't happen; stopped in moduleValidateCommandInfo(). */ |
1663 | serverPanic("Unknown begin_search_type" ); |
1664 | } |
1665 | |
1666 | switch (spec->find_keys_type) { |
1667 | case REDISMODULE_KSPEC_FK_OMITTED: |
1668 | /* Omitted field is shorthand to say that it's a single key. */ |
1669 | cmd->key_specs[j].find_keys_type = KSPEC_FK_RANGE; |
1670 | cmd->key_specs[j].fk.range.lastkey = 0; |
1671 | cmd->key_specs[j].fk.range.keystep = 1; |
1672 | cmd->key_specs[j].fk.range.limit = 0; |
1673 | break; |
1674 | case REDISMODULE_KSPEC_FK_UNKNOWN: |
1675 | cmd->key_specs[j].find_keys_type = KSPEC_FK_UNKNOWN; |
1676 | break; |
1677 | case REDISMODULE_KSPEC_FK_RANGE: |
1678 | cmd->key_specs[j].find_keys_type = KSPEC_FK_RANGE; |
1679 | cmd->key_specs[j].fk.range.lastkey = spec->fk.range.lastkey; |
1680 | cmd->key_specs[j].fk.range.keystep = spec->fk.range.keystep; |
1681 | cmd->key_specs[j].fk.range.limit = spec->fk.range.limit; |
1682 | break; |
1683 | case REDISMODULE_KSPEC_FK_KEYNUM: |
1684 | cmd->key_specs[j].find_keys_type = KSPEC_FK_KEYNUM; |
1685 | cmd->key_specs[j].fk.keynum.keynumidx = spec->fk.keynum.keynumidx; |
1686 | cmd->key_specs[j].fk.keynum.firstkey = spec->fk.keynum.firstkey; |
1687 | cmd->key_specs[j].fk.keynum.keystep = spec->fk.keynum.keystep; |
1688 | break; |
1689 | default: |
1690 | /* Can't happen; stopped in moduleValidateCommandInfo(). */ |
1691 | serverPanic("Unknown find_keys_type" ); |
1692 | } |
1693 | } |
1694 | |
1695 | /* Update the legacy (first,last,step) spec and "movablekeys" flag used by the COMMAND command, |
1696 | * by trying to "glue" consecutive range key specs. */ |
1697 | populateCommandLegacyRangeSpec(cmd); |
1698 | } |
1699 | |
1700 | if (info->args) { |
1701 | cmd->args = moduleCopyCommandArgs(info->args, version); |
1702 | /* Populate arg.num_args with the number of subargs, recursively */ |
1703 | cmd->num_args = populateArgsStructure(cmd->args); |
1704 | } |
1705 | |
1706 | /* Fields added in future versions to be added here, under conditions like |
1707 | * `if (info->version >= 2) { access version 2 fields here }` */ |
1708 | |
1709 | return REDISMODULE_OK; |
1710 | } |
1711 | |
1712 | /* Returns 1 if v is a power of two, 0 otherwise. */ |
1713 | static inline int isPowerOfTwo(uint64_t v) { |
1714 | return v && !(v & (v - 1)); |
1715 | } |
1716 | |
1717 | /* Returns 1 if the command info is valid and 0 otherwise. */ |
1718 | static int moduleValidateCommandInfo(const RedisModuleCommandInfo *info) { |
1719 | const RedisModuleCommandInfoVersion *version = info->version; |
1720 | if (!version) { |
1721 | serverLog(LL_WARNING, "Invalid command info: version missing" ); |
1722 | return 0; |
1723 | } |
1724 | |
1725 | /* No validation for the fields summary, complexity, since, tips (strings or |
1726 | * NULL) and arity (any integer). */ |
1727 | |
1728 | /* History: If since is set, changes must also be set. */ |
1729 | if (info->history) { |
1730 | for (size_t j = 0; |
1731 | moduleCmdHistoryEntryAt(version, info->history, j)->since; |
1732 | j++) |
1733 | { |
1734 | if (!moduleCmdHistoryEntryAt(version, info->history, j)->changes) { |
1735 | serverLog(LL_WARNING, "Invalid command info: history[%zd].changes missing" , j); |
1736 | return 0; |
1737 | } |
1738 | } |
1739 | } |
1740 | |
1741 | /* Key specs. */ |
1742 | if (info->key_specs) { |
1743 | for (size_t j = 0; |
1744 | moduleCmdKeySpecAt(version, info->key_specs, j)->begin_search_type; |
1745 | j++) |
1746 | { |
1747 | RedisModuleCommandKeySpec *spec = |
1748 | moduleCmdKeySpecAt(version, info->key_specs, j); |
1749 | if (j >= INT_MAX) { |
1750 | serverLog(LL_WARNING, "Invalid command info: Too many key specs" ); |
1751 | return 0; /* redisCommand.key_specs_num is an int. */ |
1752 | } |
1753 | |
1754 | /* Flags. Exactly one flag in a group is set if and only if the |
1755 | * masked bits is a power of two. */ |
1756 | uint64_t key_flags = |
1757 | REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_RW | |
1758 | REDISMODULE_CMD_KEY_OW | REDISMODULE_CMD_KEY_RM; |
1759 | uint64_t write_flags = |
1760 | REDISMODULE_CMD_KEY_INSERT | REDISMODULE_CMD_KEY_DELETE | |
1761 | REDISMODULE_CMD_KEY_UPDATE; |
1762 | if (!isPowerOfTwo(spec->flags & key_flags)) { |
1763 | serverLog(LL_WARNING, |
1764 | "Invalid command info: key_specs[%zd].flags: " |
1765 | "Exactly one of the flags RO, RW, OW, RM required" , j); |
1766 | return 0; |
1767 | } |
1768 | if ((spec->flags & write_flags) != 0 && |
1769 | !isPowerOfTwo(spec->flags & write_flags)) |
1770 | { |
1771 | serverLog(LL_WARNING, |
1772 | "Invalid command info: key_specs[%zd].flags: " |
1773 | "INSERT, DELETE and UPDATE are mutually exclusive" , j); |
1774 | return 0; |
1775 | } |
1776 | |
1777 | switch (spec->begin_search_type) { |
1778 | case REDISMODULE_KSPEC_BS_UNKNOWN: break; |
1779 | case REDISMODULE_KSPEC_BS_INDEX: break; |
1780 | case REDISMODULE_KSPEC_BS_KEYWORD: |
1781 | if (spec->bs.keyword.keyword == NULL) { |
1782 | serverLog(LL_WARNING, |
1783 | "Invalid command info: key_specs[%zd].bs.keyword.keyword " |
1784 | "required when begin_search_type is KEYWORD" , j); |
1785 | return 0; |
1786 | } |
1787 | break; |
1788 | default: |
1789 | serverLog(LL_WARNING, |
1790 | "Invalid command info: key_specs[%zd].begin_search_type: " |
1791 | "Invalid value %d" , j, spec->begin_search_type); |
1792 | return 0; |
1793 | } |
1794 | |
1795 | /* Validate find_keys_type. */ |
1796 | switch (spec->find_keys_type) { |
1797 | case REDISMODULE_KSPEC_FK_OMITTED: break; /* short for RANGE {0,1,0} */ |
1798 | case REDISMODULE_KSPEC_FK_UNKNOWN: break; |
1799 | case REDISMODULE_KSPEC_FK_RANGE: break; |
1800 | case REDISMODULE_KSPEC_FK_KEYNUM: break; |
1801 | default: |
1802 | serverLog(LL_WARNING, |
1803 | "Invalid command info: key_specs[%zd].find_keys_type: " |
1804 | "Invalid value %d" , j, spec->find_keys_type); |
1805 | return 0; |
1806 | } |
1807 | } |
1808 | } |
1809 | |
1810 | /* Args, subargs (recursive) */ |
1811 | return moduleValidateCommandArgs(info->args, version); |
1812 | } |
1813 | |
1814 | /* When from_api is true, converts from REDISMODULE_CMD_KEY_* flags to CMD_KEY_* flags. |
1815 | * When from_api is false, converts from CMD_KEY_* flags to REDISMODULE_CMD_KEY_* flags. */ |
1816 | static int64_t moduleConvertKeySpecsFlags(int64_t flags, int from_api) { |
1817 | int64_t out = 0; |
1818 | int64_t map[][2] = { |
1819 | {REDISMODULE_CMD_KEY_RO, CMD_KEY_RO}, |
1820 | {REDISMODULE_CMD_KEY_RW, CMD_KEY_RW}, |
1821 | {REDISMODULE_CMD_KEY_OW, CMD_KEY_OW}, |
1822 | {REDISMODULE_CMD_KEY_RM, CMD_KEY_RM}, |
1823 | {REDISMODULE_CMD_KEY_ACCESS, CMD_KEY_ACCESS}, |
1824 | {REDISMODULE_CMD_KEY_INSERT, CMD_KEY_INSERT}, |
1825 | {REDISMODULE_CMD_KEY_UPDATE, CMD_KEY_UPDATE}, |
1826 | {REDISMODULE_CMD_KEY_DELETE, CMD_KEY_DELETE}, |
1827 | {REDISMODULE_CMD_KEY_NOT_KEY, CMD_KEY_NOT_KEY}, |
1828 | {REDISMODULE_CMD_KEY_INCOMPLETE, CMD_KEY_INCOMPLETE}, |
1829 | {REDISMODULE_CMD_KEY_VARIABLE_FLAGS, CMD_KEY_VARIABLE_FLAGS}, |
1830 | {0,0}}; |
1831 | |
1832 | int from_idx = from_api ? 0 : 1, to_idx = !from_idx; |
1833 | for (int i=0; map[i][0]; i++) |
1834 | if (flags & map[i][from_idx]) out |= map[i][to_idx]; |
1835 | return out; |
1836 | } |
1837 | |
1838 | /* Validates an array of RedisModuleCommandArg. Returns 1 if it's valid and 0 if |
1839 | * it's invalid. */ |
1840 | static int moduleValidateCommandArgs(RedisModuleCommandArg *args, |
1841 | const RedisModuleCommandInfoVersion *version) { |
1842 | if (args == NULL) return 1; /* Missing args is OK. */ |
1843 | for (size_t j = 0; moduleCmdArgAt(version, args, j)->name != NULL; j++) { |
1844 | RedisModuleCommandArg *arg = moduleCmdArgAt(version, args, j); |
1845 | int arg_type_error = 0; |
1846 | moduleConvertArgType(arg->type, &arg_type_error); |
1847 | if (arg_type_error) { |
1848 | serverLog(LL_WARNING, |
1849 | "Invalid command info: Argument \"%s\": Undefined type %d" , |
1850 | arg->name, arg->type); |
1851 | return 0; |
1852 | } |
1853 | if (arg->type == REDISMODULE_ARG_TYPE_PURE_TOKEN && !arg->token) { |
1854 | serverLog(LL_WARNING, |
1855 | "Invalid command info: Argument \"%s\": " |
1856 | "token required when type is PURE_TOKEN" , args[j].name); |
1857 | return 0; |
1858 | } |
1859 | |
1860 | if (arg->type == REDISMODULE_ARG_TYPE_KEY) { |
1861 | if (arg->key_spec_index < 0) { |
1862 | serverLog(LL_WARNING, |
1863 | "Invalid command info: Argument \"%s\": " |
1864 | "key_spec_index required when type is KEY" , |
1865 | arg->name); |
1866 | return 0; |
1867 | } |
1868 | } else if (arg->key_spec_index != -1 && arg->key_spec_index != 0) { |
1869 | /* 0 is allowed for convenience, to allow it to be omitted in |
1870 | * compound struct literals on the form `.field = value`. */ |
1871 | serverLog(LL_WARNING, |
1872 | "Invalid command info: Argument \"%s\": " |
1873 | "key_spec_index specified but type isn't KEY" , |
1874 | arg->name); |
1875 | return 0; |
1876 | } |
1877 | |
1878 | if (arg->flags & ~(_REDISMODULE_CMD_ARG_NEXT - 1)) { |
1879 | serverLog(LL_WARNING, |
1880 | "Invalid command info: Argument \"%s\": Invalid flags" , |
1881 | arg->name); |
1882 | return 0; |
1883 | } |
1884 | |
1885 | if (arg->type == REDISMODULE_ARG_TYPE_ONEOF || |
1886 | arg->type == REDISMODULE_ARG_TYPE_BLOCK) |
1887 | { |
1888 | if (arg->subargs == NULL) { |
1889 | serverLog(LL_WARNING, |
1890 | "Invalid command info: Argument \"%s\": " |
1891 | "subargs required when type is ONEOF or BLOCK" , |
1892 | arg->name); |
1893 | return 0; |
1894 | } |
1895 | if (!moduleValidateCommandArgs(arg->subargs, version)) return 0; |
1896 | } else { |
1897 | if (arg->subargs != NULL) { |
1898 | serverLog(LL_WARNING, |
1899 | "Invalid command info: Argument \"%s\": " |
1900 | "subargs specified but type isn't ONEOF nor BLOCK" , |
1901 | arg->name); |
1902 | return 0; |
1903 | } |
1904 | } |
1905 | } |
1906 | return 1; |
1907 | } |
1908 | |
1909 | /* Converts an array of RedisModuleCommandArg into a freshly allocated array of |
1910 | * struct redisCommandArg. */ |
1911 | static struct redisCommandArg *moduleCopyCommandArgs(RedisModuleCommandArg *args, |
1912 | const RedisModuleCommandInfoVersion *version) { |
1913 | size_t count = 0; |
1914 | while (moduleCmdArgAt(version, args, count)->name) count++; |
1915 | serverAssert(count < SIZE_MAX / sizeof(struct redisCommandArg)); |
1916 | struct redisCommandArg *realargs = zcalloc((count+1) * sizeof(redisCommandArg)); |
1917 | |
1918 | for (size_t j = 0; j < count; j++) { |
1919 | RedisModuleCommandArg *arg = moduleCmdArgAt(version, args, j); |
1920 | realargs[j].name = zstrdup(arg->name); |
1921 | realargs[j].type = moduleConvertArgType(arg->type, NULL); |
1922 | if (arg->type == REDISMODULE_ARG_TYPE_KEY) |
1923 | realargs[j].key_spec_index = arg->key_spec_index; |
1924 | else |
1925 | realargs[j].key_spec_index = -1; |
1926 | if (arg->token) realargs[j].token = zstrdup(arg->token); |
1927 | if (arg->summary) realargs[j].summary = zstrdup(arg->summary); |
1928 | if (arg->since) realargs[j].since = zstrdup(arg->since); |
1929 | if (arg->deprecated_since) realargs[j].deprecated_since = zstrdup(arg->deprecated_since); |
1930 | realargs[j].flags = moduleConvertArgFlags(arg->flags); |
1931 | if (arg->subargs) realargs[j].subargs = moduleCopyCommandArgs(arg->subargs, version); |
1932 | } |
1933 | return realargs; |
1934 | } |
1935 | |
1936 | static redisCommandArgType moduleConvertArgType(RedisModuleCommandArgType type, int *error) { |
1937 | if (error) *error = 0; |
1938 | switch (type) { |
1939 | case REDISMODULE_ARG_TYPE_STRING: return ARG_TYPE_STRING; |
1940 | case REDISMODULE_ARG_TYPE_INTEGER: return ARG_TYPE_INTEGER; |
1941 | case REDISMODULE_ARG_TYPE_DOUBLE: return ARG_TYPE_DOUBLE; |
1942 | case REDISMODULE_ARG_TYPE_KEY: return ARG_TYPE_KEY; |
1943 | case REDISMODULE_ARG_TYPE_PATTERN: return ARG_TYPE_PATTERN; |
1944 | case REDISMODULE_ARG_TYPE_UNIX_TIME: return ARG_TYPE_UNIX_TIME; |
1945 | case REDISMODULE_ARG_TYPE_PURE_TOKEN: return ARG_TYPE_PURE_TOKEN; |
1946 | case REDISMODULE_ARG_TYPE_ONEOF: return ARG_TYPE_ONEOF; |
1947 | case REDISMODULE_ARG_TYPE_BLOCK: return ARG_TYPE_BLOCK; |
1948 | default: |
1949 | if (error) *error = 1; |
1950 | return -1; |
1951 | } |
1952 | } |
1953 | |
1954 | static int moduleConvertArgFlags(int flags) { |
1955 | int realflags = 0; |
1956 | if (flags & REDISMODULE_CMD_ARG_OPTIONAL) realflags |= CMD_ARG_OPTIONAL; |
1957 | if (flags & REDISMODULE_CMD_ARG_MULTIPLE) realflags |= CMD_ARG_MULTIPLE; |
1958 | if (flags & REDISMODULE_CMD_ARG_MULTIPLE_TOKEN) realflags |= CMD_ARG_MULTIPLE_TOKEN; |
1959 | return realflags; |
1960 | } |
1961 | |
1962 | /* Return `struct RedisModule *` as `void *` to avoid exposing it outside of module.c. */ |
1963 | void *moduleGetHandleByName(char *modulename) { |
1964 | return dictFetchValue(modules,modulename); |
1965 | } |
1966 | |
1967 | /* Returns 1 if `cmd` is a command of the module `modulename`. 0 otherwise. */ |
1968 | int moduleIsModuleCommand(void *module_handle, struct redisCommand *cmd) { |
1969 | if (cmd->proc != RedisModuleCommandDispatcher) |
1970 | return 0; |
1971 | if (module_handle == NULL) |
1972 | return 0; |
1973 | RedisModuleCommand *cp = cmd->module_cmd; |
1974 | return (cp->module == module_handle); |
1975 | } |
1976 | |
1977 | /* -------------------------------------------------------------------------- |
1978 | * ## Module information and time measurement |
1979 | * -------------------------------------------------------------------------- */ |
1980 | |
1981 | int moduleListConfigMatch(void *config, void *name) { |
1982 | return strcasecmp(((ModuleConfig *) config)->name, (char *) name) == 0; |
1983 | } |
1984 | |
1985 | void moduleListFree(void *config) { |
1986 | ModuleConfig *module_config = (ModuleConfig *) config; |
1987 | sdsfree(module_config->name); |
1988 | zfree(config); |
1989 | } |
1990 | |
1991 | void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver) { |
1992 | /* Called by RM_Init() to setup the `ctx->module` structure. |
1993 | * |
1994 | * This is an internal function, Redis modules developers don't need |
1995 | * to use it. */ |
1996 | RedisModule *module; |
1997 | |
1998 | if (ctx->module != NULL) return; |
1999 | module = zmalloc(sizeof(*module)); |
2000 | module->name = sdsnew(name); |
2001 | module->ver = ver; |
2002 | module->apiver = apiver; |
2003 | module->types = listCreate(); |
2004 | module->usedby = listCreate(); |
2005 | module->using = listCreate(); |
2006 | module->filters = listCreate(); |
2007 | module->module_configs = listCreate(); |
2008 | listSetMatchMethod(module->module_configs, moduleListConfigMatch); |
2009 | listSetFreeMethod(module->module_configs, moduleListFree); |
2010 | module->in_call = 0; |
2011 | module->configs_initialized = 0; |
2012 | module->in_hook = 0; |
2013 | module->options = 0; |
2014 | module->info_cb = 0; |
2015 | module->defrag_cb = 0; |
2016 | module->loadmod = NULL; |
2017 | ctx->module = module; |
2018 | } |
2019 | |
2020 | /* Return non-zero if the module name is busy. |
2021 | * Otherwise zero is returned. */ |
2022 | int RM_IsModuleNameBusy(const char *name) { |
2023 | sds modulename = sdsnew(name); |
2024 | dictEntry *de = dictFind(modules,modulename); |
2025 | sdsfree(modulename); |
2026 | return de != NULL; |
2027 | } |
2028 | |
2029 | /* Return the current UNIX time in milliseconds. */ |
2030 | long long RM_Milliseconds(void) { |
2031 | return mstime(); |
2032 | } |
2033 | |
2034 | /* Return counter of micro-seconds relative to an arbitrary point in time. */ |
2035 | uint64_t RM_MonotonicMicroseconds(void) { |
2036 | return getMonotonicUs(); |
2037 | } |
2038 | |
2039 | /* Mark a point in time that will be used as the start time to calculate |
2040 | * the elapsed execution time when RM_BlockedClientMeasureTimeEnd() is called. |
2041 | * Within the same command, you can call multiple times |
2042 | * RM_BlockedClientMeasureTimeStart() and RM_BlockedClientMeasureTimeEnd() |
2043 | * to accumulate independent time intervals to the background duration. |
2044 | * This method always return REDISMODULE_OK. */ |
2045 | int RM_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc) { |
2046 | elapsedStart(&(bc->background_timer)); |
2047 | return REDISMODULE_OK; |
2048 | } |
2049 | |
2050 | /* Mark a point in time that will be used as the end time |
2051 | * to calculate the elapsed execution time. |
2052 | * On success REDISMODULE_OK is returned. |
2053 | * This method only returns REDISMODULE_ERR if no start time was |
2054 | * previously defined ( meaning RM_BlockedClientMeasureTimeStart was not called ). */ |
2055 | int RM_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc) { |
2056 | // If the counter is 0 then we haven't called RM_BlockedClientMeasureTimeStart |
2057 | if (!bc->background_timer) |
2058 | return REDISMODULE_ERR; |
2059 | bc->background_duration += elapsedUs(bc->background_timer); |
2060 | return REDISMODULE_OK; |
2061 | } |
2062 | |
2063 | /* This API allows modules to let Redis process background tasks, and some |
2064 | * commands during long blocking execution of a module command. |
2065 | * The module can call this API periodically. |
2066 | * The flags is a bit mask of these: |
2067 | * |
2068 | * - `REDISMODULE_YIELD_FLAG_NONE`: No special flags, can perform some background |
2069 | * operations, but not process client commands. |
2070 | * - `REDISMODULE_YIELD_FLAG_CLIENTS`: Redis can also process client commands. |
2071 | * |
2072 | * The `busy_reply` argument is optional, and can be used to control the verbose |
2073 | * error string after the `-BUSY` error code. |
2074 | * |
2075 | * When the `REDISMODULE_YIELD_FLAG_CLIENTS` is used, Redis will only start |
2076 | * processing client commands after the time defined by the |
2077 | * `busy-reply-threshold` config, in which case Redis will start rejecting most |
2078 | * commands with `-BUSY` error, but allow the ones marked with the `allow-busy` |
2079 | * flag to be executed. |
2080 | * This API can also be used in thread safe context (while locked), and during |
2081 | * loading (in the `rdb_load` callback, in which case it'll reject commands with |
2082 | * the -LOADING error) |
2083 | */ |
2084 | void RM_Yield(RedisModuleCtx *ctx, int flags, const char *busy_reply) { |
2085 | static int yield_nesting = 0; |
2086 | /* Avoid nested calls to RM_Yield */ |
2087 | if (yield_nesting) |
2088 | return; |
2089 | yield_nesting++; |
2090 | |
2091 | long long now = getMonotonicUs(); |
2092 | if (now >= ctx->next_yield_time) { |
2093 | /* In loading mode, there's no need to handle busy_module_yield_reply, |
2094 | * and busy_module_yield_flags, since redis is anyway rejecting all |
2095 | * commands with -LOADING. */ |
2096 | if (server.loading) { |
2097 | /* Let redis process events */ |
2098 | processEventsWhileBlocked(); |
2099 | } else { |
2100 | const char *prev_busy_module_yield_reply = server.busy_module_yield_reply; |
2101 | server.busy_module_yield_reply = busy_reply; |
2102 | /* start the blocking operation if not already started. */ |
2103 | if (!server.busy_module_yield_flags) { |
2104 | server.busy_module_yield_flags = BUSY_MODULE_YIELD_EVENTS; |
2105 | blockingOperationStarts(); |
2106 | if (server.current_client) |
2107 | protectClient(server.current_client); |
2108 | } |
2109 | if (flags & REDISMODULE_YIELD_FLAG_CLIENTS) |
2110 | server.busy_module_yield_flags |= BUSY_MODULE_YIELD_CLIENTS; |
2111 | |
2112 | /* Let redis process events */ |
2113 | processEventsWhileBlocked(); |
2114 | |
2115 | server.busy_module_yield_reply = prev_busy_module_yield_reply; |
2116 | /* Possibly restore the previous flags in case of two nested contexts |
2117 | * that use this API with different flags, but keep the first bit |
2118 | * (PROCESS_EVENTS) set, so we know to call blockingOperationEnds on time. */ |
2119 | server.busy_module_yield_flags &= ~BUSY_MODULE_YIELD_CLIENTS; |
2120 | } |
2121 | |
2122 | /* decide when the next event should fire. */ |
2123 | ctx->next_yield_time = now + 1000000 / server.hz; |
2124 | } |
2125 | yield_nesting--; |
2126 | } |
2127 | |
2128 | /* Set flags defining capabilities or behavior bit flags. |
2129 | * |
2130 | * REDISMODULE_OPTIONS_HANDLE_IO_ERRORS: |
2131 | * Generally, modules don't need to bother with this, as the process will just |
2132 | * terminate if a read error happens, however, setting this flag would allow |
2133 | * repl-diskless-load to work if enabled. |
2134 | * The module should use RedisModule_IsIOError after reads, before using the |
2135 | * data that was read, and in case of error, propagate it upwards, and also be |
2136 | * able to release the partially populated value and all it's allocations. |
2137 | * |
2138 | * REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED: |
2139 | * See RM_SignalModifiedKey(). |
2140 | * |
2141 | * REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD: |
2142 | * Setting this flag indicates module awareness of diskless async replication (repl-diskless-load=swapdb) |
2143 | * and that redis could be serving reads during replication instead of blocking with LOADING status. |
2144 | */ |
2145 | void RM_SetModuleOptions(RedisModuleCtx *ctx, int options) { |
2146 | ctx->module->options = options; |
2147 | } |
2148 | |
2149 | /* Signals that the key is modified from user's perspective (i.e. invalidate WATCH |
2150 | * and client side caching). |
2151 | * |
2152 | * This is done automatically when a key opened for writing is closed, unless |
2153 | * the option REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED has been set using |
2154 | * RM_SetModuleOptions(). |
2155 | */ |
2156 | int RM_SignalModifiedKey(RedisModuleCtx *ctx, RedisModuleString *keyname) { |
2157 | signalModifiedKey(ctx->client,ctx->client->db,keyname); |
2158 | return REDISMODULE_OK; |
2159 | } |
2160 | |
2161 | /* -------------------------------------------------------------------------- |
2162 | * ## Automatic memory management for modules |
2163 | * -------------------------------------------------------------------------- */ |
2164 | |
2165 | /* Enable automatic memory management. |
2166 | * |
2167 | * The function must be called as the first function of a command implementation |
2168 | * that wants to use automatic memory. |
2169 | * |
2170 | * When enabled, automatic memory management tracks and automatically frees |
2171 | * keys, call replies and Redis string objects once the command returns. In most |
2172 | * cases this eliminates the need of calling the following functions: |
2173 | * |
2174 | * 1. RedisModule_CloseKey() |
2175 | * 2. RedisModule_FreeCallReply() |
2176 | * 3. RedisModule_FreeString() |
2177 | * |
2178 | * These functions can still be used with automatic memory management enabled, |
2179 | * to optimize loops that make numerous allocations for example. */ |
2180 | void RM_AutoMemory(RedisModuleCtx *ctx) { |
2181 | ctx->flags |= REDISMODULE_CTX_AUTO_MEMORY; |
2182 | } |
2183 | |
2184 | /* Add a new object to release automatically when the callback returns. */ |
2185 | void autoMemoryAdd(RedisModuleCtx *ctx, int type, void *ptr) { |
2186 | if (!(ctx->flags & REDISMODULE_CTX_AUTO_MEMORY)) return; |
2187 | if (ctx->amqueue_used == ctx->amqueue_len) { |
2188 | ctx->amqueue_len *= 2; |
2189 | if (ctx->amqueue_len < 16) ctx->amqueue_len = 16; |
2190 | ctx->amqueue = zrealloc(ctx->amqueue,sizeof(struct AutoMemEntry)*ctx->amqueue_len); |
2191 | } |
2192 | ctx->amqueue[ctx->amqueue_used].type = type; |
2193 | ctx->amqueue[ctx->amqueue_used].ptr = ptr; |
2194 | ctx->amqueue_used++; |
2195 | } |
2196 | |
2197 | /* Mark an object as freed in the auto release queue, so that users can still |
2198 | * free things manually if they want. |
2199 | * |
2200 | * The function returns 1 if the object was actually found in the auto memory |
2201 | * pool, otherwise 0 is returned. */ |
2202 | int autoMemoryFreed(RedisModuleCtx *ctx, int type, void *ptr) { |
2203 | if (!(ctx->flags & REDISMODULE_CTX_AUTO_MEMORY)) return 0; |
2204 | |
2205 | int count = (ctx->amqueue_used+1)/2; |
2206 | for (int j = 0; j < count; j++) { |
2207 | for (int side = 0; side < 2; side++) { |
2208 | /* For side = 0 check right side of the array, for |
2209 | * side = 1 check the left side instead (zig-zag scanning). */ |
2210 | int i = (side == 0) ? (ctx->amqueue_used - 1 - j) : j; |
2211 | if (ctx->amqueue[i].type == type && |
2212 | ctx->amqueue[i].ptr == ptr) |
2213 | { |
2214 | ctx->amqueue[i].type = REDISMODULE_AM_FREED; |
2215 | |
2216 | /* Switch the freed element and the last element, to avoid growing |
2217 | * the queue unnecessarily if we allocate/free in a loop */ |
2218 | if (i != ctx->amqueue_used-1) { |
2219 | ctx->amqueue[i] = ctx->amqueue[ctx->amqueue_used-1]; |
2220 | } |
2221 | |
2222 | /* Reduce the size of the queue because we either moved the top |
2223 | * element elsewhere or freed it */ |
2224 | ctx->amqueue_used--; |
2225 | return 1; |
2226 | } |
2227 | } |
2228 | } |
2229 | return 0; |
2230 | } |
2231 | |
2232 | /* Release all the objects in queue. */ |
2233 | void autoMemoryCollect(RedisModuleCtx *ctx) { |
2234 | if (!(ctx->flags & REDISMODULE_CTX_AUTO_MEMORY)) return; |
2235 | /* Clear the AUTO_MEMORY flag from the context, otherwise the functions |
2236 | * we call to free the resources, will try to scan the auto release |
2237 | * queue to mark the entries as freed. */ |
2238 | ctx->flags &= ~REDISMODULE_CTX_AUTO_MEMORY; |
2239 | int j; |
2240 | for (j = 0; j < ctx->amqueue_used; j++) { |
2241 | void *ptr = ctx->amqueue[j].ptr; |
2242 | switch(ctx->amqueue[j].type) { |
2243 | case REDISMODULE_AM_STRING: decrRefCount(ptr); break; |
2244 | case REDISMODULE_AM_REPLY: RM_FreeCallReply(ptr); break; |
2245 | case REDISMODULE_AM_KEY: RM_CloseKey(ptr); break; |
2246 | case REDISMODULE_AM_DICT: RM_FreeDict(NULL,ptr); break; |
2247 | case REDISMODULE_AM_INFO: RM_FreeServerInfo(NULL,ptr); break; |
2248 | } |
2249 | } |
2250 | ctx->flags |= REDISMODULE_CTX_AUTO_MEMORY; |
2251 | zfree(ctx->amqueue); |
2252 | ctx->amqueue = NULL; |
2253 | ctx->amqueue_len = 0; |
2254 | ctx->amqueue_used = 0; |
2255 | } |
2256 | |
2257 | /* -------------------------------------------------------------------------- |
2258 | * ## String objects APIs |
2259 | * -------------------------------------------------------------------------- */ |
2260 | |
2261 | /* Create a new module string object. The returned string must be freed |
2262 | * with RedisModule_FreeString(), unless automatic memory is enabled. |
2263 | * |
2264 | * The string is created by copying the `len` bytes starting |
2265 | * at `ptr`. No reference is retained to the passed buffer. |
2266 | * |
2267 | * The module context 'ctx' is optional and may be NULL if you want to create |
2268 | * a string out of the context scope. However in that case, the automatic |
2269 | * memory management will not be available, and the string memory must be |
2270 | * managed manually. */ |
2271 | RedisModuleString *RM_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len) { |
2272 | RedisModuleString *o = createStringObject(ptr,len); |
2273 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,o); |
2274 | return o; |
2275 | } |
2276 | |
2277 | /* Create a new module string object from a printf format and arguments. |
2278 | * The returned string must be freed with RedisModule_FreeString(), unless |
2279 | * automatic memory is enabled. |
2280 | * |
2281 | * The string is created using the sds formatter function sdscatvprintf(). |
2282 | * |
2283 | * The passed context 'ctx' may be NULL if necessary, see the |
2284 | * RedisModule_CreateString() documentation for more info. */ |
2285 | RedisModuleString *RM_CreateStringPrintf(RedisModuleCtx *ctx, const char *fmt, ...) { |
2286 | sds s = sdsempty(); |
2287 | |
2288 | va_list ap; |
2289 | va_start(ap, fmt); |
2290 | s = sdscatvprintf(s, fmt, ap); |
2291 | va_end(ap); |
2292 | |
2293 | RedisModuleString *o = createObject(OBJ_STRING, s); |
2294 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,o); |
2295 | |
2296 | return o; |
2297 | } |
2298 | |
2299 | |
2300 | /* Like RedisModule_CreateString(), but creates a string starting from a `long long` |
2301 | * integer instead of taking a buffer and its length. |
2302 | * |
2303 | * The returned string must be released with RedisModule_FreeString() or by |
2304 | * enabling automatic memory management. |
2305 | * |
2306 | * The passed context 'ctx' may be NULL if necessary, see the |
2307 | * RedisModule_CreateString() documentation for more info. */ |
2308 | RedisModuleString *RM_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll) { |
2309 | char buf[LONG_STR_SIZE]; |
2310 | size_t len = ll2string(buf,sizeof(buf),ll); |
2311 | return RM_CreateString(ctx,buf,len); |
2312 | } |
2313 | |
2314 | /* Like RedisModule_CreateString(), but creates a string starting from a `unsigned long long` |
2315 | * integer instead of taking a buffer and its length. |
2316 | * |
2317 | * The returned string must be released with RedisModule_FreeString() or by |
2318 | * enabling automatic memory management. |
2319 | * |
2320 | * The passed context 'ctx' may be NULL if necessary, see the |
2321 | * RedisModule_CreateString() documentation for more info. */ |
2322 | RedisModuleString *RM_CreateStringFromULongLong(RedisModuleCtx *ctx, unsigned long long ull) { |
2323 | char buf[LONG_STR_SIZE]; |
2324 | size_t len = ull2string(buf,sizeof(buf),ull); |
2325 | return RM_CreateString(ctx,buf,len); |
2326 | } |
2327 | |
2328 | /* Like RedisModule_CreateString(), but creates a string starting from a double |
2329 | * instead of taking a buffer and its length. |
2330 | * |
2331 | * The returned string must be released with RedisModule_FreeString() or by |
2332 | * enabling automatic memory management. */ |
2333 | RedisModuleString *RM_CreateStringFromDouble(RedisModuleCtx *ctx, double d) { |
2334 | char buf[MAX_D2STRING_CHARS]; |
2335 | size_t len = d2string(buf,sizeof(buf),d); |
2336 | return RM_CreateString(ctx,buf,len); |
2337 | } |
2338 | |
2339 | /* Like RedisModule_CreateString(), but creates a string starting from a long |
2340 | * double. |
2341 | * |
2342 | * The returned string must be released with RedisModule_FreeString() or by |
2343 | * enabling automatic memory management. |
2344 | * |
2345 | * The passed context 'ctx' may be NULL if necessary, see the |
2346 | * RedisModule_CreateString() documentation for more info. */ |
2347 | RedisModuleString *RM_CreateStringFromLongDouble(RedisModuleCtx *ctx, long double ld, int humanfriendly) { |
2348 | char buf[MAX_LONG_DOUBLE_CHARS]; |
2349 | size_t len = ld2string(buf,sizeof(buf),ld, |
2350 | (humanfriendly ? LD_STR_HUMAN : LD_STR_AUTO)); |
2351 | return RM_CreateString(ctx,buf,len); |
2352 | } |
2353 | |
2354 | /* Like RedisModule_CreateString(), but creates a string starting from another |
2355 | * RedisModuleString. |
2356 | * |
2357 | * The returned string must be released with RedisModule_FreeString() or by |
2358 | * enabling automatic memory management. |
2359 | * |
2360 | * The passed context 'ctx' may be NULL if necessary, see the |
2361 | * RedisModule_CreateString() documentation for more info. */ |
2362 | RedisModuleString *RM_CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str) { |
2363 | RedisModuleString *o = dupStringObject(str); |
2364 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,o); |
2365 | return o; |
2366 | } |
2367 | |
2368 | /* Creates a string from a stream ID. The returned string must be released with |
2369 | * RedisModule_FreeString(), unless automatic memory is enabled. |
2370 | * |
2371 | * The passed context `ctx` may be NULL if necessary. See the |
2372 | * RedisModule_CreateString() documentation for more info. */ |
2373 | RedisModuleString *RM_CreateStringFromStreamID(RedisModuleCtx *ctx, const RedisModuleStreamID *id) { |
2374 | streamID streamid = {id->ms, id->seq}; |
2375 | RedisModuleString *o = createObjectFromStreamID(&streamid); |
2376 | if (ctx != NULL) autoMemoryAdd(ctx, REDISMODULE_AM_STRING, o); |
2377 | return o; |
2378 | } |
2379 | |
2380 | /* Free a module string object obtained with one of the Redis modules API calls |
2381 | * that return new string objects. |
2382 | * |
2383 | * It is possible to call this function even when automatic memory management |
2384 | * is enabled. In that case the string will be released ASAP and removed |
2385 | * from the pool of string to release at the end. |
2386 | * |
2387 | * If the string was created with a NULL context 'ctx', it is also possible to |
2388 | * pass ctx as NULL when releasing the string (but passing a context will not |
2389 | * create any issue). Strings created with a context should be freed also passing |
2390 | * the context, so if you want to free a string out of context later, make sure |
2391 | * to create it using a NULL context. */ |
2392 | void RM_FreeString(RedisModuleCtx *ctx, RedisModuleString *str) { |
2393 | decrRefCount(str); |
2394 | if (ctx != NULL) autoMemoryFreed(ctx,REDISMODULE_AM_STRING,str); |
2395 | } |
2396 | |
2397 | /* Every call to this function, will make the string 'str' requiring |
2398 | * an additional call to RedisModule_FreeString() in order to really |
2399 | * free the string. Note that the automatic freeing of the string obtained |
2400 | * enabling modules automatic memory management counts for one |
2401 | * RedisModule_FreeString() call (it is just executed automatically). |
2402 | * |
2403 | * Normally you want to call this function when, at the same time |
2404 | * the following conditions are true: |
2405 | * |
2406 | * 1. You have automatic memory management enabled. |
2407 | * 2. You want to create string objects. |
2408 | * 3. Those string objects you create need to live *after* the callback |
2409 | * function(for example a command implementation) creating them returns. |
2410 | * |
2411 | * Usually you want this in order to store the created string object |
2412 | * into your own data structure, for example when implementing a new data |
2413 | * type. |
2414 | * |
2415 | * Note that when memory management is turned off, you don't need |
2416 | * any call to RetainString() since creating a string will always result |
2417 | * into a string that lives after the callback function returns, if |
2418 | * no FreeString() call is performed. |
2419 | * |
2420 | * It is possible to call this function with a NULL context. |
2421 | * |
2422 | * When strings are going to be retained for an extended duration, it is good |
2423 | * practice to also call RedisModule_TrimStringAllocation() in order to |
2424 | * optimize memory usage. |
2425 | * |
2426 | * Threaded modules that reference retained strings from other threads *must* |
2427 | * explicitly trim the allocation as soon as the string is retained. Not doing |
2428 | * so may result with automatic trimming which is not thread safe. */ |
2429 | void RM_RetainString(RedisModuleCtx *ctx, RedisModuleString *str) { |
2430 | if (ctx == NULL || !autoMemoryFreed(ctx,REDISMODULE_AM_STRING,str)) { |
2431 | /* Increment the string reference counting only if we can't |
2432 | * just remove the object from the list of objects that should |
2433 | * be reclaimed. Why we do that, instead of just incrementing |
2434 | * the refcount in any case, and let the automatic FreeString() |
2435 | * call at the end to bring the refcount back at the desired |
2436 | * value? Because this way we ensure that the object refcount |
2437 | * value is 1 (instead of going to 2 to be dropped later to 1) |
2438 | * after the call to this function. This is needed for functions |
2439 | * like RedisModule_StringAppendBuffer() to work. */ |
2440 | incrRefCount(str); |
2441 | } |
2442 | } |
2443 | |
2444 | /** |
2445 | * This function can be used instead of RedisModule_RetainString(). |
2446 | * The main difference between the two is that this function will always |
2447 | * succeed, whereas RedisModule_RetainString() may fail because of an |
2448 | * assertion. |
2449 | * |
2450 | * The function returns a pointer to RedisModuleString, which is owned |
2451 | * by the caller. It requires a call to RedisModule_FreeString() to free |
2452 | * the string when automatic memory management is disabled for the context. |
2453 | * When automatic memory management is enabled, you can either call |
2454 | * RedisModule_FreeString() or let the automation free it. |
2455 | * |
2456 | * This function is more efficient than RedisModule_CreateStringFromString() |
2457 | * because whenever possible, it avoids copying the underlying |
2458 | * RedisModuleString. The disadvantage of using this function is that it |
2459 | * might not be possible to use RedisModule_StringAppendBuffer() on the |
2460 | * returned RedisModuleString. |
2461 | * |
2462 | * It is possible to call this function with a NULL context. |
2463 | * |
2464 | * When strings are going to be held for an extended duration, it is good |
2465 | * practice to also call RedisModule_TrimStringAllocation() in order to |
2466 | * optimize memory usage. |
2467 | * |
2468 | * Threaded modules that reference held strings from other threads *must* |
2469 | * explicitly trim the allocation as soon as the string is held. Not doing |
2470 | * so may result with automatic trimming which is not thread safe. */ |
2471 | RedisModuleString* RM_HoldString(RedisModuleCtx *ctx, RedisModuleString *str) { |
2472 | if (str->refcount == OBJ_STATIC_REFCOUNT) { |
2473 | return RM_CreateStringFromString(ctx, str); |
2474 | } |
2475 | |
2476 | incrRefCount(str); |
2477 | if (ctx != NULL) { |
2478 | /* |
2479 | * Put the str in the auto memory management of the ctx. |
2480 | Â Â Â Â Â * It might already be there, in this case, the ref count will |
2481 | Â Â Â Â Â * be 2 and we will decrease the ref count twice and free the |
2482 | Â Â Â Â Â * object in the auto memory free function. |
2483 | Â Â Â Â Â * |
2484 | Â Â Â Â Â * Why we can not do the same trick of just remove the object |
2485 | Â Â Â Â Â * from the auto memory (like in RM_RetainString)? |
2486 | Â Â Â Â Â * This code shows the issue: |
2487 | Â Â Â Â Â * |
2488 | Â Â Â Â Â * RM_AutoMemory(ctx); |
2489 | Â Â Â Â Â * str1 = RM_CreateString(ctx, "test", 4); |
2490 | Â Â Â Â Â * str2 = RM_HoldString(ctx, str1); |
2491 | Â Â Â Â Â * RM_FreeString(str1); |
2492 | Â Â Â Â Â * RM_FreeString(str2); |
2493 | Â Â Â Â Â * |
2494 | Â Â Â Â Â * If after the RM_HoldString we would just remove the string from |
2495 | Â Â Â Â Â * the auto memory, this example will cause access to a freed memory |
2496 | Â Â Â Â Â * on 'RM_FreeString(str2);' because the String will be free |
2497 | Â Â Â Â Â * on 'RM_FreeString(str1);'. |
2498 | Â Â Â Â Â * |
2499 | Â Â Â Â Â * So it's safer to just increase the ref count |
2500 | Â Â Â Â Â * and add the String to auto memory again. |
2501 | Â Â Â Â Â * |
2502 | Â Â Â Â Â * The limitation is that it is not possible to use RedisModule_StringAppendBuffer |
2503 | Â Â Â Â Â * on the String. |
2504 | */ |
2505 | autoMemoryAdd(ctx,REDISMODULE_AM_STRING,str); |
2506 | } |
2507 | return str; |
2508 | } |
2509 | |
2510 | /* Given a string module object, this function returns the string pointer |
2511 | * and length of the string. The returned pointer and length should only |
2512 | * be used for read only accesses and never modified. */ |
2513 | const char *RM_StringPtrLen(const RedisModuleString *str, size_t *len) { |
2514 | if (str == NULL) { |
2515 | const char *errmsg = "(NULL string reply referenced in module)" ; |
2516 | if (len) *len = strlen(errmsg); |
2517 | return errmsg; |
2518 | } |
2519 | if (len) *len = sdslen(str->ptr); |
2520 | return str->ptr; |
2521 | } |
2522 | |
2523 | /* -------------------------------------------------------------------------- |
2524 | * Higher level string operations |
2525 | * ------------------------------------------------------------------------- */ |
2526 | |
2527 | /* Convert the string into a `long long` integer, storing it at `*ll`. |
2528 | * Returns REDISMODULE_OK on success. If the string can't be parsed |
2529 | * as a valid, strict `long long` (no spaces before/after), REDISMODULE_ERR |
2530 | * is returned. */ |
2531 | int RM_StringToLongLong(const RedisModuleString *str, long long *ll) { |
2532 | return string2ll(str->ptr,sdslen(str->ptr),ll) ? REDISMODULE_OK : |
2533 | REDISMODULE_ERR; |
2534 | } |
2535 | |
2536 | /* Convert the string into a `unsigned long long` integer, storing it at `*ull`. |
2537 | * Returns REDISMODULE_OK on success. If the string can't be parsed |
2538 | * as a valid, strict `unsigned long long` (no spaces before/after), REDISMODULE_ERR |
2539 | * is returned. */ |
2540 | int RM_StringToULongLong(const RedisModuleString *str, unsigned long long *ull) { |
2541 | return string2ull(str->ptr,ull) ? REDISMODULE_OK : REDISMODULE_ERR; |
2542 | } |
2543 | |
2544 | /* Convert the string into a double, storing it at `*d`. |
2545 | * Returns REDISMODULE_OK on success or REDISMODULE_ERR if the string is |
2546 | * not a valid string representation of a double value. */ |
2547 | int RM_StringToDouble(const RedisModuleString *str, double *d) { |
2548 | int retval = getDoubleFromObject(str,d); |
2549 | return (retval == C_OK) ? REDISMODULE_OK : REDISMODULE_ERR; |
2550 | } |
2551 | |
2552 | /* Convert the string into a long double, storing it at `*ld`. |
2553 | * Returns REDISMODULE_OK on success or REDISMODULE_ERR if the string is |
2554 | * not a valid string representation of a double value. */ |
2555 | int RM_StringToLongDouble(const RedisModuleString *str, long double *ld) { |
2556 | int retval = string2ld(str->ptr,sdslen(str->ptr),ld); |
2557 | return retval ? REDISMODULE_OK : REDISMODULE_ERR; |
2558 | } |
2559 | |
2560 | /* Convert the string into a stream ID, storing it at `*id`. |
2561 | * Returns REDISMODULE_OK on success and returns REDISMODULE_ERR if the string |
2562 | * is not a valid string representation of a stream ID. The special IDs "+" and |
2563 | * "-" are allowed. |
2564 | */ |
2565 | int RM_StringToStreamID(const RedisModuleString *str, RedisModuleStreamID *id) { |
2566 | streamID streamid; |
2567 | if (streamParseID(str, &streamid) == C_OK) { |
2568 | id->ms = streamid.ms; |
2569 | id->seq = streamid.seq; |
2570 | return REDISMODULE_OK; |
2571 | } else { |
2572 | return REDISMODULE_ERR; |
2573 | } |
2574 | } |
2575 | |
2576 | /* Compare two string objects, returning -1, 0 or 1 respectively if |
2577 | * a < b, a == b, a > b. Strings are compared byte by byte as two |
2578 | * binary blobs without any encoding care / collation attempt. */ |
2579 | int RM_StringCompare(RedisModuleString *a, RedisModuleString *b) { |
2580 | return compareStringObjects(a,b); |
2581 | } |
2582 | |
2583 | /* Return the (possibly modified in encoding) input 'str' object if |
2584 | * the string is unshared, otherwise NULL is returned. */ |
2585 | RedisModuleString *moduleAssertUnsharedString(RedisModuleString *str) { |
2586 | if (str->refcount != 1) { |
2587 | serverLog(LL_WARNING, |
2588 | "Module attempted to use an in-place string modify operation " |
2589 | "with a string referenced multiple times. Please check the code " |
2590 | "for API usage correctness." ); |
2591 | return NULL; |
2592 | } |
2593 | if (str->encoding == OBJ_ENCODING_EMBSTR) { |
2594 | /* Note: here we "leak" the additional allocation that was |
2595 | * used in order to store the embedded string in the object. */ |
2596 | str->ptr = sdsnewlen(str->ptr,sdslen(str->ptr)); |
2597 | str->encoding = OBJ_ENCODING_RAW; |
2598 | } else if (str->encoding == OBJ_ENCODING_INT) { |
2599 | /* Convert the string from integer to raw encoding. */ |
2600 | str->ptr = sdsfromlonglong((long)str->ptr); |
2601 | str->encoding = OBJ_ENCODING_RAW; |
2602 | } |
2603 | return str; |
2604 | } |
2605 | |
2606 | /* Append the specified buffer to the string 'str'. The string must be a |
2607 | * string created by the user that is referenced only a single time, otherwise |
2608 | * REDISMODULE_ERR is returned and the operation is not performed. */ |
2609 | int RM_StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len) { |
2610 | UNUSED(ctx); |
2611 | str = moduleAssertUnsharedString(str); |
2612 | if (str == NULL) return REDISMODULE_ERR; |
2613 | str->ptr = sdscatlen(str->ptr,buf,len); |
2614 | return REDISMODULE_OK; |
2615 | } |
2616 | |
2617 | /* Trim possible excess memory allocated for a RedisModuleString. |
2618 | * |
2619 | * Sometimes a RedisModuleString may have more memory allocated for |
2620 | * it than required, typically for argv arguments that were constructed |
2621 | * from network buffers. This function optimizes such strings by reallocating |
2622 | * their memory, which is useful for strings that are not short lived but |
2623 | * retained for an extended duration. |
2624 | * |
2625 | * This operation is *not thread safe* and should only be called when |
2626 | * no concurrent access to the string is guaranteed. Using it for an argv |
2627 | * string in a module command before the string is potentially available |
2628 | * to other threads is generally safe. |
2629 | * |
2630 | * Currently, Redis may also automatically trim retained strings when a |
2631 | * module command returns. However, doing this explicitly should still be |
2632 | * a preferred option: |
2633 | * |
2634 | * 1. Future versions of Redis may abandon auto-trimming. |
2635 | * 2. Auto-trimming as currently implemented is *not thread safe*. |
2636 | * A background thread manipulating a recently retained string may end up |
2637 | * in a race condition with the auto-trim, which could result with |
2638 | * data corruption. |
2639 | */ |
2640 | void RM_TrimStringAllocation(RedisModuleString *str) { |
2641 | if (!str) return; |
2642 | trimStringObjectIfNeeded(str); |
2643 | } |
2644 | |
2645 | /* -------------------------------------------------------------------------- |
2646 | * ## Reply APIs |
2647 | * |
2648 | * These functions are used for sending replies to the client. |
2649 | * |
2650 | * Most functions always return REDISMODULE_OK so you can use it with |
2651 | * 'return' in order to return from the command implementation with: |
2652 | * |
2653 | * if (... some condition ...) |
2654 | * return RedisModule_ReplyWithLongLong(ctx,mycount); |
2655 | * |
2656 | * ### Reply with collection functions |
2657 | * |
2658 | * After starting a collection reply, the module must make calls to other |
2659 | * `ReplyWith*` style functions in order to emit the elements of the collection. |
2660 | * Collection types include: Array, Map, Set and Attribute. |
2661 | * |
2662 | * When producing collections with a number of elements that is not known |
2663 | * beforehand, the function can be called with a special flag |
2664 | * REDISMODULE_POSTPONED_LEN (REDISMODULE_POSTPONED_ARRAY_LEN in the past), |
2665 | * and the actual number of elements can be later set with RM_ReplySet*Length() |
2666 | * call (which will set the latest "open" count if there are multiple ones). |
2667 | * -------------------------------------------------------------------------- */ |
2668 | |
2669 | /* Send an error about the number of arguments given to the command, |
2670 | * citing the command name in the error message. Returns REDISMODULE_OK. |
2671 | * |
2672 | * Example: |
2673 | * |
2674 | * if (argc != 3) return RedisModule_WrongArity(ctx); |
2675 | */ |
2676 | int RM_WrongArity(RedisModuleCtx *ctx) { |
2677 | addReplyErrorArity(ctx->client); |
2678 | return REDISMODULE_OK; |
2679 | } |
2680 | |
2681 | /* Return the client object the `RM_Reply*` functions should target. |
2682 | * Normally this is just `ctx->client`, that is the client that called |
2683 | * the module command, however in the case of thread safe contexts there |
2684 | * is no directly associated client (since it would not be safe to access |
2685 | * the client from a thread), so instead the blocked client object referenced |
2686 | * in the thread safe context, has a fake client that we just use to accumulate |
2687 | * the replies. Later, when the client is unblocked, the accumulated replies |
2688 | * are appended to the actual client. |
2689 | * |
2690 | * The function returns the client pointer depending on the context, or |
2691 | * NULL if there is no potential client. This happens when we are in the |
2692 | * context of a thread safe context that was not initialized with a blocked |
2693 | * client object. Other contexts without associated clients are the ones |
2694 | * initialized to run the timers callbacks. */ |
2695 | client *moduleGetReplyClient(RedisModuleCtx *ctx) { |
2696 | if (ctx->flags & REDISMODULE_CTX_THREAD_SAFE) { |
2697 | if (ctx->blocked_client) |
2698 | return ctx->blocked_client->reply_client; |
2699 | else |
2700 | return NULL; |
2701 | } else { |
2702 | /* If this is a non thread safe context, just return the client |
2703 | * that is running the command if any. This may be NULL as well |
2704 | * in the case of contexts that are not executed with associated |
2705 | * clients, like timer contexts. */ |
2706 | return ctx->client; |
2707 | } |
2708 | } |
2709 | |
2710 | /* Send an integer reply to the client, with the specified `long long` value. |
2711 | * The function always returns REDISMODULE_OK. */ |
2712 | int RM_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll) { |
2713 | client *c = moduleGetReplyClient(ctx); |
2714 | if (c == NULL) return REDISMODULE_OK; |
2715 | addReplyLongLong(c,ll); |
2716 | return REDISMODULE_OK; |
2717 | } |
2718 | |
2719 | /* Reply with the error 'err'. |
2720 | * |
2721 | * Note that 'err' must contain all the error, including |
2722 | * the initial error code. The function only provides the initial "-", so |
2723 | * the usage is, for example: |
2724 | * |
2725 | * RedisModule_ReplyWithError(ctx,"ERR Wrong Type"); |
2726 | * |
2727 | * and not just: |
2728 | * |
2729 | * RedisModule_ReplyWithError(ctx,"Wrong Type"); |
2730 | * |
2731 | * The function always returns REDISMODULE_OK. |
2732 | */ |
2733 | int RM_ReplyWithError(RedisModuleCtx *ctx, const char *err) { |
2734 | client *c = moduleGetReplyClient(ctx); |
2735 | if (c == NULL) return REDISMODULE_OK; |
2736 | addReplyErrorFormat(c,"-%s" ,err); |
2737 | return REDISMODULE_OK; |
2738 | } |
2739 | |
2740 | /* Reply with a simple string (`+... \r\n` in RESP protocol). This replies |
2741 | * are suitable only when sending a small non-binary string with small |
2742 | * overhead, like "OK" or similar replies. |
2743 | * |
2744 | * The function always returns REDISMODULE_OK. */ |
2745 | int RM_ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg) { |
2746 | client *c = moduleGetReplyClient(ctx); |
2747 | if (c == NULL) return REDISMODULE_OK; |
2748 | addReplyProto(c,"+" ,1); |
2749 | addReplyProto(c,msg,strlen(msg)); |
2750 | addReplyProto(c,"\r\n" ,2); |
2751 | return REDISMODULE_OK; |
2752 | } |
2753 | |
2754 | #define COLLECTION_REPLY_ARRAY 1 |
2755 | #define COLLECTION_REPLY_MAP 2 |
2756 | #define COLLECTION_REPLY_SET 3 |
2757 | #define COLLECTION_REPLY_ATTRIBUTE 4 |
2758 | |
2759 | int moduleReplyWithCollection(RedisModuleCtx *ctx, long len, int type) { |
2760 | client *c = moduleGetReplyClient(ctx); |
2761 | if (c == NULL) return REDISMODULE_OK; |
2762 | if (len == REDISMODULE_POSTPONED_LEN) { |
2763 | ctx->postponed_arrays = zrealloc(ctx->postponed_arrays,sizeof(void*)* |
2764 | (ctx->postponed_arrays_count+1)); |
2765 | ctx->postponed_arrays[ctx->postponed_arrays_count] = |
2766 | addReplyDeferredLen(c); |
2767 | ctx->postponed_arrays_count++; |
2768 | } else if (len == 0) { |
2769 | switch (type) { |
2770 | case COLLECTION_REPLY_ARRAY: |
2771 | addReply(c, shared.emptyarray); |
2772 | break; |
2773 | case COLLECTION_REPLY_MAP: |
2774 | addReply(c, shared.emptymap[c->resp]); |
2775 | break; |
2776 | case COLLECTION_REPLY_SET: |
2777 | addReply(c, shared.emptyset[c->resp]); |
2778 | break; |
2779 | case COLLECTION_REPLY_ATTRIBUTE: |
2780 | addReplyAttributeLen(c,len); |
2781 | break; |
2782 | default: |
2783 | serverPanic("Invalid module empty reply type %d" , type); } |
2784 | } else { |
2785 | switch (type) { |
2786 | case COLLECTION_REPLY_ARRAY: |
2787 | addReplyArrayLen(c,len); |
2788 | break; |
2789 | case COLLECTION_REPLY_MAP: |
2790 | addReplyMapLen(c,len); |
2791 | break; |
2792 | case COLLECTION_REPLY_SET: |
2793 | addReplySetLen(c,len); |
2794 | break; |
2795 | case COLLECTION_REPLY_ATTRIBUTE: |
2796 | addReplyAttributeLen(c,len); |
2797 | break; |
2798 | default: |
2799 | serverPanic("Invalid module reply type %d" , type); |
2800 | } |
2801 | } |
2802 | return REDISMODULE_OK; |
2803 | } |
2804 | |
2805 | /* Reply with an array type of 'len' elements. |
2806 | * |
2807 | * After starting an array reply, the module must make `len` calls to other |
2808 | * `ReplyWith*` style functions in order to emit the elements of the array. |
2809 | * See Reply APIs section for more details. |
2810 | * |
2811 | * Use RM_ReplySetArrayLength() to set deferred length. |
2812 | * |
2813 | * The function always returns REDISMODULE_OK. */ |
2814 | int RM_ReplyWithArray(RedisModuleCtx *ctx, long len) { |
2815 | return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_ARRAY); |
2816 | } |
2817 | |
2818 | /* Reply with a RESP3 Map type of 'len' pairs. |
2819 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
2820 | * |
2821 | * After starting a map reply, the module must make `len*2` calls to other |
2822 | * `ReplyWith*` style functions in order to emit the elements of the map. |
2823 | * See Reply APIs section for more details. |
2824 | * |
2825 | * If the connected client is using RESP2, the reply will be converted to a flat |
2826 | * array. |
2827 | * |
2828 | * Use RM_ReplySetMapLength() to set deferred length. |
2829 | * |
2830 | * The function always returns REDISMODULE_OK. */ |
2831 | int RM_ReplyWithMap(RedisModuleCtx *ctx, long len) { |
2832 | return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_MAP); |
2833 | } |
2834 | |
2835 | /* Reply with a RESP3 Set type of 'len' elements. |
2836 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
2837 | * |
2838 | * After starting a set reply, the module must make `len` calls to other |
2839 | * `ReplyWith*` style functions in order to emit the elements of the set. |
2840 | * See Reply APIs section for more details. |
2841 | * |
2842 | * If the connected client is using RESP2, the reply will be converted to an |
2843 | * array type. |
2844 | * |
2845 | * Use RM_ReplySetSetLength() to set deferred length. |
2846 | * |
2847 | * The function always returns REDISMODULE_OK. */ |
2848 | int RM_ReplyWithSet(RedisModuleCtx *ctx, long len) { |
2849 | return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_SET); |
2850 | } |
2851 | |
2852 | |
2853 | /* Add attributes (metadata) to the reply. Should be done before adding the |
2854 | * actual reply. see https://github.com/antirez/RESP3/blob/master/spec.md#attribute-type |
2855 | * |
2856 | * After starting an attribute's reply, the module must make `len*2` calls to other |
2857 | * `ReplyWith*` style functions in order to emit the elements of the attribute map. |
2858 | * See Reply APIs section for more details. |
2859 | * |
2860 | * Use RM_ReplySetAttributeLength() to set deferred length. |
2861 | * |
2862 | * Not supported by RESP2 and will return REDISMODULE_ERR, otherwise |
2863 | * the function always returns REDISMODULE_OK. */ |
2864 | int RM_ReplyWithAttribute(RedisModuleCtx *ctx, long len) { |
2865 | if (ctx->client->resp == 2) return REDISMODULE_ERR; |
2866 | |
2867 | return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_ATTRIBUTE); |
2868 | } |
2869 | |
2870 | /* Reply to the client with a null array, simply null in RESP3, |
2871 | * null array in RESP2. |
2872 | * |
2873 | * Note: In RESP3 there's no difference between Null reply and |
2874 | * NullArray reply, so to prevent ambiguity it's better to avoid |
2875 | * using this API and use RedisModule_ReplyWithNull instead. |
2876 | * |
2877 | * The function always returns REDISMODULE_OK. */ |
2878 | int RM_ReplyWithNullArray(RedisModuleCtx *ctx) { |
2879 | client *c = moduleGetReplyClient(ctx); |
2880 | if (c == NULL) return REDISMODULE_OK; |
2881 | addReplyNullArray(c); |
2882 | return REDISMODULE_OK; |
2883 | } |
2884 | |
2885 | /* Reply to the client with an empty array. |
2886 | * |
2887 | * The function always returns REDISMODULE_OK. */ |
2888 | int RM_ReplyWithEmptyArray(RedisModuleCtx *ctx) { |
2889 | client *c = moduleGetReplyClient(ctx); |
2890 | if (c == NULL) return REDISMODULE_OK; |
2891 | addReply(c,shared.emptyarray); |
2892 | return REDISMODULE_OK; |
2893 | } |
2894 | |
2895 | void moduleReplySetCollectionLength(RedisModuleCtx *ctx, long len, int type) { |
2896 | client *c = moduleGetReplyClient(ctx); |
2897 | if (c == NULL) return; |
2898 | if (ctx->postponed_arrays_count == 0) { |
2899 | serverLog(LL_WARNING, |
2900 | "API misuse detected in module %s: " |
2901 | "RedisModule_ReplySet*Length() called without previous " |
2902 | "RedisModule_ReplyWith*(ctx,REDISMODULE_POSTPONED_LEN) " |
2903 | "call." , ctx->module->name); |
2904 | return; |
2905 | } |
2906 | ctx->postponed_arrays_count--; |
2907 | switch(type) { |
2908 | case COLLECTION_REPLY_ARRAY: |
2909 | setDeferredArrayLen(c,ctx->postponed_arrays[ctx->postponed_arrays_count],len); |
2910 | break; |
2911 | case COLLECTION_REPLY_MAP: |
2912 | setDeferredMapLen(c,ctx->postponed_arrays[ctx->postponed_arrays_count],len); |
2913 | break; |
2914 | case COLLECTION_REPLY_SET: |
2915 | setDeferredSetLen(c,ctx->postponed_arrays[ctx->postponed_arrays_count],len); |
2916 | break; |
2917 | case COLLECTION_REPLY_ATTRIBUTE: |
2918 | setDeferredAttributeLen(c,ctx->postponed_arrays[ctx->postponed_arrays_count],len); |
2919 | break; |
2920 | default: |
2921 | serverPanic("Invalid module reply type %d" , type); |
2922 | } |
2923 | if (ctx->postponed_arrays_count == 0) { |
2924 | zfree(ctx->postponed_arrays); |
2925 | ctx->postponed_arrays = NULL; |
2926 | } |
2927 | } |
2928 | |
2929 | /* When RedisModule_ReplyWithArray() is used with the argument |
2930 | * REDISMODULE_POSTPONED_LEN, because we don't know beforehand the number |
2931 | * of items we are going to output as elements of the array, this function |
2932 | * will take care to set the array length. |
2933 | * |
2934 | * Since it is possible to have multiple array replies pending with unknown |
2935 | * length, this function guarantees to always set the latest array length |
2936 | * that was created in a postponed way. |
2937 | * |
2938 | * For example in order to output an array like [1,[10,20,30]] we |
2939 | * could write: |
2940 | * |
2941 | * RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN); |
2942 | * RedisModule_ReplyWithLongLong(ctx,1); |
2943 | * RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN); |
2944 | * RedisModule_ReplyWithLongLong(ctx,10); |
2945 | * RedisModule_ReplyWithLongLong(ctx,20); |
2946 | * RedisModule_ReplyWithLongLong(ctx,30); |
2947 | * RedisModule_ReplySetArrayLength(ctx,3); // Set len of 10,20,30 array. |
2948 | * RedisModule_ReplySetArrayLength(ctx,2); // Set len of top array |
2949 | * |
2950 | * Note that in the above example there is no reason to postpone the array |
2951 | * length, since we produce a fixed number of elements, but in the practice |
2952 | * the code may use an iterator or other ways of creating the output so |
2953 | * that is not easy to calculate in advance the number of elements. |
2954 | */ |
2955 | void RM_ReplySetArrayLength(RedisModuleCtx *ctx, long len) { |
2956 | moduleReplySetCollectionLength(ctx, len, COLLECTION_REPLY_ARRAY); |
2957 | } |
2958 | |
2959 | /* Very similar to RedisModule_ReplySetArrayLength except `len` should |
2960 | * exactly half of the number of `ReplyWith*` functions called in the |
2961 | * context of the map. |
2962 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. */ |
2963 | void RM_ReplySetMapLength(RedisModuleCtx *ctx, long len) { |
2964 | moduleReplySetCollectionLength(ctx, len, COLLECTION_REPLY_MAP); |
2965 | } |
2966 | |
2967 | /* Very similar to RedisModule_ReplySetArrayLength |
2968 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. */ |
2969 | void RM_ReplySetSetLength(RedisModuleCtx *ctx, long len) { |
2970 | moduleReplySetCollectionLength(ctx, len, COLLECTION_REPLY_SET); |
2971 | } |
2972 | |
2973 | /* Very similar to RedisModule_ReplySetMapLength |
2974 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
2975 | * |
2976 | * Must not be called if RM_ReplyWithAttribute returned an error. */ |
2977 | void RM_ReplySetAttributeLength(RedisModuleCtx *ctx, long len) { |
2978 | if (ctx->client->resp == 2) return; |
2979 | moduleReplySetCollectionLength(ctx, len, COLLECTION_REPLY_ATTRIBUTE); |
2980 | } |
2981 | |
2982 | /* Reply with a bulk string, taking in input a C buffer pointer and length. |
2983 | * |
2984 | * The function always returns REDISMODULE_OK. */ |
2985 | int RM_ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len) { |
2986 | client *c = moduleGetReplyClient(ctx); |
2987 | if (c == NULL) return REDISMODULE_OK; |
2988 | addReplyBulkCBuffer(c,(char*)buf,len); |
2989 | return REDISMODULE_OK; |
2990 | } |
2991 | |
2992 | /* Reply with a bulk string, taking in input a C buffer pointer that is |
2993 | * assumed to be null-terminated. |
2994 | * |
2995 | * The function always returns REDISMODULE_OK. */ |
2996 | int RM_ReplyWithCString(RedisModuleCtx *ctx, const char *buf) { |
2997 | client *c = moduleGetReplyClient(ctx); |
2998 | if (c == NULL) return REDISMODULE_OK; |
2999 | addReplyBulkCString(c,(char*)buf); |
3000 | return REDISMODULE_OK; |
3001 | } |
3002 | |
3003 | /* Reply with a bulk string, taking in input a RedisModuleString object. |
3004 | * |
3005 | * The function always returns REDISMODULE_OK. */ |
3006 | int RM_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str) { |
3007 | client *c = moduleGetReplyClient(ctx); |
3008 | if (c == NULL) return REDISMODULE_OK; |
3009 | addReplyBulk(c,str); |
3010 | return REDISMODULE_OK; |
3011 | } |
3012 | |
3013 | /* Reply with an empty string. |
3014 | * |
3015 | * The function always returns REDISMODULE_OK. */ |
3016 | int RM_ReplyWithEmptyString(RedisModuleCtx *ctx) { |
3017 | client *c = moduleGetReplyClient(ctx); |
3018 | if (c == NULL) return REDISMODULE_OK; |
3019 | addReply(c,shared.emptybulk); |
3020 | return REDISMODULE_OK; |
3021 | } |
3022 | |
3023 | /* Reply with a binary safe string, which should not be escaped or filtered |
3024 | * taking in input a C buffer pointer, length and a 3 character type/extension. |
3025 | * |
3026 | * The function always returns REDISMODULE_OK. */ |
3027 | int RM_ReplyWithVerbatimStringType(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext) { |
3028 | client *c = moduleGetReplyClient(ctx); |
3029 | if (c == NULL) return REDISMODULE_OK; |
3030 | addReplyVerbatim(c, buf, len, ext); |
3031 | return REDISMODULE_OK; |
3032 | } |
3033 | |
3034 | /* Reply with a binary safe string, which should not be escaped or filtered |
3035 | * taking in input a C buffer pointer and length. |
3036 | * |
3037 | * The function always returns REDISMODULE_OK. */ |
3038 | int RM_ReplyWithVerbatimString(RedisModuleCtx *ctx, const char *buf, size_t len) { |
3039 | return RM_ReplyWithVerbatimStringType(ctx, buf, len, "txt" ); |
3040 | } |
3041 | |
3042 | /* Reply to the client with a NULL. |
3043 | * |
3044 | * The function always returns REDISMODULE_OK. */ |
3045 | int RM_ReplyWithNull(RedisModuleCtx *ctx) { |
3046 | client *c = moduleGetReplyClient(ctx); |
3047 | if (c == NULL) return REDISMODULE_OK; |
3048 | addReplyNull(c); |
3049 | return REDISMODULE_OK; |
3050 | } |
3051 | |
3052 | /* Reply with a RESP3 Boolean type. |
3053 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
3054 | * |
3055 | * In RESP3, this is boolean type |
3056 | * In RESP2, it's a string response of "1" and "0" for true and false respectively. |
3057 | * |
3058 | * The function always returns REDISMODULE_OK. */ |
3059 | int RM_ReplyWithBool(RedisModuleCtx *ctx, int b) { |
3060 | client *c = moduleGetReplyClient(ctx); |
3061 | if (c == NULL) return REDISMODULE_OK; |
3062 | addReplyBool(c,b); |
3063 | return REDISMODULE_OK; |
3064 | } |
3065 | |
3066 | /* Reply exactly what a Redis command returned us with RedisModule_Call(). |
3067 | * This function is useful when we use RedisModule_Call() in order to |
3068 | * execute some command, as we want to reply to the client exactly the |
3069 | * same reply we obtained by the command. |
3070 | * |
3071 | * Return: |
3072 | * - REDISMODULE_OK on success. |
3073 | * - REDISMODULE_ERR if the given reply is in RESP3 format but the client expects RESP2. |
3074 | * In case of an error, it's the module writer responsibility to translate the reply |
3075 | * to RESP2 (or handle it differently by returning an error). Notice that for |
3076 | * module writer convenience, it is possible to pass `0` as a parameter to the fmt |
3077 | * argument of `RM_Call` so that the RedisModuleCallReply will return in the same |
3078 | * protocol (RESP2 or RESP3) as set in the current client's context. */ |
3079 | int RM_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply) { |
3080 | client *c = moduleGetReplyClient(ctx); |
3081 | if (c == NULL) return REDISMODULE_OK; |
3082 | if (c->resp == 2 && callReplyIsResp3(reply)) { |
3083 | /* The reply is in RESP3 format and the client is RESP2, |
3084 | * so it isn't possible to send this reply to the client. */ |
3085 | return REDISMODULE_ERR; |
3086 | } |
3087 | size_t proto_len; |
3088 | const char *proto = callReplyGetProto(reply, &proto_len); |
3089 | addReplyProto(c, proto, proto_len); |
3090 | /* Propagate the error list from that reply to the other client, to do some |
3091 | * post error reply handling, like statistics. |
3092 | * Note that if the original reply had an array with errors, and the module |
3093 | * replied with just a portion of the original reply, and not the entire |
3094 | * reply, the errors are currently not propagated and the errors stats |
3095 | * will not get propagated. */ |
3096 | list *errors = callReplyDeferredErrorList(reply); |
3097 | if (errors) |
3098 | deferredAfterErrorReply(c, errors); |
3099 | return REDISMODULE_OK; |
3100 | } |
3101 | |
3102 | /* Reply with a RESP3 Double type. |
3103 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
3104 | * |
3105 | * Send a string reply obtained converting the double 'd' into a bulk string. |
3106 | * This function is basically equivalent to converting a double into |
3107 | * a string into a C buffer, and then calling the function |
3108 | * RedisModule_ReplyWithStringBuffer() with the buffer and length. |
3109 | * |
3110 | * In RESP3 the string is tagged as a double, while in RESP2 it's just a plain string |
3111 | * that the user will have to parse. |
3112 | * |
3113 | * The function always returns REDISMODULE_OK. */ |
3114 | int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) { |
3115 | client *c = moduleGetReplyClient(ctx); |
3116 | if (c == NULL) return REDISMODULE_OK; |
3117 | addReplyDouble(c,d); |
3118 | return REDISMODULE_OK; |
3119 | } |
3120 | |
3121 | /* Reply with a RESP3 BigNumber type. |
3122 | * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. |
3123 | * |
3124 | * In RESP3, this is a string of length `len` that is tagged as a BigNumber, |
3125 | * however, it's up to the caller to ensure that it's a valid BigNumber. |
3126 | * In RESP2, this is just a plain bulk string response. |
3127 | * |
3128 | * The function always returns REDISMODULE_OK. */ |
3129 | int RM_ReplyWithBigNumber(RedisModuleCtx *ctx, const char *bignum, size_t len) { |
3130 | client *c = moduleGetReplyClient(ctx); |
3131 | if (c == NULL) return REDISMODULE_OK; |
3132 | addReplyBigNum(c, bignum, len); |
3133 | return REDISMODULE_OK; |
3134 | } |
3135 | |
3136 | /* Send a string reply obtained converting the long double 'ld' into a bulk |
3137 | * string. This function is basically equivalent to converting a long double |
3138 | * into a string into a C buffer, and then calling the function |
3139 | * RedisModule_ReplyWithStringBuffer() with the buffer and length. |
3140 | * The double string uses human readable formatting (see |
3141 | * `addReplyHumanLongDouble` in networking.c). |
3142 | * |
3143 | * The function always returns REDISMODULE_OK. */ |
3144 | int RM_ReplyWithLongDouble(RedisModuleCtx *ctx, long double ld) { |
3145 | client *c = moduleGetReplyClient(ctx); |
3146 | if (c == NULL) return REDISMODULE_OK; |
3147 | addReplyHumanLongDouble(c, ld); |
3148 | return REDISMODULE_OK; |
3149 | } |
3150 | |
3151 | /* -------------------------------------------------------------------------- |
3152 | * ## Commands replication API |
3153 | * -------------------------------------------------------------------------- */ |
3154 | |
3155 | /* Replicate the specified command and arguments to slaves and AOF, as effect |
3156 | * of execution of the calling command implementation. |
3157 | * |
3158 | * The replicated commands are always wrapped into the MULTI/EXEC that |
3159 | * contains all the commands replicated in a given module command |
3160 | * execution. However the commands replicated with RedisModule_Call() |
3161 | * are the first items, the ones replicated with RedisModule_Replicate() |
3162 | * will all follow before the EXEC. |
3163 | * |
3164 | * Modules should try to use one interface or the other. |
3165 | * |
3166 | * This command follows exactly the same interface of RedisModule_Call(), |
3167 | * so a set of format specifiers must be passed, followed by arguments |
3168 | * matching the provided format specifiers. |
3169 | * |
3170 | * Please refer to RedisModule_Call() for more information. |
3171 | * |
3172 | * Using the special "A" and "R" modifiers, the caller can exclude either |
3173 | * the AOF or the replicas from the propagation of the specified command. |
3174 | * Otherwise, by default, the command will be propagated in both channels. |
3175 | * |
3176 | * #### Note about calling this function from a thread safe context: |
3177 | * |
3178 | * Normally when you call this function from the callback implementing a |
3179 | * module command, or any other callback provided by the Redis Module API, |
3180 | * Redis will accumulate all the calls to this function in the context of |
3181 | * the callback, and will propagate all the commands wrapped in a MULTI/EXEC |
3182 | * transaction. However when calling this function from a threaded safe context |
3183 | * that can live an undefined amount of time, and can be locked/unlocked in |
3184 | * at will, the behavior is different: MULTI/EXEC wrapper is not emitted |
3185 | * and the command specified is inserted in the AOF and replication stream |
3186 | * immediately. |
3187 | * |
3188 | * #### Return value |
3189 | * |
3190 | * The command returns REDISMODULE_ERR if the format specifiers are invalid |
3191 | * or the command name does not belong to a known command. */ |
3192 | int RM_Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) { |
3193 | struct redisCommand *cmd; |
3194 | robj **argv = NULL; |
3195 | int argc = 0, flags = 0, j; |
3196 | va_list ap; |
3197 | |
3198 | cmd = lookupCommandByCString((char*)cmdname); |
3199 | if (!cmd) return REDISMODULE_ERR; |
3200 | |
3201 | /* Create the client and dispatch the command. */ |
3202 | va_start(ap, fmt); |
3203 | argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,NULL,&flags,ap); |
3204 | va_end(ap); |
3205 | if (argv == NULL) return REDISMODULE_ERR; |
3206 | |
3207 | /* Select the propagation target. Usually is AOF + replicas, however |
3208 | * the caller can exclude one or the other using the "A" or "R" |
3209 | * modifiers. */ |
3210 | int target = 0; |
3211 | if (!(flags & REDISMODULE_ARGV_NO_AOF)) target |= PROPAGATE_AOF; |
3212 | if (!(flags & REDISMODULE_ARGV_NO_REPLICAS)) target |= PROPAGATE_REPL; |
3213 | |
3214 | alsoPropagate(ctx->client->db->id,argv,argc,target); |
3215 | |
3216 | /* Release the argv. */ |
3217 | for (j = 0; j < argc; j++) decrRefCount(argv[j]); |
3218 | zfree(argv); |
3219 | server.dirty++; |
3220 | return REDISMODULE_OK; |
3221 | } |
3222 | |
3223 | /* This function will replicate the command exactly as it was invoked |
3224 | * by the client. Note that this function will not wrap the command into |
3225 | * a MULTI/EXEC stanza, so it should not be mixed with other replication |
3226 | * commands. |
3227 | * |
3228 | * Basically this form of replication is useful when you want to propagate |
3229 | * the command to the slaves and AOF file exactly as it was called, since |
3230 | * the command can just be re-executed to deterministically re-create the |
3231 | * new state starting from the old one. |
3232 | * |
3233 | * The function always returns REDISMODULE_OK. */ |
3234 | int RM_ReplicateVerbatim(RedisModuleCtx *ctx) { |
3235 | alsoPropagate(ctx->client->db->id, |
3236 | ctx->client->argv,ctx->client->argc, |
3237 | PROPAGATE_AOF|PROPAGATE_REPL); |
3238 | server.dirty++; |
3239 | return REDISMODULE_OK; |
3240 | } |
3241 | |
3242 | /* -------------------------------------------------------------------------- |
3243 | * ## DB and Key APIs -- Generic API |
3244 | * -------------------------------------------------------------------------- */ |
3245 | |
3246 | /* Return the ID of the current client calling the currently active module |
3247 | * command. The returned ID has a few guarantees: |
3248 | * |
3249 | * 1. The ID is different for each different client, so if the same client |
3250 | * executes a module command multiple times, it can be recognized as |
3251 | * having the same ID, otherwise the ID will be different. |
3252 | * 2. The ID increases monotonically. Clients connecting to the server later |
3253 | * are guaranteed to get IDs greater than any past ID previously seen. |
3254 | * |
3255 | * Valid IDs are from 1 to 2^64 - 1. If 0 is returned it means there is no way |
3256 | * to fetch the ID in the context the function was currently called. |
3257 | * |
3258 | * After obtaining the ID, it is possible to check if the command execution |
3259 | * is actually happening in the context of AOF loading, using this macro: |
3260 | * |
3261 | * if (RedisModule_IsAOFClient(RedisModule_GetClientId(ctx)) { |
3262 | * // Handle it differently. |
3263 | * } |
3264 | */ |
3265 | unsigned long long RM_GetClientId(RedisModuleCtx *ctx) { |
3266 | if (ctx->client == NULL) return 0; |
3267 | return ctx->client->id; |
3268 | } |
3269 | |
3270 | /* Return the ACL user name used by the client with the specified client ID. |
3271 | * Client ID can be obtained with RM_GetClientId() API. If the client does not |
3272 | * exist, NULL is returned and errno is set to ENOENT. If the client isn't |
3273 | * using an ACL user, NULL is returned and errno is set to ENOTSUP */ |
3274 | RedisModuleString *RM_GetClientUserNameById(RedisModuleCtx *ctx, uint64_t id) { |
3275 | client *client = lookupClientByID(id); |
3276 | if (client == NULL) { |
3277 | errno = ENOENT; |
3278 | return NULL; |
3279 | } |
3280 | |
3281 | if (client->user == NULL) { |
3282 | errno = ENOTSUP; |
3283 | return NULL; |
3284 | } |
3285 | |
3286 | sds name = sdsnew(client->user->name); |
3287 | robj *str = createObject(OBJ_STRING, name); |
3288 | autoMemoryAdd(ctx, REDISMODULE_AM_STRING, str); |
3289 | return str; |
3290 | } |
3291 | |
3292 | /* This is a helper for RM_GetClientInfoById() and other functions: given |
3293 | * a client, it populates the client info structure with the appropriate |
3294 | * fields depending on the version provided. If the version is not valid |
3295 | * then REDISMODULE_ERR is returned. Otherwise the function returns |
3296 | * REDISMODULE_OK and the structure pointed by 'ci' gets populated. */ |
3297 | |
3298 | int modulePopulateClientInfoStructure(void *ci, client *client, int structver) { |
3299 | if (structver != 1) return REDISMODULE_ERR; |
3300 | |
3301 | RedisModuleClientInfoV1 *ci1 = ci; |
3302 | memset(ci1,0,sizeof(*ci1)); |
3303 | ci1->version = structver; |
3304 | if (client->flags & CLIENT_MULTI) |
3305 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_MULTI; |
3306 | if (client->flags & CLIENT_PUBSUB) |
3307 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_PUBSUB; |
3308 | if (client->flags & CLIENT_UNIX_SOCKET) |
3309 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_UNIXSOCKET; |
3310 | if (client->flags & CLIENT_TRACKING) |
3311 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_TRACKING; |
3312 | if (client->flags & CLIENT_BLOCKED) |
3313 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_BLOCKED; |
3314 | if (connGetType(client->conn) == CONN_TYPE_TLS) |
3315 | ci1->flags |= REDISMODULE_CLIENTINFO_FLAG_SSL; |
3316 | |
3317 | int port; |
3318 | connPeerToString(client->conn,ci1->addr,sizeof(ci1->addr),&port); |
3319 | ci1->port = port; |
3320 | ci1->db = client->db->id; |
3321 | ci1->id = client->id; |
3322 | return REDISMODULE_OK; |
3323 | } |
3324 | |
3325 | /* This is a helper for moduleFireServerEvent() and other functions: |
3326 | * It populates the replication info structure with the appropriate |
3327 | * fields depending on the version provided. If the version is not valid |
3328 | * then REDISMODULE_ERR is returned. Otherwise the function returns |
3329 | * REDISMODULE_OK and the structure pointed by 'ri' gets populated. */ |
3330 | int modulePopulateReplicationInfoStructure(void *ri, int structver) { |
3331 | if (structver != 1) return REDISMODULE_ERR; |
3332 | |
3333 | RedisModuleReplicationInfoV1 *ri1 = ri; |
3334 | memset(ri1,0,sizeof(*ri1)); |
3335 | ri1->version = structver; |
3336 | ri1->master = server.masterhost==NULL; |
3337 | ri1->masterhost = server.masterhost? server.masterhost: "" ; |
3338 | ri1->masterport = server.masterport; |
3339 | ri1->replid1 = server.replid; |
3340 | ri1->replid2 = server.replid2; |
3341 | ri1->repl1_offset = server.master_repl_offset; |
3342 | ri1->repl2_offset = server.second_replid_offset; |
3343 | return REDISMODULE_OK; |
3344 | } |
3345 | |
3346 | /* Return information about the client with the specified ID (that was |
3347 | * previously obtained via the RedisModule_GetClientId() API). If the |
3348 | * client exists, REDISMODULE_OK is returned, otherwise REDISMODULE_ERR |
3349 | * is returned. |
3350 | * |
3351 | * When the client exist and the `ci` pointer is not NULL, but points to |
3352 | * a structure of type RedisModuleClientInfoV1, previously initialized with |
3353 | * the correct REDISMODULE_CLIENTINFO_INITIALIZER_V1, the structure is populated |
3354 | * with the following fields: |
3355 | * |
3356 | * uint64_t flags; // REDISMODULE_CLIENTINFO_FLAG_* |
3357 | * uint64_t id; // Client ID |
3358 | * char addr[46]; // IPv4 or IPv6 address. |
3359 | * uint16_t port; // TCP port. |
3360 | * uint16_t db; // Selected DB. |
3361 | * |
3362 | * Note: the client ID is useless in the context of this call, since we |
3363 | * already know, however the same structure could be used in other |
3364 | * contexts where we don't know the client ID, yet the same structure |
3365 | * is returned. |
3366 | * |
3367 | * With flags having the following meaning: |
3368 | * |
3369 | * REDISMODULE_CLIENTINFO_FLAG_SSL Client using SSL connection. |
3370 | * REDISMODULE_CLIENTINFO_FLAG_PUBSUB Client in Pub/Sub mode. |
3371 | * REDISMODULE_CLIENTINFO_FLAG_BLOCKED Client blocked in command. |
3372 | * REDISMODULE_CLIENTINFO_FLAG_TRACKING Client with keys tracking on. |
3373 | * REDISMODULE_CLIENTINFO_FLAG_UNIXSOCKET Client using unix domain socket. |
3374 | * REDISMODULE_CLIENTINFO_FLAG_MULTI Client in MULTI state. |
3375 | * |
3376 | * However passing NULL is a way to just check if the client exists in case |
3377 | * we are not interested in any additional information. |
3378 | * |
3379 | * This is the correct usage when we want the client info structure |
3380 | * returned: |
3381 | * |
3382 | * RedisModuleClientInfo ci = REDISMODULE_CLIENTINFO_INITIALIZER; |
3383 | * int retval = RedisModule_GetClientInfoById(&ci,client_id); |
3384 | * if (retval == REDISMODULE_OK) { |
3385 | * printf("Address: %s\n", ci.addr); |
3386 | * } |
3387 | */ |
3388 | int RM_GetClientInfoById(void *ci, uint64_t id) { |
3389 | client *client = lookupClientByID(id); |
3390 | if (client == NULL) return REDISMODULE_ERR; |
3391 | if (ci == NULL) return REDISMODULE_OK; |
3392 | |
3393 | /* Fill the info structure if passed. */ |
3394 | uint64_t structver = ((uint64_t*)ci)[0]; |
3395 | return modulePopulateClientInfoStructure(ci,client,structver); |
3396 | } |
3397 | |
3398 | /* Returns the name of the client connection with the given ID. |
3399 | * |
3400 | * If the client ID does not exist or if the client has no name associated with |
3401 | * it, NULL is returned. */ |
3402 | RedisModuleString *RM_GetClientNameById(RedisModuleCtx *ctx, uint64_t id) { |
3403 | client *client = lookupClientByID(id); |
3404 | if (client == NULL || client->name == NULL) return NULL; |
3405 | robj *name = client->name; |
3406 | incrRefCount(name); |
3407 | autoMemoryAdd(ctx, REDISMODULE_AM_STRING, name); |
3408 | return name; |
3409 | } |
3410 | |
3411 | /* Sets the name of the client with the given ID. This is equivalent to the client calling |
3412 | * `CLIENT SETNAME name`. |
3413 | * |
3414 | * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned |
3415 | * and errno is set as follows: |
3416 | * |
3417 | * - ENOENT if the client does not exist |
3418 | * - EINVAL if the name contains invalid characters */ |
3419 | int RM_SetClientNameById(uint64_t id, RedisModuleString *name) { |
3420 | client *client = lookupClientByID(id); |
3421 | if (client == NULL) { |
3422 | errno = ENOENT; |
3423 | return REDISMODULE_ERR; |
3424 | } |
3425 | if (clientSetName(client, name) == C_ERR) { |
3426 | errno = EINVAL; |
3427 | return REDISMODULE_ERR; |
3428 | } |
3429 | return REDISMODULE_OK; |
3430 | } |
3431 | |
3432 | /* Publish a message to subscribers (see PUBLISH command). */ |
3433 | int RM_PublishMessage(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) { |
3434 | UNUSED(ctx); |
3435 | return pubsubPublishMessageAndPropagateToCluster(channel, message, 0); |
3436 | } |
3437 | |
3438 | /* Publish a message to shard-subscribers (see SPUBLISH command). */ |
3439 | int RM_PublishMessageShard(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) { |
3440 | UNUSED(ctx); |
3441 | return pubsubPublishMessageAndPropagateToCluster(channel, message, 1); |
3442 | } |
3443 | |
3444 | /* Return the currently selected DB. */ |
3445 | int RM_GetSelectedDb(RedisModuleCtx *ctx) { |
3446 | return ctx->client->db->id; |
3447 | } |
3448 | |
3449 | |
3450 | /* Return the current context's flags. The flags provide information on the |
3451 | * current request context (whether the client is a Lua script or in a MULTI), |
3452 | * and about the Redis instance in general, i.e replication and persistence. |
3453 | * |
3454 | * It is possible to call this function even with a NULL context, however |
3455 | * in this case the following flags will not be reported: |
3456 | * |
3457 | * * LUA, MULTI, REPLICATED, DIRTY (see below for more info). |
3458 | * |
3459 | * Available flags and their meaning: |
3460 | * |
3461 | * * REDISMODULE_CTX_FLAGS_LUA: The command is running in a Lua script |
3462 | * |
3463 | * * REDISMODULE_CTX_FLAGS_MULTI: The command is running inside a transaction |
3464 | * |
3465 | * * REDISMODULE_CTX_FLAGS_REPLICATED: The command was sent over the replication |
3466 | * link by the MASTER |
3467 | * |
3468 | * * REDISMODULE_CTX_FLAGS_MASTER: The Redis instance is a master |
3469 | * |
3470 | * * REDISMODULE_CTX_FLAGS_SLAVE: The Redis instance is a slave |
3471 | * |
3472 | * * REDISMODULE_CTX_FLAGS_READONLY: The Redis instance is read-only |
3473 | * |
3474 | * * REDISMODULE_CTX_FLAGS_CLUSTER: The Redis instance is in cluster mode |
3475 | * |
3476 | * * REDISMODULE_CTX_FLAGS_AOF: The Redis instance has AOF enabled |
3477 | * |
3478 | * * REDISMODULE_CTX_FLAGS_RDB: The instance has RDB enabled |
3479 | * |
3480 | * * REDISMODULE_CTX_FLAGS_MAXMEMORY: The instance has Maxmemory set |
3481 | * |
3482 | * * REDISMODULE_CTX_FLAGS_EVICT: Maxmemory is set and has an eviction |
3483 | * policy that may delete keys |
3484 | * |
3485 | * * REDISMODULE_CTX_FLAGS_OOM: Redis is out of memory according to the |
3486 | * maxmemory setting. |
3487 | * |
3488 | * * REDISMODULE_CTX_FLAGS_OOM_WARNING: Less than 25% of memory remains before |
3489 | * reaching the maxmemory level. |
3490 | * |
3491 | * * REDISMODULE_CTX_FLAGS_LOADING: Server is loading RDB/AOF |
3492 | * |
3493 | * * REDISMODULE_CTX_FLAGS_REPLICA_IS_STALE: No active link with the master. |
3494 | * |
3495 | * * REDISMODULE_CTX_FLAGS_REPLICA_IS_CONNECTING: The replica is trying to |
3496 | * connect with the master. |
3497 | * |
3498 | * * REDISMODULE_CTX_FLAGS_REPLICA_IS_TRANSFERRING: Master -> Replica RDB |
3499 | * transfer is in progress. |
3500 | * |
3501 | * * REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE: The replica has an active link |
3502 | * with its master. This is the |
3503 | * contrary of STALE state. |
3504 | * |
3505 | * * REDISMODULE_CTX_FLAGS_ACTIVE_CHILD: There is currently some background |
3506 | * process active (RDB, AUX or module). |
3507 | * |
3508 | * * REDISMODULE_CTX_FLAGS_MULTI_DIRTY: The next EXEC will fail due to dirty |
3509 | * CAS (touched keys). |
3510 | * |
3511 | * * REDISMODULE_CTX_FLAGS_IS_CHILD: Redis is currently running inside |
3512 | * background child process. |
3513 | * |
3514 | * * REDISMODULE_CTX_FLAGS_RESP3: Indicate the that client attached to this |
3515 | * context is using RESP3. |
3516 | */ |
3517 | int RM_GetContextFlags(RedisModuleCtx *ctx) { |
3518 | int flags = 0; |
3519 | |
3520 | /* Client specific flags */ |
3521 | if (ctx) { |
3522 | if (ctx->client) { |
3523 | if (ctx->client->flags & CLIENT_DENY_BLOCKING) |
3524 | flags |= REDISMODULE_CTX_FLAGS_DENY_BLOCKING; |
3525 | /* Module command received from MASTER, is replicated. */ |
3526 | if (ctx->client->flags & CLIENT_MASTER) |
3527 | flags |= REDISMODULE_CTX_FLAGS_REPLICATED; |
3528 | if (ctx->client->resp == 3) { |
3529 | flags |= REDISMODULE_CTX_FLAGS_RESP3; |
3530 | } |
3531 | } |
3532 | |
3533 | /* For DIRTY flags, we need the blocked client if used */ |
3534 | client *c = ctx->blocked_client ? ctx->blocked_client->client : ctx->client; |
3535 | if (c && (c->flags & (CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC))) { |
3536 | flags |= REDISMODULE_CTX_FLAGS_MULTI_DIRTY; |
3537 | } |
3538 | } |
3539 | |
3540 | if (scriptIsRunning()) |
3541 | flags |= REDISMODULE_CTX_FLAGS_LUA; |
3542 | |
3543 | if (server.in_exec) |
3544 | flags |= REDISMODULE_CTX_FLAGS_MULTI; |
3545 | |
3546 | if (server.cluster_enabled) |
3547 | flags |= REDISMODULE_CTX_FLAGS_CLUSTER; |
3548 | |
3549 | if (server.async_loading) |
3550 | flags |= REDISMODULE_CTX_FLAGS_ASYNC_LOADING; |
3551 | else if (server.loading) |
3552 | flags |= REDISMODULE_CTX_FLAGS_LOADING; |
3553 | |
3554 | /* Maxmemory and eviction policy */ |
3555 | if (server.maxmemory > 0 && (!server.masterhost || !server.repl_slave_ignore_maxmemory)) { |
3556 | flags |= REDISMODULE_CTX_FLAGS_MAXMEMORY; |
3557 | |
3558 | if (server.maxmemory_policy != MAXMEMORY_NO_EVICTION) |
3559 | flags |= REDISMODULE_CTX_FLAGS_EVICT; |
3560 | } |
3561 | |
3562 | /* Persistence flags */ |
3563 | if (server.aof_state != AOF_OFF) |
3564 | flags |= REDISMODULE_CTX_FLAGS_AOF; |
3565 | if (server.saveparamslen > 0) |
3566 | flags |= REDISMODULE_CTX_FLAGS_RDB; |
3567 | |
3568 | /* Replication flags */ |
3569 | if (server.masterhost == NULL) { |
3570 | flags |= REDISMODULE_CTX_FLAGS_MASTER; |
3571 | } else { |
3572 | flags |= REDISMODULE_CTX_FLAGS_SLAVE; |
3573 | if (server.repl_slave_ro) |
3574 | flags |= REDISMODULE_CTX_FLAGS_READONLY; |
3575 | |
3576 | /* Replica state flags. */ |
3577 | if (server.repl_state == REPL_STATE_CONNECT || |
3578 | server.repl_state == REPL_STATE_CONNECTING) |
3579 | { |
3580 | flags |= REDISMODULE_CTX_FLAGS_REPLICA_IS_CONNECTING; |
3581 | } else if (server.repl_state == REPL_STATE_TRANSFER) { |
3582 | flags |= REDISMODULE_CTX_FLAGS_REPLICA_IS_TRANSFERRING; |
3583 | } else if (server.repl_state == REPL_STATE_CONNECTED) { |
3584 | flags |= REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE; |
3585 | } |
3586 | |
3587 | if (server.repl_state != REPL_STATE_CONNECTED) |
3588 | flags |= REDISMODULE_CTX_FLAGS_REPLICA_IS_STALE; |
3589 | } |
3590 | |
3591 | /* OOM flag. */ |
3592 | float level; |
3593 | int retval = getMaxmemoryState(NULL,NULL,NULL,&level); |
3594 | if (retval == C_ERR) flags |= REDISMODULE_CTX_FLAGS_OOM; |
3595 | if (level > 0.75) flags |= REDISMODULE_CTX_FLAGS_OOM_WARNING; |
3596 | |
3597 | /* Presence of children processes. */ |
3598 | if (hasActiveChildProcess()) flags |= REDISMODULE_CTX_FLAGS_ACTIVE_CHILD; |
3599 | if (server.in_fork_child) flags |= REDISMODULE_CTX_FLAGS_IS_CHILD; |
3600 | |
3601 | return flags; |
3602 | } |
3603 | |
3604 | /* Returns true if a client sent the CLIENT PAUSE command to the server or |
3605 | * if Redis Cluster does a manual failover, pausing the clients. |
3606 | * This is needed when we have a master with replicas, and want to write, |
3607 | * without adding further data to the replication channel, that the replicas |
3608 | * replication offset, match the one of the master. When this happens, it is |
3609 | * safe to failover the master without data loss. |
3610 | * |
3611 | * However modules may generate traffic by calling RedisModule_Call() with |
3612 | * the "!" flag, or by calling RedisModule_Replicate(), in a context outside |
3613 | * commands execution, for instance in timeout callbacks, threads safe |
3614 | * contexts, and so forth. When modules will generate too much traffic, it |
3615 | * will be hard for the master and replicas offset to match, because there |
3616 | * is more data to send in the replication channel. |
3617 | * |
3618 | * So modules may want to try to avoid very heavy background work that has |
3619 | * the effect of creating data to the replication channel, when this function |
3620 | * returns true. This is mostly useful for modules that have background |
3621 | * garbage collection tasks, or that do writes and replicate such writes |
3622 | * periodically in timer callbacks or other periodic callbacks. |
3623 | */ |
3624 | int RM_AvoidReplicaTraffic() { |
3625 | return checkClientPauseTimeoutAndReturnIfPaused(); |
3626 | } |
3627 | |
3628 | /* Change the currently selected DB. Returns an error if the id |
3629 | * is out of range. |
3630 | * |
3631 | * Note that the client will retain the currently selected DB even after |
3632 | * the Redis command implemented by the module calling this function |
3633 | * returns. |
3634 | * |
3635 | * If the module command wishes to change something in a different DB and |
3636 | * returns back to the original one, it should call RedisModule_GetSelectedDb() |
3637 | * before in order to restore the old DB number before returning. */ |
3638 | int RM_SelectDb(RedisModuleCtx *ctx, int newid) { |
3639 | int retval = selectDb(ctx->client,newid); |
3640 | return (retval == C_OK) ? REDISMODULE_OK : REDISMODULE_ERR; |
3641 | } |
3642 | |
3643 | /* Check if a key exists, without affecting its last access time. |
3644 | * |
3645 | * This is equivalent to calling RM_OpenKey with the mode REDISMODULE_READ | |
3646 | * REDISMODULE_OPEN_KEY_NOTOUCH, then checking if NULL was returned and, if not, |
3647 | * calling RM_CloseKey on the opened key. |
3648 | */ |
3649 | int RM_KeyExists(RedisModuleCtx *ctx, robj *keyname) { |
3650 | robj *value = lookupKeyReadWithFlags(ctx->client->db, keyname, LOOKUP_NOTOUCH); |
3651 | return (value != NULL); |
3652 | } |
3653 | |
3654 | /* Initialize a RedisModuleKey struct */ |
3655 | static void moduleInitKey(RedisModuleKey *kp, RedisModuleCtx *ctx, robj *keyname, robj *value, int mode){ |
3656 | kp->ctx = ctx; |
3657 | kp->db = ctx->client->db; |
3658 | kp->key = keyname; |
3659 | incrRefCount(keyname); |
3660 | kp->value = value; |
3661 | kp->iter = NULL; |
3662 | kp->mode = mode; |
3663 | if (kp->value) moduleInitKeyTypeSpecific(kp); |
3664 | } |
3665 | |
3666 | /* Initialize the type-specific part of the key. Only when key has a value. */ |
3667 | static void moduleInitKeyTypeSpecific(RedisModuleKey *key) { |
3668 | switch (key->value->type) { |
3669 | case OBJ_ZSET: zsetKeyReset(key); break; |
3670 | case OBJ_STREAM: key->u.stream.signalready = 0; break; |
3671 | } |
3672 | } |
3673 | |
3674 | /* Return a handle representing a Redis key, so that it is possible |
3675 | * to call other APIs with the key handle as argument to perform |
3676 | * operations on the key. |
3677 | * |
3678 | * The return value is the handle representing the key, that must be |
3679 | * closed with RM_CloseKey(). |
3680 | * |
3681 | * If the key does not exist and WRITE mode is requested, the handle |
3682 | * is still returned, since it is possible to perform operations on |
3683 | * a yet not existing key (that will be created, for example, after |
3684 | * a list push operation). If the mode is just READ instead, and the |
3685 | * key does not exist, NULL is returned. However it is still safe to |
3686 | * call RedisModule_CloseKey() and RedisModule_KeyType() on a NULL |
3687 | * value. */ |
3688 | RedisModuleKey *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode) { |
3689 | RedisModuleKey *kp; |
3690 | robj *value; |
3691 | int flags = mode & REDISMODULE_OPEN_KEY_NOTOUCH? LOOKUP_NOTOUCH: 0; |
3692 | |
3693 | if (mode & REDISMODULE_WRITE) { |
3694 | value = lookupKeyWriteWithFlags(ctx->client->db,keyname, flags); |
3695 | } else { |
3696 | value = lookupKeyReadWithFlags(ctx->client->db,keyname, flags); |
3697 | if (value == NULL) { |
3698 | return NULL; |
3699 | } |
3700 | } |
3701 | |
3702 | /* Setup the key handle. */ |
3703 | kp = zmalloc(sizeof(*kp)); |
3704 | moduleInitKey(kp, ctx, keyname, value, mode); |
3705 | autoMemoryAdd(ctx,REDISMODULE_AM_KEY,kp); |
3706 | return kp; |
3707 | } |
3708 | |
3709 | /* Destroy a RedisModuleKey struct (freeing is the responsibility of the caller). */ |
3710 | static void moduleCloseKey(RedisModuleKey *key) { |
3711 | int signal = SHOULD_SIGNAL_MODIFIED_KEYS(key->ctx); |
3712 | if ((key->mode & REDISMODULE_WRITE) && signal) |
3713 | signalModifiedKey(key->ctx->client,key->db,key->key); |
3714 | if (key->value) { |
3715 | if (key->iter) moduleFreeKeyIterator(key); |
3716 | switch (key->value->type) { |
3717 | case OBJ_ZSET: |
3718 | RM_ZsetRangeStop(key); |
3719 | break; |
3720 | case OBJ_STREAM: |
3721 | if (key->u.stream.signalready) |
3722 | /* One or more RM_StreamAdd() have been done. */ |
3723 | signalKeyAsReady(key->db, key->key, OBJ_STREAM); |
3724 | break; |
3725 | } |
3726 | } |
3727 | serverAssert(key->iter == NULL); |
3728 | decrRefCount(key->key); |
3729 | } |
3730 | |
3731 | /* Close a key handle. */ |
3732 | void RM_CloseKey(RedisModuleKey *key) { |
3733 | if (key == NULL) return; |
3734 | moduleCloseKey(key); |
3735 | autoMemoryFreed(key->ctx,REDISMODULE_AM_KEY,key); |
3736 | zfree(key); |
3737 | } |
3738 | |
3739 | /* Return the type of the key. If the key pointer is NULL then |
3740 | * REDISMODULE_KEYTYPE_EMPTY is returned. */ |
3741 | int RM_KeyType(RedisModuleKey *key) { |
3742 | if (key == NULL || key->value == NULL) return REDISMODULE_KEYTYPE_EMPTY; |
3743 | /* We map between defines so that we are free to change the internal |
3744 | * defines as desired. */ |
3745 | switch(key->value->type) { |
3746 | case OBJ_STRING: return REDISMODULE_KEYTYPE_STRING; |
3747 | case OBJ_LIST: return REDISMODULE_KEYTYPE_LIST; |
3748 | case OBJ_SET: return REDISMODULE_KEYTYPE_SET; |
3749 | case OBJ_ZSET: return REDISMODULE_KEYTYPE_ZSET; |
3750 | case OBJ_HASH: return REDISMODULE_KEYTYPE_HASH; |
3751 | case OBJ_MODULE: return REDISMODULE_KEYTYPE_MODULE; |
3752 | case OBJ_STREAM: return REDISMODULE_KEYTYPE_STREAM; |
3753 | default: return REDISMODULE_KEYTYPE_EMPTY; |
3754 | } |
3755 | } |
3756 | |
3757 | /* Return the length of the value associated with the key. |
3758 | * For strings this is the length of the string. For all the other types |
3759 | * is the number of elements (just counting keys for hashes). |
3760 | * |
3761 | * If the key pointer is NULL or the key is empty, zero is returned. */ |
3762 | size_t RM_ValueLength(RedisModuleKey *key) { |
3763 | if (key == NULL || key->value == NULL) return 0; |
3764 | switch(key->value->type) { |
3765 | case OBJ_STRING: return stringObjectLen(key->value); |
3766 | case OBJ_LIST: return listTypeLength(key->value); |
3767 | case OBJ_SET: return setTypeSize(key->value); |
3768 | case OBJ_ZSET: return zsetLength(key->value); |
3769 | case OBJ_HASH: return hashTypeLength(key->value); |
3770 | case OBJ_STREAM: return streamLength(key->value); |
3771 | default: return 0; |
3772 | } |
3773 | } |
3774 | |
3775 | /* If the key is open for writing, remove it, and setup the key to |
3776 | * accept new writes as an empty key (that will be created on demand). |
3777 | * On success REDISMODULE_OK is returned. If the key is not open for |
3778 | * writing REDISMODULE_ERR is returned. */ |
3779 | int RM_DeleteKey(RedisModuleKey *key) { |
3780 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
3781 | if (key->value) { |
3782 | dbDelete(key->db,key->key); |
3783 | key->value = NULL; |
3784 | } |
3785 | return REDISMODULE_OK; |
3786 | } |
3787 | |
3788 | /* If the key is open for writing, unlink it (that is delete it in a |
3789 | * non-blocking way, not reclaiming memory immediately) and setup the key to |
3790 | * accept new writes as an empty key (that will be created on demand). |
3791 | * On success REDISMODULE_OK is returned. If the key is not open for |
3792 | * writing REDISMODULE_ERR is returned. */ |
3793 | int RM_UnlinkKey(RedisModuleKey *key) { |
3794 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
3795 | if (key->value) { |
3796 | dbAsyncDelete(key->db,key->key); |
3797 | key->value = NULL; |
3798 | } |
3799 | return REDISMODULE_OK; |
3800 | } |
3801 | |
3802 | /* Return the key expire value, as milliseconds of remaining TTL. |
3803 | * If no TTL is associated with the key or if the key is empty, |
3804 | * REDISMODULE_NO_EXPIRE is returned. */ |
3805 | mstime_t RM_GetExpire(RedisModuleKey *key) { |
3806 | mstime_t expire = getExpire(key->db,key->key); |
3807 | if (expire == -1 || key->value == NULL) |
3808 | return REDISMODULE_NO_EXPIRE; |
3809 | expire -= mstime(); |
3810 | return expire >= 0 ? expire : 0; |
3811 | } |
3812 | |
3813 | /* Set a new expire for the key. If the special expire |
3814 | * REDISMODULE_NO_EXPIRE is set, the expire is cancelled if there was |
3815 | * one (the same as the PERSIST command). |
3816 | * |
3817 | * Note that the expire must be provided as a positive integer representing |
3818 | * the number of milliseconds of TTL the key should have. |
3819 | * |
3820 | * The function returns REDISMODULE_OK on success or REDISMODULE_ERR if |
3821 | * the key was not open for writing or is an empty key. */ |
3822 | int RM_SetExpire(RedisModuleKey *key, mstime_t expire) { |
3823 | if (!(key->mode & REDISMODULE_WRITE) || key->value == NULL || (expire < 0 && expire != REDISMODULE_NO_EXPIRE)) |
3824 | return REDISMODULE_ERR; |
3825 | if (expire != REDISMODULE_NO_EXPIRE) { |
3826 | expire += mstime(); |
3827 | setExpire(key->ctx->client,key->db,key->key,expire); |
3828 | } else { |
3829 | removeExpire(key->db,key->key); |
3830 | } |
3831 | return REDISMODULE_OK; |
3832 | } |
3833 | |
3834 | /* Return the key expire value, as absolute Unix timestamp. |
3835 | * If no TTL is associated with the key or if the key is empty, |
3836 | * REDISMODULE_NO_EXPIRE is returned. */ |
3837 | mstime_t RM_GetAbsExpire(RedisModuleKey *key) { |
3838 | mstime_t expire = getExpire(key->db,key->key); |
3839 | if (expire == -1 || key->value == NULL) |
3840 | return REDISMODULE_NO_EXPIRE; |
3841 | return expire; |
3842 | } |
3843 | |
3844 | /* Set a new expire for the key. If the special expire |
3845 | * REDISMODULE_NO_EXPIRE is set, the expire is cancelled if there was |
3846 | * one (the same as the PERSIST command). |
3847 | * |
3848 | * Note that the expire must be provided as a positive integer representing |
3849 | * the absolute Unix timestamp the key should have. |
3850 | * |
3851 | * The function returns REDISMODULE_OK on success or REDISMODULE_ERR if |
3852 | * the key was not open for writing or is an empty key. */ |
3853 | int RM_SetAbsExpire(RedisModuleKey *key, mstime_t expire) { |
3854 | if (!(key->mode & REDISMODULE_WRITE) || key->value == NULL || (expire < 0 && expire != REDISMODULE_NO_EXPIRE)) |
3855 | return REDISMODULE_ERR; |
3856 | if (expire != REDISMODULE_NO_EXPIRE) { |
3857 | setExpire(key->ctx->client,key->db,key->key,expire); |
3858 | } else { |
3859 | removeExpire(key->db,key->key); |
3860 | } |
3861 | return REDISMODULE_OK; |
3862 | } |
3863 | |
3864 | /* Performs similar operation to FLUSHALL, and optionally start a new AOF file (if enabled) |
3865 | * If restart_aof is true, you must make sure the command that triggered this call is not |
3866 | * propagated to the AOF file. |
3867 | * When async is set to true, db contents will be freed by a background thread. */ |
3868 | void RM_ResetDataset(int restart_aof, int async) { |
3869 | if (restart_aof && server.aof_state != AOF_OFF) stopAppendOnly(); |
3870 | flushAllDataAndResetRDB(async? EMPTYDB_ASYNC: EMPTYDB_NO_FLAGS); |
3871 | if (server.aof_enabled && restart_aof) restartAOFAfterSYNC(); |
3872 | } |
3873 | |
3874 | /* Returns the number of keys in the current db. */ |
3875 | unsigned long long RM_DbSize(RedisModuleCtx *ctx) { |
3876 | return dictSize(ctx->client->db->dict); |
3877 | } |
3878 | |
3879 | /* Returns a name of a random key, or NULL if current db is empty. */ |
3880 | RedisModuleString *RM_RandomKey(RedisModuleCtx *ctx) { |
3881 | robj *key = dbRandomKey(ctx->client->db); |
3882 | autoMemoryAdd(ctx,REDISMODULE_AM_STRING,key); |
3883 | return key; |
3884 | } |
3885 | |
3886 | /* Returns the name of the key currently being processed. */ |
3887 | const RedisModuleString *RM_GetKeyNameFromOptCtx(RedisModuleKeyOptCtx *ctx) { |
3888 | return ctx->from_key; |
3889 | } |
3890 | |
3891 | /* Returns the name of the target key currently being processed. */ |
3892 | const RedisModuleString *RM_GetToKeyNameFromOptCtx(RedisModuleKeyOptCtx *ctx) { |
3893 | return ctx->to_key; |
3894 | } |
3895 | |
3896 | /* Returns the dbid currently being processed. */ |
3897 | int RM_GetDbIdFromOptCtx(RedisModuleKeyOptCtx *ctx) { |
3898 | return ctx->from_dbid; |
3899 | } |
3900 | |
3901 | /* Returns the target dbid currently being processed. */ |
3902 | int RM_GetToDbIdFromOptCtx(RedisModuleKeyOptCtx *ctx) { |
3903 | return ctx->to_dbid; |
3904 | } |
3905 | /* -------------------------------------------------------------------------- |
3906 | * ## Key API for String type |
3907 | * |
3908 | * See also RM_ValueLength(), which returns the length of a string. |
3909 | * -------------------------------------------------------------------------- */ |
3910 | |
3911 | /* If the key is open for writing, set the specified string 'str' as the |
3912 | * value of the key, deleting the old value if any. |
3913 | * On success REDISMODULE_OK is returned. If the key is not open for |
3914 | * writing or there is an active iterator, REDISMODULE_ERR is returned. */ |
3915 | int RM_StringSet(RedisModuleKey *key, RedisModuleString *str) { |
3916 | if (!(key->mode & REDISMODULE_WRITE) || key->iter) return REDISMODULE_ERR; |
3917 | RM_DeleteKey(key); |
3918 | setKey(key->ctx->client,key->db,key->key,str,SETKEY_NO_SIGNAL); |
3919 | key->value = str; |
3920 | return REDISMODULE_OK; |
3921 | } |
3922 | |
3923 | /* Prepare the key associated string value for DMA access, and returns |
3924 | * a pointer and size (by reference), that the user can use to read or |
3925 | * modify the string in-place accessing it directly via pointer. |
3926 | * |
3927 | * The 'mode' is composed by bitwise OR-ing the following flags: |
3928 | * |
3929 | * REDISMODULE_READ -- Read access |
3930 | * REDISMODULE_WRITE -- Write access |
3931 | * |
3932 | * If the DMA is not requested for writing, the pointer returned should |
3933 | * only be accessed in a read-only fashion. |
3934 | * |
3935 | * On error (wrong type) NULL is returned. |
3936 | * |
3937 | * DMA access rules: |
3938 | * |
3939 | * 1. No other key writing function should be called since the moment |
3940 | * the pointer is obtained, for all the time we want to use DMA access |
3941 | * to read or modify the string. |
3942 | * |
3943 | * 2. Each time RM_StringTruncate() is called, to continue with the DMA |
3944 | * access, RM_StringDMA() should be called again to re-obtain |
3945 | * a new pointer and length. |
3946 | * |
3947 | * 3. If the returned pointer is not NULL, but the length is zero, no |
3948 | * byte can be touched (the string is empty, or the key itself is empty) |
3949 | * so a RM_StringTruncate() call should be used if there is to enlarge |
3950 | * the string, and later call StringDMA() again to get the pointer. |
3951 | */ |
3952 | char *RM_StringDMA(RedisModuleKey *key, size_t *len, int mode) { |
3953 | /* We need to return *some* pointer for empty keys, we just return |
3954 | * a string literal pointer, that is the advantage to be mapped into |
3955 | * a read only memory page, so the module will segfault if a write |
3956 | * attempt is performed. */ |
3957 | char *emptystring = "<dma-empty-string>" ; |
3958 | if (key->value == NULL) { |
3959 | *len = 0; |
3960 | return emptystring; |
3961 | } |
3962 | |
3963 | if (key->value->type != OBJ_STRING) return NULL; |
3964 | |
3965 | /* For write access, and even for read access if the object is encoded, |
3966 | * we unshare the string (that has the side effect of decoding it). */ |
3967 | if ((mode & REDISMODULE_WRITE) || key->value->encoding != OBJ_ENCODING_RAW) |
3968 | key->value = dbUnshareStringValue(key->db, key->key, key->value); |
3969 | |
3970 | *len = sdslen(key->value->ptr); |
3971 | return key->value->ptr; |
3972 | } |
3973 | |
3974 | /* If the key is open for writing and is of string type, resize it, padding |
3975 | * with zero bytes if the new length is greater than the old one. |
3976 | * |
3977 | * After this call, RM_StringDMA() must be called again to continue |
3978 | * DMA access with the new pointer. |
3979 | * |
3980 | * The function returns REDISMODULE_OK on success, and REDISMODULE_ERR on |
3981 | * error, that is, the key is not open for writing, is not a string |
3982 | * or resizing for more than 512 MB is requested. |
3983 | * |
3984 | * If the key is empty, a string key is created with the new string value |
3985 | * unless the new length value requested is zero. */ |
3986 | int RM_StringTruncate(RedisModuleKey *key, size_t newlen) { |
3987 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
3988 | if (key->value && key->value->type != OBJ_STRING) return REDISMODULE_ERR; |
3989 | if (newlen > 512*1024*1024) return REDISMODULE_ERR; |
3990 | |
3991 | /* Empty key and new len set to 0. Just return REDISMODULE_OK without |
3992 | * doing anything. */ |
3993 | if (key->value == NULL && newlen == 0) return REDISMODULE_OK; |
3994 | |
3995 | if (key->value == NULL) { |
3996 | /* Empty key: create it with the new size. */ |
3997 | robj *o = createObject(OBJ_STRING,sdsnewlen(NULL, newlen)); |
3998 | setKey(key->ctx->client,key->db,key->key,o,SETKEY_NO_SIGNAL); |
3999 | key->value = o; |
4000 | decrRefCount(o); |
4001 | } else { |
4002 | /* Unshare and resize. */ |
4003 | key->value = dbUnshareStringValue(key->db, key->key, key->value); |
4004 | size_t curlen = sdslen(key->value->ptr); |
4005 | if (newlen > curlen) { |
4006 | key->value->ptr = sdsgrowzero(key->value->ptr,newlen); |
4007 | } else if (newlen < curlen) { |
4008 | sdssubstr(key->value->ptr,0,newlen); |
4009 | /* If the string is too wasteful, reallocate it. */ |
4010 | if (sdslen(key->value->ptr) < sdsavail(key->value->ptr)) |
4011 | key->value->ptr = sdsRemoveFreeSpace(key->value->ptr); |
4012 | } |
4013 | } |
4014 | return REDISMODULE_OK; |
4015 | } |
4016 | |
4017 | /* -------------------------------------------------------------------------- |
4018 | * ## Key API for List type |
4019 | * |
4020 | * Many of the list functions access elements by index. Since a list is in |
4021 | * essence a doubly-linked list, accessing elements by index is generally an |
4022 | * O(N) operation. However, if elements are accessed sequentially or with |
4023 | * indices close together, the functions are optimized to seek the index from |
4024 | * the previous index, rather than seeking from the ends of the list. |
4025 | * |
4026 | * This enables iteration to be done efficiently using a simple for loop: |
4027 | * |
4028 | * long n = RM_ValueLength(key); |
4029 | * for (long i = 0; i < n; i++) { |
4030 | * RedisModuleString *elem = RedisModule_ListGet(key, i); |
4031 | * // Do stuff... |
4032 | * } |
4033 | * |
4034 | * Note that after modifying a list using RM_ListPop, RM_ListSet or |
4035 | * RM_ListInsert, the internal iterator is invalidated so the next operation |
4036 | * will require a linear seek. |
4037 | * |
4038 | * Modifying a list in any another way, for example using RM_Call(), while a key |
4039 | * is open will confuse the internal iterator and may cause trouble if the key |
4040 | * is used after such modifications. The key must be reopened in this case. |
4041 | * |
4042 | * See also RM_ValueLength(), which returns the length of a list. |
4043 | * -------------------------------------------------------------------------- */ |
4044 | |
4045 | /* Seeks the key's internal list iterator to the given index. On success, 1 is |
4046 | * returned and key->iter, key->u.list.entry and key->u.list.index are set. On |
4047 | * failure, 0 is returned and errno is set as required by the list API |
4048 | * functions. */ |
4049 | int moduleListIteratorSeek(RedisModuleKey *key, long index, int mode) { |
4050 | if (!key) { |
4051 | errno = EINVAL; |
4052 | return 0; |
4053 | } else if (!key->value || key->value->type != OBJ_LIST) { |
4054 | errno = ENOTSUP; |
4055 | return 0; |
4056 | } if (!(key->mode & mode)) { |
4057 | errno = EBADF; |
4058 | return 0; |
4059 | } |
4060 | |
4061 | long length = listTypeLength(key->value); |
4062 | if (index < -length || index >= length) { |
4063 | errno = EDOM; /* Invalid index */ |
4064 | return 0; |
4065 | } |
4066 | |
4067 | if (key->iter == NULL) { |
4068 | /* No existing iterator. Create one. */ |
4069 | key->iter = listTypeInitIterator(key->value, index, LIST_TAIL); |
4070 | serverAssert(key->iter != NULL); |
4071 | serverAssert(listTypeNext(key->iter, &key->u.list.entry)); |
4072 | key->u.list.index = index; |
4073 | return 1; |
4074 | } |
4075 | |
4076 | /* There's an existing iterator. Make sure the requested index has the same |
4077 | * sign as the iterator's index. */ |
4078 | if (index < 0 && key->u.list.index >= 0) index += length; |
4079 | else if (index >= 0 && key->u.list.index < 0) index -= length; |
4080 | |
4081 | if (index == key->u.list.index) return 1; /* We're done. */ |
4082 | |
4083 | /* Seek the iterator to the requested index. */ |
4084 | unsigned char dir = key->u.list.index < index ? LIST_TAIL : LIST_HEAD; |
4085 | listTypeSetIteratorDirection(key->iter, dir); |
4086 | while (key->u.list.index != index) { |
4087 | serverAssert(listTypeNext(key->iter, &key->u.list.entry)); |
4088 | key->u.list.index += dir == LIST_HEAD ? -1 : 1; |
4089 | } |
4090 | return 1; |
4091 | } |
4092 | |
4093 | /* Push an element into a list, on head or tail depending on 'where' argument |
4094 | * (REDISMODULE_LIST_HEAD or REDISMODULE_LIST_TAIL). If the key refers to an |
4095 | * empty key opened for writing, the key is created. On success, REDISMODULE_OK |
4096 | * is returned. On failure, REDISMODULE_ERR is returned and `errno` is set as |
4097 | * follows: |
4098 | * |
4099 | * - EINVAL if key or ele is NULL. |
4100 | * - ENOTSUP if the key is of another type than list. |
4101 | * - EBADF if the key is not opened for writing. |
4102 | * |
4103 | * Note: Before Redis 7.0, `errno` was not set by this function. */ |
4104 | int RM_ListPush(RedisModuleKey *key, int where, RedisModuleString *ele) { |
4105 | if (!key || !ele) { |
4106 | errno = EINVAL; |
4107 | return REDISMODULE_ERR; |
4108 | } else if (key->value != NULL && key->value->type != OBJ_LIST) { |
4109 | errno = ENOTSUP; |
4110 | return REDISMODULE_ERR; |
4111 | } if (!(key->mode & REDISMODULE_WRITE)) { |
4112 | errno = EBADF; |
4113 | return REDISMODULE_ERR; |
4114 | } |
4115 | |
4116 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
4117 | if (key->value && key->value->type != OBJ_LIST) return REDISMODULE_ERR; |
4118 | if (key->iter) { |
4119 | listTypeReleaseIterator(key->iter); |
4120 | key->iter = NULL; |
4121 | } |
4122 | if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_LIST); |
4123 | listTypePush(key->value, ele, |
4124 | (where == REDISMODULE_LIST_HEAD) ? LIST_HEAD : LIST_TAIL); |
4125 | return REDISMODULE_OK; |
4126 | } |
4127 | |
4128 | /* Pop an element from the list, and returns it as a module string object |
4129 | * that the user should be free with RM_FreeString() or by enabling |
4130 | * automatic memory. The `where` argument specifies if the element should be |
4131 | * popped from the beginning or the end of the list (REDISMODULE_LIST_HEAD or |
4132 | * REDISMODULE_LIST_TAIL). On failure, the command returns NULL and sets |
4133 | * `errno` as follows: |
4134 | * |
4135 | * - EINVAL if key is NULL. |
4136 | * - ENOTSUP if the key is empty or of another type than list. |
4137 | * - EBADF if the key is not opened for writing. |
4138 | * |
4139 | * Note: Before Redis 7.0, `errno` was not set by this function. */ |
4140 | RedisModuleString *RM_ListPop(RedisModuleKey *key, int where) { |
4141 | if (!key) { |
4142 | errno = EINVAL; |
4143 | return NULL; |
4144 | } else if (key->value == NULL || key->value->type != OBJ_LIST) { |
4145 | errno = ENOTSUP; |
4146 | return NULL; |
4147 | } else if (!(key->mode & REDISMODULE_WRITE)) { |
4148 | errno = EBADF; |
4149 | return NULL; |
4150 | } |
4151 | if (key->iter) { |
4152 | listTypeReleaseIterator(key->iter); |
4153 | key->iter = NULL; |
4154 | } |
4155 | robj *ele = listTypePop(key->value, |
4156 | (where == REDISMODULE_LIST_HEAD) ? LIST_HEAD : LIST_TAIL); |
4157 | robj *decoded = getDecodedObject(ele); |
4158 | decrRefCount(ele); |
4159 | moduleDelKeyIfEmpty(key); |
4160 | autoMemoryAdd(key->ctx,REDISMODULE_AM_STRING,decoded); |
4161 | return decoded; |
4162 | } |
4163 | |
4164 | /* Returns the element at index `index` in the list stored at `key`, like the |
4165 | * LINDEX command. The element should be free'd using RM_FreeString() or using |
4166 | * automatic memory management. |
4167 | * |
4168 | * The index is zero-based, so 0 means the first element, 1 the second element |
4169 | * and so on. Negative indices can be used to designate elements starting at the |
4170 | * tail of the list. Here, -1 means the last element, -2 means the penultimate |
4171 | * and so forth. |
4172 | * |
4173 | * When no value is found at the given key and index, NULL is returned and |
4174 | * `errno` is set as follows: |
4175 | * |
4176 | * - EINVAL if key is NULL. |
4177 | * - ENOTSUP if the key is not a list. |
4178 | * - EBADF if the key is not opened for reading. |
4179 | * - EDOM if the index is not a valid index in the list. |
4180 | */ |
4181 | RedisModuleString *RM_ListGet(RedisModuleKey *key, long index) { |
4182 | if (moduleListIteratorSeek(key, index, REDISMODULE_READ)) { |
4183 | robj *elem = listTypeGet(&key->u.list.entry); |
4184 | robj *decoded = getDecodedObject(elem); |
4185 | decrRefCount(elem); |
4186 | autoMemoryAdd(key->ctx, REDISMODULE_AM_STRING, decoded); |
4187 | return decoded; |
4188 | } else { |
4189 | return NULL; |
4190 | } |
4191 | } |
4192 | |
4193 | /* Replaces the element at index `index` in the list stored at `key`. |
4194 | * |
4195 | * The index is zero-based, so 0 means the first element, 1 the second element |
4196 | * and so on. Negative indices can be used to designate elements starting at the |
4197 | * tail of the list. Here, -1 means the last element, -2 means the penultimate |
4198 | * and so forth. |
4199 | * |
4200 | * On success, REDISMODULE_OK is returned. On failure, REDISMODULE_ERR is |
4201 | * returned and `errno` is set as follows: |
4202 | * |
4203 | * - EINVAL if key or value is NULL. |
4204 | * - ENOTSUP if the key is not a list. |
4205 | * - EBADF if the key is not opened for writing. |
4206 | * - EDOM if the index is not a valid index in the list. |
4207 | */ |
4208 | int RM_ListSet(RedisModuleKey *key, long index, RedisModuleString *value) { |
4209 | if (!value) { |
4210 | errno = EINVAL; |
4211 | return REDISMODULE_ERR; |
4212 | } |
4213 | if (moduleListIteratorSeek(key, index, REDISMODULE_WRITE)) { |
4214 | listTypeReplace(&key->u.list.entry, value); |
4215 | /* A note in quicklist.c forbids use of iterator after insert, so |
4216 | * probably also after replace. */ |
4217 | listTypeReleaseIterator(key->iter); |
4218 | key->iter = NULL; |
4219 | return REDISMODULE_OK; |
4220 | } else { |
4221 | return REDISMODULE_ERR; |
4222 | } |
4223 | } |
4224 | |
4225 | /* Inserts an element at the given index. |
4226 | * |
4227 | * The index is zero-based, so 0 means the first element, 1 the second element |
4228 | * and so on. Negative indices can be used to designate elements starting at the |
4229 | * tail of the list. Here, -1 means the last element, -2 means the penultimate |
4230 | * and so forth. The index is the element's index after inserting it. |
4231 | * |
4232 | * On success, REDISMODULE_OK is returned. On failure, REDISMODULE_ERR is |
4233 | * returned and `errno` is set as follows: |
4234 | * |
4235 | * - EINVAL if key or value is NULL. |
4236 | * - ENOTSUP if the key of another type than list. |
4237 | * - EBADF if the key is not opened for writing. |
4238 | * - EDOM if the index is not a valid index in the list. |
4239 | */ |
4240 | int RM_ListInsert(RedisModuleKey *key, long index, RedisModuleString *value) { |
4241 | if (!value) { |
4242 | errno = EINVAL; |
4243 | return REDISMODULE_ERR; |
4244 | } else if (key != NULL && key->value == NULL && |
4245 | (index == 0 || index == -1)) { |
4246 | /* Insert in empty key => push. */ |
4247 | return RM_ListPush(key, REDISMODULE_LIST_TAIL, value); |
4248 | } else if (key != NULL && key->value != NULL && |
4249 | key->value->type == OBJ_LIST && |
4250 | (index == (long)listTypeLength(key->value) || index == -1)) { |
4251 | /* Insert after the last element => push tail. */ |
4252 | return RM_ListPush(key, REDISMODULE_LIST_TAIL, value); |
4253 | } else if (key != NULL && key->value != NULL && |
4254 | key->value->type == OBJ_LIST && |
4255 | (index == 0 || index == -(long)listTypeLength(key->value) - 1)) { |
4256 | /* Insert before the first element => push head. */ |
4257 | return RM_ListPush(key, REDISMODULE_LIST_HEAD, value); |
4258 | } |
4259 | if (moduleListIteratorSeek(key, index, REDISMODULE_WRITE)) { |
4260 | int where = index < 0 ? LIST_TAIL : LIST_HEAD; |
4261 | listTypeInsert(&key->u.list.entry, value, where); |
4262 | /* A note in quicklist.c forbids use of iterator after insert. */ |
4263 | listTypeReleaseIterator(key->iter); |
4264 | key->iter = NULL; |
4265 | return REDISMODULE_OK; |
4266 | } else { |
4267 | return REDISMODULE_ERR; |
4268 | } |
4269 | } |
4270 | |
4271 | /* Removes an element at the given index. The index is 0-based. A negative index |
4272 | * can also be used, counting from the end of the list. |
4273 | * |
4274 | * On success, REDISMODULE_OK is returned. On failure, REDISMODULE_ERR is |
4275 | * returned and `errno` is set as follows: |
4276 | * |
4277 | * - EINVAL if key or value is NULL. |
4278 | * - ENOTSUP if the key is not a list. |
4279 | * - EBADF if the key is not opened for writing. |
4280 | * - EDOM if the index is not a valid index in the list. |
4281 | */ |
4282 | int RM_ListDelete(RedisModuleKey *key, long index) { |
4283 | if (moduleListIteratorSeek(key, index, REDISMODULE_WRITE)) { |
4284 | listTypeDelete(key->iter, &key->u.list.entry); |
4285 | moduleDelKeyIfEmpty(key); |
4286 | return REDISMODULE_OK; |
4287 | } else { |
4288 | return REDISMODULE_ERR; |
4289 | } |
4290 | } |
4291 | |
4292 | /* -------------------------------------------------------------------------- |
4293 | * ## Key API for Sorted Set type |
4294 | * |
4295 | * See also RM_ValueLength(), which returns the length of a sorted set. |
4296 | * -------------------------------------------------------------------------- */ |
4297 | |
4298 | /* Conversion from/to public flags of the Modules API and our private flags, |
4299 | * so that we have everything decoupled. */ |
4300 | int moduleZsetAddFlagsToCoreFlags(int flags) { |
4301 | int retflags = 0; |
4302 | if (flags & REDISMODULE_ZADD_XX) retflags |= ZADD_IN_XX; |
4303 | if (flags & REDISMODULE_ZADD_NX) retflags |= ZADD_IN_NX; |
4304 | if (flags & REDISMODULE_ZADD_GT) retflags |= ZADD_IN_GT; |
4305 | if (flags & REDISMODULE_ZADD_LT) retflags |= ZADD_IN_LT; |
4306 | return retflags; |
4307 | } |
4308 | |
4309 | /* See previous function comment. */ |
4310 | int moduleZsetAddFlagsFromCoreFlags(int flags) { |
4311 | int retflags = 0; |
4312 | if (flags & ZADD_OUT_ADDED) retflags |= REDISMODULE_ZADD_ADDED; |
4313 | if (flags & ZADD_OUT_UPDATED) retflags |= REDISMODULE_ZADD_UPDATED; |
4314 | if (flags & ZADD_OUT_NOP) retflags |= REDISMODULE_ZADD_NOP; |
4315 | return retflags; |
4316 | } |
4317 | |
4318 | /* Add a new element into a sorted set, with the specified 'score'. |
4319 | * If the element already exists, the score is updated. |
4320 | * |
4321 | * A new sorted set is created at value if the key is an empty open key |
4322 | * setup for writing. |
4323 | * |
4324 | * Additional flags can be passed to the function via a pointer, the flags |
4325 | * are both used to receive input and to communicate state when the function |
4326 | * returns. 'flagsptr' can be NULL if no special flags are used. |
4327 | * |
4328 | * The input flags are: |
4329 | * |
4330 | * REDISMODULE_ZADD_XX: Element must already exist. Do nothing otherwise. |
4331 | * REDISMODULE_ZADD_NX: Element must not exist. Do nothing otherwise. |
4332 | * REDISMODULE_ZADD_GT: If element exists, new score must be greater than the current score. |
4333 | * Do nothing otherwise. Can optionally be combined with XX. |
4334 | * REDISMODULE_ZADD_LT: If element exists, new score must be less than the current score. |
4335 | * Do nothing otherwise. Can optionally be combined with XX. |
4336 | * |
4337 | * The output flags are: |
4338 | * |
4339 | * REDISMODULE_ZADD_ADDED: The new element was added to the sorted set. |
4340 | * REDISMODULE_ZADD_UPDATED: The score of the element was updated. |
4341 | * REDISMODULE_ZADD_NOP: No operation was performed because XX or NX flags. |
4342 | * |
4343 | * On success the function returns REDISMODULE_OK. On the following errors |
4344 | * REDISMODULE_ERR is returned: |
4345 | * |
4346 | * * The key was not opened for writing. |
4347 | * * The key is of the wrong type. |
4348 | * * 'score' double value is not a number (NaN). |
4349 | */ |
4350 | int RM_ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr) { |
4351 | int in_flags = 0, out_flags = 0; |
4352 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
4353 | if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4354 | if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_ZSET); |
4355 | if (flagsptr) in_flags = moduleZsetAddFlagsToCoreFlags(*flagsptr); |
4356 | if (zsetAdd(key->value,score,ele->ptr,in_flags,&out_flags,NULL) == 0) { |
4357 | if (flagsptr) *flagsptr = 0; |
4358 | return REDISMODULE_ERR; |
4359 | } |
4360 | if (flagsptr) *flagsptr = moduleZsetAddFlagsFromCoreFlags(out_flags); |
4361 | return REDISMODULE_OK; |
4362 | } |
4363 | |
4364 | /* This function works exactly like RM_ZsetAdd(), but instead of setting |
4365 | * a new score, the score of the existing element is incremented, or if the |
4366 | * element does not already exist, it is added assuming the old score was |
4367 | * zero. |
4368 | * |
4369 | * The input and output flags, and the return value, have the same exact |
4370 | * meaning, with the only difference that this function will return |
4371 | * REDISMODULE_ERR even when 'score' is a valid double number, but adding it |
4372 | * to the existing score results into a NaN (not a number) condition. |
4373 | * |
4374 | * This function has an additional field 'newscore', if not NULL is filled |
4375 | * with the new score of the element after the increment, if no error |
4376 | * is returned. */ |
4377 | int RM_ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore) { |
4378 | int in_flags = 0, out_flags = 0; |
4379 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
4380 | if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4381 | if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_ZSET); |
4382 | if (flagsptr) in_flags = moduleZsetAddFlagsToCoreFlags(*flagsptr); |
4383 | in_flags |= ZADD_IN_INCR; |
4384 | if (zsetAdd(key->value,score,ele->ptr,in_flags,&out_flags,newscore) == 0) { |
4385 | if (flagsptr) *flagsptr = 0; |
4386 | return REDISMODULE_ERR; |
4387 | } |
4388 | if (flagsptr) *flagsptr = moduleZsetAddFlagsFromCoreFlags(out_flags); |
4389 | return REDISMODULE_OK; |
4390 | } |
4391 | |
4392 | /* Remove the specified element from the sorted set. |
4393 | * The function returns REDISMODULE_OK on success, and REDISMODULE_ERR |
4394 | * on one of the following conditions: |
4395 | * |
4396 | * * The key was not opened for writing. |
4397 | * * The key is of the wrong type. |
4398 | * |
4399 | * The return value does NOT indicate the fact the element was really |
4400 | * removed (since it existed) or not, just if the function was executed |
4401 | * with success. |
4402 | * |
4403 | * In order to know if the element was removed, the additional argument |
4404 | * 'deleted' must be passed, that populates the integer by reference |
4405 | * setting it to 1 or 0 depending on the outcome of the operation. |
4406 | * The 'deleted' argument can be NULL if the caller is not interested |
4407 | * to know if the element was really removed. |
4408 | * |
4409 | * Empty keys will be handled correctly by doing nothing. */ |
4410 | int RM_ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted) { |
4411 | if (!(key->mode & REDISMODULE_WRITE)) return REDISMODULE_ERR; |
4412 | if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4413 | if (key->value != NULL && zsetDel(key->value,ele->ptr)) { |
4414 | if (deleted) *deleted = 1; |
4415 | moduleDelKeyIfEmpty(key); |
4416 | } else { |
4417 | if (deleted) *deleted = 0; |
4418 | } |
4419 | return REDISMODULE_OK; |
4420 | } |
4421 | |
4422 | /* On success retrieve the double score associated at the sorted set element |
4423 | * 'ele' and returns REDISMODULE_OK. Otherwise REDISMODULE_ERR is returned |
4424 | * to signal one of the following conditions: |
4425 | * |
4426 | * * There is no such element 'ele' in the sorted set. |
4427 | * * The key is not a sorted set. |
4428 | * * The key is an open empty key. |
4429 | */ |
4430 | int RM_ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score) { |
4431 | if (key->value == NULL) return REDISMODULE_ERR; |
4432 | if (key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4433 | if (zsetScore(key->value,ele->ptr,score) == C_ERR) return REDISMODULE_ERR; |
4434 | return REDISMODULE_OK; |
4435 | } |
4436 | |
4437 | /* -------------------------------------------------------------------------- |
4438 | * ## Key API for Sorted Set iterator |
4439 | * -------------------------------------------------------------------------- */ |
4440 | |
4441 | void zsetKeyReset(RedisModuleKey *key) { |
4442 | key->u.zset.type = REDISMODULE_ZSET_RANGE_NONE; |
4443 | key->u.zset.current = NULL; |
4444 | key->u.zset.er = 1; |
4445 | } |
4446 | |
4447 | /* Stop a sorted set iteration. */ |
4448 | void RM_ZsetRangeStop(RedisModuleKey *key) { |
4449 | if (!key->value || key->value->type != OBJ_ZSET) return; |
4450 | /* Free resources if needed. */ |
4451 | if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) |
4452 | zslFreeLexRange(&key->u.zset.lrs); |
4453 | /* Setup sensible values so that misused iteration API calls when an |
4454 | * iterator is not active will result into something more sensible |
4455 | * than crashing. */ |
4456 | zsetKeyReset(key); |
4457 | } |
4458 | |
4459 | /* Return the "End of range" flag value to signal the end of the iteration. */ |
4460 | int RM_ZsetRangeEndReached(RedisModuleKey *key) { |
4461 | if (!key->value || key->value->type != OBJ_ZSET) return 1; |
4462 | return key->u.zset.er; |
4463 | } |
4464 | |
4465 | /* Helper function for RM_ZsetFirstInScoreRange() and RM_ZsetLastInScoreRange(). |
4466 | * Setup the sorted set iteration according to the specified score range |
4467 | * (see the functions calling it for more info). If 'first' is true the |
4468 | * first element in the range is used as a starting point for the iterator |
4469 | * otherwise the last. Return REDISMODULE_OK on success otherwise |
4470 | * REDISMODULE_ERR. */ |
4471 | int zsetInitScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex, int first) { |
4472 | if (!key->value || key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4473 | |
4474 | RM_ZsetRangeStop(key); |
4475 | key->u.zset.type = REDISMODULE_ZSET_RANGE_SCORE; |
4476 | key->u.zset.er = 0; |
4477 | |
4478 | /* Setup the range structure used by the sorted set core implementation |
4479 | * in order to seek at the specified element. */ |
4480 | zrangespec *zrs = &key->u.zset.rs; |
4481 | zrs->min = min; |
4482 | zrs->max = max; |
4483 | zrs->minex = minex; |
4484 | zrs->maxex = maxex; |
4485 | |
4486 | if (key->value->encoding == OBJ_ENCODING_LISTPACK) { |
4487 | key->u.zset.current = first ? zzlFirstInRange(key->value->ptr,zrs) : |
4488 | zzlLastInRange(key->value->ptr,zrs); |
4489 | } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { |
4490 | zset *zs = key->value->ptr; |
4491 | zskiplist *zsl = zs->zsl; |
4492 | key->u.zset.current = first ? zslFirstInRange(zsl,zrs) : |
4493 | zslLastInRange(zsl,zrs); |
4494 | } else { |
4495 | serverPanic("Unsupported zset encoding" ); |
4496 | } |
4497 | if (key->u.zset.current == NULL) key->u.zset.er = 1; |
4498 | return REDISMODULE_OK; |
4499 | } |
4500 | |
4501 | /* Setup a sorted set iterator seeking the first element in the specified |
4502 | * range. Returns REDISMODULE_OK if the iterator was correctly initialized |
4503 | * otherwise REDISMODULE_ERR is returned in the following conditions: |
4504 | * |
4505 | * 1. The value stored at key is not a sorted set or the key is empty. |
4506 | * |
4507 | * The range is specified according to the two double values 'min' and 'max'. |
4508 | * Both can be infinite using the following two macros: |
4509 | * |
4510 | * * REDISMODULE_POSITIVE_INFINITE for positive infinite value |
4511 | * * REDISMODULE_NEGATIVE_INFINITE for negative infinite value |
4512 | * |
4513 | * 'minex' and 'maxex' parameters, if true, respectively setup a range |
4514 | * where the min and max value are exclusive (not included) instead of |
4515 | * inclusive. */ |
4516 | int RM_ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex) { |
4517 | return zsetInitScoreRange(key,min,max,minex,maxex,1); |
4518 | } |
4519 | |
4520 | /* Exactly like RedisModule_ZsetFirstInScoreRange() but the last element of |
4521 | * the range is selected for the start of the iteration instead. */ |
4522 | int RM_ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex) { |
4523 | return zsetInitScoreRange(key,min,max,minex,maxex,0); |
4524 | } |
4525 | |
4526 | /* Helper function for RM_ZsetFirstInLexRange() and RM_ZsetLastInLexRange(). |
4527 | * Setup the sorted set iteration according to the specified lexicographical |
4528 | * range (see the functions calling it for more info). If 'first' is true the |
4529 | * first element in the range is used as a starting point for the iterator |
4530 | * otherwise the last. Return REDISMODULE_OK on success otherwise |
4531 | * REDISMODULE_ERR. |
4532 | * |
4533 | * Note that this function takes 'min' and 'max' in the same form of the |
4534 | * Redis ZRANGEBYLEX command. */ |
4535 | int zsetInitLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max, int first) { |
4536 | if (!key->value || key->value->type != OBJ_ZSET) return REDISMODULE_ERR; |
4537 | |
4538 | RM_ZsetRangeStop(key); |
4539 | key->u.zset.er = 0; |
4540 | |
4541 | /* Setup the range structure used by the sorted set core implementation |
4542 | * in order to seek at the specified element. */ |
4543 | zlexrangespec *zlrs = &key->u.zset.lrs; |
4544 | if (zslParseLexRange(min, max, zlrs) == C_ERR) return REDISMODULE_ERR; |
4545 | |
4546 | /* Set the range type to lex only after successfully parsing the range, |
4547 | * otherwise we don't want the zlexrangespec to be freed. */ |
4548 | key->u.zset.type = REDISMODULE_ZSET_RANGE_LEX; |
4549 | |
4550 | if (key->value->encoding == OBJ_ENCODING_LISTPACK) { |
4551 | key->u.zset.current = first ? zzlFirstInLexRange(key->value->ptr,zlrs) : |
4552 | zzlLastInLexRange(key->value->ptr,zlrs); |
4553 | } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { |
4554 | zset *zs = key->value->ptr; |
4555 | zskiplist *zsl = zs->zsl; |
4556 | key->u.zset.current = first ? zslFirstInLexRange(zsl,zlrs) : |
4557 | zslLastInLexRange(zsl,zlrs); |
4558 | } else { |
4559 | serverPanic("Unsupported zset encoding" ); |
4560 | } |
4561 | if (key->u.zset.current == NULL) key->u.zset.er = 1; |
4562 | |
4563 | return REDISMODULE_OK; |
4564 | } |
4565 | |
4566 | /* Setup a sorted set iterator seeking the first element in the specified |
4567 | * lexicographical range. Returns REDISMODULE_OK if the iterator was correctly |
4568 | * initialized otherwise REDISMODULE_ERR is returned in the |
4569 | * following conditions: |
4570 | * |
4571 | * 1. The value stored at key is not a sorted set or the key is empty. |
4572 | * 2. The lexicographical range 'min' and 'max' format is invalid. |
4573 | * |
4574 | * 'min' and 'max' should be provided as two RedisModuleString objects |
4575 | * in the same format as the parameters passed to the ZRANGEBYLEX command. |
4576 | * The function does not take ownership of the objects, so they can be released |
4577 | * ASAP after the iterator is setup. */ |
4578 | int RM_ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max) { |
4579 | return zsetInitLexRange(key,min,max,1); |
4580 | } |
4581 | |
4582 | /* Exactly like RedisModule_ZsetFirstInLexRange() but the last element of |
4583 | * the range is selected for the start of the iteration instead. */ |
4584 | int RM_ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max) { |
4585 | return zsetInitLexRange(key,min,max,0); |
4586 | } |
4587 | |
4588 | /* Return the current sorted set element of an active sorted set iterator |
4589 | * or NULL if the range specified in the iterator does not include any |
4590 | * element. */ |
4591 | RedisModuleString *RM_ZsetRangeCurrentElement(RedisModuleKey *key, double *score) { |
4592 | RedisModuleString *str; |
4593 | |
4594 | if (!key->value || key->value->type != OBJ_ZSET) return NULL; |
4595 | if (key->u.zset.current == NULL) return NULL; |
4596 | if (key->value->encoding == OBJ_ENCODING_LISTPACK) { |
4597 | unsigned char *eptr, *sptr; |
4598 | eptr = key->u.zset.current; |
4599 | sds ele = lpGetObject(eptr); |
4600 | if (score) { |
4601 | sptr = lpNext(key->value->ptr,eptr); |
4602 | *score = zzlGetScore(sptr); |
4603 | } |
4604 | str = createObject(OBJ_STRING,ele); |
4605 | } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { |
4606 | zskiplistNode *ln = key->u.zset.current; |
4607 | if (score) *score = ln->score; |
4608 | str = createStringObject(ln->ele,sdslen(ln->ele)); |
4609 | } else { |
4610 | serverPanic("Unsupported zset encoding" ); |
4611 | } |
4612 | autoMemoryAdd(key->ctx,REDISMODULE_AM_STRING,str); |
4613 | return str; |
4614 | } |
4615 | |
4616 | /* Go to the next element of the sorted set iterator. Returns 1 if there was |
4617 | * a next element, 0 if we are already at the latest element or the range |
4618 | * does not include any item at all. */ |
4619 | int RM_ZsetRangeNext(RedisModuleKey *key) { |
4620 | if (!key->value || key->value->type != OBJ_ZSET) return 0; |
4621 | if (!key->u.zset.type || !key->u.zset.current) return 0; /* No active iterator. */ |
4622 | |
4623 | if (key->value->encoding == OBJ_ENCODING_LISTPACK) { |
4624 | unsigned char *zl = key->value->ptr; |
4625 | unsigned char *eptr = key->u.zset.current; |
4626 | unsigned char *next; |
4627 | next = lpNext(zl,eptr); /* Skip element. */ |
4628 | if (next) next = lpNext(zl,next); /* Skip score. */ |
4629 | if (next == NULL) { |
4630 | key->u.zset.er = 1; |
4631 | return 0; |
4632 | } else { |
4633 | /* Are we still within the range? */ |
4634 | if (key->u.zset.type == REDISMODULE_ZSET_RANGE_SCORE) { |
4635 | /* Fetch the next element score for the |
4636 | * range check. */ |
4637 | unsigned char *saved_next = next; |
4638 | next = lpNext(zl,next); /* Skip next element. */ |
4639 | double score = zzlGetScore(next); /* Obtain the next score. */ |
4640 | if (!zslValueLteMax(score,&key->u.zset.rs)) { |
4641 | key->u.zset.er = 1; |
4642 | return 0; |
4643 | } |
4644 | next = saved_next; |
4645 | } else if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) { |
4646 | if (!zzlLexValueLteMax(next,&key->u.zset.lrs)) { |
4647 | key->u.zset.er = 1; |
4648 | return 0; |
4649 | } |
4650 | } |
4651 | key->u.zset.current = next; |
4652 | return 1; |
4653 | } |
4654 | } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { |
4655 | zskiplistNode *ln = key->u.zset.current, *next = ln->level[0].forward; |
4656 | if (next == NULL) { |
4657 | key->u.zset.er = 1; |
4658 | return 0; |
4659 | } else { |
4660 | /* Are we still within the range? */ |
4661 | if (key->u.zset.type == REDISMODULE_ZSET_RANGE_SCORE && |
4662 | !zslValueLteMax(next->score,&key->u.zset.rs)) |
4663 | { |
4664 | key->u.zset.er = 1; |
4665 | return 0; |
4666 | } else if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) { |
4667 | if (!zslLexValueLteMax(next->ele,&key->u.zset.lrs)) { |
4668 | key->u.zset.er = 1; |
4669 | return 0; |
4670 | } |
4671 | } |
4672 | key->u.zset.current = next; |
4673 | return 1; |
4674 | } |
4675 | } else { |
4676 | serverPanic("Unsupported zset encoding" ); |
4677 | } |
4678 | } |
4679 | |
4680 | /* Go to the previous element of the sorted set iterator. Returns 1 if there was |
4681 | * a previous element, 0 if we are already at the first element or the range |
4682 | * does not include any item at all. */ |
4683 | int RM_ZsetRangePrev(RedisModuleKey *key) { |
4684 | if (!key->value || key->value->type != OBJ_ZSET) return 0; |
4685 | if (!key->u.zset.type || !key->u.zset.current) return 0; /* No active iterator. */ |
4686 | |
4687 | if (key->value->encoding == OBJ_ENCODING_LISTPACK) { |
4688 | unsigned char *zl = key->value->ptr; |
4689 | unsigned char *eptr = key->u.zset.current; |
4690 | unsigned char *prev; |
4691 | prev = lpPrev(zl,eptr); /* Go back to previous score. */ |
4692 | if (prev) prev = lpPrev(zl,prev); /* Back to previous ele. */ |
4693 | if (prev == NULL) { |
4694 | key->u.zset.er = 1; |
4695 | return 0; |
4696 | } else { |
4697 | /* Are we still within the range? */ |
4698 | if (key->u.zset.type == REDISMODULE_ZSET_RANGE_SCORE) { |
4699 | /* Fetch the previous element score for the |
4700 | * range check. */ |
4701 | unsigned char *saved_prev = prev; |
4702 | prev = lpNext(zl,prev); /* Skip element to get the score.*/ |
4703 | double score = zzlGetScore(prev); /* Obtain the prev score. */ |
4704 | if (!zslValueGteMin(score,&key->u.zset.rs)) { |
4705 | key->u.zset.er = 1; |
4706 | return 0; |
4707 | } |
4708 | prev = saved_prev; |
4709 | } else if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) { |
4710 | if (!zzlLexValueGteMin(prev,&key->u.zset.lrs)) { |
4711 | key->u.zset.er = 1; |
4712 | return 0; |
4713 | } |
4714 | } |
4715 | key->u.zset.current = prev; |
4716 | return 1; |
4717 | } |
4718 | } else if (key->value->encoding == OBJ_ENCODING_SKIPLIST) { |
4719 | zskiplistNode *ln = key->u.zset.current, *prev = ln->backward; |
4720 | if (prev == NULL) { |
4721 | key->u.zset.er = 1; |
4722 | return 0; |
4723 | } else { |
4724 | /* Are we still within the range? */ |
4725 | if (key->u.zset.type == REDISMODULE_ZSET_RANGE_SCORE && |
4726 | !zslValueGteMin(prev->score,&key->u.zset.rs)) |
4727 | { |
4728 | key->u.zset.er = 1; |
4729 | return 0; |
4730 | } else if (key->u.zset.type == REDISMODULE_ZSET_RANGE_LEX) { |
4731 | if (!zslLexValueGteMin(prev->ele,&key->u.zset.lrs)) { |
4732 | key->u.zset.er = 1; |
4733 | return 0; |
4734 | } |
4735 | } |
4736 | key->u.zset.current = prev; |
4737 | return 1; |
4738 | } |
4739 | } else { |
4740 | serverPanic("Unsupported zset encoding" ); |
4741 | } |
4742 | } |
4743 | |
4744 | /* -------------------------------------------------------------------------- |
4745 | * ## Key API for Hash type |
4746 | * |
4747 | * See also RM_ValueLength(), which returns the number of fields in a hash. |
4748 | * -------------------------------------------------------------------------- */ |
4749 | |
4750 | /* Set the field of the specified hash field to the specified value. |
4751 | * If the key is an empty key open for writing, it is created with an empty |
4752 | * hash value, in order to set the specified field. |
4753 | * |
4754 | * The function is variadic and the user must specify pairs of field |
4755 | * names and values, both as RedisModuleString pointers (unless the |
4756 | * CFIELD option is set, see later). At the end of the field/value-ptr pairs, |
4757 | * NULL must be specified as last argument to signal the end of the arguments |
4758 | * in the variadic function. |
4759 | * |
4760 | * Example to set the hash argv[1] to the value argv[2]: |
4761 | * |
4762 | * RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[1],argv[2],NULL); |
4763 | * |
4764 | * The function can also be used in order to delete fields (if they exist) |
4765 | * by setting them to the specified value of REDISMODULE_HASH_DELETE: |
4766 | * |
4767 | * RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[1], |
4768 | * REDISMODULE_HASH_DELETE,NULL); |
4769 | * |
4770 | * The behavior of the command changes with the specified flags, that can be |
4771 | * set to REDISMODULE_HASH_NONE if no special behavior is needed. |
4772 | * |
4773 | * REDISMODULE_HASH_NX: The operation is performed only if the field was not |
4774 | * already existing in the hash. |
4775 | * REDISMODULE_HASH_XX: The operation is performed only if the field was |
4776 | * already existing, so that a new value could be |
4777 | * associated to an existing filed, but no new fields |
4778 | * are created. |
4779 | * REDISMODULE_HASH_CFIELDS: The field names passed are null terminated C |
4780 | * strings instead of RedisModuleString objects. |
4781 | * REDISMODULE_HASH_COUNT_ALL: Include the number of inserted fields in the |
4782 | * returned number, in addition to the number of |
4783 | * updated and deleted fields. (Added in Redis |
4784 | * 6.2.) |
4785 | * |
4786 | * Unless NX is specified, the command overwrites the old field value with |
4787 | * the new one. |
4788 | * |
4789 | * When using REDISMODULE_HASH_CFIELDS, field names are reported using |
4790 | * normal C strings, so for example to delete the field "foo" the following |
4791 | * code can be used: |
4792 | * |
4793 | * RedisModule_HashSet(key,REDISMODULE_HASH_CFIELDS,"foo", |
4794 | * REDISMODULE_HASH_DELETE,NULL); |
4795 | * |
4796 | * Return value: |
4797 | * |
4798 | * The number of fields existing in the hash prior to the call, which have been |
4799 | * updated (its old value has been replaced by a new value) or deleted. If the |
4800 | * flag REDISMODULE_HASH_COUNT_ALL is set, inserted fields not previously |
4801 | * existing in the hash are also counted. |
4802 | * |
4803 | * If the return value is zero, `errno` is set (since Redis 6.2) as follows: |
4804 | * |
4805 | * - EINVAL if any unknown flags are set or if key is NULL. |
4806 | * - ENOTSUP if the key is associated with a non Hash value. |
4807 | * - EBADF if the key was not opened for writing. |
4808 | * - ENOENT if no fields were counted as described under Return value above. |
4809 | * This is not actually an error. The return value can be zero if all fields |
4810 | * were just created and the COUNT_ALL flag was unset, or if changes were held |
4811 | * back due to the NX and XX flags. |
4812 | * |
4813 | * NOTICE: The return value semantics of this function are very different |
4814 | * between Redis 6.2 and older versions. Modules that use it should determine |
4815 | * the Redis version and handle it accordingly. |
4816 | */ |
4817 | int RM_HashSet(RedisModuleKey *key, int flags, ...) { |
4818 | va_list ap; |
4819 | if (!key || (flags & ~(REDISMODULE_HASH_NX | |
4820 | REDISMODULE_HASH_XX | |
4821 | REDISMODULE_HASH_CFIELDS | |
4822 | REDISMODULE_HASH_COUNT_ALL))) { |
4823 | errno = EINVAL; |
4824 | return 0; |
4825 | } else if (key->value && key->value->type != OBJ_HASH) { |
4826 | errno = ENOTSUP; |
4827 | return 0; |
4828 | } else if (!(key->mode & REDISMODULE_WRITE)) { |
4829 | errno = EBADF; |
4830 | return 0; |
4831 | } |
4832 | if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_HASH); |
4833 | |
4834 | int count = 0; |
4835 | va_start(ap, flags); |
4836 | while(1) { |
4837 | RedisModuleString *field, *value; |
4838 | /* Get the field and value objects. */ |
4839 | if (flags & REDISMODULE_HASH_CFIELDS) { |
4840 | char *cfield = va_arg(ap,char*); |
4841 | if (cfield == NULL) break; |
4842 | field = createRawStringObject(cfield,strlen(cfield)); |
4843 | } else { |
4844 | field = va_arg(ap,RedisModuleString*); |
4845 | if (field == NULL) break; |
4846 | } |
4847 | value = va_arg(ap,RedisModuleString*); |
4848 | |
4849 | /* Handle XX and NX */ |
4850 | if (flags & (REDISMODULE_HASH_XX|REDISMODULE_HASH_NX)) { |
4851 | int exists = hashTypeExists(key->value, field->ptr); |
4852 | if (((flags & REDISMODULE_HASH_XX) && !exists) || |
4853 | ((flags & REDISMODULE_HASH_NX) && exists)) |
4854 | { |
4855 | if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field); |
4856 | continue; |
4857 | } |
4858 | } |
4859 | |
4860 | /* Handle deletion if value is REDISMODULE_HASH_DELETE. */ |
4861 | if (value == REDISMODULE_HASH_DELETE) { |
4862 | count += hashTypeDelete(key->value, field->ptr); |
4863 | if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field); |
4864 | continue; |
4865 | } |
4866 | |
4867 | int low_flags = HASH_SET_COPY; |
4868 | /* If CFIELDS is active, we can pass the ownership of the |
4869 | * SDS object to the low level function that sets the field |
4870 | * to avoid a useless copy. */ |
4871 | if (flags & REDISMODULE_HASH_CFIELDS) |
4872 | low_flags |= HASH_SET_TAKE_FIELD; |
4873 | |
4874 | robj *argv[2] = {field,value}; |
4875 | hashTypeTryConversion(key->value,argv,0,1); |
4876 | int updated = hashTypeSet(key->value, field->ptr, value->ptr, low_flags); |
4877 | count += (flags & REDISMODULE_HASH_COUNT_ALL) ? 1 : updated; |
4878 | |
4879 | /* If CFIELDS is active, SDS string ownership is now of hashTypeSet(), |
4880 | * however we still have to release the 'field' object shell. */ |
4881 | if (flags & REDISMODULE_HASH_CFIELDS) { |
4882 | field->ptr = NULL; /* Prevent the SDS string from being freed. */ |
4883 | decrRefCount(field); |
4884 | } |
4885 | } |
4886 | va_end(ap); |
4887 | moduleDelKeyIfEmpty(key); |
4888 | if (count == 0) errno = ENOENT; |
4889 | return count; |
4890 | } |
4891 | |
4892 | /* Get fields from a hash value. This function is called using a variable |
4893 | * number of arguments, alternating a field name (as a RedisModuleString |
4894 | * pointer) with a pointer to a RedisModuleString pointer, that is set to the |
4895 | * value of the field if the field exists, or NULL if the field does not exist. |
4896 | * At the end of the field/value-ptr pairs, NULL must be specified as last |
4897 | * argument to signal the end of the arguments in the variadic function. |
4898 | * |
4899 | * This is an example usage: |
4900 | * |
4901 | * RedisModuleString *first, *second; |
4902 | * RedisModule_HashGet(mykey,REDISMODULE_HASH_NONE,argv[1],&first, |
4903 | * argv[2],&second,NULL); |
4904 | * |
4905 | * As with RedisModule_HashSet() the behavior of the command can be specified |
4906 | * passing flags different than REDISMODULE_HASH_NONE: |
4907 | * |
4908 | * REDISMODULE_HASH_CFIELDS: field names as null terminated C strings. |
4909 | * |
4910 | * REDISMODULE_HASH_EXISTS: instead of setting the value of the field |
4911 | * expecting a RedisModuleString pointer to pointer, the function just |
4912 | * reports if the field exists or not and expects an integer pointer |
4913 | * as the second element of each pair. |
4914 | * |
4915 | * Example of REDISMODULE_HASH_CFIELDS: |
4916 | * |
4917 | * RedisModuleString *username, *hashedpass; |
4918 | * RedisModule_HashGet(mykey,REDISMODULE_HASH_CFIELDS,"username",&username,"hp",&hashedpass, NULL); |
4919 | * |
4920 | * Example of REDISMODULE_HASH_EXISTS: |
4921 | * |
4922 | * int exists; |
4923 | * RedisModule_HashGet(mykey,REDISMODULE_HASH_EXISTS,argv[1],&exists,NULL); |
4924 | * |
4925 | * The function returns REDISMODULE_OK on success and REDISMODULE_ERR if |
4926 | * the key is not a hash value. |
4927 | * |
4928 | * Memory management: |
4929 | * |
4930 | * The returned RedisModuleString objects should be released with |
4931 | * RedisModule_FreeString(), or by enabling automatic memory management. |
4932 | */ |
4933 | int RM_HashGet(RedisModuleKey *key, int flags, ...) { |
4934 | va_list ap; |
4935 | if (key->value && key->value->type != OBJ_HASH) return REDISMODULE_ERR; |
4936 | |
4937 | va_start(ap, flags); |
4938 | while(1) { |
4939 | RedisModuleString *field, **valueptr; |
4940 | int *existsptr; |
4941 | /* Get the field object and the value pointer to pointer. */ |
4942 | if (flags & REDISMODULE_HASH_CFIELDS) { |
4943 | char *cfield = va_arg(ap,char*); |
4944 | if (cfield == NULL) break; |
4945 | field = createRawStringObject(cfield,strlen(cfield)); |
4946 | } else { |
4947 | field = va_arg(ap,RedisModuleString*); |
4948 | if (field == NULL) break; |
4949 | } |
4950 | |
4951 | /* Query the hash for existence or value object. */ |
4952 | if (flags & REDISMODULE_HASH_EXISTS) { |
4953 | existsptr = va_arg(ap,int*); |
4954 | if (key->value) |
4955 | *existsptr = hashTypeExists(key->value,field->ptr); |
4956 | else |
4957 | *existsptr = 0; |
4958 | } else { |
4959 | valueptr = va_arg(ap,RedisModuleString**); |
4960 | if (key->value) { |
4961 | *valueptr = hashTypeGetValueObject(key->value,field->ptr); |
4962 | if (*valueptr) { |
4963 | robj *decoded = getDecodedObject(*valueptr); |
4964 | decrRefCount(*valueptr); |
4965 | *valueptr = decoded; |
4966 | } |
4967 | if (*valueptr) |
4968 | autoMemoryAdd(key->ctx,REDISMODULE_AM_STRING,*valueptr); |
4969 | } else { |
4970 | *valueptr = NULL; |
4971 | } |
4972 | } |
4973 | |
4974 | /* Cleanup */ |
4975 | if (flags & REDISMODULE_HASH_CFIELDS) decrRefCount(field); |
4976 | } |
4977 | va_end(ap); |
4978 | return REDISMODULE_OK; |
4979 | } |
4980 | |
4981 | /* -------------------------------------------------------------------------- |
4982 | * ## Key API for Stream type |
4983 | * |
4984 | * For an introduction to streams, see https://redis.io/topics/streams-intro. |
4985 | * |
4986 | * The type RedisModuleStreamID, which is used in stream functions, is a struct |
4987 | * with two 64-bit fields and is defined as |
4988 | * |
4989 | * typedef struct RedisModuleStreamID { |
4990 | * uint64_t ms; |
4991 | * uint64_t seq; |
4992 | * } RedisModuleStreamID; |
4993 | * |
4994 | * See also RM_ValueLength(), which returns the length of a stream, and the |
4995 | * conversion functions RM_StringToStreamID() and RM_CreateStringFromStreamID(). |
4996 | * -------------------------------------------------------------------------- */ |
4997 | |
4998 | /* Adds an entry to a stream. Like XADD without trimming. |
4999 | * |
5000 | * - `key`: The key where the stream is (or will be) stored |
5001 | * - `flags`: A bit field of |
5002 | * - `REDISMODULE_STREAM_ADD_AUTOID`: Assign a stream ID automatically, like |
5003 | * `*` in the XADD command. |
5004 | * - `id`: If the `AUTOID` flag is set, this is where the assigned ID is |
5005 | * returned. Can be NULL if `AUTOID` is set, if you don't care to receive the |
5006 | * ID. If `AUTOID` is not set, this is the requested ID. |
5007 | * - `argv`: A pointer to an array of size `numfields * 2` containing the |
5008 | * fields and values. |
5009 | * - `numfields`: The number of field-value pairs in `argv`. |
5010 | * |
5011 | * Returns REDISMODULE_OK if an entry has been added. On failure, |
5012 | * REDISMODULE_ERR is returned and `errno` is set as follows: |
5013 | * |
5014 | * - EINVAL if called with invalid arguments |
5015 | * - ENOTSUP if the key refers to a value of a type other than stream |
5016 | * - EBADF if the key was not opened for writing |
5017 | * - EDOM if the given ID was 0-0 or not greater than all other IDs in the |
5018 | * stream (only if the AUTOID flag is unset) |
5019 | * - EFBIG if the stream has reached the last possible ID |
5020 | * - ERANGE if the elements are too large to be stored. |
5021 | */ |
5022 | int RM_StreamAdd(RedisModuleKey *key, int flags, RedisModuleStreamID *id, RedisModuleString **argv, long numfields) { |
5023 | /* Validate args */ |
5024 | if (!key || (numfields != 0 && !argv) || /* invalid key or argv */ |
5025 | (flags & ~(REDISMODULE_STREAM_ADD_AUTOID)) || /* invalid flags */ |
5026 | (!(flags & REDISMODULE_STREAM_ADD_AUTOID) && !id)) { /* id required */ |
5027 | errno = EINVAL; |
5028 | return REDISMODULE_ERR; |
5029 | } else if (key->value && key->value->type != OBJ_STREAM) { |
5030 | errno = ENOTSUP; /* wrong type */ |
5031 | return REDISMODULE_ERR; |
5032 | } else if (!(key->mode & REDISMODULE_WRITE)) { |
5033 | errno = EBADF; /* key not open for writing */ |
5034 | return REDISMODULE_ERR; |
5035 | } else if (!(flags & REDISMODULE_STREAM_ADD_AUTOID) && |
5036 | id->ms == 0 && id->seq == 0) { |
5037 | errno = EDOM; /* ID out of range */ |
5038 | return REDISMODULE_ERR; |
5039 | } |
5040 | |
5041 | /* Create key if necessary */ |
5042 | int created = 0; |
5043 | if (key->value == NULL) { |
5044 | moduleCreateEmptyKey(key, REDISMODULE_KEYTYPE_STREAM); |
5045 | created = 1; |
5046 | } |
5047 | |
5048 | stream *s = key->value->ptr; |
5049 | if (s->last_id.ms == UINT64_MAX && s->last_id.seq == UINT64_MAX) { |
5050 | /* The stream has reached the last possible ID */ |
5051 | errno = EFBIG; |
5052 | return REDISMODULE_ERR; |
5053 | } |
5054 | |
5055 | streamID added_id; |
5056 | streamID use_id; |
5057 | streamID *use_id_ptr = NULL; |
5058 | if (!(flags & REDISMODULE_STREAM_ADD_AUTOID)) { |
5059 | use_id.ms = id->ms; |
5060 | use_id.seq = id->seq; |
5061 | use_id_ptr = &use_id; |
5062 | } |
5063 | |
5064 | if (streamAppendItem(s,argv,numfields,&added_id,use_id_ptr,1) == C_ERR) { |
5065 | /* Either the ID not greater than all existing IDs in the stream, or |
5066 | * the elements are too large to be stored. either way, errno is already |
5067 | * set by streamAppendItem. */ |
5068 | return REDISMODULE_ERR; |
5069 | } |
5070 | /* Postponed signalKeyAsReady(). Done implicitly by moduleCreateEmptyKey() |
5071 | * so not needed if the stream has just been created. */ |
5072 | if (!created) key->u.stream.signalready = 1; |
5073 | |
5074 | if (id != NULL) { |
5075 | id->ms = added_id.ms; |
5076 | id->seq = added_id.seq; |
5077 | } |
5078 | |
5079 | return REDISMODULE_OK; |
5080 | } |
5081 | |
5082 | /* Deletes an entry from a stream. |
5083 | * |
5084 | * - `key`: A key opened for writing, with no stream iterator started. |
5085 | * - `id`: The stream ID of the entry to delete. |
5086 | * |
5087 | * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned |
5088 | * and `errno` is set as follows: |
5089 | * |
5090 | * - EINVAL if called with invalid arguments |
5091 | * - ENOTSUP if the key refers to a value of a type other than stream or if the |
5092 | * key is empty |
5093 | * - EBADF if the key was not opened for writing or if a stream iterator is |
5094 | * associated with the key |
5095 | * - ENOENT if no entry with the given stream ID exists |
5096 | * |
5097 | * See also RM_StreamIteratorDelete() for deleting the current entry while |
5098 | * iterating using a stream iterator. |
5099 | */ |
5100 | int RM_StreamDelete(RedisModuleKey *key, RedisModuleStreamID *id) { |
5101 | if (!key || !id) { |
5102 | errno = EINVAL; |
5103 | return REDISMODULE_ERR; |
5104 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5105 | errno = ENOTSUP; /* wrong type */ |
5106 | return REDISMODULE_ERR; |
5107 | } else if (!(key->mode & REDISMODULE_WRITE) || |
5108 | key->iter != NULL) { |
5109 | errno = EBADF; /* key not opened for writing or iterator started */ |
5110 | return REDISMODULE_ERR; |
5111 | } |
5112 | stream *s = key->value->ptr; |
5113 | streamID streamid = {id->ms, id->seq}; |
5114 | if (streamDeleteItem(s, &streamid)) { |
5115 | return REDISMODULE_OK; |
5116 | } else { |
5117 | errno = ENOENT; /* no entry with this id */ |
5118 | return REDISMODULE_ERR; |
5119 | } |
5120 | } |
5121 | |
5122 | /* Sets up a stream iterator. |
5123 | * |
5124 | * - `key`: The stream key opened for reading using RedisModule_OpenKey(). |
5125 | * - `flags`: |
5126 | * - `REDISMODULE_STREAM_ITERATOR_EXCLUSIVE`: Don't include `start` and `end` |
5127 | * in the iterated range. |
5128 | * - `REDISMODULE_STREAM_ITERATOR_REVERSE`: Iterate in reverse order, starting |
5129 | * from the `end` of the range. |
5130 | * - `start`: The lower bound of the range. Use NULL for the beginning of the |
5131 | * stream. |
5132 | * - `end`: The upper bound of the range. Use NULL for the end of the stream. |
5133 | * |
5134 | * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned |
5135 | * and `errno` is set as follows: |
5136 | * |
5137 | * - EINVAL if called with invalid arguments |
5138 | * - ENOTSUP if the key refers to a value of a type other than stream or if the |
5139 | * key is empty |
5140 | * - EBADF if the key was not opened for writing or if a stream iterator is |
5141 | * already associated with the key |
5142 | * - EDOM if `start` or `end` is outside the valid range |
5143 | * |
5144 | * Returns REDISMODULE_OK on success and REDISMODULE_ERR if the key doesn't |
5145 | * refer to a stream or if invalid arguments were given. |
5146 | * |
5147 | * The stream IDs are retrieved using RedisModule_StreamIteratorNextID() and |
5148 | * for each stream ID, the fields and values are retrieved using |
5149 | * RedisModule_StreamIteratorNextField(). The iterator is freed by calling |
5150 | * RedisModule_StreamIteratorStop(). |
5151 | * |
5152 | * Example (error handling omitted): |
5153 | * |
5154 | * RedisModule_StreamIteratorStart(key, 0, startid_ptr, endid_ptr); |
5155 | * RedisModuleStreamID id; |
5156 | * long numfields; |
5157 | * while (RedisModule_StreamIteratorNextID(key, &id, &numfields) == |
5158 | * REDISMODULE_OK) { |
5159 | * RedisModuleString *field, *value; |
5160 | * while (RedisModule_StreamIteratorNextField(key, &field, &value) == |
5161 | * REDISMODULE_OK) { |
5162 | * // |
5163 | * // ... Do stuff ... |
5164 | * // |
5165 | * RedisModule_FreeString(ctx, field); |
5166 | * RedisModule_FreeString(ctx, value); |
5167 | * } |
5168 | * } |
5169 | * RedisModule_StreamIteratorStop(key); |
5170 | */ |
5171 | int RM_StreamIteratorStart(RedisModuleKey *key, int flags, RedisModuleStreamID *start, RedisModuleStreamID *end) { |
5172 | /* check args */ |
5173 | if (!key || |
5174 | (flags & ~(REDISMODULE_STREAM_ITERATOR_EXCLUSIVE | |
5175 | REDISMODULE_STREAM_ITERATOR_REVERSE))) { |
5176 | errno = EINVAL; /* key missing or invalid flags */ |
5177 | return REDISMODULE_ERR; |
5178 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5179 | errno = ENOTSUP; |
5180 | return REDISMODULE_ERR; /* not a stream */ |
5181 | } else if (key->iter) { |
5182 | errno = EBADF; /* iterator already started */ |
5183 | return REDISMODULE_ERR; |
5184 | } |
5185 | |
5186 | /* define range for streamIteratorStart() */ |
5187 | streamID lower, upper; |
5188 | if (start) lower = (streamID){start->ms, start->seq}; |
5189 | if (end) upper = (streamID){end->ms, end->seq}; |
5190 | if (flags & REDISMODULE_STREAM_ITERATOR_EXCLUSIVE) { |
5191 | if ((start && streamIncrID(&lower) != C_OK) || |
5192 | (end && streamDecrID(&upper) != C_OK)) { |
5193 | errno = EDOM; /* end is 0-0 or start is MAX-MAX? */ |
5194 | return REDISMODULE_ERR; |
5195 | } |
5196 | } |
5197 | |
5198 | /* create iterator */ |
5199 | stream *s = key->value->ptr; |
5200 | int rev = flags & REDISMODULE_STREAM_ITERATOR_REVERSE; |
5201 | streamIterator *si = zmalloc(sizeof(*si)); |
5202 | streamIteratorStart(si, s, start ? &lower : NULL, end ? &upper : NULL, rev); |
5203 | key->iter = si; |
5204 | key->u.stream.currentid.ms = 0; /* for RM_StreamIteratorDelete() */ |
5205 | key->u.stream.currentid.seq = 0; |
5206 | key->u.stream.numfieldsleft = 0; /* for RM_StreamIteratorNextField() */ |
5207 | return REDISMODULE_OK; |
5208 | } |
5209 | |
5210 | /* Stops a stream iterator created using RedisModule_StreamIteratorStart() and |
5211 | * reclaims its memory. |
5212 | * |
5213 | * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned |
5214 | * and `errno` is set as follows: |
5215 | * |
5216 | * - EINVAL if called with a NULL key |
5217 | * - ENOTSUP if the key refers to a value of a type other than stream or if the |
5218 | * key is empty |
5219 | * - EBADF if the key was not opened for writing or if no stream iterator is |
5220 | * associated with the key |
5221 | */ |
5222 | int RM_StreamIteratorStop(RedisModuleKey *key) { |
5223 | if (!key) { |
5224 | errno = EINVAL; |
5225 | return REDISMODULE_ERR; |
5226 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5227 | errno = ENOTSUP; |
5228 | return REDISMODULE_ERR; |
5229 | } else if (!key->iter) { |
5230 | errno = EBADF; |
5231 | return REDISMODULE_ERR; |
5232 | } |
5233 | streamIteratorStop(key->iter); |
5234 | zfree(key->iter); |
5235 | key->iter = NULL; |
5236 | return REDISMODULE_OK; |
5237 | } |
5238 | |
5239 | /* Finds the next stream entry and returns its stream ID and the number of |
5240 | * fields. |
5241 | * |
5242 | * - `key`: Key for which a stream iterator has been started using |
5243 | * RedisModule_StreamIteratorStart(). |
5244 | * - `id`: The stream ID returned. NULL if you don't care. |
5245 | * - `numfields`: The number of fields in the found stream entry. NULL if you |
5246 | * don't care. |
5247 | * |
5248 | * Returns REDISMODULE_OK and sets `*id` and `*numfields` if an entry was found. |
5249 | * On failure, REDISMODULE_ERR is returned and `errno` is set as follows: |
5250 | * |
5251 | * - EINVAL if called with a NULL key |
5252 | * - ENOTSUP if the key refers to a value of a type other than stream or if the |
5253 | * key is empty |
5254 | * - EBADF if no stream iterator is associated with the key |
5255 | * - ENOENT if there are no more entries in the range of the iterator |
5256 | * |
5257 | * In practice, if RM_StreamIteratorNextID() is called after a successful call |
5258 | * to RM_StreamIteratorStart() and with the same key, it is safe to assume that |
5259 | * an REDISMODULE_ERR return value means that there are no more entries. |
5260 | * |
5261 | * Use RedisModule_StreamIteratorNextField() to retrieve the fields and values. |
5262 | * See the example at RedisModule_StreamIteratorStart(). |
5263 | */ |
5264 | int RM_StreamIteratorNextID(RedisModuleKey *key, RedisModuleStreamID *id, long *numfields) { |
5265 | if (!key) { |
5266 | errno = EINVAL; |
5267 | return REDISMODULE_ERR; |
5268 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5269 | errno = ENOTSUP; |
5270 | return REDISMODULE_ERR; |
5271 | } else if (!key->iter) { |
5272 | errno = EBADF; |
5273 | return REDISMODULE_ERR; |
5274 | } |
5275 | streamIterator *si = key->iter; |
5276 | int64_t *num_ptr = &key->u.stream.numfieldsleft; |
5277 | streamID *streamid_ptr = &key->u.stream.currentid; |
5278 | if (streamIteratorGetID(si, streamid_ptr, num_ptr)) { |
5279 | if (id) { |
5280 | id->ms = streamid_ptr->ms; |
5281 | id->seq = streamid_ptr->seq; |
5282 | } |
5283 | if (numfields) *numfields = *num_ptr; |
5284 | return REDISMODULE_OK; |
5285 | } else { |
5286 | /* No entry found. */ |
5287 | key->u.stream.currentid.ms = 0; /* for RM_StreamIteratorDelete() */ |
5288 | key->u.stream.currentid.seq = 0; |
5289 | key->u.stream.numfieldsleft = 0; /* for RM_StreamIteratorNextField() */ |
5290 | errno = ENOENT; |
5291 | return REDISMODULE_ERR; |
5292 | } |
5293 | } |
5294 | |
5295 | /* Retrieves the next field of the current stream ID and its corresponding value |
5296 | * in a stream iteration. This function should be called repeatedly after calling |
5297 | * RedisModule_StreamIteratorNextID() to fetch each field-value pair. |
5298 | * |
5299 | * - `key`: Key where a stream iterator has been started. |
5300 | * - `field_ptr`: This is where the field is returned. |
5301 | * - `value_ptr`: This is where the value is returned. |
5302 | * |
5303 | * Returns REDISMODULE_OK and points `*field_ptr` and `*value_ptr` to freshly |
5304 | * allocated RedisModuleString objects. The string objects are freed |
5305 | * automatically when the callback finishes if automatic memory is enabled. On |
5306 | * failure, REDISMODULE_ERR is returned and `errno` is set as follows: |
5307 | * |
5308 | * - EINVAL if called with a NULL key |
5309 | * - ENOTSUP if the key refers to a value of a type other than stream or if the |
5310 | * key is empty |
5311 | * - EBADF if no stream iterator is associated with the key |
5312 | * - ENOENT if there are no more fields in the current stream entry |
5313 | * |
5314 | * In practice, if RM_StreamIteratorNextField() is called after a successful |
5315 | * call to RM_StreamIteratorNextID() and with the same key, it is safe to assume |
5316 | * that an REDISMODULE_ERR return value means that there are no more fields. |
5317 | * |
5318 | * See the example at RedisModule_StreamIteratorStart(). |
5319 | */ |
5320 | int RM_StreamIteratorNextField(RedisModuleKey *key, RedisModuleString **field_ptr, RedisModuleString **value_ptr) { |
5321 | if (!key) { |
5322 | errno = EINVAL; |
5323 | return REDISMODULE_ERR; |
5324 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5325 | errno = ENOTSUP; |
5326 | return REDISMODULE_ERR; |
5327 | } else if (!key->iter) { |
5328 | errno = EBADF; |
5329 | return REDISMODULE_ERR; |
5330 | } else if (key->u.stream.numfieldsleft <= 0) { |
5331 | errno = ENOENT; |
5332 | return REDISMODULE_ERR; |
5333 | } |
5334 | streamIterator *si = key->iter; |
5335 | unsigned char *field, *value; |
5336 | int64_t field_len, value_len; |
5337 | streamIteratorGetField(si, &field, &value, &field_len, &value_len); |
5338 | if (field_ptr) { |
5339 | *field_ptr = createRawStringObject((char *)field, field_len); |
5340 | autoMemoryAdd(key->ctx, REDISMODULE_AM_STRING, *field_ptr); |
5341 | } |
5342 | if (value_ptr) { |
5343 | *value_ptr = createRawStringObject((char *)value, value_len); |
5344 | autoMemoryAdd(key->ctx, REDISMODULE_AM_STRING, *value_ptr); |
5345 | } |
5346 | key->u.stream.numfieldsleft--; |
5347 | return REDISMODULE_OK; |
5348 | } |
5349 | |
5350 | /* Deletes the current stream entry while iterating. |
5351 | * |
5352 | * This function can be called after RM_StreamIteratorNextID() or after any |
5353 | * calls to RM_StreamIteratorNextField(). |
5354 | * |
5355 | * Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned |
5356 | * and `errno` is set as follows: |
5357 | * |
5358 | * - EINVAL if key is NULL |
5359 | * - ENOTSUP if the key is empty or is of another type than stream |
5360 | * - EBADF if the key is not opened for writing, if no iterator has been started |
5361 | * - ENOENT if the iterator has no current stream entry |
5362 | */ |
5363 | int RM_StreamIteratorDelete(RedisModuleKey *key) { |
5364 | if (!key) { |
5365 | errno = EINVAL; |
5366 | return REDISMODULE_ERR; |
5367 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5368 | errno = ENOTSUP; |
5369 | return REDISMODULE_ERR; |
5370 | } else if (!(key->mode & REDISMODULE_WRITE) || !key->iter) { |
5371 | errno = EBADF; |
5372 | return REDISMODULE_ERR; |
5373 | } else if (key->u.stream.currentid.ms == 0 && |
5374 | key->u.stream.currentid.seq == 0) { |
5375 | errno = ENOENT; |
5376 | return REDISMODULE_ERR; |
5377 | } |
5378 | streamIterator *si = key->iter; |
5379 | streamIteratorRemoveEntry(si, &key->u.stream.currentid); |
5380 | key->u.stream.currentid.ms = 0; /* Make sure repeated Delete() fails */ |
5381 | key->u.stream.currentid.seq = 0; |
5382 | key->u.stream.numfieldsleft = 0; /* Make sure NextField() fails */ |
5383 | return REDISMODULE_OK; |
5384 | } |
5385 | |
5386 | /* Trim a stream by length, similar to XTRIM with MAXLEN. |
5387 | * |
5388 | * - `key`: Key opened for writing. |
5389 | * - `flags`: A bitfield of |
5390 | * - `REDISMODULE_STREAM_TRIM_APPROX`: Trim less if it improves performance, |
5391 | * like XTRIM with `~`. |
5392 | * - `length`: The number of stream entries to keep after trimming. |
5393 | * |
5394 | * Returns the number of entries deleted. On failure, a negative value is |
5395 | * returned and `errno` is set as follows: |
5396 | * |
5397 | * - EINVAL if called with invalid arguments |
5398 | * - ENOTSUP if the key is empty or of a type other than stream |
5399 | * - EBADF if the key is not opened for writing |
5400 | */ |
5401 | long long RM_StreamTrimByLength(RedisModuleKey *key, int flags, long long length) { |
5402 | if (!key || (flags & ~(REDISMODULE_STREAM_TRIM_APPROX)) || length < 0) { |
5403 | errno = EINVAL; |
5404 | return -1; |
5405 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5406 | errno = ENOTSUP; |
5407 | return -1; |
5408 | } else if (!(key->mode & REDISMODULE_WRITE)) { |
5409 | errno = EBADF; |
5410 | return -1; |
5411 | } |
5412 | int approx = flags & REDISMODULE_STREAM_TRIM_APPROX ? 1 : 0; |
5413 | return streamTrimByLength((stream *)key->value->ptr, length, approx); |
5414 | } |
5415 | |
5416 | /* Trim a stream by ID, similar to XTRIM with MINID. |
5417 | * |
5418 | * - `key`: Key opened for writing. |
5419 | * - `flags`: A bitfield of |
5420 | * - `REDISMODULE_STREAM_TRIM_APPROX`: Trim less if it improves performance, |
5421 | * like XTRIM with `~`. |
5422 | * - `id`: The smallest stream ID to keep after trimming. |
5423 | * |
5424 | * Returns the number of entries deleted. On failure, a negative value is |
5425 | * returned and `errno` is set as follows: |
5426 | * |
5427 | * - EINVAL if called with invalid arguments |
5428 | * - ENOTSUP if the key is empty or of a type other than stream |
5429 | * - EBADF if the key is not opened for writing |
5430 | */ |
5431 | long long RM_StreamTrimByID(RedisModuleKey *key, int flags, RedisModuleStreamID *id) { |
5432 | if (!key || (flags & ~(REDISMODULE_STREAM_TRIM_APPROX)) || !id) { |
5433 | errno = EINVAL; |
5434 | return -1; |
5435 | } else if (!key->value || key->value->type != OBJ_STREAM) { |
5436 | errno = ENOTSUP; |
5437 | return -1; |
5438 | } else if (!(key->mode & REDISMODULE_WRITE)) { |
5439 | errno = EBADF; |
5440 | return -1; |
5441 | } |
5442 | int approx = flags & REDISMODULE_STREAM_TRIM_APPROX ? 1 : 0; |
5443 | streamID minid = (streamID){id->ms, id->seq}; |
5444 | return streamTrimByID((stream *)key->value->ptr, minid, approx); |
5445 | } |
5446 | |
5447 | /* -------------------------------------------------------------------------- |
5448 | * ## Calling Redis commands from modules |
5449 | * |
5450 | * RM_Call() sends a command to Redis. The remaining functions handle the reply. |
5451 | * -------------------------------------------------------------------------- */ |
5452 | |
5453 | |
5454 | void moduleParseCallReply_Int(RedisModuleCallReply *reply); |
5455 | void moduleParseCallReply_BulkString(RedisModuleCallReply *reply); |
5456 | void moduleParseCallReply_SimpleString(RedisModuleCallReply *reply); |
5457 | void moduleParseCallReply_Array(RedisModuleCallReply *reply); |
5458 | |
5459 | |
5460 | |
5461 | |
5462 | /* Free a Call reply and all the nested replies it contains if it's an |
5463 | * array. */ |
5464 | void RM_FreeCallReply(RedisModuleCallReply *reply) { |
5465 | /* This is a wrapper for the recursive free reply function. This is needed |
5466 | * in order to have the first level function to return on nested replies, |
5467 | * but only if called by the module API. */ |
5468 | RedisModuleCtx *ctx = callReplyGetPrivateData(reply); |
5469 | freeCallReply(reply); |
5470 | autoMemoryFreed(ctx,REDISMODULE_AM_REPLY,reply); |
5471 | } |
5472 | |
5473 | /* Return the reply type as one of the following: |
5474 | * |
5475 | * - REDISMODULE_REPLY_UNKNOWN |
5476 | * - REDISMODULE_REPLY_STRING |
5477 | * - REDISMODULE_REPLY_ERROR |
5478 | * - REDISMODULE_REPLY_INTEGER |
5479 | * - REDISMODULE_REPLY_ARRAY |
5480 | * - REDISMODULE_REPLY_NULL |
5481 | * - REDISMODULE_REPLY_MAP |
5482 | * - REDISMODULE_REPLY_SET |
5483 | * - REDISMODULE_REPLY_BOOL |
5484 | * - REDISMODULE_REPLY_DOUBLE |
5485 | * - REDISMODULE_REPLY_BIG_NUMBER |
5486 | * - REDISMODULE_REPLY_VERBATIM_STRING |
5487 | * - REDISMODULE_REPLY_ATTRIBUTE */ |
5488 | int RM_CallReplyType(RedisModuleCallReply *reply) { |
5489 | return callReplyType(reply); |
5490 | } |
5491 | |
5492 | /* Return the reply type length, where applicable. */ |
5493 | size_t RM_CallReplyLength(RedisModuleCallReply *reply) { |
5494 | return callReplyGetLen(reply); |
5495 | } |
5496 | |
5497 | /* Return the 'idx'-th nested call reply element of an array reply, or NULL |
5498 | * if the reply type is wrong or the index is out of range. */ |
5499 | RedisModuleCallReply *RM_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx) { |
5500 | return callReplyGetArrayElement(reply, idx); |
5501 | } |
5502 | |
5503 | /* Return the `long long` of an integer reply. */ |
5504 | long long RM_CallReplyInteger(RedisModuleCallReply *reply) { |
5505 | return callReplyGetLongLong(reply); |
5506 | } |
5507 | |
5508 | /* Return the double value of a double reply. */ |
5509 | double RM_CallReplyDouble(RedisModuleCallReply *reply) { |
5510 | return callReplyGetDouble(reply); |
5511 | } |
5512 | |
5513 | /* Return the big number value of a big number reply. */ |
5514 | const char *RM_CallReplyBigNumber(RedisModuleCallReply *reply, size_t *len) { |
5515 | return callReplyGetBigNumber(reply, len); |
5516 | } |
5517 | |
5518 | /* Return the value of a verbatim string reply, |
5519 | * An optional output argument can be given to get verbatim reply format. */ |
5520 | const char *RM_CallReplyVerbatim(RedisModuleCallReply *reply, size_t *len, const char **format) { |
5521 | return callReplyGetVerbatim(reply, len, format); |
5522 | } |
5523 | |
5524 | /* Return the Boolean value of a Boolean reply. */ |
5525 | int RM_CallReplyBool(RedisModuleCallReply *reply) { |
5526 | return callReplyGetBool(reply); |
5527 | } |
5528 | |
5529 | /* Return the 'idx'-th nested call reply element of a set reply, or NULL |
5530 | * if the reply type is wrong or the index is out of range. */ |
5531 | RedisModuleCallReply *RM_CallReplySetElement(RedisModuleCallReply *reply, size_t idx) { |
5532 | return callReplyGetSetElement(reply, idx); |
5533 | } |
5534 | |
5535 | /* Retrieve the 'idx'-th key and value of a map reply. |
5536 | * |
5537 | * Returns: |
5538 | * - REDISMODULE_OK on success. |
5539 | * - REDISMODULE_ERR if idx out of range or if the reply type is wrong. |
5540 | * |
5541 | * The `key` and `value` arguments are used to return by reference, and may be |
5542 | * NULL if not required. */ |
5543 | int RM_CallReplyMapElement(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) { |
5544 | if (callReplyGetMapElement(reply, idx, key, val) == C_OK){ |
5545 | return REDISMODULE_OK; |
5546 | } |
5547 | return REDISMODULE_ERR; |
5548 | } |
5549 | |
5550 | /* Return the attribute of the given reply, or NULL if no attribute exists. */ |
5551 | RedisModuleCallReply *RM_CallReplyAttribute(RedisModuleCallReply *reply) { |
5552 | return callReplyGetAttribute(reply); |
5553 | } |
5554 | |
5555 | /* Retrieve the 'idx'-th key and value of an attribute reply. |
5556 | * |
5557 | * Returns: |
5558 | * - REDISMODULE_OK on success. |
5559 | * - REDISMODULE_ERR if idx out of range or if the reply type is wrong. |
5560 | * |
5561 | * The `key` and `value` arguments are used to return by reference, and may be |
5562 | * NULL if not required. */ |
5563 | int RM_CallReplyAttributeElement(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) { |
5564 | if (callReplyGetAttributeElement(reply, idx, key, val) == C_OK){ |
5565 | return REDISMODULE_OK; |
5566 | } |
5567 | return REDISMODULE_ERR; |
5568 | } |
5569 | |
5570 | /* Return the pointer and length of a string or error reply. */ |
5571 | const char *RM_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len) { |
5572 | size_t private_len; |
5573 | if (!len) len = &private_len; |
5574 | return callReplyGetString(reply, len); |
5575 | } |
5576 | |
5577 | /* Return a new string object from a call reply of type string, error or |
5578 | * integer. Otherwise (wrong reply type) return NULL. */ |
5579 | RedisModuleString *RM_CreateStringFromCallReply(RedisModuleCallReply *reply) { |
5580 | RedisModuleCtx* ctx = callReplyGetPrivateData(reply); |
5581 | size_t len; |
5582 | const char *str; |
5583 | switch(callReplyType(reply)) { |
5584 | case REDISMODULE_REPLY_STRING: |
5585 | case REDISMODULE_REPLY_ERROR: |
5586 | str = callReplyGetString(reply, &len); |
5587 | return RM_CreateString(ctx, str, len); |
5588 | case REDISMODULE_REPLY_INTEGER: { |
5589 | char buf[64]; |
5590 | int len = ll2string(buf,sizeof(buf),callReplyGetLongLong(reply)); |
5591 | return RM_CreateString(ctx ,buf,len); |
5592 | } |
5593 | default: |
5594 | return NULL; |
5595 | } |
5596 | } |
5597 | |
5598 | /* Returns an array of robj pointers, by parsing the format specifier "fmt" as described for |
5599 | * the RM_Call(), RM_Replicate() and other module APIs. Populates *argcp with the number of |
5600 | * items and *argvlenp with the length of the allocated argv. |
5601 | * |
5602 | * The integer pointed by 'flags' is populated with flags according |
5603 | * to special modifiers in "fmt". |
5604 | * |
5605 | * "!" -> REDISMODULE_ARGV_REPLICATE |
5606 | * "A" -> REDISMODULE_ARGV_NO_AOF |
5607 | * "R" -> REDISMODULE_ARGV_NO_REPLICAS |
5608 | * "3" -> REDISMODULE_ARGV_RESP_3 |
5609 | * "0" -> REDISMODULE_ARGV_RESP_AUTO |
5610 | * "C" -> REDISMODULE_ARGV_CHECK_ACL |
5611 | * |
5612 | * On error (format specifier error) NULL is returned and nothing is |
5613 | * allocated. On success the argument vector is returned. */ |
5614 | robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int *argcp, int *argvlenp, int *flags, va_list ap) { |
5615 | int argc = 0, argv_size, j; |
5616 | robj **argv = NULL; |
5617 | |
5618 | /* As a first guess to avoid useless reallocations, size argv to |
5619 | * hold one argument for each char specifier in 'fmt'. */ |
5620 | argv_size = strlen(fmt)+1; /* +1 because of the command name. */ |
5621 | argv = zrealloc(argv,sizeof(robj*)*argv_size); |
5622 | |
5623 | /* Build the arguments vector based on the format specifier. */ |
5624 | argv[0] = createStringObject(cmdname,strlen(cmdname)); |
5625 | argc++; |
5626 | |
5627 | /* Create the client and dispatch the command. */ |
5628 | const char *p = fmt; |
5629 | while(*p) { |
5630 | if (*p == 'c') { |
5631 | char *cstr = va_arg(ap,char*); |
5632 | argv[argc++] = createStringObject(cstr,strlen(cstr)); |
5633 | } else if (*p == 's') { |
5634 | robj *obj = va_arg(ap,void*); |
5635 | if (obj->refcount == OBJ_STATIC_REFCOUNT) |
5636 | obj = createStringObject(obj->ptr,sdslen(obj->ptr)); |
5637 | else |
5638 | incrRefCount(obj); |
5639 | argv[argc++] = obj; |
5640 | } else if (*p == 'b') { |
5641 | char *buf = va_arg(ap,char*); |
5642 | size_t len = va_arg(ap,size_t); |
5643 | argv[argc++] = createStringObject(buf,len); |
5644 | } else if (*p == 'l') { |
5645 | long long ll = va_arg(ap,long long); |
5646 | argv[argc++] = createObject(OBJ_STRING,sdsfromlonglong(ll)); |
5647 | } else if (*p == 'v') { |
5648 | /* A vector of strings */ |
5649 | robj **v = va_arg(ap, void*); |
5650 | size_t vlen = va_arg(ap, size_t); |
5651 | |
5652 | /* We need to grow argv to hold the vector's elements. |
5653 | * We resize by vector_len-1 elements, because we held |
5654 | * one element in argv for the vector already */ |
5655 | argv_size += vlen-1; |
5656 | argv = zrealloc(argv,sizeof(robj*)*argv_size); |
5657 | |
5658 | size_t i = 0; |
5659 | for (i = 0; i < vlen; i++) { |
5660 | incrRefCount(v[i]); |
5661 | argv[argc++] = v[i]; |
5662 | } |
5663 | } else if (*p == '!') { |
5664 | if (flags) (*flags) |= REDISMODULE_ARGV_REPLICATE; |
5665 | } else if (*p == 'A') { |
5666 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_AOF; |
5667 | } else if (*p == 'R') { |
5668 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_REPLICAS; |
5669 | } else if (*p == '3') { |
5670 | if (flags) (*flags) |= REDISMODULE_ARGV_RESP_3; |
5671 | } else if (*p == '0') { |
5672 | if (flags) (*flags) |= REDISMODULE_ARGV_RESP_AUTO; |
5673 | } else if (*p == 'C') { |
5674 | if (flags) (*flags) |= REDISMODULE_ARGV_CHECK_ACL; |
5675 | } else if (*p == 'S') { |
5676 | if (flags) (*flags) |= REDISMODULE_ARGV_SCRIPT_MODE; |
5677 | } else if (*p == 'W') { |
5678 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_WRITES; |
5679 | } else if (*p == 'M') { |
5680 | if (flags) (*flags) |= REDISMODULE_ARGV_RESPECT_DENY_OOM; |
5681 | } else if (*p == 'E') { |
5682 | if (flags) (*flags) |= REDISMODULE_ARGV_CALL_REPLIES_AS_ERRORS; |
5683 | } else { |
5684 | goto fmterr; |
5685 | } |
5686 | p++; |
5687 | } |
5688 | if (argcp) *argcp = argc; |
5689 | if (argvlenp) *argvlenp = argv_size; |
5690 | return argv; |
5691 | |
5692 | fmterr: |
5693 | for (j = 0; j < argc; j++) |
5694 | decrRefCount(argv[j]); |
5695 | zfree(argv); |
5696 | return NULL; |
5697 | } |
5698 | |
5699 | /* Exported API to call any Redis command from modules. |
5700 | * |
5701 | * * **cmdname**: The Redis command to call. |
5702 | * * **fmt**: A format specifier string for the command's arguments. Each |
5703 | * of the arguments should be specified by a valid type specification. The |
5704 | * format specifier can also contain the modifiers `!`, `A`, `3` and `R` which |
5705 | * don't have a corresponding argument. |
5706 | * |
5707 | * * `b` -- The argument is a buffer and is immediately followed by another |
5708 | * argument that is the buffer's length. |
5709 | * * `c` -- The argument is a pointer to a plain C string (null-terminated). |
5710 | * * `l` -- The argument is a `long long` integer. |
5711 | * * `s` -- The argument is a RedisModuleString. |
5712 | * * `v` -- The argument(s) is a vector of RedisModuleString. |
5713 | * * `!` -- Sends the Redis command and its arguments to replicas and AOF. |
5714 | * * `A` -- Suppress AOF propagation, send only to replicas (requires `!`). |
5715 | * * `R` -- Suppress replicas propagation, send only to AOF (requires `!`). |
5716 | * * `3` -- Return a RESP3 reply. This will change the command reply. |
5717 | * e.g., HGETALL returns a map instead of a flat array. |
5718 | * * `0` -- Return the reply in auto mode, i.e. the reply format will be the |
5719 | * same as the client attached to the given RedisModuleCtx. This will |
5720 | * probably used when you want to pass the reply directly to the client. |
5721 | * * `C` -- Check if command can be executed according to ACL rules. |
5722 | * * `S` -- Run the command in a script mode, this means that it will raise |
5723 | * an error if a command which are not allowed inside a script |
5724 | * (flagged with the `deny-script` flag) is invoked (like SHUTDOWN). |
5725 | * In addition, on script mode, write commands are not allowed if there are |
5726 | * not enough good replicas (as configured with `min-replicas-to-write`) |
5727 | * or when the server is unable to persist to the disk. |
5728 | * * `W` -- Do not allow to run any write command (flagged with the `write` flag). |
5729 | * * `M` -- Do not allow `deny-oom` flagged commands when over the memory limit. |
5730 | * * `E` -- Return error as RedisModuleCallReply. If there is an error before |
5731 | * invoking the command, the error is returned using errno mechanism. |
5732 | * This flag allows to get the error also as an error CallReply with |
5733 | * relevant error message. |
5734 | * * **...**: The actual arguments to the Redis command. |
5735 | * |
5736 | * On success a RedisModuleCallReply object is returned, otherwise |
5737 | * NULL is returned and errno is set to the following values: |
5738 | * |
5739 | * * EBADF: wrong format specifier. |
5740 | * * EINVAL: wrong command arity. |
5741 | * * ENOENT: command does not exist. |
5742 | * * EPERM: operation in Cluster instance with key in non local slot. |
5743 | * * EROFS: operation in Cluster instance when a write command is sent |
5744 | * in a readonly state. |
5745 | * * ENETDOWN: operation in Cluster instance when cluster is down. |
5746 | * * ENOTSUP: No ACL user for the specified module context |
5747 | * * EACCES: Command cannot be executed, according to ACL rules |
5748 | * * ENOSPC: Write or deny-oom command is not allowed |
5749 | * * ESPIPE: Command not allowed on script mode |
5750 | * |
5751 | * Example code fragment: |
5752 | * |
5753 | * reply = RedisModule_Call(ctx,"INCRBY","sc",argv[1],"10"); |
5754 | * if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_INTEGER) { |
5755 | * long long myval = RedisModule_CallReplyInteger(reply); |
5756 | * // Do something with myval. |
5757 | * } |
5758 | * |
5759 | * This API is documented here: https://redis.io/topics/modules-intro |
5760 | */ |
5761 | RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) { |
5762 | struct redisCommand *cmd; |
5763 | client *c = NULL; |
5764 | robj **argv = NULL; |
5765 | int argc = 0, argv_len = 0, flags = 0; |
5766 | va_list ap; |
5767 | RedisModuleCallReply *reply = NULL; |
5768 | int replicate = 0; /* Replicate this command? */ |
5769 | int error_as_call_replies = 0; /* return errors as RedisModuleCallReply object */ |
5770 | |
5771 | /* Handle arguments. */ |
5772 | va_start(ap, fmt); |
5773 | argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,&argv_len,&flags,ap); |
5774 | replicate = flags & REDISMODULE_ARGV_REPLICATE; |
5775 | error_as_call_replies = flags & REDISMODULE_ARGV_CALL_REPLIES_AS_ERRORS; |
5776 | va_end(ap); |
5777 | |
5778 | c = moduleAllocTempClient(); |
5779 | |
5780 | /* We do not want to allow block, the module do not expect it */ |
5781 | c->flags |= CLIENT_DENY_BLOCKING; |
5782 | c->db = ctx->client->db; |
5783 | c->argv = argv; |
5784 | c->argc = argc; |
5785 | c->argv_len = argv_len; |
5786 | c->resp = 2; |
5787 | if (flags & REDISMODULE_ARGV_RESP_3) { |
5788 | c->resp = 3; |
5789 | } else if (flags & REDISMODULE_ARGV_RESP_AUTO) { |
5790 | /* Auto mode means to take the same protocol as the ctx client. */ |
5791 | c->resp = ctx->client->resp; |
5792 | } |
5793 | if (ctx->module) ctx->module->in_call++; |
5794 | |
5795 | /* We handle the above format error only when the client is setup so that |
5796 | * we can free it normally. */ |
5797 | if (argv == NULL) { |
5798 | /* We do not return a call reply here this is an error that should only |
5799 | * be catch by the module indicating wrong fmt was given, the module should |
5800 | * handle this error and decide how to continue. It is not an error that |
5801 | * should be propagated to the user. */ |
5802 | errno = EBADF; |
5803 | goto cleanup; |
5804 | } |
5805 | |
5806 | /* Call command filters */ |
5807 | moduleCallCommandFilters(c); |
5808 | |
5809 | /* Lookup command now, after filters had a chance to make modifications |
5810 | * if necessary. |
5811 | */ |
5812 | cmd = c->cmd = c->lastcmd = c->realcmd = lookupCommand(c->argv,c->argc); |
5813 | sds err; |
5814 | if (!commandCheckExistence(c, error_as_call_replies? &err : NULL)) { |
5815 | errno = ENOENT; |
5816 | if (error_as_call_replies) |
5817 | reply = callReplyCreateError(err, ctx); |
5818 | goto cleanup; |
5819 | } |
5820 | if (!commandCheckArity(c, error_as_call_replies? &err : NULL)) { |
5821 | errno = EINVAL; |
5822 | if (error_as_call_replies) |
5823 | reply = callReplyCreateError(err, ctx); |
5824 | goto cleanup; |
5825 | } |
5826 | |
5827 | if (flags & REDISMODULE_ARGV_SCRIPT_MODE) { |
5828 | /* Basically on script mode we want to only allow commands that can |
5829 | * be executed on scripts (CMD_NOSCRIPT is not set on the command flags) */ |
5830 | if (cmd->flags & CMD_NOSCRIPT) { |
5831 | errno = ESPIPE; |
5832 | if (error_as_call_replies) { |
5833 | sds msg = sdscatfmt(sdsempty(), "command '%S' is not allowed on script mode" , c->cmd->fullname); |
5834 | reply = callReplyCreateError(msg, ctx); |
5835 | } |
5836 | goto cleanup; |
5837 | } |
5838 | } |
5839 | |
5840 | if (flags & REDISMODULE_ARGV_RESPECT_DENY_OOM) { |
5841 | if (cmd->flags & CMD_DENYOOM) { |
5842 | int oom_state; |
5843 | if (ctx->flags & REDISMODULE_CTX_THREAD_SAFE) { |
5844 | /* On background thread we can not count on server.pre_command_oom_state. |
5845 | * Because it is only set on the main thread, in such case we will check |
5846 | * the actual memory usage. */ |
5847 | oom_state = (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_ERR); |
5848 | } else { |
5849 | oom_state = server.pre_command_oom_state; |
5850 | } |
5851 | if (oom_state) { |
5852 | errno = ENOSPC; |
5853 | if (error_as_call_replies) { |
5854 | sds msg = sdsdup(shared.oomerr->ptr); |
5855 | reply = callReplyCreateError(msg, ctx); |
5856 | } |
5857 | goto cleanup; |
5858 | } |
5859 | } |
5860 | } |
5861 | |
5862 | if (flags & REDISMODULE_ARGV_NO_WRITES) { |
5863 | if (cmd->flags & CMD_WRITE) { |
5864 | errno = ENOSPC; |
5865 | if (error_as_call_replies) { |
5866 | sds msg = sdscatfmt(sdsempty(), "Write command '%S' was " |
5867 | "called while write is not allowed." , c->cmd->fullname); |
5868 | reply = callReplyCreateError(msg, ctx); |
5869 | } |
5870 | goto cleanup; |
5871 | } |
5872 | } |
5873 | |
5874 | /* Script mode tests */ |
5875 | if (flags & REDISMODULE_ARGV_SCRIPT_MODE) { |
5876 | if (cmd->flags & CMD_WRITE) { |
5877 | /* on script mode, if a command is a write command, |
5878 | * We will not run it if we encounter disk error |
5879 | * or we do not have enough replicas */ |
5880 | |
5881 | if (!checkGoodReplicasStatus()) { |
5882 | errno = ESPIPE; |
5883 | if (error_as_call_replies) { |
5884 | sds msg = sdsdup(shared.noreplicaserr->ptr); |
5885 | reply = callReplyCreateError(msg, ctx); |
5886 | } |
5887 | goto cleanup; |
5888 | } |
5889 | |
5890 | int deny_write_type = writeCommandsDeniedByDiskError(); |
5891 | int obey_client = (server.current_client && mustObeyClient(server.current_client)); |
5892 | |
5893 | if (deny_write_type != DISK_ERROR_TYPE_NONE && !obey_client) { |
5894 | errno = ESPIPE; |
5895 | if (error_as_call_replies) { |
5896 | sds msg = writeCommandsGetDiskErrorMessage(deny_write_type); |
5897 | reply = callReplyCreateError(msg, ctx); |
5898 | } |
5899 | goto cleanup; |
5900 | } |
5901 | |
5902 | if (server.masterhost && server.repl_slave_ro && !obey_client) { |
5903 | errno = ESPIPE; |
5904 | if (error_as_call_replies) { |
5905 | sds msg = sdsdup(shared.roslaveerr->ptr); |
5906 | reply = callReplyCreateError(msg, ctx); |
5907 | } |
5908 | goto cleanup; |
5909 | } |
5910 | } |
5911 | |
5912 | if (server.masterhost && server.repl_state != REPL_STATE_CONNECTED && |
5913 | server.repl_serve_stale_data == 0 && !(cmd->flags & CMD_STALE)) { |
5914 | errno = ESPIPE; |
5915 | if (error_as_call_replies) { |
5916 | sds msg = sdsdup(shared.masterdownerr->ptr); |
5917 | reply = callReplyCreateError(msg, ctx); |
5918 | } |
5919 | goto cleanup; |
5920 | } |
5921 | } |
5922 | |
5923 | /* Check if the user can run this command according to the current |
5924 | * ACLs. */ |
5925 | if (flags & REDISMODULE_ARGV_CHECK_ACL) { |
5926 | int acl_errpos; |
5927 | int acl_retval; |
5928 | |
5929 | if (ctx->client->user == NULL) { |
5930 | errno = ENOTSUP; |
5931 | if (error_as_call_replies) { |
5932 | sds msg = sdsnew("acl verification failed, context is not attached to a client." ); |
5933 | reply = callReplyCreateError(msg, ctx); |
5934 | } |
5935 | goto cleanup; |
5936 | } |
5937 | acl_retval = ACLCheckAllUserCommandPerm(ctx->client->user,c->cmd,c->argv,c->argc,&acl_errpos); |
5938 | if (acl_retval != ACL_OK) { |
5939 | sds object = (acl_retval == ACL_DENIED_CMD) ? sdsdup(c->cmd->fullname) : sdsdup(c->argv[acl_errpos]->ptr); |
5940 | addACLLogEntry(ctx->client, acl_retval, ACL_LOG_CTX_MODULE, -1, ctx->client->user->name, object); |
5941 | if (error_as_call_replies) { |
5942 | sds msg = sdscatfmt(sdsempty(), "acl verification failed, %s." , getAclErrorMessage(acl_retval)); |
5943 | reply = callReplyCreateError(msg, ctx); |
5944 | } |
5945 | errno = EACCES; |
5946 | goto cleanup; |
5947 | } |
5948 | } |
5949 | |
5950 | /* If this is a Redis Cluster node, we need to make sure the module is not |
5951 | * trying to access non-local keys, with the exception of commands |
5952 | * received from our master. */ |
5953 | if (server.cluster_enabled && !mustObeyClient(ctx->client)) { |
5954 | int error_code; |
5955 | /* Duplicate relevant flags in the module client. */ |
5956 | c->flags &= ~(CLIENT_READONLY|CLIENT_ASKING); |
5957 | c->flags |= ctx->client->flags & (CLIENT_READONLY|CLIENT_ASKING); |
5958 | if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,&error_code) != |
5959 | server.cluster->myself) |
5960 | { |
5961 | sds msg = NULL; |
5962 | if (error_code == CLUSTER_REDIR_DOWN_RO_STATE) { |
5963 | if (error_as_call_replies) { |
5964 | msg = sdscatfmt(sdsempty(), "Can not execute a write command '%S' while the cluster is down and readonly" , c->cmd->fullname); |
5965 | } |
5966 | errno = EROFS; |
5967 | } else if (error_code == CLUSTER_REDIR_DOWN_STATE) { |
5968 | if (error_as_call_replies) { |
5969 | msg = sdscatfmt(sdsempty(), "Can not execute a command '%S' while the cluster is down" , c->cmd->fullname); |
5970 | } |
5971 | errno = ENETDOWN; |
5972 | } else { |
5973 | if (error_as_call_replies) { |
5974 | msg = sdsnew("Attempted to access a non local key in a cluster node" ); |
5975 | } |
5976 | errno = EPERM; |
5977 | } |
5978 | if (msg) { |
5979 | reply = callReplyCreateError(msg, ctx); |
5980 | } |
5981 | goto cleanup; |
5982 | } |
5983 | } |
5984 | |
5985 | /* We need to use a global replication_allowed flag in order to prevent |
5986 | * replication of nested RM_Calls. Example: |
5987 | * 1. module1.foo does RM_Call of module2.bar without replication (i.e. no '!') |
5988 | * 2. module2.bar internally calls RM_Call of INCR with '!' |
5989 | * 3. at the end of module1.foo we call RM_ReplicateVerbatim |
5990 | * We want the replica/AOF to see only module1.foo and not the INCR from module2.bar */ |
5991 | int prev_replication_allowed = server.replication_allowed; |
5992 | server.replication_allowed = replicate && server.replication_allowed; |
5993 | |
5994 | /* Run the command */ |
5995 | int call_flags = CMD_CALL_SLOWLOG | CMD_CALL_STATS | CMD_CALL_FROM_MODULE; |
5996 | if (replicate) { |
5997 | if (!(flags & REDISMODULE_ARGV_NO_AOF)) |
5998 | call_flags |= CMD_CALL_PROPAGATE_AOF; |
5999 | if (!(flags & REDISMODULE_ARGV_NO_REPLICAS)) |
6000 | call_flags |= CMD_CALL_PROPAGATE_REPL; |
6001 | } |
6002 | call(c,call_flags); |
6003 | server.replication_allowed = prev_replication_allowed; |
6004 | |
6005 | serverAssert((c->flags & CLIENT_BLOCKED) == 0); |
6006 | |
6007 | /* Convert the result of the Redis command into a module reply. */ |
6008 | sds proto = sdsnewlen(c->buf,c->bufpos); |
6009 | c->bufpos = 0; |
6010 | while(listLength(c->reply)) { |
6011 | clientReplyBlock *o = listNodeValue(listFirst(c->reply)); |
6012 | |
6013 | proto = sdscatlen(proto,o->buf,o->used); |
6014 | listDelNode(c->reply,listFirst(c->reply)); |
6015 | } |
6016 | reply = callReplyCreate(proto, c->deferred_reply_errors, ctx); |
6017 | c->deferred_reply_errors = NULL; /* now the responsibility of the reply object. */ |
6018 | |
6019 | cleanup: |
6020 | if (reply) autoMemoryAdd(ctx,REDISMODULE_AM_REPLY,reply); |
6021 | if (ctx->module) ctx->module->in_call--; |
6022 | moduleReleaseTempClient(c); |
6023 | return reply; |
6024 | } |
6025 | |
6026 | /* Return a pointer, and a length, to the protocol returned by the command |
6027 | * that returned the reply object. */ |
6028 | const char *RM_CallReplyProto(RedisModuleCallReply *reply, size_t *len) { |
6029 | return callReplyGetProto(reply, len); |
6030 | } |
6031 | |
6032 | /* -------------------------------------------------------------------------- |
6033 | * ## Modules data types |
6034 | * |
6035 | * When String DMA or using existing data structures is not enough, it is |
6036 | * possible to create new data types from scratch and export them to |
6037 | * Redis. The module must provide a set of callbacks for handling the |
6038 | * new values exported (for example in order to provide RDB saving/loading, |
6039 | * AOF rewrite, and so forth). In this section we define this API. |
6040 | * -------------------------------------------------------------------------- */ |
6041 | |
6042 | /* Turn a 9 chars name in the specified charset and a 10 bit encver into |
6043 | * a single 64 bit unsigned integer that represents this exact module name |
6044 | * and version. This final number is called a "type ID" and is used when |
6045 | * writing module exported values to RDB files, in order to re-associate the |
6046 | * value to the right module to load them during RDB loading. |
6047 | * |
6048 | * If the string is not of the right length or the charset is wrong, or |
6049 | * if encver is outside the unsigned 10 bit integer range, 0 is returned, |
6050 | * otherwise the function returns the right type ID. |
6051 | * |
6052 | * The resulting 64 bit integer is composed as follows: |
6053 | * |
6054 | * (high order bits) 6|6|6|6|6|6|6|6|6|10 (low order bits) |
6055 | * |
6056 | * The first 6 bits value is the first character, name[0], while the last |
6057 | * 6 bits value, immediately before the 10 bits integer, is name[8]. |
6058 | * The last 10 bits are the encoding version. |
6059 | * |
6060 | * Note that a name and encver combo of "AAAAAAAAA" and 0, will produce |
6061 | * zero as return value, that is the same we use to signal errors, thus |
6062 | * this combination is invalid, and also useless since type names should |
6063 | * try to be vary to avoid collisions. */ |
6064 | |
6065 | const char *ModuleTypeNameCharSet = |
6066 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
6067 | "abcdefghijklmnopqrstuvwxyz" |
6068 | "0123456789-_" ; |
6069 | |
6070 | uint64_t moduleTypeEncodeId(const char *name, int encver) { |
6071 | /* We use 64 symbols so that we can map each character into 6 bits |
6072 | * of the final output. */ |
6073 | const char *cset = ModuleTypeNameCharSet; |
6074 | if (strlen(name) != 9) return 0; |
6075 | if (encver < 0 || encver > 1023) return 0; |
6076 | |
6077 | uint64_t id = 0; |
6078 | for (int j = 0; j < 9; j++) { |
6079 | char *p = strchr(cset,name[j]); |
6080 | if (!p) return 0; |
6081 | unsigned long pos = p-cset; |
6082 | id = (id << 6) | pos; |
6083 | } |
6084 | id = (id << 10) | encver; |
6085 | return id; |
6086 | } |
6087 | |
6088 | /* Search, in the list of exported data types of all the modules registered, |
6089 | * a type with the same name as the one given. Returns the moduleType |
6090 | * structure pointer if such a module is found, or NULL otherwise. */ |
6091 | moduleType *moduleTypeLookupModuleByName(const char *name) { |
6092 | dictIterator *di = dictGetIterator(modules); |
6093 | dictEntry *de; |
6094 | |
6095 | while ((de = dictNext(di)) != NULL) { |
6096 | struct RedisModule *module = dictGetVal(de); |
6097 | listIter li; |
6098 | listNode *ln; |
6099 | |
6100 | listRewind(module->types,&li); |
6101 | while((ln = listNext(&li))) { |
6102 | moduleType *mt = ln->value; |
6103 | if (memcmp(name,mt->name,sizeof(mt->name)) == 0) { |
6104 | dictReleaseIterator(di); |
6105 | return mt; |
6106 | } |
6107 | } |
6108 | } |
6109 | dictReleaseIterator(di); |
6110 | return NULL; |
6111 | } |
6112 | |
6113 | /* Lookup a module by ID, with caching. This function is used during RDB |
6114 | * loading. Modules exporting data types should never be able to unload, so |
6115 | * our cache does not need to expire. */ |
6116 | #define MODULE_LOOKUP_CACHE_SIZE 3 |
6117 | |
6118 | moduleType *moduleTypeLookupModuleByID(uint64_t id) { |
6119 | static struct { |
6120 | uint64_t id; |
6121 | moduleType *mt; |
6122 | } cache[MODULE_LOOKUP_CACHE_SIZE]; |
6123 | |
6124 | /* Search in cache to start. */ |
6125 | int j; |
6126 | for (j = 0; j < MODULE_LOOKUP_CACHE_SIZE && cache[j].mt != NULL; j++) |
6127 | if (cache[j].id == id) return cache[j].mt; |
6128 | |
6129 | /* Slow module by module lookup. */ |
6130 | moduleType *mt = NULL; |
6131 | dictIterator *di = dictGetIterator(modules); |
6132 | dictEntry *de; |
6133 | |
6134 | while ((de = dictNext(di)) != NULL && mt == NULL) { |
6135 | struct RedisModule *module = dictGetVal(de); |
6136 | listIter li; |
6137 | listNode *ln; |
6138 | |
6139 | listRewind(module->types,&li); |
6140 | while((ln = listNext(&li))) { |
6141 | moduleType *this_mt = ln->value; |
6142 | /* Compare only the 54 bit module identifier and not the |
6143 | * encoding version. */ |
6144 | if (this_mt->id >> 10 == id >> 10) { |
6145 | mt = this_mt; |
6146 | break; |
6147 | } |
6148 | } |
6149 | } |
6150 | dictReleaseIterator(di); |
6151 | |
6152 | /* Add to cache if possible. */ |
6153 | if (mt && j < MODULE_LOOKUP_CACHE_SIZE) { |
6154 | cache[j].id = id; |
6155 | cache[j].mt = mt; |
6156 | } |
6157 | return mt; |
6158 | } |
6159 | |
6160 | /* Turn an (unresolved) module ID into a type name, to show the user an |
6161 | * error when RDB files contain module data we can't load. |
6162 | * The buffer pointed by 'name' must be 10 bytes at least. The function will |
6163 | * fill it with a null terminated module name. */ |
6164 | void moduleTypeNameByID(char *name, uint64_t moduleid) { |
6165 | const char *cset = ModuleTypeNameCharSet; |
6166 | |
6167 | name[9] = '\0'; |
6168 | char *p = name+8; |
6169 | moduleid >>= 10; |
6170 | for (int j = 0; j < 9; j++) { |
6171 | *p-- = cset[moduleid & 63]; |
6172 | moduleid >>= 6; |
6173 | } |
6174 | } |
6175 | |
6176 | /* Return the name of the module that owns the specified moduleType. */ |
6177 | const char *moduleTypeModuleName(moduleType *mt) { |
6178 | if (!mt || !mt->module) return NULL; |
6179 | return mt->module->name; |
6180 | } |
6181 | |
6182 | /* Return the module name from a module command */ |
6183 | const char *moduleNameFromCommand(struct redisCommand *cmd) { |
6184 | serverAssert(cmd->proc == RedisModuleCommandDispatcher); |
6185 | |
6186 | RedisModuleCommand *cp = cmd->module_cmd; |
6187 | return cp->module->name; |
6188 | } |
6189 | |
6190 | /* Create a copy of a module type value using the copy callback. If failed |
6191 | * or not supported, produce an error reply and return NULL. |
6192 | */ |
6193 | robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj *value) { |
6194 | moduleValue *mv = value->ptr; |
6195 | moduleType *mt = mv->type; |
6196 | if (!mt->copy && !mt->copy2) { |
6197 | addReplyError(c, "not supported for this module key" ); |
6198 | return NULL; |
6199 | } |
6200 | void *newval = NULL; |
6201 | if (mt->copy2 != NULL) { |
6202 | RedisModuleKeyOptCtx ctx = {fromkey, tokey, c->db->id, todb}; |
6203 | newval = mt->copy2(&ctx, mv->value); |
6204 | } else { |
6205 | newval = mt->copy(fromkey, tokey, mv->value); |
6206 | } |
6207 | |
6208 | if (!newval) { |
6209 | addReplyError(c, "module key failed to copy" ); |
6210 | return NULL; |
6211 | } |
6212 | return createModuleObject(mt, newval); |
6213 | } |
6214 | |
6215 | /* Register a new data type exported by the module. The parameters are the |
6216 | * following. Please for in depth documentation check the modules API |
6217 | * documentation, especially https://redis.io/topics/modules-native-types. |
6218 | * |
6219 | * * **name**: A 9 characters data type name that MUST be unique in the Redis |
6220 | * Modules ecosystem. Be creative... and there will be no collisions. Use |
6221 | * the charset A-Z a-z 9-0, plus the two "-_" characters. A good |
6222 | * idea is to use, for example `<typename>-<vendor>`. For example |
6223 | * "tree-AntZ" may mean "Tree data structure by @antirez". To use both |
6224 | * lower case and upper case letters helps in order to prevent collisions. |
6225 | * * **encver**: Encoding version, which is, the version of the serialization |
6226 | * that a module used in order to persist data. As long as the "name" |
6227 | * matches, the RDB loading will be dispatched to the type callbacks |
6228 | * whatever 'encver' is used, however the module can understand if |
6229 | * the encoding it must load are of an older version of the module. |
6230 | * For example the module "tree-AntZ" initially used encver=0. Later |
6231 | * after an upgrade, it started to serialize data in a different format |
6232 | * and to register the type with encver=1. However this module may |
6233 | * still load old data produced by an older version if the rdb_load |
6234 | * callback is able to check the encver value and act accordingly. |
6235 | * The encver must be a positive value between 0 and 1023. |
6236 | * |
6237 | * * **typemethods_ptr** is a pointer to a RedisModuleTypeMethods structure |
6238 | * that should be populated with the methods callbacks and structure |
6239 | * version, like in the following example: |
6240 | * |
6241 | * RedisModuleTypeMethods tm = { |
6242 | * .version = REDISMODULE_TYPE_METHOD_VERSION, |
6243 | * .rdb_load = myType_RDBLoadCallBack, |
6244 | * .rdb_save = myType_RDBSaveCallBack, |
6245 | * .aof_rewrite = myType_AOFRewriteCallBack, |
6246 | * .free = myType_FreeCallBack, |
6247 | * |
6248 | * // Optional fields |
6249 | * .digest = myType_DigestCallBack, |
6250 | * .mem_usage = myType_MemUsageCallBack, |
6251 | * .aux_load = myType_AuxRDBLoadCallBack, |
6252 | * .aux_save = myType_AuxRDBSaveCallBack, |
6253 | * .free_effort = myType_FreeEffortCallBack, |
6254 | * .unlink = myType_UnlinkCallBack, |
6255 | * .copy = myType_CopyCallback, |
6256 | * .defrag = myType_DefragCallback |
6257 | * |
6258 | * // Enhanced optional fields |
6259 | * .mem_usage2 = myType_MemUsageCallBack2, |
6260 | * .free_effort2 = myType_FreeEffortCallBack2, |
6261 | * .unlink2 = myType_UnlinkCallBack2, |
6262 | * .copy2 = myType_CopyCallback2, |
6263 | * } |
6264 | * |
6265 | * * **rdb_load**: A callback function pointer that loads data from RDB files. |
6266 | * * **rdb_save**: A callback function pointer that saves data to RDB files. |
6267 | * * **aof_rewrite**: A callback function pointer that rewrites data as commands. |
6268 | * * **digest**: A callback function pointer that is used for `DEBUG DIGEST`. |
6269 | * * **free**: A callback function pointer that can free a type value. |
6270 | * * **aux_save**: A callback function pointer that saves out of keyspace data to RDB files. |
6271 | * 'when' argument is either REDISMODULE_AUX_BEFORE_RDB or REDISMODULE_AUX_AFTER_RDB. |
6272 | * * **aux_load**: A callback function pointer that loads out of keyspace data from RDB files. |
6273 | * Similar to aux_save, returns REDISMODULE_OK on success, and ERR otherwise. |
6274 | * * **free_effort**: A callback function pointer that used to determine whether the module's |
6275 | * memory needs to be lazy reclaimed. The module should return the complexity involved by |
6276 | * freeing the value. for example: how many pointers are gonna be freed. Note that if it |
6277 | * returns 0, we'll always do an async free. |
6278 | * * **unlink**: A callback function pointer that used to notifies the module that the key has |
6279 | * been removed from the DB by redis, and may soon be freed by a background thread. Note that |
6280 | * it won't be called on FLUSHALL/FLUSHDB (both sync and async), and the module can use the |
6281 | * RedisModuleEvent_FlushDB to hook into that. |
6282 | * * **copy**: A callback function pointer that is used to make a copy of the specified key. |
6283 | * The module is expected to perform a deep copy of the specified value and return it. |
6284 | * In addition, hints about the names of the source and destination keys is provided. |
6285 | * A NULL return value is considered an error and the copy operation fails. |
6286 | * Note: if the target key exists and is being overwritten, the copy callback will be |
6287 | * called first, followed by a free callback to the value that is being replaced. |
6288 | * |
6289 | * * **defrag**: A callback function pointer that is used to request the module to defrag |
6290 | * a key. The module should then iterate pointers and call the relevant RM_Defrag*() |
6291 | * functions to defragment pointers or complex types. The module should continue |
6292 | * iterating as long as RM_DefragShouldStop() returns a zero value, and return a |
6293 | * zero value if finished or non-zero value if more work is left to be done. If more work |
6294 | * needs to be done, RM_DefragCursorSet() and RM_DefragCursorGet() can be used to track |
6295 | * this work across different calls. |
6296 | * Normally, the defrag mechanism invokes the callback without a time limit, so |
6297 | * RM_DefragShouldStop() always returns zero. The "late defrag" mechanism which has |
6298 | * a time limit and provides cursor support is used only for keys that are determined |
6299 | * to have significant internal complexity. To determine this, the defrag mechanism |
6300 | * uses the free_effort callback and the 'active-defrag-max-scan-fields' config directive. |
6301 | * NOTE: The value is passed as a `void**` and the function is expected to update the |
6302 | * pointer if the top-level value pointer is defragmented and consequently changes. |
6303 | * |
6304 | * * **mem_usage2**: Similar to `mem_usage`, but provides the `RedisModuleKeyOptCtx` parameter |
6305 | * so that meta information such as key name and db id can be obtained, and |
6306 | * the `sample_size` for size estimation (see MEMORY USAGE command). |
6307 | * * **free_effort2**: Similar to `free_effort`, but provides the `RedisModuleKeyOptCtx` parameter |
6308 | * so that meta information such as key name and db id can be obtained. |
6309 | * * **unlink2**: Similar to `unlink`, but provides the `RedisModuleKeyOptCtx` parameter |
6310 | * so that meta information such as key name and db id can be obtained. |
6311 | * * **copy2**: Similar to `copy`, but provides the `RedisModuleKeyOptCtx` parameter |
6312 | * so that meta information such as key names and db ids can be obtained. |
6313 | * |
6314 | * Note: the module name "AAAAAAAAA" is reserved and produces an error, it |
6315 | * happens to be pretty lame as well. |
6316 | * |
6317 | * If there is already a module registering a type with the same name, |
6318 | * and if the module name or encver is invalid, NULL is returned. |
6319 | * Otherwise the new type is registered into Redis, and a reference of |
6320 | * type RedisModuleType is returned: the caller of the function should store |
6321 | * this reference into a global variable to make future use of it in the |
6322 | * modules type API, since a single module may register multiple types. |
6323 | * Example code fragment: |
6324 | * |
6325 | * static RedisModuleType *BalancedTreeType; |
6326 | * |
6327 | * int RedisModule_OnLoad(RedisModuleCtx *ctx) { |
6328 | * // some code here ... |
6329 | * BalancedTreeType = RM_CreateDataType(...); |
6330 | * } |
6331 | */ |
6332 | moduleType *RM_CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, void *typemethods_ptr) { |
6333 | uint64_t id = moduleTypeEncodeId(name,encver); |
6334 | if (id == 0) return NULL; |
6335 | if (moduleTypeLookupModuleByName(name) != NULL) return NULL; |
6336 | |
6337 | long typemethods_version = ((long*)typemethods_ptr)[0]; |
6338 | if (typemethods_version == 0) return NULL; |
6339 | |
6340 | struct typemethods { |
6341 | uint64_t version; |
6342 | moduleTypeLoadFunc rdb_load; |
6343 | moduleTypeSaveFunc rdb_save; |
6344 | moduleTypeRewriteFunc aof_rewrite; |
6345 | moduleTypeMemUsageFunc mem_usage; |
6346 | moduleTypeDigestFunc digest; |
6347 | moduleTypeFreeFunc free; |
6348 | struct { |
6349 | moduleTypeAuxLoadFunc aux_load; |
6350 | moduleTypeAuxSaveFunc aux_save; |
6351 | int aux_save_triggers; |
6352 | } v2; |
6353 | struct { |
6354 | moduleTypeFreeEffortFunc free_effort; |
6355 | moduleTypeUnlinkFunc unlink; |
6356 | moduleTypeCopyFunc copy; |
6357 | moduleTypeDefragFunc defrag; |
6358 | } v3; |
6359 | struct { |
6360 | moduleTypeMemUsageFunc2 mem_usage2; |
6361 | moduleTypeFreeEffortFunc2 free_effort2; |
6362 | moduleTypeUnlinkFunc2 unlink2; |
6363 | moduleTypeCopyFunc2 copy2; |
6364 | } v4; |
6365 | } *tms = (struct typemethods*) typemethods_ptr; |
6366 | |
6367 | moduleType *mt = zcalloc(sizeof(*mt)); |
6368 | mt->id = id; |
6369 | mt->module = ctx->module; |
6370 | mt->rdb_load = tms->rdb_load; |
6371 | mt->rdb_save = tms->rdb_save; |
6372 | mt->aof_rewrite = tms->aof_rewrite; |
6373 | mt->mem_usage = tms->mem_usage; |
6374 | mt->digest = tms->digest; |
6375 | mt->free = tms->free; |
6376 | if (tms->version >= 2) { |
6377 | mt->aux_load = tms->v2.aux_load; |
6378 | mt->aux_save = tms->v2.aux_save; |
6379 | mt->aux_save_triggers = tms->v2.aux_save_triggers; |
6380 | } |
6381 | if (tms->version >= 3) { |
6382 | mt->free_effort = tms->v3.free_effort; |
6383 | mt->unlink = tms->v3.unlink; |
6384 | mt->copy = tms->v3.copy; |
6385 | mt->defrag = tms->v3.defrag; |
6386 | } |
6387 | if (tms->version >= 4) { |
6388 | mt->mem_usage2 = tms->v4.mem_usage2; |
6389 | mt->unlink2 = tms->v4.unlink2; |
6390 | mt->free_effort2 = tms->v4.free_effort2; |
6391 | mt->copy2 = tms->v4.copy2; |
6392 | } |
6393 | memcpy(mt->name,name,sizeof(mt->name)); |
6394 | listAddNodeTail(ctx->module->types,mt); |
6395 | return mt; |
6396 | } |
6397 | |
6398 | /* If the key is open for writing, set the specified module type object |
6399 | * as the value of the key, deleting the old value if any. |
6400 | * On success REDISMODULE_OK is returned. If the key is not open for |
6401 | * writing or there is an active iterator, REDISMODULE_ERR is returned. */ |
6402 | int RM_ModuleTypeSetValue(RedisModuleKey *key, moduleType *mt, void *value) { |
6403 | if (!(key->mode & REDISMODULE_WRITE) || key->iter) return REDISMODULE_ERR; |
6404 | RM_DeleteKey(key); |
6405 | robj *o = createModuleObject(mt,value); |
6406 | setKey(key->ctx->client,key->db,key->key,o,SETKEY_NO_SIGNAL); |
6407 | decrRefCount(o); |
6408 | key->value = o; |
6409 | return REDISMODULE_OK; |
6410 | } |
6411 | |
6412 | /* Assuming RedisModule_KeyType() returned REDISMODULE_KEYTYPE_MODULE on |
6413 | * the key, returns the module type pointer of the value stored at key. |
6414 | * |
6415 | * If the key is NULL, is not associated with a module type, or is empty, |
6416 | * then NULL is returned instead. */ |
6417 | moduleType *RM_ModuleTypeGetType(RedisModuleKey *key) { |
6418 | if (key == NULL || |
6419 | key->value == NULL || |
6420 | RM_KeyType(key) != REDISMODULE_KEYTYPE_MODULE) return NULL; |
6421 | moduleValue *mv = key->value->ptr; |
6422 | return mv->type; |
6423 | } |
6424 | |
6425 | /* Assuming RedisModule_KeyType() returned REDISMODULE_KEYTYPE_MODULE on |
6426 | * the key, returns the module type low-level value stored at key, as |
6427 | * it was set by the user via RedisModule_ModuleTypeSetValue(). |
6428 | * |
6429 | * If the key is NULL, is not associated with a module type, or is empty, |
6430 | * then NULL is returned instead. */ |
6431 | void *RM_ModuleTypeGetValue(RedisModuleKey *key) { |
6432 | if (key == NULL || |
6433 | key->value == NULL || |
6434 | RM_KeyType(key) != REDISMODULE_KEYTYPE_MODULE) return NULL; |
6435 | moduleValue *mv = key->value->ptr; |
6436 | return mv->value; |
6437 | } |
6438 | |
6439 | /* -------------------------------------------------------------------------- |
6440 | * ## RDB loading and saving functions |
6441 | * -------------------------------------------------------------------------- */ |
6442 | |
6443 | /* Called when there is a load error in the context of a module. On some |
6444 | * modules this cannot be recovered, but if the module declared capability |
6445 | * to handle errors, we'll raise a flag rather than exiting. */ |
6446 | void moduleRDBLoadError(RedisModuleIO *io) { |
6447 | if (io->type->module->options & REDISMODULE_OPTIONS_HANDLE_IO_ERRORS) { |
6448 | io->error = 1; |
6449 | return; |
6450 | } |
6451 | serverPanic( |
6452 | "Error loading data from RDB (short read or EOF). " |
6453 | "Read performed by module '%s' about type '%s' " |
6454 | "after reading '%llu' bytes of a value " |
6455 | "for key named: '%s'." , |
6456 | io->type->module->name, |
6457 | io->type->name, |
6458 | (unsigned long long)io->bytes, |
6459 | io->key? (char*)io->key->ptr: "(null)" ); |
6460 | } |
6461 | |
6462 | /* Returns 0 if there's at least one registered data type that did not declare |
6463 | * REDISMODULE_OPTIONS_HANDLE_IO_ERRORS, in which case diskless loading should |
6464 | * be avoided since it could cause data loss. */ |
6465 | int moduleAllDatatypesHandleErrors() { |
6466 | dictIterator *di = dictGetIterator(modules); |
6467 | dictEntry *de; |
6468 | |
6469 | while ((de = dictNext(di)) != NULL) { |
6470 | struct RedisModule *module = dictGetVal(de); |
6471 | if (listLength(module->types) && |
6472 | !(module->options & REDISMODULE_OPTIONS_HANDLE_IO_ERRORS)) |
6473 | { |
6474 | dictReleaseIterator(di); |
6475 | return 0; |
6476 | } |
6477 | } |
6478 | dictReleaseIterator(di); |
6479 | return 1; |
6480 | } |
6481 | |
6482 | /* Returns 0 if module did not declare REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD, in which case |
6483 | * diskless async loading should be avoided because module doesn't know there can be traffic during |
6484 | * database full resynchronization. */ |
6485 | int moduleAllModulesHandleReplAsyncLoad() { |
6486 | dictIterator *di = dictGetIterator(modules); |
6487 | dictEntry *de; |
6488 | |
6489 | while ((de = dictNext(di)) != NULL) { |
6490 | struct RedisModule *module = dictGetVal(de); |
6491 | if (!(module->options & REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD)) { |
6492 | dictReleaseIterator(di); |
6493 | return 0; |
6494 | } |
6495 | } |
6496 | dictReleaseIterator(di); |
6497 | return 1; |
6498 | } |
6499 | |
6500 | /* Returns true if any previous IO API failed. |
6501 | * for `Load*` APIs the REDISMODULE_OPTIONS_HANDLE_IO_ERRORS flag must be set with |
6502 | * RedisModule_SetModuleOptions first. */ |
6503 | int RM_IsIOError(RedisModuleIO *io) { |
6504 | return io->error; |
6505 | } |
6506 | |
6507 | /* Save an unsigned 64 bit value into the RDB file. This function should only |
6508 | * be called in the context of the rdb_save method of modules implementing new |
6509 | * data types. */ |
6510 | void RM_SaveUnsigned(RedisModuleIO *io, uint64_t value) { |
6511 | if (io->error) return; |
6512 | /* Save opcode. */ |
6513 | int retval = rdbSaveLen(io->rio, RDB_MODULE_OPCODE_UINT); |
6514 | if (retval == -1) goto saveerr; |
6515 | io->bytes += retval; |
6516 | /* Save value. */ |
6517 | retval = rdbSaveLen(io->rio, value); |
6518 | if (retval == -1) goto saveerr; |
6519 | io->bytes += retval; |
6520 | return; |
6521 | |
6522 | saveerr: |
6523 | io->error = 1; |
6524 | } |
6525 | |
6526 | /* Load an unsigned 64 bit value from the RDB file. This function should only |
6527 | * be called in the context of the `rdb_load` method of modules implementing |
6528 | * new data types. */ |
6529 | uint64_t RM_LoadUnsigned(RedisModuleIO *io) { |
6530 | if (io->error) return 0; |
6531 | if (io->ver == 2) { |
6532 | uint64_t opcode = rdbLoadLen(io->rio,NULL); |
6533 | if (opcode != RDB_MODULE_OPCODE_UINT) goto loaderr; |
6534 | } |
6535 | uint64_t value; |
6536 | int retval = rdbLoadLenByRef(io->rio, NULL, &value); |
6537 | if (retval == -1) goto loaderr; |
6538 | return value; |
6539 | |
6540 | loaderr: |
6541 | moduleRDBLoadError(io); |
6542 | return 0; |
6543 | } |
6544 | |
6545 | /* Like RedisModule_SaveUnsigned() but for signed 64 bit values. */ |
6546 | void RM_SaveSigned(RedisModuleIO *io, int64_t value) { |
6547 | union {uint64_t u; int64_t i;} conv; |
6548 | conv.i = value; |
6549 | RM_SaveUnsigned(io,conv.u); |
6550 | } |
6551 | |
6552 | /* Like RedisModule_LoadUnsigned() but for signed 64 bit values. */ |
6553 | int64_t RM_LoadSigned(RedisModuleIO *io) { |
6554 | union {uint64_t u; int64_t i;} conv; |
6555 | conv.u = RM_LoadUnsigned(io); |
6556 | return conv.i; |
6557 | } |
6558 | |
6559 | /* In the context of the rdb_save method of a module type, saves a |
6560 | * string into the RDB file taking as input a RedisModuleString. |
6561 | * |
6562 | * The string can be later loaded with RedisModule_LoadString() or |
6563 | * other Load family functions expecting a serialized string inside |
6564 | * the RDB file. */ |
6565 | void RM_SaveString(RedisModuleIO *io, RedisModuleString *s) { |
6566 | if (io->error) return; |
6567 | /* Save opcode. */ |
6568 | ssize_t retval = rdbSaveLen(io->rio, RDB_MODULE_OPCODE_STRING); |
6569 | if (retval == -1) goto saveerr; |
6570 | io->bytes += retval; |
6571 | /* Save value. */ |
6572 | retval = rdbSaveStringObject(io->rio, s); |
6573 | if (retval == -1) goto saveerr; |
6574 | io->bytes += retval; |
6575 | return; |
6576 | |
6577 | saveerr: |
6578 | io->error = 1; |
6579 | } |
6580 | |
6581 | /* Like RedisModule_SaveString() but takes a raw C pointer and length |
6582 | * as input. */ |
6583 | void RM_SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len) { |
6584 | if (io->error) return; |
6585 | /* Save opcode. */ |
6586 | ssize_t retval = rdbSaveLen(io->rio, RDB_MODULE_OPCODE_STRING); |
6587 | if (retval == -1) goto saveerr; |
6588 | io->bytes += retval; |
6589 | /* Save value. */ |
6590 | retval = rdbSaveRawString(io->rio, (unsigned char*)str,len); |
6591 | if (retval == -1) goto saveerr; |
6592 | io->bytes += retval; |
6593 | return; |
6594 | |
6595 | saveerr: |
6596 | io->error = 1; |
6597 | } |
6598 | |
6599 | /* Implements RM_LoadString() and RM_LoadStringBuffer() */ |
6600 | void *moduleLoadString(RedisModuleIO *io, int plain, size_t *lenptr) { |
6601 | if (io->error) return NULL; |
6602 | if (io->ver == 2) { |
6603 | uint64_t opcode = rdbLoadLen(io->rio,NULL); |
6604 | if (opcode != RDB_MODULE_OPCODE_STRING) goto loaderr; |
6605 | } |
6606 | void *s = rdbGenericLoadStringObject(io->rio, |
6607 | plain ? RDB_LOAD_PLAIN : RDB_LOAD_NONE, lenptr); |
6608 | if (s == NULL) goto loaderr; |
6609 | return s; |
6610 | |
6611 | loaderr: |
6612 | moduleRDBLoadError(io); |
6613 | return NULL; |
6614 | } |
6615 | |
6616 | /* In the context of the rdb_load method of a module data type, loads a string |
6617 | * from the RDB file, that was previously saved with RedisModule_SaveString() |
6618 | * functions family. |
6619 | * |
6620 | * The returned string is a newly allocated RedisModuleString object, and |
6621 | * the user should at some point free it with a call to RedisModule_FreeString(). |
6622 | * |
6623 | * If the data structure does not store strings as RedisModuleString objects, |
6624 | * the similar function RedisModule_LoadStringBuffer() could be used instead. */ |
6625 | RedisModuleString *RM_LoadString(RedisModuleIO *io) { |
6626 | return moduleLoadString(io,0,NULL); |
6627 | } |
6628 | |
6629 | /* Like RedisModule_LoadString() but returns a heap allocated string that |
6630 | * was allocated with RedisModule_Alloc(), and can be resized or freed with |
6631 | * RedisModule_Realloc() or RedisModule_Free(). |
6632 | * |
6633 | * The size of the string is stored at '*lenptr' if not NULL. |
6634 | * The returned string is not automatically NULL terminated, it is loaded |
6635 | * exactly as it was stored inside the RDB file. */ |
6636 | char *RM_LoadStringBuffer(RedisModuleIO *io, size_t *lenptr) { |
6637 | return moduleLoadString(io,1,lenptr); |
6638 | } |
6639 | |
6640 | /* In the context of the rdb_save method of a module data type, saves a double |
6641 | * value to the RDB file. The double can be a valid number, a NaN or infinity. |
6642 | * It is possible to load back the value with RedisModule_LoadDouble(). */ |
6643 | void RM_SaveDouble(RedisModuleIO *io, double value) { |
6644 | if (io->error) return; |
6645 | /* Save opcode. */ |
6646 | int retval = rdbSaveLen(io->rio, RDB_MODULE_OPCODE_DOUBLE); |
6647 | if (retval == -1) goto saveerr; |
6648 | io->bytes += retval; |
6649 | /* Save value. */ |
6650 | retval = rdbSaveBinaryDoubleValue(io->rio, value); |
6651 | if (retval == -1) goto saveerr; |
6652 | io->bytes += retval; |
6653 | return; |
6654 | |
6655 | saveerr: |
6656 | io->error = 1; |
6657 | } |
6658 | |
6659 | /* In the context of the rdb_save method of a module data type, loads back the |
6660 | * double value saved by RedisModule_SaveDouble(). */ |
6661 | double RM_LoadDouble(RedisModuleIO *io) { |
6662 | if (io->error) return 0; |
6663 | if (io->ver == 2) { |
6664 | uint64_t opcode = rdbLoadLen(io->rio,NULL); |
6665 | if (opcode != RDB_MODULE_OPCODE_DOUBLE) goto loaderr; |
6666 | } |
6667 | double value; |
6668 | int retval = rdbLoadBinaryDoubleValue(io->rio, &value); |
6669 | if (retval == -1) goto loaderr; |
6670 | return value; |
6671 | |
6672 | loaderr: |
6673 | moduleRDBLoadError(io); |
6674 | return 0; |
6675 | } |
6676 | |
6677 | /* In the context of the rdb_save method of a module data type, saves a float |
6678 | * value to the RDB file. The float can be a valid number, a NaN or infinity. |
6679 | * It is possible to load back the value with RedisModule_LoadFloat(). */ |
6680 | void RM_SaveFloat(RedisModuleIO *io, float value) { |
6681 | if (io->error) return; |
6682 | /* Save opcode. */ |
6683 | int retval = rdbSaveLen(io->rio, RDB_MODULE_OPCODE_FLOAT); |
6684 | if (retval == -1) goto saveerr; |
6685 | io->bytes += retval; |
6686 | /* Save value. */ |
6687 | retval = rdbSaveBinaryFloatValue(io->rio, value); |
6688 | if (retval == -1) goto saveerr; |
6689 | io->bytes += retval; |
6690 | return; |
6691 | |
6692 | saveerr: |
6693 | io->error = 1; |
6694 | } |
6695 | |
6696 | /* In the context of the rdb_save method of a module data type, loads back the |
6697 | * float value saved by RedisModule_SaveFloat(). */ |
6698 | float RM_LoadFloat(RedisModuleIO *io) { |
6699 | if (io->error) return 0; |
6700 | if (io->ver == 2) { |
6701 | uint64_t opcode = rdbLoadLen(io->rio,NULL); |
6702 | if (opcode != RDB_MODULE_OPCODE_FLOAT) goto loaderr; |
6703 | } |
6704 | float value; |
6705 | int retval = rdbLoadBinaryFloatValue(io->rio, &value); |
6706 | if (retval == -1) goto loaderr; |
6707 | return value; |
6708 | |
6709 | loaderr: |
6710 | moduleRDBLoadError(io); |
6711 | return 0; |
6712 | } |
6713 | |
6714 | /* In the context of the rdb_save method of a module data type, saves a long double |
6715 | * value to the RDB file. The double can be a valid number, a NaN or infinity. |
6716 | * It is possible to load back the value with RedisModule_LoadLongDouble(). */ |
6717 | void RM_SaveLongDouble(RedisModuleIO *io, long double value) { |
6718 | if (io->error) return; |
6719 | char buf[MAX_LONG_DOUBLE_CHARS]; |
6720 | /* Long double has different number of bits in different platforms, so we |
6721 | * save it as a string type. */ |
6722 | size_t len = ld2string(buf,sizeof(buf),value,LD_STR_HEX); |
6723 | RM_SaveStringBuffer(io,buf,len); |
6724 | } |
6725 | |
6726 | /* In the context of the rdb_save method of a module data type, loads back the |
6727 | * long double value saved by RedisModule_SaveLongDouble(). */ |
6728 | long double RM_LoadLongDouble(RedisModuleIO *io) { |
6729 | if (io->error) return 0; |
6730 | long double value; |
6731 | size_t len; |
6732 | char* str = RM_LoadStringBuffer(io,&len); |
6733 | if (!str) return 0; |
6734 | string2ld(str,len,&value); |
6735 | RM_Free(str); |
6736 | return value; |
6737 | } |
6738 | |
6739 | /* Iterate over modules, and trigger rdb aux saving for the ones modules types |
6740 | * who asked for it. */ |
6741 | ssize_t rdbSaveModulesAux(rio *rdb, int when) { |
6742 | size_t total_written = 0; |
6743 | dictIterator *di = dictGetIterator(modules); |
6744 | dictEntry *de; |
6745 | |
6746 | while ((de = dictNext(di)) != NULL) { |
6747 | struct RedisModule *module = dictGetVal(de); |
6748 | listIter li; |
6749 | listNode *ln; |
6750 | |
6751 | listRewind(module->types,&li); |
6752 | while((ln = listNext(&li))) { |
6753 | moduleType *mt = ln->value; |
6754 | if (!mt->aux_save || !(mt->aux_save_triggers & when)) |
6755 | continue; |
6756 | ssize_t ret = rdbSaveSingleModuleAux(rdb, when, mt); |
6757 | if (ret==-1) { |
6758 | dictReleaseIterator(di); |
6759 | return -1; |
6760 | } |
6761 | total_written += ret; |
6762 | } |
6763 | } |
6764 | |
6765 | dictReleaseIterator(di); |
6766 | return total_written; |
6767 | } |
6768 | |
6769 | /* -------------------------------------------------------------------------- |
6770 | * ## Key digest API (DEBUG DIGEST interface for modules types) |
6771 | * -------------------------------------------------------------------------- */ |
6772 | |
6773 | /* Add a new element to the digest. This function can be called multiple times |
6774 | * one element after the other, for all the elements that constitute a given |
6775 | * data structure. The function call must be followed by the call to |
6776 | * `RedisModule_DigestEndSequence` eventually, when all the elements that are |
6777 | * always in a given order are added. See the Redis Modules data types |
6778 | * documentation for more info. However this is a quick example that uses Redis |
6779 | * data types as an example. |
6780 | * |
6781 | * To add a sequence of unordered elements (for example in the case of a Redis |
6782 | * Set), the pattern to use is: |
6783 | * |
6784 | * foreach element { |
6785 | * AddElement(element); |
6786 | * EndSequence(); |
6787 | * } |
6788 | * |
6789 | * Because Sets are not ordered, so every element added has a position that |
6790 | * does not depend from the other. However if instead our elements are |
6791 | * ordered in pairs, like field-value pairs of a Hash, then one should |
6792 | * use: |
6793 | * |
6794 | * foreach key,value { |
6795 | * AddElement(key); |
6796 | * AddElement(value); |
6797 | * EndSequence(); |
6798 | * } |
6799 | * |
6800 | * Because the key and value will be always in the above order, while instead |
6801 | * the single key-value pairs, can appear in any position into a Redis hash. |
6802 | * |
6803 | * A list of ordered elements would be implemented with: |
6804 | * |
6805 | * foreach element { |
6806 | * AddElement(element); |
6807 | * } |
6808 | * EndSequence(); |
6809 | * |
6810 | */ |
6811 | void RM_DigestAddStringBuffer(RedisModuleDigest *md, const char *ele, size_t len) { |
6812 | mixDigest(md->o,ele,len); |
6813 | } |
6814 | |
6815 | /* Like `RedisModule_DigestAddStringBuffer()` but takes a `long long` as input |
6816 | * that gets converted into a string before adding it to the digest. */ |
6817 | void RM_DigestAddLongLong(RedisModuleDigest *md, long long ll) { |
6818 | char buf[LONG_STR_SIZE]; |
6819 | size_t len = ll2string(buf,sizeof(buf),ll); |
6820 | mixDigest(md->o,buf,len); |
6821 | } |
6822 | |
6823 | /* See the documentation for `RedisModule_DigestAddElement()`. */ |
6824 | void RM_DigestEndSequence(RedisModuleDigest *md) { |
6825 | xorDigest(md->x,md->o,sizeof(md->o)); |
6826 | memset(md->o,0,sizeof(md->o)); |
6827 | } |
6828 | |
6829 | /* Decode a serialized representation of a module data type 'mt', in a specific encoding version 'encver' |
6830 | * from string 'str' and return a newly allocated value, or NULL if decoding failed. |
6831 | * |
6832 | * This call basically reuses the 'rdb_load' callback which module data types |
6833 | * implement in order to allow a module to arbitrarily serialize/de-serialize |
6834 | * keys, similar to how the Redis 'DUMP' and 'RESTORE' commands are implemented. |
6835 | * |
6836 | * Modules should generally use the REDISMODULE_OPTIONS_HANDLE_IO_ERRORS flag and |
6837 | * make sure the de-serialization code properly checks and handles IO errors |
6838 | * (freeing allocated buffers and returning a NULL). |
6839 | * |
6840 | * If this is NOT done, Redis will handle corrupted (or just truncated) serialized |
6841 | * data by producing an error message and terminating the process. |
6842 | */ |
6843 | void *RM_LoadDataTypeFromStringEncver(const RedisModuleString *str, const moduleType *mt, int encver) { |
6844 | rio payload; |
6845 | RedisModuleIO io; |
6846 | void *ret; |
6847 | |
6848 | rioInitWithBuffer(&payload, str->ptr); |
6849 | moduleInitIOContext(io,(moduleType *)mt,&payload,NULL,-1); |
6850 | |
6851 | /* All RM_Save*() calls always write a version 2 compatible format, so we |
6852 | * need to make sure we read the same. |
6853 | */ |
6854 | io.ver = 2; |
6855 | ret = mt->rdb_load(&io,encver); |
6856 | if (io.ctx) { |
6857 | moduleFreeContext(io.ctx); |
6858 | zfree(io.ctx); |
6859 | } |
6860 | return ret; |
6861 | } |
6862 | |
6863 | /* Similar to RM_LoadDataTypeFromStringEncver, original version of the API, kept |
6864 | * for backward compatibility. |
6865 | */ |
6866 | void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *mt) { |
6867 | return RM_LoadDataTypeFromStringEncver(str, mt, 0); |
6868 | } |
6869 | |
6870 | /* Encode a module data type 'mt' value 'data' into serialized form, and return it |
6871 | * as a newly allocated RedisModuleString. |
6872 | * |
6873 | * This call basically reuses the 'rdb_save' callback which module data types |
6874 | * implement in order to allow a module to arbitrarily serialize/de-serialize |
6875 | * keys, similar to how the Redis 'DUMP' and 'RESTORE' commands are implemented. |
6876 | */ |
6877 | RedisModuleString *RM_SaveDataTypeToString(RedisModuleCtx *ctx, void *data, const moduleType *mt) { |
6878 | rio payload; |
6879 | RedisModuleIO io; |
6880 | |
6881 | rioInitWithBuffer(&payload,sdsempty()); |
6882 | moduleInitIOContext(io,(moduleType *)mt,&payload,NULL,-1); |
6883 | mt->rdb_save(&io,data); |
6884 | if (io.ctx) { |
6885 | moduleFreeContext(io.ctx); |
6886 | zfree(io.ctx); |
6887 | } |
6888 | if (io.error) { |
6889 | return NULL; |
6890 | } else { |
6891 | robj *str = createObject(OBJ_STRING,payload.io.buffer.ptr); |
6892 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,str); |
6893 | return str; |
6894 | } |
6895 | } |
6896 | |
6897 | /* Returns the name of the key currently being processed. */ |
6898 | const RedisModuleString *RM_GetKeyNameFromDigest(RedisModuleDigest *dig) { |
6899 | return dig->key; |
6900 | } |
6901 | |
6902 | /* Returns the database id of the key currently being processed. */ |
6903 | int RM_GetDbIdFromDigest(RedisModuleDigest *dig) { |
6904 | return dig->dbid; |
6905 | } |
6906 | /* -------------------------------------------------------------------------- |
6907 | * ## AOF API for modules data types |
6908 | * -------------------------------------------------------------------------- */ |
6909 | |
6910 | /* Emits a command into the AOF during the AOF rewriting process. This function |
6911 | * is only called in the context of the aof_rewrite method of data types exported |
6912 | * by a module. The command works exactly like RedisModule_Call() in the way |
6913 | * the parameters are passed, but it does not return anything as the error |
6914 | * handling is performed by Redis itself. */ |
6915 | void RM_EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...) { |
6916 | if (io->error) return; |
6917 | struct redisCommand *cmd; |
6918 | robj **argv = NULL; |
6919 | int argc = 0, flags = 0, j; |
6920 | va_list ap; |
6921 | |
6922 | cmd = lookupCommandByCString((char*)cmdname); |
6923 | if (!cmd) { |
6924 | serverLog(LL_WARNING, |
6925 | "Fatal: AOF method for module data type '%s' tried to " |
6926 | "emit unknown command '%s'" , |
6927 | io->type->name, cmdname); |
6928 | io->error = 1; |
6929 | errno = EINVAL; |
6930 | return; |
6931 | } |
6932 | |
6933 | /* Emit the arguments into the AOF in Redis protocol format. */ |
6934 | va_start(ap, fmt); |
6935 | argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,NULL,&flags,ap); |
6936 | va_end(ap); |
6937 | if (argv == NULL) { |
6938 | serverLog(LL_WARNING, |
6939 | "Fatal: AOF method for module data type '%s' tried to " |
6940 | "call RedisModule_EmitAOF() with wrong format specifiers '%s'" , |
6941 | io->type->name, fmt); |
6942 | io->error = 1; |
6943 | errno = EINVAL; |
6944 | return; |
6945 | } |
6946 | |
6947 | /* Bulk count. */ |
6948 | if (!io->error && rioWriteBulkCount(io->rio,'*',argc) == 0) |
6949 | io->error = 1; |
6950 | |
6951 | /* Arguments. */ |
6952 | for (j = 0; j < argc; j++) { |
6953 | if (!io->error && rioWriteBulkObject(io->rio,argv[j]) == 0) |
6954 | io->error = 1; |
6955 | decrRefCount(argv[j]); |
6956 | } |
6957 | zfree(argv); |
6958 | return; |
6959 | } |
6960 | |
6961 | /* -------------------------------------------------------------------------- |
6962 | * ## IO context handling |
6963 | * -------------------------------------------------------------------------- */ |
6964 | |
6965 | RedisModuleCtx *RM_GetContextFromIO(RedisModuleIO *io) { |
6966 | if (io->ctx) return io->ctx; /* Can't have more than one... */ |
6967 | io->ctx = zmalloc(sizeof(RedisModuleCtx)); |
6968 | moduleCreateContext(io->ctx, io->type->module, REDISMODULE_CTX_NONE); |
6969 | return io->ctx; |
6970 | } |
6971 | |
6972 | /* Returns the name of the key currently being processed. |
6973 | * There is no guarantee that the key name is always available, so this may return NULL. |
6974 | */ |
6975 | const RedisModuleString *RM_GetKeyNameFromIO(RedisModuleIO *io) { |
6976 | return io->key; |
6977 | } |
6978 | |
6979 | /* Returns a RedisModuleString with the name of the key from RedisModuleKey. */ |
6980 | const RedisModuleString *RM_GetKeyNameFromModuleKey(RedisModuleKey *key) { |
6981 | return key ? key->key : NULL; |
6982 | } |
6983 | |
6984 | /* Returns a database id of the key from RedisModuleKey. */ |
6985 | int RM_GetDbIdFromModuleKey(RedisModuleKey *key) { |
6986 | return key ? key->db->id : -1; |
6987 | } |
6988 | |
6989 | /* Returns the database id of the key currently being processed. |
6990 | * There is no guarantee that this info is always available, so this may return -1. |
6991 | */ |
6992 | int RM_GetDbIdFromIO(RedisModuleIO *io) { |
6993 | return io->dbid; |
6994 | } |
6995 | |
6996 | /* -------------------------------------------------------------------------- |
6997 | * ## Logging |
6998 | * -------------------------------------------------------------------------- */ |
6999 | |
7000 | /* This is the low level function implementing both: |
7001 | * |
7002 | * RM_Log() |
7003 | * RM_LogIOError() |
7004 | * |
7005 | */ |
7006 | void moduleLogRaw(RedisModule *module, const char *levelstr, const char *fmt, va_list ap) { |
7007 | char msg[LOG_MAX_LEN]; |
7008 | size_t name_len; |
7009 | int level; |
7010 | |
7011 | if (!strcasecmp(levelstr,"debug" )) level = LL_DEBUG; |
7012 | else if (!strcasecmp(levelstr,"verbose" )) level = LL_VERBOSE; |
7013 | else if (!strcasecmp(levelstr,"notice" )) level = LL_NOTICE; |
7014 | else if (!strcasecmp(levelstr,"warning" )) level = LL_WARNING; |
7015 | else level = LL_VERBOSE; /* Default. */ |
7016 | |
7017 | if (level < server.verbosity) return; |
7018 | |
7019 | name_len = snprintf(msg, sizeof(msg),"<%s> " , module? module->name: "module" ); |
7020 | vsnprintf(msg + name_len, sizeof(msg) - name_len, fmt, ap); |
7021 | serverLogRaw(level,msg); |
7022 | } |
7023 | |
7024 | /* Produces a log message to the standard Redis log, the format accepts |
7025 | * printf-alike specifiers, while level is a string describing the log |
7026 | * level to use when emitting the log, and must be one of the following: |
7027 | * |
7028 | * * "debug" (`REDISMODULE_LOGLEVEL_DEBUG`) |
7029 | * * "verbose" (`REDISMODULE_LOGLEVEL_VERBOSE`) |
7030 | * * "notice" (`REDISMODULE_LOGLEVEL_NOTICE`) |
7031 | * * "warning" (`REDISMODULE_LOGLEVEL_WARNING`) |
7032 | * |
7033 | * If the specified log level is invalid, verbose is used by default. |
7034 | * There is a fixed limit to the length of the log line this function is able |
7035 | * to emit, this limit is not specified but is guaranteed to be more than |
7036 | * a few lines of text. |
7037 | * |
7038 | * The ctx argument may be NULL if cannot be provided in the context of the |
7039 | * caller for instance threads or callbacks, in which case a generic "module" |
7040 | * will be used instead of the module name. |
7041 | */ |
7042 | void RM_Log(RedisModuleCtx *ctx, const char *levelstr, const char *fmt, ...) { |
7043 | va_list ap; |
7044 | va_start(ap, fmt); |
7045 | moduleLogRaw(ctx? ctx->module: NULL,levelstr,fmt,ap); |
7046 | va_end(ap); |
7047 | } |
7048 | |
7049 | /* Log errors from RDB / AOF serialization callbacks. |
7050 | * |
7051 | * This function should be used when a callback is returning a critical |
7052 | * error to the caller since cannot load or save the data for some |
7053 | * critical reason. */ |
7054 | void RM_LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...) { |
7055 | va_list ap; |
7056 | va_start(ap, fmt); |
7057 | moduleLogRaw(io->type->module,levelstr,fmt,ap); |
7058 | va_end(ap); |
7059 | } |
7060 | |
7061 | /* Redis-like assert function. |
7062 | * |
7063 | * The macro `RedisModule_Assert(expression)` is recommended, rather than |
7064 | * calling this function directly. |
7065 | * |
7066 | * A failed assertion will shut down the server and produce logging information |
7067 | * that looks identical to information generated by Redis itself. |
7068 | */ |
7069 | void RM__Assert(const char *estr, const char *file, int line) { |
7070 | _serverAssert(estr, file, line); |
7071 | } |
7072 | |
7073 | /* Allows adding event to the latency monitor to be observed by the LATENCY |
7074 | * command. The call is skipped if the latency is smaller than the configured |
7075 | * latency-monitor-threshold. */ |
7076 | void RM_LatencyAddSample(const char *event, mstime_t latency) { |
7077 | if (latency >= server.latency_monitor_threshold) |
7078 | latencyAddSample(event, latency); |
7079 | } |
7080 | |
7081 | /* -------------------------------------------------------------------------- |
7082 | * ## Blocking clients from modules |
7083 | * |
7084 | * For a guide about blocking commands in modules, see |
7085 | * https://redis.io/topics/modules-blocking-ops. |
7086 | * -------------------------------------------------------------------------- */ |
7087 | |
7088 | /* This is called from blocked.c in order to unblock a client: may be called |
7089 | * for multiple reasons while the client is in the middle of being blocked |
7090 | * because the client is terminated, but is also called for cleanup when a |
7091 | * client is unblocked in a clean way after replaying. |
7092 | * |
7093 | * What we do here is just to set the client to NULL in the redis module |
7094 | * blocked client handle. This way if the client is terminated while there |
7095 | * is a pending threaded operation involving the blocked client, we'll know |
7096 | * that the client no longer exists and no reply callback should be called. |
7097 | * |
7098 | * The structure RedisModuleBlockedClient will be always deallocated when |
7099 | * running the list of clients blocked by a module that need to be unblocked. */ |
7100 | void unblockClientFromModule(client *c) { |
7101 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7102 | |
7103 | /* Call the disconnection callback if any. Note that |
7104 | * bc->disconnect_callback is set to NULL if the client gets disconnected |
7105 | * by the module itself or because of a timeout, so the callback will NOT |
7106 | * get called if this is not an actual disconnection event. */ |
7107 | if (bc->disconnect_callback) { |
7108 | RedisModuleCtx ctx; |
7109 | moduleCreateContext(&ctx, bc->module, REDISMODULE_CTX_NONE); |
7110 | ctx.blocked_privdata = bc->privdata; |
7111 | ctx.client = bc->client; |
7112 | bc->disconnect_callback(&ctx,bc); |
7113 | moduleFreeContext(&ctx); |
7114 | } |
7115 | |
7116 | /* If we made it here and client is still blocked it means that the command |
7117 | * timed-out, client was killed or disconnected and disconnect_callback was |
7118 | * not implemented (or it was, but RM_UnblockClient was not called from |
7119 | * within it, as it should). |
7120 | * We must call moduleUnblockClient in order to free privdata and |
7121 | * RedisModuleBlockedClient. |
7122 | * |
7123 | * Note that we only do that for clients that are blocked on keys, for which |
7124 | * the contract is that the module should not call RM_UnblockClient under |
7125 | * normal circumstances. |
7126 | * Clients implementing threads and working with private data should be |
7127 | * aware that calling RM_UnblockClient for every blocked client is their |
7128 | * responsibility, and if they fail to do so memory may leak. Ideally they |
7129 | * should implement the disconnect and timeout callbacks and call |
7130 | * RM_UnblockClient, but any other way is also acceptable. */ |
7131 | if (bc->blocked_on_keys && !bc->unblocked) |
7132 | moduleUnblockClient(c); |
7133 | |
7134 | bc->client = NULL; |
7135 | } |
7136 | |
7137 | /* Block a client in the context of a module: this function implements both |
7138 | * RM_BlockClient() and RM_BlockClientOnKeys() depending on the fact the |
7139 | * keys are passed or not. |
7140 | * |
7141 | * When not blocking for keys, the keys, numkeys, and privdata parameters are |
7142 | * not needed. The privdata in that case must be NULL, since later is |
7143 | * RM_UnblockClient() that will provide some private data that the reply |
7144 | * callback will receive. |
7145 | * |
7146 | * Instead when blocking for keys, normally RM_UnblockClient() will not be |
7147 | * called (because the client will unblock when the key is modified), so |
7148 | * 'privdata' should be provided in that case, so that once the client is |
7149 | * unlocked and the reply callback is called, it will receive its associated |
7150 | * private data. |
7151 | * |
7152 | * Even when blocking on keys, RM_UnblockClient() can be called however, but |
7153 | * in that case the privdata argument is disregarded, because we pass the |
7154 | * reply callback the privdata that is set here while blocking. |
7155 | * |
7156 | */ |
7157 | RedisModuleBlockedClient *moduleBlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata) { |
7158 | client *c = ctx->client; |
7159 | int islua = scriptIsRunning(); |
7160 | int ismulti = server.in_exec; |
7161 | |
7162 | c->bpop.module_blocked_handle = zmalloc(sizeof(RedisModuleBlockedClient)); |
7163 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7164 | ctx->module->blocked_clients++; |
7165 | |
7166 | /* We need to handle the invalid operation of calling modules blocking |
7167 | * commands from Lua or MULTI. We actually create an already aborted |
7168 | * (client set to NULL) blocked client handle, and actually reply with |
7169 | * an error. */ |
7170 | mstime_t timeout = timeout_ms ? (mstime()+timeout_ms) : 0; |
7171 | bc->client = (islua || ismulti) ? NULL : c; |
7172 | bc->module = ctx->module; |
7173 | bc->reply_callback = reply_callback; |
7174 | bc->timeout_callback = timeout_callback; |
7175 | bc->disconnect_callback = NULL; /* Set by RM_SetDisconnectCallback() */ |
7176 | bc->free_privdata = free_privdata; |
7177 | bc->privdata = privdata; |
7178 | bc->reply_client = moduleAllocTempClient(); |
7179 | bc->thread_safe_ctx_client = moduleAllocTempClient(); |
7180 | if (bc->client) |
7181 | bc->reply_client->resp = bc->client->resp; |
7182 | bc->dbid = c->db->id; |
7183 | bc->blocked_on_keys = keys != NULL; |
7184 | bc->unblocked = 0; |
7185 | bc->background_timer = 0; |
7186 | bc->background_duration = 0; |
7187 | c->bpop.timeout = timeout; |
7188 | |
7189 | if (islua || ismulti) { |
7190 | c->bpop.module_blocked_handle = NULL; |
7191 | addReplyError(c, islua ? |
7192 | "Blocking module command called from Lua script" : |
7193 | "Blocking module command called from transaction" ); |
7194 | } else { |
7195 | if (keys) { |
7196 | blockForKeys(c,BLOCKED_MODULE,keys,numkeys,-1,timeout,NULL,NULL,NULL); |
7197 | } else { |
7198 | blockClient(c,BLOCKED_MODULE); |
7199 | } |
7200 | } |
7201 | return bc; |
7202 | } |
7203 | |
7204 | /* This function is called from module.c in order to check if a module |
7205 | * blocked for BLOCKED_MODULE and subtype 'on keys' (bc->blocked_on_keys true) |
7206 | * can really be unblocked, since the module was able to serve the client. |
7207 | * If the callback returns REDISMODULE_OK, then the client can be unblocked, |
7208 | * otherwise the client remains blocked and we'll retry again when one of |
7209 | * the keys it blocked for becomes "ready" again. |
7210 | * This function returns 1 if client was served (and should be unblocked) */ |
7211 | int moduleTryServeClientBlockedOnKey(client *c, robj *key) { |
7212 | int served = 0; |
7213 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7214 | |
7215 | /* Protect against re-processing: don't serve clients that are already |
7216 | * in the unblocking list for any reason (including RM_UnblockClient() |
7217 | * explicit call). See #6798. */ |
7218 | if (bc->unblocked) return 0; |
7219 | |
7220 | RedisModuleCtx ctx; |
7221 | moduleCreateContext(&ctx, bc->module, REDISMODULE_CTX_BLOCKED_REPLY); |
7222 | ctx.blocked_ready_key = key; |
7223 | ctx.blocked_privdata = bc->privdata; |
7224 | ctx.client = bc->client; |
7225 | ctx.blocked_client = bc; |
7226 | if (bc->reply_callback(&ctx,(void**)c->argv,c->argc) == REDISMODULE_OK) |
7227 | served = 1; |
7228 | moduleFreeContext(&ctx); |
7229 | return served; |
7230 | } |
7231 | |
7232 | /* Block a client in the context of a blocking command, returning a handle |
7233 | * which will be used, later, in order to unblock the client with a call to |
7234 | * RedisModule_UnblockClient(). The arguments specify callback functions |
7235 | * and a timeout after which the client is unblocked. |
7236 | * |
7237 | * The callbacks are called in the following contexts: |
7238 | * |
7239 | * reply_callback: called after a successful RedisModule_UnblockClient() |
7240 | * call in order to reply to the client and unblock it. |
7241 | * |
7242 | * timeout_callback: called when the timeout is reached or if `CLIENT UNBLOCK` |
7243 | * is invoked, in order to send an error to the client. |
7244 | * |
7245 | * free_privdata: called in order to free the private data that is passed |
7246 | * by RedisModule_UnblockClient() call. |
7247 | * |
7248 | * Note: RedisModule_UnblockClient should be called for every blocked client, |
7249 | * even if client was killed, timed-out or disconnected. Failing to do so |
7250 | * will result in memory leaks. |
7251 | * |
7252 | * There are some cases where RedisModule_BlockClient() cannot be used: |
7253 | * |
7254 | * 1. If the client is a Lua script. |
7255 | * 2. If the client is executing a MULTI block. |
7256 | * |
7257 | * In these cases, a call to RedisModule_BlockClient() will **not** block the |
7258 | * client, but instead produce a specific error reply. |
7259 | * |
7260 | * A module that registers a timeout_callback function can also be unblocked |
7261 | * using the `CLIENT UNBLOCK` command, which will trigger the timeout callback. |
7262 | * If a callback function is not registered, then the blocked client will be |
7263 | * treated as if it is not in a blocked state and `CLIENT UNBLOCK` will return |
7264 | * a zero value. |
7265 | * |
7266 | * Measuring background time: By default the time spent in the blocked command |
7267 | * is not account for the total command duration. To include such time you should |
7268 | * use RM_BlockedClientMeasureTimeStart() and RM_BlockedClientMeasureTimeEnd() one, |
7269 | * or multiple times within the blocking command background work. |
7270 | */ |
7271 | RedisModuleBlockedClient *RM_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) { |
7272 | return moduleBlockClient(ctx,reply_callback,timeout_callback,free_privdata,timeout_ms, NULL,0,NULL); |
7273 | } |
7274 | |
7275 | /* This call is similar to RedisModule_BlockClient(), however in this case we |
7276 | * don't just block the client, but also ask Redis to unblock it automatically |
7277 | * once certain keys become "ready", that is, contain more data. |
7278 | * |
7279 | * Basically this is similar to what a typical Redis command usually does, |
7280 | * like BLPOP or BZPOPMAX: the client blocks if it cannot be served ASAP, |
7281 | * and later when the key receives new data (a list push for instance), the |
7282 | * client is unblocked and served. |
7283 | * |
7284 | * However in the case of this module API, when the client is unblocked? |
7285 | * |
7286 | * 1. If you block on a key of a type that has blocking operations associated, |
7287 | * like a list, a sorted set, a stream, and so forth, the client may be |
7288 | * unblocked once the relevant key is targeted by an operation that normally |
7289 | * unblocks the native blocking operations for that type. So if we block |
7290 | * on a list key, an RPUSH command may unblock our client and so forth. |
7291 | * 2. If you are implementing your native data type, or if you want to add new |
7292 | * unblocking conditions in addition to "1", you can call the modules API |
7293 | * RedisModule_SignalKeyAsReady(). |
7294 | * |
7295 | * Anyway we can't be sure if the client should be unblocked just because the |
7296 | * key is signaled as ready: for instance a successive operation may change the |
7297 | * key, or a client in queue before this one can be served, modifying the key |
7298 | * as well and making it empty again. So when a client is blocked with |
7299 | * RedisModule_BlockClientOnKeys() the reply callback is not called after |
7300 | * RM_UnblockClient() is called, but every time a key is signaled as ready: |
7301 | * if the reply callback can serve the client, it returns REDISMODULE_OK |
7302 | * and the client is unblocked, otherwise it will return REDISMODULE_ERR |
7303 | * and we'll try again later. |
7304 | * |
7305 | * The reply callback can access the key that was signaled as ready by |
7306 | * calling the API RedisModule_GetBlockedClientReadyKey(), that returns |
7307 | * just the string name of the key as a RedisModuleString object. |
7308 | * |
7309 | * Thanks to this system we can setup complex blocking scenarios, like |
7310 | * unblocking a client only if a list contains at least 5 items or other |
7311 | * more fancy logics. |
7312 | * |
7313 | * Note that another difference with RedisModule_BlockClient(), is that here |
7314 | * we pass the private data directly when blocking the client: it will |
7315 | * be accessible later in the reply callback. Normally when blocking with |
7316 | * RedisModule_BlockClient() the private data to reply to the client is |
7317 | * passed when calling RedisModule_UnblockClient() but here the unblocking |
7318 | * is performed by Redis itself, so we need to have some private data before |
7319 | * hand. The private data is used to store any information about the specific |
7320 | * unblocking operation that you are implementing. Such information will be |
7321 | * freed using the free_privdata callback provided by the user. |
7322 | * |
7323 | * However the reply callback will be able to access the argument vector of |
7324 | * the command, so the private data is often not needed. |
7325 | * |
7326 | * Note: Under normal circumstances RedisModule_UnblockClient should not be |
7327 | * called for clients that are blocked on keys (Either the key will |
7328 | * become ready or a timeout will occur). If for some reason you do want |
7329 | * to call RedisModule_UnblockClient it is possible: Client will be |
7330 | * handled as if it were timed-out (You must implement the timeout |
7331 | * callback in that case). |
7332 | */ |
7333 | RedisModuleBlockedClient *RM_BlockClientOnKeys(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata) { |
7334 | return moduleBlockClient(ctx,reply_callback,timeout_callback,free_privdata,timeout_ms, keys,numkeys,privdata); |
7335 | } |
7336 | |
7337 | /* This function is used in order to potentially unblock a client blocked |
7338 | * on keys with RedisModule_BlockClientOnKeys(). When this function is called, |
7339 | * all the clients blocked for this key will get their reply_callback called. |
7340 | * |
7341 | * Note: The function has no effect if the signaled key doesn't exist. */ |
7342 | void RM_SignalKeyAsReady(RedisModuleCtx *ctx, RedisModuleString *key) { |
7343 | signalKeyAsReady(ctx->client->db, key, OBJ_MODULE); |
7344 | } |
7345 | |
7346 | /* Implements RM_UnblockClient() and moduleUnblockClient(). */ |
7347 | int moduleUnblockClientByHandle(RedisModuleBlockedClient *bc, void *privdata) { |
7348 | pthread_mutex_lock(&moduleUnblockedClientsMutex); |
7349 | if (!bc->blocked_on_keys) bc->privdata = privdata; |
7350 | bc->unblocked = 1; |
7351 | if (listLength(moduleUnblockedClients) == 0) { |
7352 | if (write(server.module_pipe[1],"A" ,1) != 1) { |
7353 | /* Ignore the error, this is best-effort. */ |
7354 | } |
7355 | } |
7356 | listAddNodeTail(moduleUnblockedClients,bc); |
7357 | pthread_mutex_unlock(&moduleUnblockedClientsMutex); |
7358 | return REDISMODULE_OK; |
7359 | } |
7360 | |
7361 | /* This API is used by the Redis core to unblock a client that was blocked |
7362 | * by a module. */ |
7363 | void moduleUnblockClient(client *c) { |
7364 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7365 | moduleUnblockClientByHandle(bc,NULL); |
7366 | } |
7367 | |
7368 | /* Return true if the client 'c' was blocked by a module using |
7369 | * RM_BlockClientOnKeys(). */ |
7370 | int moduleClientIsBlockedOnKeys(client *c) { |
7371 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7372 | return bc->blocked_on_keys; |
7373 | } |
7374 | |
7375 | /* Unblock a client blocked by `RedisModule_BlockedClient`. This will trigger |
7376 | * the reply callbacks to be called in order to reply to the client. |
7377 | * The 'privdata' argument will be accessible by the reply callback, so |
7378 | * the caller of this function can pass any value that is needed in order to |
7379 | * actually reply to the client. |
7380 | * |
7381 | * A common usage for 'privdata' is a thread that computes something that |
7382 | * needs to be passed to the client, included but not limited some slow |
7383 | * to compute reply or some reply obtained via networking. |
7384 | * |
7385 | * Note 1: this function can be called from threads spawned by the module. |
7386 | * |
7387 | * Note 2: when we unblock a client that is blocked for keys using the API |
7388 | * RedisModule_BlockClientOnKeys(), the privdata argument here is not used. |
7389 | * Unblocking a client that was blocked for keys using this API will still |
7390 | * require the client to get some reply, so the function will use the |
7391 | * "timeout" handler in order to do so (The privdata provided in |
7392 | * RedisModule_BlockClientOnKeys() is accessible from the timeout |
7393 | * callback via RM_GetBlockedClientPrivateData). */ |
7394 | int RM_UnblockClient(RedisModuleBlockedClient *bc, void *privdata) { |
7395 | if (bc->blocked_on_keys) { |
7396 | /* In theory the user should always pass the timeout handler as an |
7397 | * argument, but better to be safe than sorry. */ |
7398 | if (bc->timeout_callback == NULL) return REDISMODULE_ERR; |
7399 | if (bc->unblocked) return REDISMODULE_OK; |
7400 | if (bc->client) moduleBlockedClientTimedOut(bc->client); |
7401 | } |
7402 | moduleUnblockClientByHandle(bc,privdata); |
7403 | return REDISMODULE_OK; |
7404 | } |
7405 | |
7406 | /* Abort a blocked client blocking operation: the client will be unblocked |
7407 | * without firing any callback. */ |
7408 | int RM_AbortBlock(RedisModuleBlockedClient *bc) { |
7409 | bc->reply_callback = NULL; |
7410 | bc->disconnect_callback = NULL; |
7411 | return RM_UnblockClient(bc,NULL); |
7412 | } |
7413 | |
7414 | /* Set a callback that will be called if a blocked client disconnects |
7415 | * before the module has a chance to call RedisModule_UnblockClient() |
7416 | * |
7417 | * Usually what you want to do there, is to cleanup your module state |
7418 | * so that you can call RedisModule_UnblockClient() safely, otherwise |
7419 | * the client will remain blocked forever if the timeout is large. |
7420 | * |
7421 | * Notes: |
7422 | * |
7423 | * 1. It is not safe to call Reply* family functions here, it is also |
7424 | * useless since the client is gone. |
7425 | * |
7426 | * 2. This callback is not called if the client disconnects because of |
7427 | * a timeout. In such a case, the client is unblocked automatically |
7428 | * and the timeout callback is called. |
7429 | */ |
7430 | void RM_SetDisconnectCallback(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback) { |
7431 | bc->disconnect_callback = callback; |
7432 | } |
7433 | |
7434 | /* This function will check the moduleUnblockedClients queue in order to |
7435 | * call the reply callback and really unblock the client. |
7436 | * |
7437 | * Clients end into this list because of calls to RM_UnblockClient(), |
7438 | * however it is possible that while the module was doing work for the |
7439 | * blocked client, it was terminated by Redis (for timeout or other reasons). |
7440 | * When this happens the RedisModuleBlockedClient structure in the queue |
7441 | * will have the 'client' field set to NULL. */ |
7442 | void moduleHandleBlockedClients(void) { |
7443 | listNode *ln; |
7444 | RedisModuleBlockedClient *bc; |
7445 | |
7446 | pthread_mutex_lock(&moduleUnblockedClientsMutex); |
7447 | while (listLength(moduleUnblockedClients)) { |
7448 | ln = listFirst(moduleUnblockedClients); |
7449 | bc = ln->value; |
7450 | client *c = bc->client; |
7451 | listDelNode(moduleUnblockedClients,ln); |
7452 | pthread_mutex_unlock(&moduleUnblockedClientsMutex); |
7453 | |
7454 | /* Release the lock during the loop, as long as we don't |
7455 | * touch the shared list. */ |
7456 | |
7457 | /* Call the reply callback if the client is valid and we have |
7458 | * any callback. However the callback is not called if the client |
7459 | * was blocked on keys (RM_BlockClientOnKeys()), because we already |
7460 | * called such callback in moduleTryServeClientBlockedOnKey() when |
7461 | * the key was signaled as ready. */ |
7462 | long long prev_error_replies = server.stat_total_error_replies; |
7463 | uint64_t reply_us = 0; |
7464 | if (c && !bc->blocked_on_keys && bc->reply_callback) { |
7465 | RedisModuleCtx ctx; |
7466 | moduleCreateContext(&ctx, bc->module, REDISMODULE_CTX_BLOCKED_REPLY); |
7467 | ctx.blocked_privdata = bc->privdata; |
7468 | ctx.blocked_ready_key = NULL; |
7469 | ctx.client = bc->client; |
7470 | ctx.blocked_client = bc; |
7471 | monotime replyTimer; |
7472 | elapsedStart(&replyTimer); |
7473 | bc->reply_callback(&ctx,(void**)c->argv,c->argc); |
7474 | reply_us = elapsedUs(replyTimer); |
7475 | moduleFreeContext(&ctx); |
7476 | } |
7477 | |
7478 | /* Free privdata if any. */ |
7479 | if (bc->privdata && bc->free_privdata) { |
7480 | RedisModuleCtx ctx; |
7481 | int ctx_flags = c == NULL ? REDISMODULE_CTX_BLOCKED_DISCONNECTED : REDISMODULE_CTX_NONE; |
7482 | moduleCreateContext(&ctx, bc->module, ctx_flags); |
7483 | ctx.blocked_privdata = bc->privdata; |
7484 | ctx.client = bc->client; |
7485 | bc->free_privdata(&ctx,bc->privdata); |
7486 | moduleFreeContext(&ctx); |
7487 | } |
7488 | |
7489 | /* It is possible that this blocked client object accumulated |
7490 | * replies to send to the client in a thread safe context. |
7491 | * We need to glue such replies to the client output buffer and |
7492 | * free the temporary client we just used for the replies. */ |
7493 | if (c) AddReplyFromClient(c, bc->reply_client); |
7494 | moduleReleaseTempClient(bc->reply_client); |
7495 | moduleReleaseTempClient(bc->thread_safe_ctx_client); |
7496 | |
7497 | /* Update stats now that we've finished the blocking operation. |
7498 | * This needs to be out of the reply callback above given that a |
7499 | * module might not define any callback and still do blocking ops. |
7500 | */ |
7501 | if (c && !bc->blocked_on_keys) { |
7502 | updateStatsOnUnblock(c, bc->background_duration, reply_us, server.stat_total_error_replies != prev_error_replies); |
7503 | } |
7504 | |
7505 | if (c != NULL) { |
7506 | /* Before unblocking the client, set the disconnect callback |
7507 | * to NULL, because if we reached this point, the client was |
7508 | * properly unblocked by the module. */ |
7509 | bc->disconnect_callback = NULL; |
7510 | unblockClient(c); |
7511 | /* Put the client in the list of clients that need to write |
7512 | * if there are pending replies here. This is needed since |
7513 | * during a non blocking command the client may receive output. */ |
7514 | if (clientHasPendingReplies(c) && |
7515 | !(c->flags & CLIENT_PENDING_WRITE)) |
7516 | { |
7517 | c->flags |= CLIENT_PENDING_WRITE; |
7518 | listAddNodeHead(server.clients_pending_write,c); |
7519 | } |
7520 | } |
7521 | |
7522 | /* Free 'bc' only after unblocking the client, since it is |
7523 | * referenced in the client blocking context, and must be valid |
7524 | * when calling unblockClient(). */ |
7525 | bc->module->blocked_clients--; |
7526 | zfree(bc); |
7527 | |
7528 | /* Lock again before to iterate the loop. */ |
7529 | pthread_mutex_lock(&moduleUnblockedClientsMutex); |
7530 | } |
7531 | pthread_mutex_unlock(&moduleUnblockedClientsMutex); |
7532 | } |
7533 | |
7534 | /* Check if the specified client can be safely timed out using |
7535 | * moduleBlockedClientTimedOut(). |
7536 | */ |
7537 | int moduleBlockedClientMayTimeout(client *c) { |
7538 | if (c->btype != BLOCKED_MODULE) |
7539 | return 1; |
7540 | |
7541 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7542 | return (bc && bc->timeout_callback != NULL); |
7543 | } |
7544 | |
7545 | /* Called when our client timed out. After this function unblockClient() |
7546 | * is called, and it will invalidate the blocked client. So this function |
7547 | * does not need to do any cleanup. Eventually the module will call the |
7548 | * API to unblock the client and the memory will be released. */ |
7549 | void moduleBlockedClientTimedOut(client *c) { |
7550 | RedisModuleBlockedClient *bc = c->bpop.module_blocked_handle; |
7551 | |
7552 | /* Protect against re-processing: don't serve clients that are already |
7553 | * in the unblocking list for any reason (including RM_UnblockClient() |
7554 | * explicit call). See #6798. */ |
7555 | if (bc->unblocked) return; |
7556 | |
7557 | RedisModuleCtx ctx; |
7558 | moduleCreateContext(&ctx, bc->module, REDISMODULE_CTX_BLOCKED_TIMEOUT); |
7559 | ctx.client = bc->client; |
7560 | ctx.blocked_client = bc; |
7561 | ctx.blocked_privdata = bc->privdata; |
7562 | long long prev_error_replies = server.stat_total_error_replies; |
7563 | bc->timeout_callback(&ctx,(void**)c->argv,c->argc); |
7564 | moduleFreeContext(&ctx); |
7565 | if (!bc->blocked_on_keys) { |
7566 | updateStatsOnUnblock(c, bc->background_duration, 0, server.stat_total_error_replies != prev_error_replies); |
7567 | } |
7568 | /* For timeout events, we do not want to call the disconnect callback, |
7569 | * because the blocked client will be automatically disconnected in |
7570 | * this case, and the user can still hook using the timeout callback. */ |
7571 | bc->disconnect_callback = NULL; |
7572 | } |
7573 | |
7574 | /* Return non-zero if a module command was called in order to fill the |
7575 | * reply for a blocked client. */ |
7576 | int RM_IsBlockedReplyRequest(RedisModuleCtx *ctx) { |
7577 | return (ctx->flags & REDISMODULE_CTX_BLOCKED_REPLY) != 0; |
7578 | } |
7579 | |
7580 | /* Return non-zero if a module command was called in order to fill the |
7581 | * reply for a blocked client that timed out. */ |
7582 | int RM_IsBlockedTimeoutRequest(RedisModuleCtx *ctx) { |
7583 | return (ctx->flags & REDISMODULE_CTX_BLOCKED_TIMEOUT) != 0; |
7584 | } |
7585 | |
7586 | /* Get the private data set by RedisModule_UnblockClient() */ |
7587 | void *RM_GetBlockedClientPrivateData(RedisModuleCtx *ctx) { |
7588 | return ctx->blocked_privdata; |
7589 | } |
7590 | |
7591 | /* Get the key that is ready when the reply callback is called in the context |
7592 | * of a client blocked by RedisModule_BlockClientOnKeys(). */ |
7593 | RedisModuleString *RM_GetBlockedClientReadyKey(RedisModuleCtx *ctx) { |
7594 | return ctx->blocked_ready_key; |
7595 | } |
7596 | |
7597 | /* Get the blocked client associated with a given context. |
7598 | * This is useful in the reply and timeout callbacks of blocked clients, |
7599 | * before sometimes the module has the blocked client handle references |
7600 | * around, and wants to cleanup it. */ |
7601 | RedisModuleBlockedClient *RM_GetBlockedClientHandle(RedisModuleCtx *ctx) { |
7602 | return ctx->blocked_client; |
7603 | } |
7604 | |
7605 | /* Return true if when the free callback of a blocked client is called, |
7606 | * the reason for the client to be unblocked is that it disconnected |
7607 | * while it was blocked. */ |
7608 | int RM_BlockedClientDisconnected(RedisModuleCtx *ctx) { |
7609 | return (ctx->flags & REDISMODULE_CTX_BLOCKED_DISCONNECTED) != 0; |
7610 | } |
7611 | |
7612 | /* -------------------------------------------------------------------------- |
7613 | * ## Thread Safe Contexts |
7614 | * -------------------------------------------------------------------------- */ |
7615 | |
7616 | /* Return a context which can be used inside threads to make Redis context |
7617 | * calls with certain modules APIs. If 'bc' is not NULL then the module will |
7618 | * be bound to a blocked client, and it will be possible to use the |
7619 | * `RedisModule_Reply*` family of functions to accumulate a reply for when the |
7620 | * client will be unblocked. Otherwise the thread safe context will be |
7621 | * detached by a specific client. |
7622 | * |
7623 | * To call non-reply APIs, the thread safe context must be prepared with: |
7624 | * |
7625 | * RedisModule_ThreadSafeContextLock(ctx); |
7626 | * ... make your call here ... |
7627 | * RedisModule_ThreadSafeContextUnlock(ctx); |
7628 | * |
7629 | * This is not needed when using `RedisModule_Reply*` functions, assuming |
7630 | * that a blocked client was used when the context was created, otherwise |
7631 | * no RedisModule_Reply* call should be made at all. |
7632 | * |
7633 | * NOTE: If you're creating a detached thread safe context (bc is NULL), |
7634 | * consider using `RM_GetDetachedThreadSafeContext` which will also retain |
7635 | * the module ID and thus be more useful for logging. */ |
7636 | RedisModuleCtx *RM_GetThreadSafeContext(RedisModuleBlockedClient *bc) { |
7637 | RedisModuleCtx *ctx = zmalloc(sizeof(*ctx)); |
7638 | RedisModule *module = bc ? bc->module : NULL; |
7639 | int flags = REDISMODULE_CTX_THREAD_SAFE; |
7640 | |
7641 | /* Creating a new client object is costly. To avoid that, we have an |
7642 | * internal pool of client objects. In blockClient(), a client object is |
7643 | * assigned to bc->thread_safe_ctx_client to be used for the thread safe |
7644 | * context. |
7645 | * For detached thread safe contexts, we create a new client object. |
7646 | * Otherwise, as this function can be called from different threads, we |
7647 | * would need to synchronize access to internal pool of client objects. |
7648 | * Assuming creating detached context is rare and not that performance |
7649 | * critical, we avoid synchronizing access to the client pool by creating |
7650 | * a new client */ |
7651 | if (!bc) flags |= REDISMODULE_CTX_NEW_CLIENT; |
7652 | moduleCreateContext(ctx, module, flags); |
7653 | /* Even when the context is associated with a blocked client, we can't |
7654 | * access it safely from another thread, so we use a fake client here |
7655 | * in order to keep things like the currently selected database and similar |
7656 | * things. */ |
7657 | if (bc) { |
7658 | ctx->blocked_client = bc; |
7659 | ctx->client = bc->thread_safe_ctx_client; |
7660 | selectDb(ctx->client,bc->dbid); |
7661 | if (bc->client) { |
7662 | ctx->client->id = bc->client->id; |
7663 | ctx->client->resp = bc->client->resp; |
7664 | } |
7665 | } |
7666 | return ctx; |
7667 | } |
7668 | |
7669 | /* Return a detached thread safe context that is not associated with any |
7670 | * specific blocked client, but is associated with the module's context. |
7671 | * |
7672 | * This is useful for modules that wish to hold a global context over |
7673 | * a long term, for purposes such as logging. */ |
7674 | RedisModuleCtx *RM_GetDetachedThreadSafeContext(RedisModuleCtx *ctx) { |
7675 | RedisModuleCtx *new_ctx = zmalloc(sizeof(*new_ctx)); |
7676 | /* We create a new client object for the detached context. |
7677 | * See RM_GetThreadSafeContext() for more information */ |
7678 | moduleCreateContext(new_ctx, ctx->module, |
7679 | REDISMODULE_CTX_THREAD_SAFE|REDISMODULE_CTX_NEW_CLIENT); |
7680 | return new_ctx; |
7681 | } |
7682 | |
7683 | /* Release a thread safe context. */ |
7684 | void RM_FreeThreadSafeContext(RedisModuleCtx *ctx) { |
7685 | moduleFreeContext(ctx); |
7686 | zfree(ctx); |
7687 | } |
7688 | |
7689 | void moduleGILAfterLock() { |
7690 | /* We should never get here if we already inside a module |
7691 | * code block which already opened a context. */ |
7692 | serverAssert(server.module_ctx_nesting == 0); |
7693 | /* Bump up the nesting level to prevent immediate propagation |
7694 | * of possible RM_Call from th thread */ |
7695 | server.module_ctx_nesting++; |
7696 | } |
7697 | |
7698 | /* Acquire the server lock before executing a thread safe API call. |
7699 | * This is not needed for `RedisModule_Reply*` calls when there is |
7700 | * a blocked client connected to the thread safe context. */ |
7701 | void RM_ThreadSafeContextLock(RedisModuleCtx *ctx) { |
7702 | UNUSED(ctx); |
7703 | moduleAcquireGIL(); |
7704 | moduleGILAfterLock(); |
7705 | } |
7706 | |
7707 | /* Similar to RM_ThreadSafeContextLock but this function |
7708 | * would not block if the server lock is already acquired. |
7709 | * |
7710 | * If successful (lock acquired) REDISMODULE_OK is returned, |
7711 | * otherwise REDISMODULE_ERR is returned and errno is set |
7712 | * accordingly. */ |
7713 | int RM_ThreadSafeContextTryLock(RedisModuleCtx *ctx) { |
7714 | UNUSED(ctx); |
7715 | |
7716 | int res = moduleTryAcquireGIL(); |
7717 | if(res != 0) { |
7718 | errno = res; |
7719 | return REDISMODULE_ERR; |
7720 | } |
7721 | moduleGILAfterLock(); |
7722 | return REDISMODULE_OK; |
7723 | } |
7724 | |
7725 | void moduleGILBeforeUnlock() { |
7726 | /* We should never get here if we already inside a module |
7727 | * code block which already opened a context, except |
7728 | * the bump-up from moduleGILAcquired. */ |
7729 | serverAssert(server.module_ctx_nesting == 1); |
7730 | /* Restore ctx_nesting and propagate pending commands |
7731 | * (because it's u clear when thread safe contexts are |
7732 | * released we have to propagate here). */ |
7733 | server.module_ctx_nesting--; |
7734 | propagatePendingCommands(); |
7735 | |
7736 | if (server.busy_module_yield_flags) { |
7737 | blockingOperationEnds(); |
7738 | server.busy_module_yield_flags = BUSY_MODULE_YIELD_NONE; |
7739 | if (server.current_client) |
7740 | unprotectClient(server.current_client); |
7741 | unblockPostponedClients(); |
7742 | } |
7743 | } |
7744 | |
7745 | /* Release the server lock after a thread safe API call was executed. */ |
7746 | void RM_ThreadSafeContextUnlock(RedisModuleCtx *ctx) { |
7747 | UNUSED(ctx); |
7748 | moduleGILBeforeUnlock(); |
7749 | moduleReleaseGIL(); |
7750 | } |
7751 | |
7752 | void moduleAcquireGIL(void) { |
7753 | pthread_mutex_lock(&moduleGIL); |
7754 | } |
7755 | |
7756 | int moduleTryAcquireGIL(void) { |
7757 | return pthread_mutex_trylock(&moduleGIL); |
7758 | } |
7759 | |
7760 | void moduleReleaseGIL(void) { |
7761 | pthread_mutex_unlock(&moduleGIL); |
7762 | } |
7763 | |
7764 | |
7765 | /* -------------------------------------------------------------------------- |
7766 | * ## Module Keyspace Notifications API |
7767 | * -------------------------------------------------------------------------- */ |
7768 | |
7769 | /* Subscribe to keyspace notifications. This is a low-level version of the |
7770 | * keyspace-notifications API. A module can register callbacks to be notified |
7771 | * when keyspace events occur. |
7772 | * |
7773 | * Notification events are filtered by their type (string events, set events, |
7774 | * etc), and the subscriber callback receives only events that match a specific |
7775 | * mask of event types. |
7776 | * |
7777 | * When subscribing to notifications with RedisModule_SubscribeToKeyspaceEvents |
7778 | * the module must provide an event type-mask, denoting the events the subscriber |
7779 | * is interested in. This can be an ORed mask of any of the following flags: |
7780 | * |
7781 | * - REDISMODULE_NOTIFY_GENERIC: Generic commands like DEL, EXPIRE, RENAME |
7782 | * - REDISMODULE_NOTIFY_STRING: String events |
7783 | * - REDISMODULE_NOTIFY_LIST: List events |
7784 | * - REDISMODULE_NOTIFY_SET: Set events |
7785 | * - REDISMODULE_NOTIFY_HASH: Hash events |
7786 | * - REDISMODULE_NOTIFY_ZSET: Sorted Set events |
7787 | * - REDISMODULE_NOTIFY_EXPIRED: Expiration events |
7788 | * - REDISMODULE_NOTIFY_EVICTED: Eviction events |
7789 | * - REDISMODULE_NOTIFY_STREAM: Stream events |
7790 | * - REDISMODULE_NOTIFY_MODULE: Module types events |
7791 | * - REDISMODULE_NOTIFY_KEYMISS: Key-miss events |
7792 | * - REDISMODULE_NOTIFY_ALL: All events (Excluding REDISMODULE_NOTIFY_KEYMISS) |
7793 | * - REDISMODULE_NOTIFY_LOADED: A special notification available only for modules, |
7794 | * indicates that the key was loaded from persistence. |
7795 | * Notice, when this event fires, the given key |
7796 | * can not be retained, use RM_CreateStringFromString |
7797 | * instead. |
7798 | * |
7799 | * We do not distinguish between key events and keyspace events, and it is up |
7800 | * to the module to filter the actions taken based on the key. |
7801 | * |
7802 | * The subscriber signature is: |
7803 | * |
7804 | * int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, |
7805 | * const char *event, |
7806 | * RedisModuleString *key); |
7807 | * |
7808 | * `type` is the event type bit, that must match the mask given at registration |
7809 | * time. The event string is the actual command being executed, and key is the |
7810 | * relevant Redis key. |
7811 | * |
7812 | * Notification callback gets executed with a redis context that can not be |
7813 | * used to send anything to the client, and has the db number where the event |
7814 | * occurred as its selected db number. |
7815 | * |
7816 | * Notice that it is not necessary to enable notifications in redis.conf for |
7817 | * module notifications to work. |
7818 | * |
7819 | * Warning: the notification callbacks are performed in a synchronous manner, |
7820 | * so notification callbacks must to be fast, or they would slow Redis down. |
7821 | * If you need to take long actions, use threads to offload them. |
7822 | * |
7823 | * See https://redis.io/topics/notifications for more information. |
7824 | */ |
7825 | int RM_SubscribeToKeyspaceEvents(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc callback) { |
7826 | RedisModuleKeyspaceSubscriber *sub = zmalloc(sizeof(*sub)); |
7827 | sub->module = ctx->module; |
7828 | sub->event_mask = types; |
7829 | sub->notify_callback = callback; |
7830 | sub->active = 0; |
7831 | |
7832 | listAddNodeTail(moduleKeyspaceSubscribers, sub); |
7833 | return REDISMODULE_OK; |
7834 | } |
7835 | |
7836 | /* Get the configured bitmap of notify-keyspace-events (Could be used |
7837 | * for additional filtering in RedisModuleNotificationFunc) */ |
7838 | int RM_GetNotifyKeyspaceEvents() { |
7839 | return server.notify_keyspace_events; |
7840 | } |
7841 | |
7842 | /* Expose notifyKeyspaceEvent to modules */ |
7843 | int RM_NotifyKeyspaceEvent(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { |
7844 | if (!ctx || !ctx->client) |
7845 | return REDISMODULE_ERR; |
7846 | notifyKeyspaceEvent(type, (char *)event, key, ctx->client->db->id); |
7847 | return REDISMODULE_OK; |
7848 | } |
7849 | |
7850 | /* Dispatcher for keyspace notifications to module subscriber functions. |
7851 | * This gets called only if at least one module requested to be notified on |
7852 | * keyspace notifications */ |
7853 | void moduleNotifyKeyspaceEvent(int type, const char *event, robj *key, int dbid) { |
7854 | /* Don't do anything if there aren't any subscribers */ |
7855 | if (listLength(moduleKeyspaceSubscribers) == 0) return; |
7856 | |
7857 | listIter li; |
7858 | listNode *ln; |
7859 | listRewind(moduleKeyspaceSubscribers,&li); |
7860 | |
7861 | /* Remove irrelevant flags from the type mask */ |
7862 | type &= ~(NOTIFY_KEYEVENT | NOTIFY_KEYSPACE); |
7863 | |
7864 | while((ln = listNext(&li))) { |
7865 | RedisModuleKeyspaceSubscriber *sub = ln->value; |
7866 | /* Only notify subscribers on events matching the registration, |
7867 | * and avoid subscribers triggering themselves */ |
7868 | if ((sub->event_mask & type) && sub->active == 0) { |
7869 | RedisModuleCtx ctx; |
7870 | moduleCreateContext(&ctx, sub->module, REDISMODULE_CTX_TEMP_CLIENT); |
7871 | selectDb(ctx.client, dbid); |
7872 | |
7873 | /* mark the handler as active to avoid reentrant loops. |
7874 | * If the subscriber performs an action triggering itself, |
7875 | * it will not be notified about it. */ |
7876 | sub->active = 1; |
7877 | sub->notify_callback(&ctx, type, event, key); |
7878 | sub->active = 0; |
7879 | moduleFreeContext(&ctx); |
7880 | } |
7881 | } |
7882 | } |
7883 | |
7884 | /* Unsubscribe any notification subscribers this module has upon unloading */ |
7885 | void moduleUnsubscribeNotifications(RedisModule *module) { |
7886 | listIter li; |
7887 | listNode *ln; |
7888 | listRewind(moduleKeyspaceSubscribers,&li); |
7889 | while((ln = listNext(&li))) { |
7890 | RedisModuleKeyspaceSubscriber *sub = ln->value; |
7891 | if (sub->module == module) { |
7892 | listDelNode(moduleKeyspaceSubscribers, ln); |
7893 | zfree(sub); |
7894 | } |
7895 | } |
7896 | } |
7897 | |
7898 | /* -------------------------------------------------------------------------- |
7899 | * ## Modules Cluster API |
7900 | * -------------------------------------------------------------------------- */ |
7901 | |
7902 | /* The Cluster message callback function pointer type. */ |
7903 | typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len); |
7904 | |
7905 | /* This structure identifies a registered caller: it must match a given module |
7906 | * ID, for a given message type. The callback function is just the function |
7907 | * that was registered as receiver. */ |
7908 | typedef struct moduleClusterReceiver { |
7909 | uint64_t module_id; |
7910 | RedisModuleClusterMessageReceiver callback; |
7911 | struct RedisModule *module; |
7912 | struct moduleClusterReceiver *next; |
7913 | } moduleClusterReceiver; |
7914 | |
7915 | typedef struct moduleClusterNodeInfo { |
7916 | int flags; |
7917 | char ip[NET_IP_STR_LEN]; |
7918 | int port; |
7919 | char master_id[40]; /* Only if flags & REDISMODULE_NODE_MASTER is true. */ |
7920 | } mdouleClusterNodeInfo; |
7921 | |
7922 | /* We have an array of message types: each bucket is a linked list of |
7923 | * configured receivers. */ |
7924 | static moduleClusterReceiver *clusterReceivers[UINT8_MAX]; |
7925 | |
7926 | /* Dispatch the message to the right module receiver. */ |
7927 | void moduleCallClusterReceivers(const char *sender_id, uint64_t module_id, uint8_t type, const unsigned char *payload, uint32_t len) { |
7928 | moduleClusterReceiver *r = clusterReceivers[type]; |
7929 | while(r) { |
7930 | if (r->module_id == module_id) { |
7931 | RedisModuleCtx ctx; |
7932 | moduleCreateContext(&ctx, r->module, REDISMODULE_CTX_TEMP_CLIENT); |
7933 | selectDb(ctx.client, 0); |
7934 | r->callback(&ctx,sender_id,type,payload,len); |
7935 | moduleFreeContext(&ctx); |
7936 | return; |
7937 | } |
7938 | r = r->next; |
7939 | } |
7940 | } |
7941 | |
7942 | /* Register a callback receiver for cluster messages of type 'type'. If there |
7943 | * was already a registered callback, this will replace the callback function |
7944 | * with the one provided, otherwise if the callback is set to NULL and there |
7945 | * is already a callback for this function, the callback is unregistered |
7946 | * (so this API call is also used in order to delete the receiver). */ |
7947 | void RM_RegisterClusterMessageReceiver(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback) { |
7948 | if (!server.cluster_enabled) return; |
7949 | |
7950 | uint64_t module_id = moduleTypeEncodeId(ctx->module->name,0); |
7951 | moduleClusterReceiver *r = clusterReceivers[type], *prev = NULL; |
7952 | while(r) { |
7953 | if (r->module_id == module_id) { |
7954 | /* Found! Set or delete. */ |
7955 | if (callback) { |
7956 | r->callback = callback; |
7957 | } else { |
7958 | /* Delete the receiver entry if the user is setting |
7959 | * it to NULL. Just unlink the receiver node from the |
7960 | * linked list. */ |
7961 | if (prev) |
7962 | prev->next = r->next; |
7963 | else |
7964 | clusterReceivers[type]->next = r->next; |
7965 | zfree(r); |
7966 | } |
7967 | return; |
7968 | } |
7969 | prev = r; |
7970 | r = r->next; |
7971 | } |
7972 | |
7973 | /* Not found, let's add it. */ |
7974 | if (callback) { |
7975 | r = zmalloc(sizeof(*r)); |
7976 | r->module_id = module_id; |
7977 | r->module = ctx->module; |
7978 | r->callback = callback; |
7979 | r->next = clusterReceivers[type]; |
7980 | clusterReceivers[type] = r; |
7981 | } |
7982 | } |
7983 | |
7984 | /* Send a message to all the nodes in the cluster if `target` is NULL, otherwise |
7985 | * at the specified target, which is a REDISMODULE_NODE_ID_LEN bytes node ID, as |
7986 | * returned by the receiver callback or by the nodes iteration functions. |
7987 | * |
7988 | * The function returns REDISMODULE_OK if the message was successfully sent, |
7989 | * otherwise if the node is not connected or such node ID does not map to any |
7990 | * known cluster node, REDISMODULE_ERR is returned. */ |
7991 | int RM_SendClusterMessage(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len) { |
7992 | if (!server.cluster_enabled) return REDISMODULE_ERR; |
7993 | uint64_t module_id = moduleTypeEncodeId(ctx->module->name,0); |
7994 | if (clusterSendModuleMessageToTarget(target_id,module_id,type,msg,len) == C_OK) |
7995 | return REDISMODULE_OK; |
7996 | else |
7997 | return REDISMODULE_ERR; |
7998 | } |
7999 | |
8000 | /* Return an array of string pointers, each string pointer points to a cluster |
8001 | * node ID of exactly REDISMODULE_NODE_ID_LEN bytes (without any null term). |
8002 | * The number of returned node IDs is stored into `*numnodes`. |
8003 | * However if this function is called by a module not running an a Redis |
8004 | * instance with Redis Cluster enabled, NULL is returned instead. |
8005 | * |
8006 | * The IDs returned can be used with RedisModule_GetClusterNodeInfo() in order |
8007 | * to get more information about single node. |
8008 | * |
8009 | * The array returned by this function must be freed using the function |
8010 | * RedisModule_FreeClusterNodesList(). |
8011 | * |
8012 | * Example: |
8013 | * |
8014 | * size_t count, j; |
8015 | * char **ids = RedisModule_GetClusterNodesList(ctx,&count); |
8016 | * for (j = 0; j < count; j++) { |
8017 | * RedisModule_Log(ctx,"notice","Node %.*s", |
8018 | * REDISMODULE_NODE_ID_LEN,ids[j]); |
8019 | * } |
8020 | * RedisModule_FreeClusterNodesList(ids); |
8021 | */ |
8022 | char **RM_GetClusterNodesList(RedisModuleCtx *ctx, size_t *numnodes) { |
8023 | UNUSED(ctx); |
8024 | |
8025 | if (!server.cluster_enabled) return NULL; |
8026 | size_t count = dictSize(server.cluster->nodes); |
8027 | char **ids = zmalloc((count+1)*REDISMODULE_NODE_ID_LEN); |
8028 | dictIterator *di = dictGetIterator(server.cluster->nodes); |
8029 | dictEntry *de; |
8030 | int j = 0; |
8031 | while((de = dictNext(di)) != NULL) { |
8032 | clusterNode *node = dictGetVal(de); |
8033 | if (node->flags & (CLUSTER_NODE_NOADDR|CLUSTER_NODE_HANDSHAKE)) continue; |
8034 | ids[j] = zmalloc(REDISMODULE_NODE_ID_LEN); |
8035 | memcpy(ids[j],node->name,REDISMODULE_NODE_ID_LEN); |
8036 | j++; |
8037 | } |
8038 | *numnodes = j; |
8039 | ids[j] = NULL; /* Null term so that FreeClusterNodesList does not need |
8040 | * to also get the count argument. */ |
8041 | dictReleaseIterator(di); |
8042 | return ids; |
8043 | } |
8044 | |
8045 | /* Free the node list obtained with RedisModule_GetClusterNodesList. */ |
8046 | void RM_FreeClusterNodesList(char **ids) { |
8047 | if (ids == NULL) return; |
8048 | for (int j = 0; ids[j]; j++) zfree(ids[j]); |
8049 | zfree(ids); |
8050 | } |
8051 | |
8052 | /* Return this node ID (REDISMODULE_CLUSTER_ID_LEN bytes) or NULL if the cluster |
8053 | * is disabled. */ |
8054 | const char *RM_GetMyClusterID(void) { |
8055 | if (!server.cluster_enabled) return NULL; |
8056 | return server.cluster->myself->name; |
8057 | } |
8058 | |
8059 | /* Return the number of nodes in the cluster, regardless of their state |
8060 | * (handshake, noaddress, ...) so that the number of active nodes may actually |
8061 | * be smaller, but not greater than this number. If the instance is not in |
8062 | * cluster mode, zero is returned. */ |
8063 | size_t RM_GetClusterSize(void) { |
8064 | if (!server.cluster_enabled) return 0; |
8065 | return dictSize(server.cluster->nodes); |
8066 | } |
8067 | |
8068 | /* Populate the specified info for the node having as ID the specified 'id', |
8069 | * then returns REDISMODULE_OK. Otherwise if the format of node ID is invalid |
8070 | * or the node ID does not exist from the POV of this local node, REDISMODULE_ERR |
8071 | * is returned. |
8072 | * |
8073 | * The arguments `ip`, `master_id`, `port` and `flags` can be NULL in case we don't |
8074 | * need to populate back certain info. If an `ip` and `master_id` (only populated |
8075 | * if the instance is a slave) are specified, they point to buffers holding |
8076 | * at least REDISMODULE_NODE_ID_LEN bytes. The strings written back as `ip` |
8077 | * and `master_id` are not null terminated. |
8078 | * |
8079 | * The list of flags reported is the following: |
8080 | * |
8081 | * * REDISMODULE_NODE_MYSELF: This node |
8082 | * * REDISMODULE_NODE_MASTER: The node is a master |
8083 | * * REDISMODULE_NODE_SLAVE: The node is a replica |
8084 | * * REDISMODULE_NODE_PFAIL: We see the node as failing |
8085 | * * REDISMODULE_NODE_FAIL: The cluster agrees the node is failing |
8086 | * * REDISMODULE_NODE_NOFAILOVER: The slave is configured to never failover |
8087 | */ |
8088 | int RM_GetClusterNodeInfo(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags) { |
8089 | UNUSED(ctx); |
8090 | |
8091 | clusterNode *node = clusterLookupNode(id, strlen(id)); |
8092 | if (node == NULL || |
8093 | node->flags & (CLUSTER_NODE_NOADDR|CLUSTER_NODE_HANDSHAKE)) |
8094 | { |
8095 | return REDISMODULE_ERR; |
8096 | } |
8097 | |
8098 | if (ip) strncpy(ip,node->ip,NET_IP_STR_LEN); |
8099 | |
8100 | if (master_id) { |
8101 | /* If the information is not available, the function will set the |
8102 | * field to zero bytes, so that when the field can't be populated the |
8103 | * function kinda remains predictable. */ |
8104 | if (node->flags & CLUSTER_NODE_SLAVE && node->slaveof) |
8105 | memcpy(master_id,node->slaveof->name,REDISMODULE_NODE_ID_LEN); |
8106 | else |
8107 | memset(master_id,0,REDISMODULE_NODE_ID_LEN); |
8108 | } |
8109 | if (port) *port = node->port; |
8110 | |
8111 | /* As usually we have to remap flags for modules, in order to ensure |
8112 | * we can provide binary compatibility. */ |
8113 | if (flags) { |
8114 | *flags = 0; |
8115 | if (node->flags & CLUSTER_NODE_MYSELF) *flags |= REDISMODULE_NODE_MYSELF; |
8116 | if (node->flags & CLUSTER_NODE_MASTER) *flags |= REDISMODULE_NODE_MASTER; |
8117 | if (node->flags & CLUSTER_NODE_SLAVE) *flags |= REDISMODULE_NODE_SLAVE; |
8118 | if (node->flags & CLUSTER_NODE_PFAIL) *flags |= REDISMODULE_NODE_PFAIL; |
8119 | if (node->flags & CLUSTER_NODE_FAIL) *flags |= REDISMODULE_NODE_FAIL; |
8120 | if (node->flags & CLUSTER_NODE_NOFAILOVER) *flags |= REDISMODULE_NODE_NOFAILOVER; |
8121 | } |
8122 | return REDISMODULE_OK; |
8123 | } |
8124 | |
8125 | /* Set Redis Cluster flags in order to change the normal behavior of |
8126 | * Redis Cluster, especially with the goal of disabling certain functions. |
8127 | * This is useful for modules that use the Cluster API in order to create |
8128 | * a different distributed system, but still want to use the Redis Cluster |
8129 | * message bus. Flags that can be set: |
8130 | * |
8131 | * * CLUSTER_MODULE_FLAG_NO_FAILOVER |
8132 | * * CLUSTER_MODULE_FLAG_NO_REDIRECTION |
8133 | * |
8134 | * With the following effects: |
8135 | * |
8136 | * * NO_FAILOVER: prevent Redis Cluster slaves from failing over a dead master. |
8137 | * Also disables the replica migration feature. |
8138 | * |
8139 | * * NO_REDIRECTION: Every node will accept any key, without trying to perform |
8140 | * partitioning according to the Redis Cluster algorithm. |
8141 | * Slots information will still be propagated across the |
8142 | * cluster, but without effect. */ |
8143 | void RM_SetClusterFlags(RedisModuleCtx *ctx, uint64_t flags) { |
8144 | UNUSED(ctx); |
8145 | if (flags & REDISMODULE_CLUSTER_FLAG_NO_FAILOVER) |
8146 | server.cluster_module_flags |= CLUSTER_MODULE_FLAG_NO_FAILOVER; |
8147 | if (flags & REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION) |
8148 | server.cluster_module_flags |= CLUSTER_MODULE_FLAG_NO_REDIRECTION; |
8149 | } |
8150 | |
8151 | /* -------------------------------------------------------------------------- |
8152 | * ## Modules Timers API |
8153 | * |
8154 | * Module timers are a high precision "green timers" abstraction where |
8155 | * every module can register even millions of timers without problems, even if |
8156 | * the actual event loop will just have a single timer that is used to awake the |
8157 | * module timers subsystem in order to process the next event. |
8158 | * |
8159 | * All the timers are stored into a radix tree, ordered by expire time, when |
8160 | * the main Redis event loop timer callback is called, we try to process all |
8161 | * the timers already expired one after the other. Then we re-enter the event |
8162 | * loop registering a timer that will expire when the next to process module |
8163 | * timer will expire. |
8164 | * |
8165 | * Every time the list of active timers drops to zero, we unregister the |
8166 | * main event loop timer, so that there is no overhead when such feature is |
8167 | * not used. |
8168 | * -------------------------------------------------------------------------- */ |
8169 | |
8170 | static rax *Timers; /* The radix tree of all the timers sorted by expire. */ |
8171 | long long aeTimer = -1; /* Main event loop (ae.c) timer identifier. */ |
8172 | |
8173 | typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data); |
8174 | |
8175 | /* The timer descriptor, stored as value in the radix tree. */ |
8176 | typedef struct RedisModuleTimer { |
8177 | RedisModule *module; /* Module reference. */ |
8178 | RedisModuleTimerProc callback; /* The callback to invoke on expire. */ |
8179 | void *data; /* Private data for the callback. */ |
8180 | int dbid; /* Database number selected by the original client. */ |
8181 | } RedisModuleTimer; |
8182 | |
8183 | /* This is the timer handler that is called by the main event loop. We schedule |
8184 | * this timer to be called when the nearest of our module timers will expire. */ |
8185 | int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *clientData) { |
8186 | UNUSED(eventLoop); |
8187 | UNUSED(id); |
8188 | UNUSED(clientData); |
8189 | |
8190 | /* To start let's try to fire all the timers already expired. */ |
8191 | raxIterator ri; |
8192 | raxStart(&ri,Timers); |
8193 | uint64_t now = ustime(); |
8194 | long long next_period = 0; |
8195 | while(1) { |
8196 | raxSeek(&ri,"^" ,NULL,0); |
8197 | if (!raxNext(&ri)) break; |
8198 | uint64_t expiretime; |
8199 | memcpy(&expiretime,ri.key,sizeof(expiretime)); |
8200 | expiretime = ntohu64(expiretime); |
8201 | if (now >= expiretime) { |
8202 | RedisModuleTimer *timer = ri.data; |
8203 | RedisModuleCtx ctx; |
8204 | moduleCreateContext(&ctx,timer->module,REDISMODULE_CTX_TEMP_CLIENT); |
8205 | selectDb(ctx.client, timer->dbid); |
8206 | timer->callback(&ctx,timer->data); |
8207 | moduleFreeContext(&ctx); |
8208 | raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL); |
8209 | zfree(timer); |
8210 | } else { |
8211 | /* We call ustime() again instead of using the cached 'now' so that |
8212 | * 'next_period' isn't affected by the time it took to execute |
8213 | * previous calls to 'callback. |
8214 | * We need to cast 'expiretime' so that the compiler will not treat |
8215 | * the difference as unsigned (Causing next_period to be huge) in |
8216 | * case expiretime < ustime() */ |
8217 | next_period = ((long long)expiretime-ustime())/1000; /* Scale to milliseconds. */ |
8218 | break; |
8219 | } |
8220 | } |
8221 | raxStop(&ri); |
8222 | |
8223 | /* Reschedule the next timer or cancel it. */ |
8224 | if (next_period <= 0) next_period = 1; |
8225 | if (raxSize(Timers) > 0) { |
8226 | return next_period; |
8227 | } else { |
8228 | aeTimer = -1; |
8229 | return AE_NOMORE; |
8230 | } |
8231 | } |
8232 | |
8233 | /* Create a new timer that will fire after `period` milliseconds, and will call |
8234 | * the specified function using `data` as argument. The returned timer ID can be |
8235 | * used to get information from the timer or to stop it before it fires. |
8236 | * Note that for the common use case of a repeating timer (Re-registration |
8237 | * of the timer inside the RedisModuleTimerProc callback) it matters when |
8238 | * this API is called: |
8239 | * If it is called at the beginning of 'callback' it means |
8240 | * the event will triggered every 'period'. |
8241 | * If it is called at the end of 'callback' it means |
8242 | * there will 'period' milliseconds gaps between events. |
8243 | * (If the time it takes to execute 'callback' is negligible the two |
8244 | * statements above mean the same) */ |
8245 | RedisModuleTimerID RM_CreateTimer(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) { |
8246 | RedisModuleTimer *timer = zmalloc(sizeof(*timer)); |
8247 | timer->module = ctx->module; |
8248 | timer->callback = callback; |
8249 | timer->data = data; |
8250 | timer->dbid = ctx->client ? ctx->client->db->id : 0; |
8251 | uint64_t expiretime = ustime()+period*1000; |
8252 | uint64_t key; |
8253 | |
8254 | while(1) { |
8255 | key = htonu64(expiretime); |
8256 | if (raxFind(Timers, (unsigned char*)&key,sizeof(key)) == raxNotFound) { |
8257 | raxInsert(Timers,(unsigned char*)&key,sizeof(key),timer,NULL); |
8258 | break; |
8259 | } else { |
8260 | expiretime++; |
8261 | } |
8262 | } |
8263 | |
8264 | /* We need to install the main event loop timer if it's not already |
8265 | * installed, or we may need to refresh its period if we just installed |
8266 | * a timer that will expire sooner than any other else (i.e. the timer |
8267 | * we just installed is the first timer in the Timers rax). */ |
8268 | if (aeTimer != -1) { |
8269 | raxIterator ri; |
8270 | raxStart(&ri,Timers); |
8271 | raxSeek(&ri,"^" ,NULL,0); |
8272 | raxNext(&ri); |
8273 | if (memcmp(ri.key,&key,sizeof(key)) == 0) { |
8274 | /* This is the first key, we need to re-install the timer according |
8275 | * to the just added event. */ |
8276 | aeDeleteTimeEvent(server.el,aeTimer); |
8277 | aeTimer = -1; |
8278 | } |
8279 | raxStop(&ri); |
8280 | } |
8281 | |
8282 | /* If we have no main timer (the old one was invalidated, or this is the |
8283 | * first module timer we have), install one. */ |
8284 | if (aeTimer == -1) |
8285 | aeTimer = aeCreateTimeEvent(server.el,period,moduleTimerHandler,NULL,NULL); |
8286 | |
8287 | return key; |
8288 | } |
8289 | |
8290 | /* Stop a timer, returns REDISMODULE_OK if the timer was found, belonged to the |
8291 | * calling module, and was stopped, otherwise REDISMODULE_ERR is returned. |
8292 | * If not NULL, the data pointer is set to the value of the data argument when |
8293 | * the timer was created. */ |
8294 | int RM_StopTimer(RedisModuleCtx *ctx, RedisModuleTimerID id, void **data) { |
8295 | RedisModuleTimer *timer = raxFind(Timers,(unsigned char*)&id,sizeof(id)); |
8296 | if (timer == raxNotFound || timer->module != ctx->module) |
8297 | return REDISMODULE_ERR; |
8298 | if (data) *data = timer->data; |
8299 | raxRemove(Timers,(unsigned char*)&id,sizeof(id),NULL); |
8300 | zfree(timer); |
8301 | return REDISMODULE_OK; |
8302 | } |
8303 | |
8304 | /* Obtain information about a timer: its remaining time before firing |
8305 | * (in milliseconds), and the private data pointer associated with the timer. |
8306 | * If the timer specified does not exist or belongs to a different module |
8307 | * no information is returned and the function returns REDISMODULE_ERR, otherwise |
8308 | * REDISMODULE_OK is returned. The arguments remaining or data can be NULL if |
8309 | * the caller does not need certain information. */ |
8310 | int RM_GetTimerInfo(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data) { |
8311 | RedisModuleTimer *timer = raxFind(Timers,(unsigned char*)&id,sizeof(id)); |
8312 | if (timer == raxNotFound || timer->module != ctx->module) |
8313 | return REDISMODULE_ERR; |
8314 | if (remaining) { |
8315 | int64_t rem = ntohu64(id)-ustime(); |
8316 | if (rem < 0) rem = 0; |
8317 | *remaining = rem/1000; /* Scale to milliseconds. */ |
8318 | } |
8319 | if (data) *data = timer->data; |
8320 | return REDISMODULE_OK; |
8321 | } |
8322 | |
8323 | /* Query timers to see if any timer belongs to the module. |
8324 | * Return 1 if any timer was found, otherwise 0 would be returned. */ |
8325 | int moduleHoldsTimer(struct RedisModule *module) { |
8326 | raxIterator iter; |
8327 | int found = 0; |
8328 | raxStart(&iter,Timers); |
8329 | raxSeek(&iter,"^" ,NULL,0); |
8330 | while (raxNext(&iter)) { |
8331 | RedisModuleTimer *timer = iter.data; |
8332 | if (timer->module == module) { |
8333 | found = 1; |
8334 | break; |
8335 | } |
8336 | } |
8337 | raxStop(&iter); |
8338 | return found; |
8339 | } |
8340 | |
8341 | /* -------------------------------------------------------------------------- |
8342 | * ## Modules EventLoop API |
8343 | * --------------------------------------------------------------------------*/ |
8344 | |
8345 | typedef struct EventLoopData { |
8346 | RedisModuleEventLoopFunc rFunc; |
8347 | RedisModuleEventLoopFunc wFunc; |
8348 | void *user_data; |
8349 | } EventLoopData; |
8350 | |
8351 | typedef struct EventLoopOneShot { |
8352 | RedisModuleEventLoopOneShotFunc func; |
8353 | void *user_data; |
8354 | } EventLoopOneShot; |
8355 | |
8356 | list *moduleEventLoopOneShots; |
8357 | static pthread_mutex_t moduleEventLoopMutex = PTHREAD_MUTEX_INITIALIZER; |
8358 | |
8359 | static int eventLoopToAeMask(int mask) { |
8360 | int aeMask = 0; |
8361 | if (mask & REDISMODULE_EVENTLOOP_READABLE) |
8362 | aeMask |= AE_READABLE; |
8363 | if (mask & REDISMODULE_EVENTLOOP_WRITABLE) |
8364 | aeMask |= AE_WRITABLE; |
8365 | return aeMask; |
8366 | } |
8367 | |
8368 | static int eventLoopFromAeMask(int ae_mask) { |
8369 | int mask = 0; |
8370 | if (ae_mask & AE_READABLE) |
8371 | mask |= REDISMODULE_EVENTLOOP_READABLE; |
8372 | if (ae_mask & AE_WRITABLE) |
8373 | mask |= REDISMODULE_EVENTLOOP_WRITABLE; |
8374 | return mask; |
8375 | } |
8376 | |
8377 | static void eventLoopCbReadable(struct aeEventLoop *ae, int fd, void *user_data, int ae_mask) { |
8378 | UNUSED(ae); |
8379 | EventLoopData *data = user_data; |
8380 | data->rFunc(fd, data->user_data, eventLoopFromAeMask(ae_mask)); |
8381 | } |
8382 | |
8383 | static void eventLoopCbWritable(struct aeEventLoop *ae, int fd, void *user_data, int ae_mask) { |
8384 | UNUSED(ae); |
8385 | EventLoopData *data = user_data; |
8386 | data->wFunc(fd, data->user_data, eventLoopFromAeMask(ae_mask)); |
8387 | } |
8388 | |
8389 | /* Add a pipe / socket event to the event loop. |
8390 | * |
8391 | * * `mask` must be one of the following values: |
8392 | * |
8393 | * * `REDISMODULE_EVENTLOOP_READABLE` |
8394 | * * `REDISMODULE_EVENTLOOP_WRITABLE` |
8395 | * * `REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE` |
8396 | * |
8397 | * On success REDISMODULE_OK is returned, otherwise |
8398 | * REDISMODULE_ERR is returned and errno is set to the following values: |
8399 | * |
8400 | * * ERANGE: `fd` is negative or higher than `maxclients` Redis config. |
8401 | * * EINVAL: `callback` is NULL or `mask` value is invalid. |
8402 | * |
8403 | * `errno` might take other values in case of an internal error. |
8404 | * |
8405 | * Example: |
8406 | * |
8407 | * void onReadable(int fd, void *user_data, int mask) { |
8408 | * char buf[32]; |
8409 | * int bytes = read(fd,buf,sizeof(buf)); |
8410 | * printf("Read %d bytes \n", bytes); |
8411 | * } |
8412 | * RM_EventLoopAdd(fd, REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL); |
8413 | */ |
8414 | int RM_EventLoopAdd(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) { |
8415 | if (fd < 0 || fd >= aeGetSetSize(server.el)) { |
8416 | errno = ERANGE; |
8417 | return REDISMODULE_ERR; |
8418 | } |
8419 | |
8420 | if (!func || mask & ~(REDISMODULE_EVENTLOOP_READABLE | |
8421 | REDISMODULE_EVENTLOOP_WRITABLE)) { |
8422 | errno = EINVAL; |
8423 | return REDISMODULE_ERR; |
8424 | } |
8425 | |
8426 | /* We are going to register stub callbacks to 'ae' for two reasons: |
8427 | * |
8428 | * - "ae" callback signature is different from RedisModuleEventLoopCallback, |
8429 | * that will be handled it in our stub callbacks. |
8430 | * - We need to remap 'mask' value to provide binary compatibility. |
8431 | * |
8432 | * For the stub callbacks, saving user 'callback' and 'user_data' in an |
8433 | * EventLoopData object and passing it to ae, later, we'll extract |
8434 | * 'callback' and 'user_data' from that. |
8435 | */ |
8436 | EventLoopData *data = aeGetFileClientData(server.el, fd); |
8437 | if (!data) |
8438 | data = zcalloc(sizeof(*data)); |
8439 | |
8440 | aeFileProc *aeProc; |
8441 | if (mask & REDISMODULE_EVENTLOOP_READABLE) |
8442 | aeProc = eventLoopCbReadable; |
8443 | else |
8444 | aeProc = eventLoopCbWritable; |
8445 | |
8446 | int aeMask = eventLoopToAeMask(mask); |
8447 | |
8448 | if (aeCreateFileEvent(server.el, fd, aeMask, aeProc, data) != AE_OK) { |
8449 | if (aeGetFileEvents(server.el, fd) == AE_NONE) |
8450 | zfree(data); |
8451 | return REDISMODULE_ERR; |
8452 | } |
8453 | |
8454 | data->user_data = user_data; |
8455 | if (mask & REDISMODULE_EVENTLOOP_READABLE) |
8456 | data->rFunc = func; |
8457 | if (mask & REDISMODULE_EVENTLOOP_WRITABLE) |
8458 | data->wFunc = func; |
8459 | |
8460 | errno = 0; |
8461 | return REDISMODULE_OK; |
8462 | } |
8463 | |
8464 | /* Delete a pipe / socket event from the event loop. |
8465 | * |
8466 | * * `mask` must be one of the following values: |
8467 | * |
8468 | * * `REDISMODULE_EVENTLOOP_READABLE` |
8469 | * * `REDISMODULE_EVENTLOOP_WRITABLE` |
8470 | * * `REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE` |
8471 | * |
8472 | * On success REDISMODULE_OK is returned, otherwise |
8473 | * REDISMODULE_ERR is returned and errno is set to the following values: |
8474 | * |
8475 | * * ERANGE: `fd` is negative or higher than `maxclients` Redis config. |
8476 | * * EINVAL: `mask` value is invalid. |
8477 | */ |
8478 | int RM_EventLoopDel(int fd, int mask) { |
8479 | if (fd < 0 || fd >= aeGetSetSize(server.el)) { |
8480 | errno = ERANGE; |
8481 | return REDISMODULE_ERR; |
8482 | } |
8483 | |
8484 | if (mask & ~(REDISMODULE_EVENTLOOP_READABLE | |
8485 | REDISMODULE_EVENTLOOP_WRITABLE)) { |
8486 | errno = EINVAL; |
8487 | return REDISMODULE_ERR; |
8488 | } |
8489 | |
8490 | /* After deleting the event, if fd does not have any registered event |
8491 | * anymore, we can free the EventLoopData object. */ |
8492 | EventLoopData *data = aeGetFileClientData(server.el, fd); |
8493 | aeDeleteFileEvent(server.el, fd, eventLoopToAeMask(mask)); |
8494 | if (aeGetFileEvents(server.el, fd) == AE_NONE) |
8495 | zfree(data); |
8496 | |
8497 | errno = 0; |
8498 | return REDISMODULE_OK; |
8499 | } |
8500 | |
8501 | /* This function can be called from other threads to trigger callback on Redis |
8502 | * main thread. On success REDISMODULE_OK is returned. If `func` is NULL |
8503 | * REDISMODULE_ERR is returned and errno is set to EINVAL. |
8504 | */ |
8505 | int RM_EventLoopAddOneShot(RedisModuleEventLoopOneShotFunc func, void *user_data) { |
8506 | if (!func) { |
8507 | errno = EINVAL; |
8508 | return REDISMODULE_ERR; |
8509 | } |
8510 | |
8511 | EventLoopOneShot *oneshot = zmalloc(sizeof(*oneshot)); |
8512 | oneshot->func = func; |
8513 | oneshot->user_data = user_data; |
8514 | |
8515 | pthread_mutex_lock(&moduleEventLoopMutex); |
8516 | if (!moduleEventLoopOneShots) moduleEventLoopOneShots = listCreate(); |
8517 | listAddNodeTail(moduleEventLoopOneShots, oneshot); |
8518 | pthread_mutex_unlock(&moduleEventLoopMutex); |
8519 | |
8520 | if (write(server.module_pipe[1],"A" ,1) != 1) { |
8521 | /* Pipe is non-blocking, write() may fail if it's full. */ |
8522 | } |
8523 | |
8524 | errno = 0; |
8525 | return REDISMODULE_OK; |
8526 | } |
8527 | |
8528 | /* This function will check the moduleEventLoopOneShots queue in order to |
8529 | * call the callback for the registered oneshot events. */ |
8530 | static void eventLoopHandleOneShotEvents() { |
8531 | pthread_mutex_lock(&moduleEventLoopMutex); |
8532 | if (moduleEventLoopOneShots) { |
8533 | while (listLength(moduleEventLoopOneShots)) { |
8534 | listNode *ln = listFirst(moduleEventLoopOneShots); |
8535 | EventLoopOneShot *oneshot = ln->value; |
8536 | listDelNode(moduleEventLoopOneShots, ln); |
8537 | /* Unlock mutex before the callback. Another oneshot event can be |
8538 | * added in the callback, it will need to lock the mutex. */ |
8539 | pthread_mutex_unlock(&moduleEventLoopMutex); |
8540 | oneshot->func(oneshot->user_data); |
8541 | zfree(oneshot); |
8542 | /* Lock again for the next iteration */ |
8543 | pthread_mutex_lock(&moduleEventLoopMutex); |
8544 | } |
8545 | } |
8546 | pthread_mutex_unlock(&moduleEventLoopMutex); |
8547 | } |
8548 | |
8549 | /* -------------------------------------------------------------------------- |
8550 | * ## Modules ACL API |
8551 | * |
8552 | * Implements a hook into the authentication and authorization within Redis. |
8553 | * --------------------------------------------------------------------------*/ |
8554 | |
8555 | /* This function is called when a client's user has changed and invokes the |
8556 | * client's user changed callback if it was set. This callback should |
8557 | * cleanup any state the module was tracking about this client. |
8558 | * |
8559 | * A client's user can be changed through the AUTH command, module |
8560 | * authentication, and when a client is freed. */ |
8561 | void moduleNotifyUserChanged(client *c) { |
8562 | if (c->auth_callback) { |
8563 | c->auth_callback(c->id, c->auth_callback_privdata); |
8564 | |
8565 | /* The callback will fire exactly once, even if the user remains |
8566 | * the same. It is expected to completely clean up the state |
8567 | * so all references are cleared here. */ |
8568 | c->auth_callback = NULL; |
8569 | c->auth_callback_privdata = NULL; |
8570 | c->auth_module = NULL; |
8571 | } |
8572 | } |
8573 | |
8574 | void revokeClientAuthentication(client *c) { |
8575 | /* Freeing the client would result in moduleNotifyUserChanged() to be |
8576 | * called later, however since we use revokeClientAuthentication() also |
8577 | * in moduleFreeAuthenticatedClients() to implement module unloading, we |
8578 | * do this action ASAP: this way if the module is unloaded, when the client |
8579 | * is eventually freed we don't rely on the module to still exist. */ |
8580 | moduleNotifyUserChanged(c); |
8581 | |
8582 | c->user = DefaultUser; |
8583 | c->authenticated = 0; |
8584 | /* We will write replies to this client later, so we can't close it |
8585 | * directly even if async. */ |
8586 | if (c == server.current_client) { |
8587 | c->flags |= CLIENT_CLOSE_AFTER_COMMAND; |
8588 | } else { |
8589 | freeClientAsync(c); |
8590 | } |
8591 | } |
8592 | |
8593 | /* Cleanup all clients that have been authenticated with this module. This |
8594 | * is called from onUnload() to give the module a chance to cleanup any |
8595 | * resources associated with clients it has authenticated. */ |
8596 | static void moduleFreeAuthenticatedClients(RedisModule *module) { |
8597 | listIter li; |
8598 | listNode *ln; |
8599 | listRewind(server.clients,&li); |
8600 | while ((ln = listNext(&li)) != NULL) { |
8601 | client *c = listNodeValue(ln); |
8602 | if (!c->auth_module) continue; |
8603 | |
8604 | RedisModule *auth_module = (RedisModule *) c->auth_module; |
8605 | if (auth_module == module) { |
8606 | revokeClientAuthentication(c); |
8607 | } |
8608 | } |
8609 | } |
8610 | |
8611 | /* Creates a Redis ACL user that the module can use to authenticate a client. |
8612 | * After obtaining the user, the module should set what such user can do |
8613 | * using the RM_SetUserACL() function. Once configured, the user |
8614 | * can be used in order to authenticate a connection, with the specified |
8615 | * ACL rules, using the RedisModule_AuthClientWithUser() function. |
8616 | * |
8617 | * Note that: |
8618 | * |
8619 | * * Users created here are not listed by the ACL command. |
8620 | * * Users created here are not checked for duplicated name, so it's up to |
8621 | * the module calling this function to take care of not creating users |
8622 | * with the same name. |
8623 | * * The created user can be used to authenticate multiple Redis connections. |
8624 | * |
8625 | * The caller can later free the user using the function |
8626 | * RM_FreeModuleUser(). When this function is called, if there are |
8627 | * still clients authenticated with this user, they are disconnected. |
8628 | * The function to free the user should only be used when the caller really |
8629 | * wants to invalidate the user to define a new one with different |
8630 | * capabilities. */ |
8631 | RedisModuleUser *RM_CreateModuleUser(const char *name) { |
8632 | RedisModuleUser *new_user = zmalloc(sizeof(RedisModuleUser)); |
8633 | new_user->user = ACLCreateUnlinkedUser(); |
8634 | new_user->free_user = 1; |
8635 | |
8636 | /* Free the previous temporarily assigned name to assign the new one */ |
8637 | sdsfree(new_user->user->name); |
8638 | new_user->user->name = sdsnew(name); |
8639 | return new_user; |
8640 | } |
8641 | |
8642 | /* Frees a given user and disconnects all of the clients that have been |
8643 | * authenticated with it. See RM_CreateModuleUser for detailed usage.*/ |
8644 | int RM_FreeModuleUser(RedisModuleUser *user) { |
8645 | if (user->free_user) |
8646 | ACLFreeUserAndKillClients(user->user); |
8647 | zfree(user); |
8648 | return REDISMODULE_OK; |
8649 | } |
8650 | |
8651 | /* Sets the permissions of a user created through the redis module |
8652 | * interface. The syntax is the same as ACL SETUSER, so refer to the |
8653 | * documentation in acl.c for more information. See RM_CreateModuleUser |
8654 | * for detailed usage. |
8655 | * |
8656 | * Returns REDISMODULE_OK on success and REDISMODULE_ERR on failure |
8657 | * and will set an errno describing why the operation failed. */ |
8658 | int RM_SetModuleUserACL(RedisModuleUser *user, const char* acl) { |
8659 | return ACLSetUser(user->user, acl, -1); |
8660 | } |
8661 | |
8662 | /* Retrieve the user name of the client connection behind the current context. |
8663 | * The user name can be used later, in order to get a RedisModuleUser. |
8664 | * See more information in RM_GetModuleUserFromUserName. |
8665 | * |
8666 | * The returned string must be released with RedisModule_FreeString() or by |
8667 | * enabling automatic memory management. */ |
8668 | RedisModuleString *RM_GetCurrentUserName(RedisModuleCtx *ctx) { |
8669 | return RM_CreateString(ctx,ctx->client->user->name,sdslen(ctx->client->user->name)); |
8670 | } |
8671 | |
8672 | /* A RedisModuleUser can be used to check if command, key or channel can be executed or |
8673 | * accessed according to the ACLs rules associated with that user. |
8674 | * When a Module wants to do ACL checks on a general ACL user (not created by RM_CreateModuleUser), |
8675 | * it can get the RedisModuleUser from this API, based on the user name retrieved by RM_GetCurrentUserName. |
8676 | * |
8677 | * Since a general ACL user can be deleted at any time, this RedisModuleUser should be used only in the context |
8678 | * where this function was called. In order to do ACL checks out of that context, the Module can store the user name, |
8679 | * and call this API at any other context. |
8680 | * |
8681 | * Returns NULL if the user is disabled or the user does not exist. |
8682 | * The caller should later free the user using the function RM_FreeModuleUser().*/ |
8683 | RedisModuleUser *RM_GetModuleUserFromUserName(RedisModuleString *name) { |
8684 | /* First, verify that the user exist */ |
8685 | user *acl_user = ACLGetUserByName(name->ptr, sdslen(name->ptr)); |
8686 | if (acl_user == NULL) { |
8687 | return NULL; |
8688 | } |
8689 | |
8690 | RedisModuleUser *new_user = zmalloc(sizeof(RedisModuleUser)); |
8691 | new_user->user = acl_user; |
8692 | new_user->free_user = 0; |
8693 | return new_user; |
8694 | } |
8695 | |
8696 | /* Checks if the command can be executed by the user, according to the ACLs associated with it. |
8697 | * |
8698 | * On success a REDISMODULE_OK is returned, otherwise |
8699 | * REDISMODULE_ERR is returned and errno is set to the following values: |
8700 | * |
8701 | * * ENOENT: Specified command does not exist. |
8702 | * * EACCES: Command cannot be executed, according to ACL rules |
8703 | */ |
8704 | int RM_ACLCheckCommandPermissions(RedisModuleUser *user, RedisModuleString **argv, int argc) { |
8705 | int keyidxptr; |
8706 | struct redisCommand *cmd; |
8707 | |
8708 | /* Find command */ |
8709 | if ((cmd = lookupCommand(argv, argc)) == NULL) { |
8710 | errno = ENOENT; |
8711 | return REDISMODULE_ERR; |
8712 | } |
8713 | |
8714 | if (ACLCheckAllUserCommandPerm(user->user, cmd, argv, argc, &keyidxptr) != ACL_OK) { |
8715 | errno = EACCES; |
8716 | return REDISMODULE_ERR; |
8717 | } |
8718 | |
8719 | return REDISMODULE_OK; |
8720 | } |
8721 | |
8722 | /* Check if the key can be accessed by the user according to the ACLs attached to the user |
8723 | * and the flags representing the key access. The flags are the same that are used in the |
8724 | * keyspec for logical operations. These flags are documented in RedisModule_SetCommandInfo as |
8725 | * the REDISMODULE_CMD_KEY_ACCESS, REDISMODULE_CMD_KEY_UPDATE, REDISMODULE_CMD_KEY_INSERT, |
8726 | * and REDISMODULE_CMD_KEY_DELETE flags. |
8727 | * |
8728 | * If no flags are supplied, the user is still required to have some access to the key for |
8729 | * this command to return successfully. |
8730 | * |
8731 | * If the user is able to access the key then REDISMODULE_OK is returned, otherwise |
8732 | * REDISMODULE_ERR is returned and errno is set to one of the following values: |
8733 | * |
8734 | * * EINVAL: The provided flags are invalid. |
8735 | * * EACCESS: The user does not have permission to access the key. |
8736 | */ |
8737 | int RM_ACLCheckKeyPermissions(RedisModuleUser *user, RedisModuleString *key, int flags) { |
8738 | const int allow_mask = (REDISMODULE_CMD_KEY_ACCESS |
8739 | | REDISMODULE_CMD_KEY_INSERT |
8740 | | REDISMODULE_CMD_KEY_DELETE |
8741 | | REDISMODULE_CMD_KEY_UPDATE); |
8742 | |
8743 | if ((flags & allow_mask) != flags) { |
8744 | errno = EINVAL; |
8745 | return REDISMODULE_ERR; |
8746 | } |
8747 | |
8748 | int keyspec_flags = moduleConvertKeySpecsFlags(flags, 0); |
8749 | if (ACLUserCheckKeyPerm(user->user, key->ptr, sdslen(key->ptr), keyspec_flags) != ACL_OK) { |
8750 | errno = EACCES; |
8751 | return REDISMODULE_ERR; |
8752 | } |
8753 | |
8754 | return REDISMODULE_OK; |
8755 | } |
8756 | |
8757 | /* Check if the pubsub channel can be accessed by the user based off of the given |
8758 | * access flags. See RM_ChannelAtPosWithFlags for more information about the |
8759 | * possible flags that can be passed in. |
8760 | * |
8761 | * If the user is able to access the pubsub channel then REDISMODULE_OK is returned, otherwise |
8762 | * REDISMODULE_ERR is returned and errno is set to one of the following values: |
8763 | * |
8764 | * * EINVAL: The provided flags are invalid. |
8765 | * * EACCESS: The user does not have permission to access the pubsub channel. |
8766 | */ |
8767 | int RM_ACLCheckChannelPermissions(RedisModuleUser *user, RedisModuleString *ch, int flags) { |
8768 | const int allow_mask = (REDISMODULE_CMD_CHANNEL_PUBLISH |
8769 | | REDISMODULE_CMD_CHANNEL_SUBSCRIBE |
8770 | | REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE |
8771 | | REDISMODULE_CMD_CHANNEL_PATTERN); |
8772 | |
8773 | if ((flags & allow_mask) != flags) { |
8774 | errno = EINVAL; |
8775 | return REDISMODULE_ERR; |
8776 | } |
8777 | |
8778 | /* Unsubscribe permissions are currently always allowed. */ |
8779 | if (flags & REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE){ |
8780 | return REDISMODULE_OK; |
8781 | } |
8782 | |
8783 | int is_pattern = flags & REDISMODULE_CMD_CHANNEL_PATTERN; |
8784 | if (ACLUserCheckChannelPerm(user->user, ch->ptr, is_pattern) != ACL_OK) |
8785 | return REDISMODULE_ERR; |
8786 | |
8787 | return REDISMODULE_OK; |
8788 | } |
8789 | |
8790 | /* Adds a new entry in the ACL log. |
8791 | * Returns REDISMODULE_OK on success and REDISMODULE_ERR on error. |
8792 | * |
8793 | * For more information about ACL log, please refer to https://redis.io/commands/acl-log */ |
8794 | int RM_ACLAddLogEntry(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason) { |
8795 | int acl_reason; |
8796 | switch (reason) { |
8797 | case REDISMODULE_ACL_LOG_AUTH: acl_reason = ACL_DENIED_AUTH; break; |
8798 | case REDISMODULE_ACL_LOG_KEY: acl_reason = ACL_DENIED_KEY; break; |
8799 | case REDISMODULE_ACL_LOG_CHANNEL: acl_reason = ACL_DENIED_CHANNEL; break; |
8800 | case REDISMODULE_ACL_LOG_CMD: acl_reason = ACL_DENIED_CMD; break; |
8801 | default: return REDISMODULE_ERR; |
8802 | } |
8803 | |
8804 | addACLLogEntry(ctx->client, acl_reason, ACL_LOG_CTX_MODULE, -1, user->user->name, sdsdup(object->ptr)); |
8805 | return REDISMODULE_OK; |
8806 | } |
8807 | |
8808 | /* Authenticate the client associated with the context with |
8809 | * the provided user. Returns REDISMODULE_OK on success and |
8810 | * REDISMODULE_ERR on error. |
8811 | * |
8812 | * This authentication can be tracked with the optional callback and private |
8813 | * data fields. The callback will be called whenever the user of the client |
8814 | * changes. This callback should be used to cleanup any state that is being |
8815 | * kept in the module related to the client authentication. It will only be |
8816 | * called once, even when the user hasn't changed, in order to allow for a |
8817 | * new callback to be specified. If this authentication does not need to be |
8818 | * tracked, pass in NULL for the callback and privdata. |
8819 | * |
8820 | * If client_id is not NULL, it will be filled with the id of the client |
8821 | * that was authenticated. This can be used with the |
8822 | * RM_DeauthenticateAndCloseClient() API in order to deauthenticate a |
8823 | * previously authenticated client if the authentication is no longer valid. |
8824 | * |
8825 | * For expensive authentication operations, it is recommended to block the |
8826 | * client and do the authentication in the background and then attach the user |
8827 | * to the client in a threadsafe context. */ |
8828 | static int authenticateClientWithUser(RedisModuleCtx *ctx, user *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) { |
8829 | if (user->flags & USER_FLAG_DISABLED) { |
8830 | return REDISMODULE_ERR; |
8831 | } |
8832 | |
8833 | /* Avoid settings which are meaningless and will be lost */ |
8834 | if (!ctx->client || (ctx->client->flags & CLIENT_MODULE)) { |
8835 | return REDISMODULE_ERR; |
8836 | } |
8837 | |
8838 | moduleNotifyUserChanged(ctx->client); |
8839 | |
8840 | ctx->client->user = user; |
8841 | ctx->client->authenticated = 1; |
8842 | |
8843 | if (callback) { |
8844 | ctx->client->auth_callback = callback; |
8845 | ctx->client->auth_callback_privdata = privdata; |
8846 | ctx->client->auth_module = ctx->module; |
8847 | } |
8848 | |
8849 | if (client_id) { |
8850 | *client_id = ctx->client->id; |
8851 | } |
8852 | |
8853 | return REDISMODULE_OK; |
8854 | } |
8855 | |
8856 | |
8857 | /* Authenticate the current context's user with the provided redis acl user. |
8858 | * Returns REDISMODULE_ERR if the user is disabled. |
8859 | * |
8860 | * See authenticateClientWithUser for information about callback, client_id, |
8861 | * and general usage for authentication. */ |
8862 | int RM_AuthenticateClientWithUser(RedisModuleCtx *ctx, RedisModuleUser *module_user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) { |
8863 | return authenticateClientWithUser(ctx, module_user->user, callback, privdata, client_id); |
8864 | } |
8865 | |
8866 | /* Authenticate the current context's user with the provided redis acl user. |
8867 | * Returns REDISMODULE_ERR if the user is disabled or the user does not exist. |
8868 | * |
8869 | * See authenticateClientWithUser for information about callback, client_id, |
8870 | * and general usage for authentication. */ |
8871 | int RM_AuthenticateClientWithACLUser(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) { |
8872 | user *acl_user = ACLGetUserByName(name, len); |
8873 | |
8874 | if (!acl_user) { |
8875 | return REDISMODULE_ERR; |
8876 | } |
8877 | return authenticateClientWithUser(ctx, acl_user, callback, privdata, client_id); |
8878 | } |
8879 | |
8880 | /* Deauthenticate and close the client. The client resources will not be |
8881 | * immediately freed, but will be cleaned up in a background job. This is |
8882 | * the recommended way to deauthenticate a client since most clients can't |
8883 | * handle users becoming deauthenticated. Returns REDISMODULE_ERR when the |
8884 | * client doesn't exist and REDISMODULE_OK when the operation was successful. |
8885 | * |
8886 | * The client ID is returned from the RM_AuthenticateClientWithUser and |
8887 | * RM_AuthenticateClientWithACLUser APIs, but can be obtained through |
8888 | * the CLIENT api or through server events. |
8889 | * |
8890 | * This function is not thread safe, and must be executed within the context |
8891 | * of a command or thread safe context. */ |
8892 | int RM_DeauthenticateAndCloseClient(RedisModuleCtx *ctx, uint64_t client_id) { |
8893 | UNUSED(ctx); |
8894 | client *c = lookupClientByID(client_id); |
8895 | if (c == NULL) return REDISMODULE_ERR; |
8896 | |
8897 | /* Revoke also marks client to be closed ASAP */ |
8898 | revokeClientAuthentication(c); |
8899 | return REDISMODULE_OK; |
8900 | } |
8901 | |
8902 | /* Redact the client command argument specified at the given position. Redacted arguments |
8903 | * are obfuscated in user facing commands such as SLOWLOG or MONITOR, as well as |
8904 | * never being written to server logs. This command may be called multiple times on the |
8905 | * same position. |
8906 | * |
8907 | * Note that the command name, position 0, can not be redacted. |
8908 | * |
8909 | * Returns REDISMODULE_OK if the argument was redacted and REDISMODULE_ERR if there |
8910 | * was an invalid parameter passed in or the position is outside the client |
8911 | * argument range. */ |
8912 | int RM_RedactClientCommandArgument(RedisModuleCtx *ctx, int pos) { |
8913 | if (!ctx || !ctx->client || pos <= 0 || ctx->client->argc <= pos) { |
8914 | return REDISMODULE_ERR; |
8915 | } |
8916 | redactClientCommandArgument(ctx->client, pos); |
8917 | return REDISMODULE_OK; |
8918 | } |
8919 | |
8920 | /* Return the X.509 client-side certificate used by the client to authenticate |
8921 | * this connection. |
8922 | * |
8923 | * The return value is an allocated RedisModuleString that is a X.509 certificate |
8924 | * encoded in PEM (Base64) format. It should be freed (or auto-freed) by the caller. |
8925 | * |
8926 | * A NULL value is returned in the following conditions: |
8927 | * |
8928 | * - Connection ID does not exist |
8929 | * - Connection is not a TLS connection |
8930 | * - Connection is a TLS connection but no client certificate was used |
8931 | */ |
8932 | RedisModuleString *RM_GetClientCertificate(RedisModuleCtx *ctx, uint64_t client_id) { |
8933 | client *c = lookupClientByID(client_id); |
8934 | if (c == NULL) return NULL; |
8935 | |
8936 | sds cert = connTLSGetPeerCert(c->conn); |
8937 | if (!cert) return NULL; |
8938 | |
8939 | RedisModuleString *s = createObject(OBJ_STRING, cert); |
8940 | if (ctx != NULL) autoMemoryAdd(ctx, REDISMODULE_AM_STRING, s); |
8941 | |
8942 | return s; |
8943 | } |
8944 | |
8945 | /* -------------------------------------------------------------------------- |
8946 | * ## Modules Dictionary API |
8947 | * |
8948 | * Implements a sorted dictionary (actually backed by a radix tree) with |
8949 | * the usual get / set / del / num-items API, together with an iterator |
8950 | * capable of going back and forth. |
8951 | * -------------------------------------------------------------------------- */ |
8952 | |
8953 | /* Create a new dictionary. The 'ctx' pointer can be the current module context |
8954 | * or NULL, depending on what you want. Please follow the following rules: |
8955 | * |
8956 | * 1. Use a NULL context if you plan to retain a reference to this dictionary |
8957 | * that will survive the time of the module callback where you created it. |
8958 | * 2. Use a NULL context if no context is available at the time you are creating |
8959 | * the dictionary (of course...). |
8960 | * 3. However use the current callback context as 'ctx' argument if the |
8961 | * dictionary time to live is just limited to the callback scope. In this |
8962 | * case, if enabled, you can enjoy the automatic memory management that will |
8963 | * reclaim the dictionary memory, as well as the strings returned by the |
8964 | * Next / Prev dictionary iterator calls. |
8965 | */ |
8966 | RedisModuleDict *RM_CreateDict(RedisModuleCtx *ctx) { |
8967 | struct RedisModuleDict *d = zmalloc(sizeof(*d)); |
8968 | d->rax = raxNew(); |
8969 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_DICT,d); |
8970 | return d; |
8971 | } |
8972 | |
8973 | /* Free a dictionary created with RM_CreateDict(). You need to pass the |
8974 | * context pointer 'ctx' only if the dictionary was created using the |
8975 | * context instead of passing NULL. */ |
8976 | void RM_FreeDict(RedisModuleCtx *ctx, RedisModuleDict *d) { |
8977 | if (ctx != NULL) autoMemoryFreed(ctx,REDISMODULE_AM_DICT,d); |
8978 | raxFree(d->rax); |
8979 | zfree(d); |
8980 | } |
8981 | |
8982 | /* Return the size of the dictionary (number of keys). */ |
8983 | uint64_t RM_DictSize(RedisModuleDict *d) { |
8984 | return raxSize(d->rax); |
8985 | } |
8986 | |
8987 | /* Store the specified key into the dictionary, setting its value to the |
8988 | * pointer 'ptr'. If the key was added with success, since it did not |
8989 | * already exist, REDISMODULE_OK is returned. Otherwise if the key already |
8990 | * exists the function returns REDISMODULE_ERR. */ |
8991 | int RM_DictSetC(RedisModuleDict *d, void *key, size_t keylen, void *ptr) { |
8992 | int retval = raxTryInsert(d->rax,key,keylen,ptr,NULL); |
8993 | return (retval == 1) ? REDISMODULE_OK : REDISMODULE_ERR; |
8994 | } |
8995 | |
8996 | /* Like RedisModule_DictSetC() but will replace the key with the new |
8997 | * value if the key already exists. */ |
8998 | int RM_DictReplaceC(RedisModuleDict *d, void *key, size_t keylen, void *ptr) { |
8999 | int retval = raxInsert(d->rax,key,keylen,ptr,NULL); |
9000 | return (retval == 1) ? REDISMODULE_OK : REDISMODULE_ERR; |
9001 | } |
9002 | |
9003 | /* Like RedisModule_DictSetC() but takes the key as a RedisModuleString. */ |
9004 | int RM_DictSet(RedisModuleDict *d, RedisModuleString *key, void *ptr) { |
9005 | return RM_DictSetC(d,key->ptr,sdslen(key->ptr),ptr); |
9006 | } |
9007 | |
9008 | /* Like RedisModule_DictReplaceC() but takes the key as a RedisModuleString. */ |
9009 | int RM_DictReplace(RedisModuleDict *d, RedisModuleString *key, void *ptr) { |
9010 | return RM_DictReplaceC(d,key->ptr,sdslen(key->ptr),ptr); |
9011 | } |
9012 | |
9013 | /* Return the value stored at the specified key. The function returns NULL |
9014 | * both in the case the key does not exist, or if you actually stored |
9015 | * NULL at key. So, optionally, if the 'nokey' pointer is not NULL, it will |
9016 | * be set by reference to 1 if the key does not exist, or to 0 if the key |
9017 | * exists. */ |
9018 | void *RM_DictGetC(RedisModuleDict *d, void *key, size_t keylen, int *nokey) { |
9019 | void *res = raxFind(d->rax,key,keylen); |
9020 | if (nokey) *nokey = (res == raxNotFound); |
9021 | return (res == raxNotFound) ? NULL : res; |
9022 | } |
9023 | |
9024 | /* Like RedisModule_DictGetC() but takes the key as a RedisModuleString. */ |
9025 | void *RM_DictGet(RedisModuleDict *d, RedisModuleString *key, int *nokey) { |
9026 | return RM_DictGetC(d,key->ptr,sdslen(key->ptr),nokey); |
9027 | } |
9028 | |
9029 | /* Remove the specified key from the dictionary, returning REDISMODULE_OK if |
9030 | * the key was found and deleted, or REDISMODULE_ERR if instead there was |
9031 | * no such key in the dictionary. When the operation is successful, if |
9032 | * 'oldval' is not NULL, then '*oldval' is set to the value stored at the |
9033 | * key before it was deleted. Using this feature it is possible to get |
9034 | * a pointer to the value (for instance in order to release it), without |
9035 | * having to call RedisModule_DictGet() before deleting the key. */ |
9036 | int RM_DictDelC(RedisModuleDict *d, void *key, size_t keylen, void *oldval) { |
9037 | int retval = raxRemove(d->rax,key,keylen,oldval); |
9038 | return retval ? REDISMODULE_OK : REDISMODULE_ERR; |
9039 | } |
9040 | |
9041 | /* Like RedisModule_DictDelC() but gets the key as a RedisModuleString. */ |
9042 | int RM_DictDel(RedisModuleDict *d, RedisModuleString *key, void *oldval) { |
9043 | return RM_DictDelC(d,key->ptr,sdslen(key->ptr),oldval); |
9044 | } |
9045 | |
9046 | /* Return an iterator, setup in order to start iterating from the specified |
9047 | * key by applying the operator 'op', which is just a string specifying the |
9048 | * comparison operator to use in order to seek the first element. The |
9049 | * operators available are: |
9050 | * |
9051 | * * `^` -- Seek the first (lexicographically smaller) key. |
9052 | * * `$` -- Seek the last (lexicographically bigger) key. |
9053 | * * `>` -- Seek the first element greater than the specified key. |
9054 | * * `>=` -- Seek the first element greater or equal than the specified key. |
9055 | * * `<` -- Seek the first element smaller than the specified key. |
9056 | * * `<=` -- Seek the first element smaller or equal than the specified key. |
9057 | * * `==` -- Seek the first element matching exactly the specified key. |
9058 | * |
9059 | * Note that for `^` and `$` the passed key is not used, and the user may |
9060 | * just pass NULL with a length of 0. |
9061 | * |
9062 | * If the element to start the iteration cannot be seeked based on the |
9063 | * key and operator passed, RedisModule_DictNext() / Prev() will just return |
9064 | * REDISMODULE_ERR at the first call, otherwise they'll produce elements. |
9065 | */ |
9066 | RedisModuleDictIter *RM_DictIteratorStartC(RedisModuleDict *d, const char *op, void *key, size_t keylen) { |
9067 | RedisModuleDictIter *di = zmalloc(sizeof(*di)); |
9068 | di->dict = d; |
9069 | raxStart(&di->ri,d->rax); |
9070 | raxSeek(&di->ri,op,key,keylen); |
9071 | return di; |
9072 | } |
9073 | |
9074 | /* Exactly like RedisModule_DictIteratorStartC, but the key is passed as a |
9075 | * RedisModuleString. */ |
9076 | RedisModuleDictIter *RM_DictIteratorStart(RedisModuleDict *d, const char *op, RedisModuleString *key) { |
9077 | return RM_DictIteratorStartC(d,op,key->ptr,sdslen(key->ptr)); |
9078 | } |
9079 | |
9080 | /* Release the iterator created with RedisModule_DictIteratorStart(). This call |
9081 | * is mandatory otherwise a memory leak is introduced in the module. */ |
9082 | void RM_DictIteratorStop(RedisModuleDictIter *di) { |
9083 | raxStop(&di->ri); |
9084 | zfree(di); |
9085 | } |
9086 | |
9087 | /* After its creation with RedisModule_DictIteratorStart(), it is possible to |
9088 | * change the currently selected element of the iterator by using this |
9089 | * API call. The result based on the operator and key is exactly like |
9090 | * the function RedisModule_DictIteratorStart(), however in this case the |
9091 | * return value is just REDISMODULE_OK in case the seeked element was found, |
9092 | * or REDISMODULE_ERR in case it was not possible to seek the specified |
9093 | * element. It is possible to reseek an iterator as many times as you want. */ |
9094 | int RM_DictIteratorReseekC(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) { |
9095 | return raxSeek(&di->ri,op,key,keylen); |
9096 | } |
9097 | |
9098 | /* Like RedisModule_DictIteratorReseekC() but takes the key as a |
9099 | * RedisModuleString. */ |
9100 | int RM_DictIteratorReseek(RedisModuleDictIter *di, const char *op, RedisModuleString *key) { |
9101 | return RM_DictIteratorReseekC(di,op,key->ptr,sdslen(key->ptr)); |
9102 | } |
9103 | |
9104 | /* Return the current item of the dictionary iterator `di` and steps to the |
9105 | * next element. If the iterator already yield the last element and there |
9106 | * are no other elements to return, NULL is returned, otherwise a pointer |
9107 | * to a string representing the key is provided, and the `*keylen` length |
9108 | * is set by reference (if keylen is not NULL). The `*dataptr`, if not NULL |
9109 | * is set to the value of the pointer stored at the returned key as auxiliary |
9110 | * data (as set by the RedisModule_DictSet API). |
9111 | * |
9112 | * Usage example: |
9113 | * |
9114 | * ... create the iterator here ... |
9115 | * char *key; |
9116 | * void *data; |
9117 | * while((key = RedisModule_DictNextC(iter,&keylen,&data)) != NULL) { |
9118 | * printf("%.*s %p\n", (int)keylen, key, data); |
9119 | * } |
9120 | * |
9121 | * The returned pointer is of type void because sometimes it makes sense |
9122 | * to cast it to a `char*` sometimes to an unsigned `char*` depending on the |
9123 | * fact it contains or not binary data, so this API ends being more |
9124 | * comfortable to use. |
9125 | * |
9126 | * The validity of the returned pointer is until the next call to the |
9127 | * next/prev iterator step. Also the pointer is no longer valid once the |
9128 | * iterator is released. */ |
9129 | void *RM_DictNextC(RedisModuleDictIter *di, size_t *keylen, void **dataptr) { |
9130 | if (!raxNext(&di->ri)) return NULL; |
9131 | if (keylen) *keylen = di->ri.key_len; |
9132 | if (dataptr) *dataptr = di->ri.data; |
9133 | return di->ri.key; |
9134 | } |
9135 | |
9136 | /* This function is exactly like RedisModule_DictNext() but after returning |
9137 | * the currently selected element in the iterator, it selects the previous |
9138 | * element (lexicographically smaller) instead of the next one. */ |
9139 | void *RM_DictPrevC(RedisModuleDictIter *di, size_t *keylen, void **dataptr) { |
9140 | if (!raxPrev(&di->ri)) return NULL; |
9141 | if (keylen) *keylen = di->ri.key_len; |
9142 | if (dataptr) *dataptr = di->ri.data; |
9143 | return di->ri.key; |
9144 | } |
9145 | |
9146 | /* Like RedisModuleNextC(), but instead of returning an internally allocated |
9147 | * buffer and key length, it returns directly a module string object allocated |
9148 | * in the specified context 'ctx' (that may be NULL exactly like for the main |
9149 | * API RedisModule_CreateString). |
9150 | * |
9151 | * The returned string object should be deallocated after use, either manually |
9152 | * or by using a context that has automatic memory management active. */ |
9153 | RedisModuleString *RM_DictNext(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr) { |
9154 | size_t keylen; |
9155 | void *key = RM_DictNextC(di,&keylen,dataptr); |
9156 | if (key == NULL) return NULL; |
9157 | return RM_CreateString(ctx,key,keylen); |
9158 | } |
9159 | |
9160 | /* Like RedisModule_DictNext() but after returning the currently selected |
9161 | * element in the iterator, it selects the previous element (lexicographically |
9162 | * smaller) instead of the next one. */ |
9163 | RedisModuleString *RM_DictPrev(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr) { |
9164 | size_t keylen; |
9165 | void *key = RM_DictPrevC(di,&keylen,dataptr); |
9166 | if (key == NULL) return NULL; |
9167 | return RM_CreateString(ctx,key,keylen); |
9168 | } |
9169 | |
9170 | /* Compare the element currently pointed by the iterator to the specified |
9171 | * element given by key/keylen, according to the operator 'op' (the set of |
9172 | * valid operators are the same valid for RedisModule_DictIteratorStart). |
9173 | * If the comparison is successful the command returns REDISMODULE_OK |
9174 | * otherwise REDISMODULE_ERR is returned. |
9175 | * |
9176 | * This is useful when we want to just emit a lexicographical range, so |
9177 | * in the loop, as we iterate elements, we can also check if we are still |
9178 | * on range. |
9179 | * |
9180 | * The function return REDISMODULE_ERR if the iterator reached the |
9181 | * end of elements condition as well. */ |
9182 | int RM_DictCompareC(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) { |
9183 | if (raxEOF(&di->ri)) return REDISMODULE_ERR; |
9184 | int res = raxCompare(&di->ri,op,key,keylen); |
9185 | return res ? REDISMODULE_OK : REDISMODULE_ERR; |
9186 | } |
9187 | |
9188 | /* Like RedisModule_DictCompareC but gets the key to compare with the current |
9189 | * iterator key as a RedisModuleString. */ |
9190 | int RM_DictCompare(RedisModuleDictIter *di, const char *op, RedisModuleString *key) { |
9191 | if (raxEOF(&di->ri)) return REDISMODULE_ERR; |
9192 | int res = raxCompare(&di->ri,op,key->ptr,sdslen(key->ptr)); |
9193 | return res ? REDISMODULE_OK : REDISMODULE_ERR; |
9194 | } |
9195 | |
9196 | |
9197 | |
9198 | |
9199 | /* -------------------------------------------------------------------------- |
9200 | * ## Modules Info fields |
9201 | * -------------------------------------------------------------------------- */ |
9202 | |
9203 | int RM_InfoEndDictField(RedisModuleInfoCtx *ctx); |
9204 | |
9205 | /* Used to start a new section, before adding any fields. the section name will |
9206 | * be prefixed by `<modulename>_` and must only include A-Z,a-z,0-9. |
9207 | * NULL or empty string indicates the default section (only `<modulename>`) is used. |
9208 | * When return value is REDISMODULE_ERR, the section should and will be skipped. */ |
9209 | int RM_InfoAddSection(RedisModuleInfoCtx *ctx, const char *name) { |
9210 | sds full_name = sdsdup(ctx->module->name); |
9211 | if (name != NULL && strlen(name) > 0) |
9212 | full_name = sdscatfmt(full_name, "_%s" , name); |
9213 | |
9214 | /* Implicitly end dicts, instead of returning an error which is likely un checked. */ |
9215 | if (ctx->in_dict_field) |
9216 | RM_InfoEndDictField(ctx); |
9217 | |
9218 | /* proceed only if: |
9219 | * 1) no section was requested (emit all) |
9220 | * 2) the module name was requested (emit all) |
9221 | * 3) this specific section was requested. */ |
9222 | if (ctx->requested_sections) { |
9223 | if ((!full_name || !dictFind(ctx->requested_sections, full_name)) && |
9224 | (!dictFind(ctx->requested_sections, ctx->module->name))) |
9225 | { |
9226 | sdsfree(full_name); |
9227 | ctx->in_section = 0; |
9228 | return REDISMODULE_ERR; |
9229 | } |
9230 | } |
9231 | if (ctx->sections++) ctx->info = sdscat(ctx->info,"\r\n" ); |
9232 | ctx->info = sdscatfmt(ctx->info, "# %S\r\n" , full_name); |
9233 | ctx->in_section = 1; |
9234 | sdsfree(full_name); |
9235 | return REDISMODULE_OK; |
9236 | } |
9237 | |
9238 | /* Starts a dict field, similar to the ones in INFO KEYSPACE. Use normal |
9239 | * RedisModule_InfoAddField* functions to add the items to this field, and |
9240 | * terminate with RedisModule_InfoEndDictField. */ |
9241 | int RM_InfoBeginDictField(RedisModuleInfoCtx *ctx, const char *name) { |
9242 | if (!ctx->in_section) |
9243 | return REDISMODULE_ERR; |
9244 | /* Implicitly end dicts, instead of returning an error which is likely un checked. */ |
9245 | if (ctx->in_dict_field) |
9246 | RM_InfoEndDictField(ctx); |
9247 | char *tmpmodname, *tmpname; |
9248 | ctx->info = sdscatfmt(ctx->info, |
9249 | "%s_%s:" , |
9250 | getSafeInfoString(ctx->module->name, strlen(ctx->module->name), &tmpmodname), |
9251 | getSafeInfoString(name, strlen(name), &tmpname)); |
9252 | if (tmpmodname != NULL) zfree(tmpmodname); |
9253 | if (tmpname != NULL) zfree(tmpname); |
9254 | ctx->in_dict_field = 1; |
9255 | return REDISMODULE_OK; |
9256 | } |
9257 | |
9258 | /* Ends a dict field, see RedisModule_InfoBeginDictField */ |
9259 | int RM_InfoEndDictField(RedisModuleInfoCtx *ctx) { |
9260 | if (!ctx->in_dict_field) |
9261 | return REDISMODULE_ERR; |
9262 | /* trim the last ',' if found. */ |
9263 | if (ctx->info[sdslen(ctx->info)-1]==',') |
9264 | sdsIncrLen(ctx->info, -1); |
9265 | ctx->info = sdscat(ctx->info, "\r\n" ); |
9266 | ctx->in_dict_field = 0; |
9267 | return REDISMODULE_OK; |
9268 | } |
9269 | |
9270 | /* Used by RedisModuleInfoFunc to add info fields. |
9271 | * Each field will be automatically prefixed by `<modulename>_`. |
9272 | * Field names or values must not include `\r\n` or `:`. */ |
9273 | int RM_InfoAddFieldString(RedisModuleInfoCtx *ctx, const char *field, RedisModuleString *value) { |
9274 | if (!ctx->in_section) |
9275 | return REDISMODULE_ERR; |
9276 | if (ctx->in_dict_field) { |
9277 | ctx->info = sdscatfmt(ctx->info, |
9278 | "%s=%S," , |
9279 | field, |
9280 | (sds)value->ptr); |
9281 | return REDISMODULE_OK; |
9282 | } |
9283 | ctx->info = sdscatfmt(ctx->info, |
9284 | "%s_%s:%S\r\n" , |
9285 | ctx->module->name, |
9286 | field, |
9287 | (sds)value->ptr); |
9288 | return REDISMODULE_OK; |
9289 | } |
9290 | |
9291 | /* See RedisModule_InfoAddFieldString(). */ |
9292 | int RM_InfoAddFieldCString(RedisModuleInfoCtx *ctx, const char *field, const char *value) { |
9293 | if (!ctx->in_section) |
9294 | return REDISMODULE_ERR; |
9295 | if (ctx->in_dict_field) { |
9296 | ctx->info = sdscatfmt(ctx->info, |
9297 | "%s=%s," , |
9298 | field, |
9299 | value); |
9300 | return REDISMODULE_OK; |
9301 | } |
9302 | ctx->info = sdscatfmt(ctx->info, |
9303 | "%s_%s:%s\r\n" , |
9304 | ctx->module->name, |
9305 | field, |
9306 | value); |
9307 | return REDISMODULE_OK; |
9308 | } |
9309 | |
9310 | /* See RedisModule_InfoAddFieldString(). */ |
9311 | int RM_InfoAddFieldDouble(RedisModuleInfoCtx *ctx, const char *field, double value) { |
9312 | if (!ctx->in_section) |
9313 | return REDISMODULE_ERR; |
9314 | if (ctx->in_dict_field) { |
9315 | ctx->info = sdscatprintf(ctx->info, |
9316 | "%s=%.17g," , |
9317 | field, |
9318 | value); |
9319 | return REDISMODULE_OK; |
9320 | } |
9321 | ctx->info = sdscatprintf(ctx->info, |
9322 | "%s_%s:%.17g\r\n" , |
9323 | ctx->module->name, |
9324 | field, |
9325 | value); |
9326 | return REDISMODULE_OK; |
9327 | } |
9328 | |
9329 | /* See RedisModule_InfoAddFieldString(). */ |
9330 | int RM_InfoAddFieldLongLong(RedisModuleInfoCtx *ctx, const char *field, long long value) { |
9331 | if (!ctx->in_section) |
9332 | return REDISMODULE_ERR; |
9333 | if (ctx->in_dict_field) { |
9334 | ctx->info = sdscatfmt(ctx->info, |
9335 | "%s=%I," , |
9336 | field, |
9337 | value); |
9338 | return REDISMODULE_OK; |
9339 | } |
9340 | ctx->info = sdscatfmt(ctx->info, |
9341 | "%s_%s:%I\r\n" , |
9342 | ctx->module->name, |
9343 | field, |
9344 | value); |
9345 | return REDISMODULE_OK; |
9346 | } |
9347 | |
9348 | /* See RedisModule_InfoAddFieldString(). */ |
9349 | int RM_InfoAddFieldULongLong(RedisModuleInfoCtx *ctx, const char *field, unsigned long long value) { |
9350 | if (!ctx->in_section) |
9351 | return REDISMODULE_ERR; |
9352 | if (ctx->in_dict_field) { |
9353 | ctx->info = sdscatfmt(ctx->info, |
9354 | "%s=%U," , |
9355 | field, |
9356 | value); |
9357 | return REDISMODULE_OK; |
9358 | } |
9359 | ctx->info = sdscatfmt(ctx->info, |
9360 | "%s_%s:%U\r\n" , |
9361 | ctx->module->name, |
9362 | field, |
9363 | value); |
9364 | return REDISMODULE_OK; |
9365 | } |
9366 | |
9367 | /* Registers callback for the INFO command. The callback should add INFO fields |
9368 | * by calling the `RedisModule_InfoAddField*()` functions. */ |
9369 | int RM_RegisterInfoFunc(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) { |
9370 | ctx->module->info_cb = cb; |
9371 | return REDISMODULE_OK; |
9372 | } |
9373 | |
9374 | sds modulesCollectInfo(sds info, dict *sections_dict, int for_crash_report, int sections) { |
9375 | dictIterator *di = dictGetIterator(modules); |
9376 | dictEntry *de; |
9377 | |
9378 | while ((de = dictNext(di)) != NULL) { |
9379 | struct RedisModule *module = dictGetVal(de); |
9380 | if (!module->info_cb) |
9381 | continue; |
9382 | RedisModuleInfoCtx info_ctx = {module, sections_dict, info, sections, 0, 0}; |
9383 | module->info_cb(&info_ctx, for_crash_report); |
9384 | /* Implicitly end dicts (no way to handle errors, and we must add the newline). */ |
9385 | if (info_ctx.in_dict_field) |
9386 | RM_InfoEndDictField(&info_ctx); |
9387 | info = info_ctx.info; |
9388 | sections = info_ctx.sections; |
9389 | } |
9390 | dictReleaseIterator(di); |
9391 | return info; |
9392 | } |
9393 | |
9394 | /* Get information about the server similar to the one that returns from the |
9395 | * INFO command. This function takes an optional 'section' argument that may |
9396 | * be NULL. The return value holds the output and can be used with |
9397 | * RedisModule_ServerInfoGetField and alike to get the individual fields. |
9398 | * When done, it needs to be freed with RedisModule_FreeServerInfo or with the |
9399 | * automatic memory management mechanism if enabled. */ |
9400 | RedisModuleServerInfoData *RM_GetServerInfo(RedisModuleCtx *ctx, const char *section) { |
9401 | struct RedisModuleServerInfoData *d = zmalloc(sizeof(*d)); |
9402 | d->rax = raxNew(); |
9403 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_INFO,d); |
9404 | int all = 0, everything = 0; |
9405 | robj *argv[1]; |
9406 | argv[0] = section ? createStringObject(section, strlen(section)) : NULL; |
9407 | dict *section_dict = genInfoSectionDict(argv, section ? 1 : 0, NULL, &all, &everything); |
9408 | sds info = genRedisInfoString(section_dict, all, everything); |
9409 | int totlines, i; |
9410 | sds *lines = sdssplitlen(info, sdslen(info), "\r\n" , 2, &totlines); |
9411 | for(i=0; i<totlines; i++) { |
9412 | sds line = lines[i]; |
9413 | if (line[0]=='#') continue; |
9414 | char *sep = strchr(line, ':'); |
9415 | if (!sep) continue; |
9416 | unsigned char *key = (unsigned char*)line; |
9417 | size_t keylen = (intptr_t)sep-(intptr_t)line; |
9418 | sds val = sdsnewlen(sep+1,sdslen(line)-((intptr_t)sep-(intptr_t)line)-1); |
9419 | if (!raxTryInsert(d->rax,key,keylen,val,NULL)) |
9420 | sdsfree(val); |
9421 | } |
9422 | sdsfree(info); |
9423 | sdsfreesplitres(lines,totlines); |
9424 | releaseInfoSectionDict(section_dict); |
9425 | if(argv[0]) decrRefCount(argv[0]); |
9426 | return d; |
9427 | } |
9428 | |
9429 | /* Free data created with RM_GetServerInfo(). You need to pass the |
9430 | * context pointer 'ctx' only if the dictionary was created using the |
9431 | * context instead of passing NULL. */ |
9432 | void RM_FreeServerInfo(RedisModuleCtx *ctx, RedisModuleServerInfoData *data) { |
9433 | if (ctx != NULL) autoMemoryFreed(ctx,REDISMODULE_AM_INFO,data); |
9434 | raxFreeWithCallback(data->rax, (void(*)(void*))sdsfree); |
9435 | zfree(data); |
9436 | } |
9437 | |
9438 | /* Get the value of a field from data collected with RM_GetServerInfo(). You |
9439 | * need to pass the context pointer 'ctx' only if you want to use auto memory |
9440 | * mechanism to release the returned string. Return value will be NULL if the |
9441 | * field was not found. */ |
9442 | RedisModuleString *RM_ServerInfoGetField(RedisModuleCtx *ctx, RedisModuleServerInfoData *data, const char* field) { |
9443 | sds val = raxFind(data->rax, (unsigned char *)field, strlen(field)); |
9444 | if (val == raxNotFound) return NULL; |
9445 | RedisModuleString *o = createStringObject(val,sdslen(val)); |
9446 | if (ctx != NULL) autoMemoryAdd(ctx,REDISMODULE_AM_STRING,o); |
9447 | return o; |
9448 | } |
9449 | |
9450 | /* Similar to RM_ServerInfoGetField, but returns a char* which should not be freed but the caller. */ |
9451 | const char *RM_ServerInfoGetFieldC(RedisModuleServerInfoData *data, const char* field) { |
9452 | sds val = raxFind(data->rax, (unsigned char *)field, strlen(field)); |
9453 | if (val == raxNotFound) return NULL; |
9454 | return val; |
9455 | } |
9456 | |
9457 | /* Get the value of a field from data collected with RM_GetServerInfo(). If the |
9458 | * field is not found, or is not numerical or out of range, return value will be |
9459 | * 0, and the optional out_err argument will be set to REDISMODULE_ERR. */ |
9460 | long long RM_ServerInfoGetFieldSigned(RedisModuleServerInfoData *data, const char* field, int *out_err) { |
9461 | long long ll; |
9462 | sds val = raxFind(data->rax, (unsigned char *)field, strlen(field)); |
9463 | if (val == raxNotFound) { |
9464 | if (out_err) *out_err = REDISMODULE_ERR; |
9465 | return 0; |
9466 | } |
9467 | if (!string2ll(val,sdslen(val),&ll)) { |
9468 | if (out_err) *out_err = REDISMODULE_ERR; |
9469 | return 0; |
9470 | } |
9471 | if (out_err) *out_err = REDISMODULE_OK; |
9472 | return ll; |
9473 | } |
9474 | |
9475 | /* Get the value of a field from data collected with RM_GetServerInfo(). If the |
9476 | * field is not found, or is not numerical or out of range, return value will be |
9477 | * 0, and the optional out_err argument will be set to REDISMODULE_ERR. */ |
9478 | unsigned long long RM_ServerInfoGetFieldUnsigned(RedisModuleServerInfoData *data, const char* field, int *out_err) { |
9479 | unsigned long long ll; |
9480 | sds val = raxFind(data->rax, (unsigned char *)field, strlen(field)); |
9481 | if (val == raxNotFound) { |
9482 | if (out_err) *out_err = REDISMODULE_ERR; |
9483 | return 0; |
9484 | } |
9485 | if (!string2ull(val,&ll)) { |
9486 | if (out_err) *out_err = REDISMODULE_ERR; |
9487 | return 0; |
9488 | } |
9489 | if (out_err) *out_err = REDISMODULE_OK; |
9490 | return ll; |
9491 | } |
9492 | |
9493 | /* Get the value of a field from data collected with RM_GetServerInfo(). If the |
9494 | * field is not found, or is not a double, return value will be 0, and the |
9495 | * optional out_err argument will be set to REDISMODULE_ERR. */ |
9496 | double RM_ServerInfoGetFieldDouble(RedisModuleServerInfoData *data, const char* field, int *out_err) { |
9497 | double dbl; |
9498 | sds val = raxFind(data->rax, (unsigned char *)field, strlen(field)); |
9499 | if (val == raxNotFound) { |
9500 | if (out_err) *out_err = REDISMODULE_ERR; |
9501 | return 0; |
9502 | } |
9503 | if (!string2d(val,sdslen(val),&dbl)) { |
9504 | if (out_err) *out_err = REDISMODULE_ERR; |
9505 | return 0; |
9506 | } |
9507 | if (out_err) *out_err = REDISMODULE_OK; |
9508 | return dbl; |
9509 | } |
9510 | |
9511 | /* -------------------------------------------------------------------------- |
9512 | * ## Modules utility APIs |
9513 | * -------------------------------------------------------------------------- */ |
9514 | |
9515 | /* Return random bytes using SHA1 in counter mode with a /dev/urandom |
9516 | * initialized seed. This function is fast so can be used to generate |
9517 | * many bytes without any effect on the operating system entropy pool. |
9518 | * Currently this function is not thread safe. */ |
9519 | void RM_GetRandomBytes(unsigned char *dst, size_t len) { |
9520 | getRandomBytes(dst,len); |
9521 | } |
9522 | |
9523 | /* Like RedisModule_GetRandomBytes() but instead of setting the string to |
9524 | * random bytes the string is set to random characters in the in the |
9525 | * hex charset [0-9a-f]. */ |
9526 | void RM_GetRandomHexChars(char *dst, size_t len) { |
9527 | getRandomHexChars(dst,len); |
9528 | } |
9529 | |
9530 | /* -------------------------------------------------------------------------- |
9531 | * ## Modules API exporting / importing |
9532 | * -------------------------------------------------------------------------- */ |
9533 | |
9534 | /* This function is called by a module in order to export some API with a |
9535 | * given name. Other modules will be able to use this API by calling the |
9536 | * symmetrical function RM_GetSharedAPI() and casting the return value to |
9537 | * the right function pointer. |
9538 | * |
9539 | * The function will return REDISMODULE_OK if the name is not already taken, |
9540 | * otherwise REDISMODULE_ERR will be returned and no operation will be |
9541 | * performed. |
9542 | * |
9543 | * IMPORTANT: the apiname argument should be a string literal with static |
9544 | * lifetime. The API relies on the fact that it will always be valid in |
9545 | * the future. */ |
9546 | int RM_ExportSharedAPI(RedisModuleCtx *ctx, const char *apiname, void *func) { |
9547 | RedisModuleSharedAPI *sapi = zmalloc(sizeof(*sapi)); |
9548 | sapi->module = ctx->module; |
9549 | sapi->func = func; |
9550 | if (dictAdd(server.sharedapi, (char*)apiname, sapi) != DICT_OK) { |
9551 | zfree(sapi); |
9552 | return REDISMODULE_ERR; |
9553 | } |
9554 | return REDISMODULE_OK; |
9555 | } |
9556 | |
9557 | /* Request an exported API pointer. The return value is just a void pointer |
9558 | * that the caller of this function will be required to cast to the right |
9559 | * function pointer, so this is a private contract between modules. |
9560 | * |
9561 | * If the requested API is not available then NULL is returned. Because |
9562 | * modules can be loaded at different times with different order, this |
9563 | * function calls should be put inside some module generic API registering |
9564 | * step, that is called every time a module attempts to execute a |
9565 | * command that requires external APIs: if some API cannot be resolved, the |
9566 | * command should return an error. |
9567 | * |
9568 | * Here is an example: |
9569 | * |
9570 | * int ... myCommandImplementation() { |
9571 | * if (getExternalAPIs() == 0) { |
9572 | * reply with an error here if we cannot have the APIs |
9573 | * } |
9574 | * // Use the API: |
9575 | * myFunctionPointer(foo); |
9576 | * } |
9577 | * |
9578 | * And the function registerAPI() is: |
9579 | * |
9580 | * int getExternalAPIs(void) { |
9581 | * static int api_loaded = 0; |
9582 | * if (api_loaded != 0) return 1; // APIs already resolved. |
9583 | * |
9584 | * myFunctionPointer = RedisModule_GetOtherModuleAPI("..."); |
9585 | * if (myFunctionPointer == NULL) return 0; |
9586 | * |
9587 | * return 1; |
9588 | * } |
9589 | */ |
9590 | void *RM_GetSharedAPI(RedisModuleCtx *ctx, const char *apiname) { |
9591 | dictEntry *de = dictFind(server.sharedapi, apiname); |
9592 | if (de == NULL) return NULL; |
9593 | RedisModuleSharedAPI *sapi = dictGetVal(de); |
9594 | if (listSearchKey(sapi->module->usedby,ctx->module) == NULL) { |
9595 | listAddNodeTail(sapi->module->usedby,ctx->module); |
9596 | listAddNodeTail(ctx->module->using,sapi->module); |
9597 | } |
9598 | return sapi->func; |
9599 | } |
9600 | |
9601 | /* Remove all the APIs registered by the specified module. Usually you |
9602 | * want this when the module is going to be unloaded. This function |
9603 | * assumes that's caller responsibility to make sure the APIs are not |
9604 | * used by other modules. |
9605 | * |
9606 | * The number of unregistered APIs is returned. */ |
9607 | int moduleUnregisterSharedAPI(RedisModule *module) { |
9608 | int count = 0; |
9609 | dictIterator *di = dictGetSafeIterator(server.sharedapi); |
9610 | dictEntry *de; |
9611 | while ((de = dictNext(di)) != NULL) { |
9612 | const char *apiname = dictGetKey(de); |
9613 | RedisModuleSharedAPI *sapi = dictGetVal(de); |
9614 | if (sapi->module == module) { |
9615 | dictDelete(server.sharedapi,apiname); |
9616 | zfree(sapi); |
9617 | count++; |
9618 | } |
9619 | } |
9620 | dictReleaseIterator(di); |
9621 | return count; |
9622 | } |
9623 | |
9624 | /* Remove the specified module as an user of APIs of ever other module. |
9625 | * This is usually called when a module is unloaded. |
9626 | * |
9627 | * Returns the number of modules this module was using APIs from. */ |
9628 | int moduleUnregisterUsedAPI(RedisModule *module) { |
9629 | listIter li; |
9630 | listNode *ln; |
9631 | int count = 0; |
9632 | |
9633 | listRewind(module->using,&li); |
9634 | while((ln = listNext(&li))) { |
9635 | RedisModule *used = ln->value; |
9636 | listNode *ln = listSearchKey(used->usedby,module); |
9637 | if (ln) { |
9638 | listDelNode(used->usedby,ln); |
9639 | count++; |
9640 | } |
9641 | } |
9642 | return count; |
9643 | } |
9644 | |
9645 | /* Unregister all filters registered by a module. |
9646 | * This is called when a module is being unloaded. |
9647 | * |
9648 | * Returns the number of filters unregistered. */ |
9649 | int moduleUnregisterFilters(RedisModule *module) { |
9650 | listIter li; |
9651 | listNode *ln; |
9652 | int count = 0; |
9653 | |
9654 | listRewind(module->filters,&li); |
9655 | while((ln = listNext(&li))) { |
9656 | RedisModuleCommandFilter *filter = ln->value; |
9657 | listNode *ln = listSearchKey(moduleCommandFilters,filter); |
9658 | if (ln) { |
9659 | listDelNode(moduleCommandFilters,ln); |
9660 | count++; |
9661 | } |
9662 | zfree(filter); |
9663 | } |
9664 | return count; |
9665 | } |
9666 | |
9667 | /* -------------------------------------------------------------------------- |
9668 | * ## Module Command Filter API |
9669 | * -------------------------------------------------------------------------- */ |
9670 | |
9671 | /* Register a new command filter function. |
9672 | * |
9673 | * Command filtering makes it possible for modules to extend Redis by plugging |
9674 | * into the execution flow of all commands. |
9675 | * |
9676 | * A registered filter gets called before Redis executes *any* command. This |
9677 | * includes both core Redis commands and commands registered by any module. The |
9678 | * filter applies in all execution paths including: |
9679 | * |
9680 | * 1. Invocation by a client. |
9681 | * 2. Invocation through `RedisModule_Call()` by any module. |
9682 | * 3. Invocation through Lua `redis.call()`. |
9683 | * 4. Replication of a command from a master. |
9684 | * |
9685 | * The filter executes in a special filter context, which is different and more |
9686 | * limited than a RedisModuleCtx. Because the filter affects any command, it |
9687 | * must be implemented in a very efficient way to reduce the performance impact |
9688 | * on Redis. All Redis Module API calls that require a valid context (such as |
9689 | * `RedisModule_Call()`, `RedisModule_OpenKey()`, etc.) are not supported in a |
9690 | * filter context. |
9691 | * |
9692 | * The `RedisModuleCommandFilterCtx` can be used to inspect or modify the |
9693 | * executed command and its arguments. As the filter executes before Redis |
9694 | * begins processing the command, any change will affect the way the command is |
9695 | * processed. For example, a module can override Redis commands this way: |
9696 | * |
9697 | * 1. Register a `MODULE.SET` command which implements an extended version of |
9698 | * the Redis `SET` command. |
9699 | * 2. Register a command filter which detects invocation of `SET` on a specific |
9700 | * pattern of keys. Once detected, the filter will replace the first |
9701 | * argument from `SET` to `MODULE.SET`. |
9702 | * 3. When filter execution is complete, Redis considers the new command name |
9703 | * and therefore executes the module's own command. |
9704 | * |
9705 | * Note that in the above use case, if `MODULE.SET` itself uses |
9706 | * `RedisModule_Call()` the filter will be applied on that call as well. If |
9707 | * that is not desired, the `REDISMODULE_CMDFILTER_NOSELF` flag can be set when |
9708 | * registering the filter. |
9709 | * |
9710 | * The `REDISMODULE_CMDFILTER_NOSELF` flag prevents execution flows that |
9711 | * originate from the module's own `RM_Call()` from reaching the filter. This |
9712 | * flag is effective for all execution flows, including nested ones, as long as |
9713 | * the execution begins from the module's command context or a thread-safe |
9714 | * context that is associated with a blocking command. |
9715 | * |
9716 | * Detached thread-safe contexts are *not* associated with the module and cannot |
9717 | * be protected by this flag. |
9718 | * |
9719 | * If multiple filters are registered (by the same or different modules), they |
9720 | * are executed in the order of registration. |
9721 | */ |
9722 | RedisModuleCommandFilter *RM_RegisterCommandFilter(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc callback, int flags) { |
9723 | RedisModuleCommandFilter *filter = zmalloc(sizeof(*filter)); |
9724 | filter->module = ctx->module; |
9725 | filter->callback = callback; |
9726 | filter->flags = flags; |
9727 | |
9728 | listAddNodeTail(moduleCommandFilters, filter); |
9729 | listAddNodeTail(ctx->module->filters, filter); |
9730 | return filter; |
9731 | } |
9732 | |
9733 | /* Unregister a command filter. |
9734 | */ |
9735 | int RM_UnregisterCommandFilter(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter) { |
9736 | listNode *ln; |
9737 | |
9738 | /* A module can only remove its own filters */ |
9739 | if (filter->module != ctx->module) return REDISMODULE_ERR; |
9740 | |
9741 | ln = listSearchKey(moduleCommandFilters,filter); |
9742 | if (!ln) return REDISMODULE_ERR; |
9743 | listDelNode(moduleCommandFilters,ln); |
9744 | |
9745 | ln = listSearchKey(ctx->module->filters,filter); |
9746 | if (!ln) return REDISMODULE_ERR; /* Shouldn't happen */ |
9747 | listDelNode(ctx->module->filters,ln); |
9748 | |
9749 | zfree(filter); |
9750 | |
9751 | return REDISMODULE_OK; |
9752 | } |
9753 | |
9754 | void moduleCallCommandFilters(client *c) { |
9755 | if (listLength(moduleCommandFilters) == 0) return; |
9756 | |
9757 | listIter li; |
9758 | listNode *ln; |
9759 | listRewind(moduleCommandFilters,&li); |
9760 | |
9761 | RedisModuleCommandFilterCtx filter = { |
9762 | .argv = c->argv, |
9763 | .argc = c->argc |
9764 | }; |
9765 | |
9766 | while((ln = listNext(&li))) { |
9767 | RedisModuleCommandFilter *f = ln->value; |
9768 | |
9769 | /* Skip filter if REDISMODULE_CMDFILTER_NOSELF is set and module is |
9770 | * currently processing a command. |
9771 | */ |
9772 | if ((f->flags & REDISMODULE_CMDFILTER_NOSELF) && f->module->in_call) continue; |
9773 | |
9774 | /* Call filter */ |
9775 | f->callback(&filter); |
9776 | } |
9777 | |
9778 | c->argv = filter.argv; |
9779 | c->argc = filter.argc; |
9780 | } |
9781 | |
9782 | /* Return the number of arguments a filtered command has. The number of |
9783 | * arguments include the command itself. |
9784 | */ |
9785 | int RM_CommandFilterArgsCount(RedisModuleCommandFilterCtx *fctx) |
9786 | { |
9787 | return fctx->argc; |
9788 | } |
9789 | |
9790 | /* Return the specified command argument. The first argument (position 0) is |
9791 | * the command itself, and the rest are user-provided args. |
9792 | */ |
9793 | RedisModuleString *RM_CommandFilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos) |
9794 | { |
9795 | if (pos < 0 || pos >= fctx->argc) return NULL; |
9796 | return fctx->argv[pos]; |
9797 | } |
9798 | |
9799 | /* Modify the filtered command by inserting a new argument at the specified |
9800 | * position. The specified RedisModuleString argument may be used by Redis |
9801 | * after the filter context is destroyed, so it must not be auto-memory |
9802 | * allocated, freed or used elsewhere. |
9803 | */ |
9804 | int RM_CommandFilterArgInsert(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) |
9805 | { |
9806 | int i; |
9807 | |
9808 | if (pos < 0 || pos > fctx->argc) return REDISMODULE_ERR; |
9809 | |
9810 | fctx->argv = zrealloc(fctx->argv, (fctx->argc+1)*sizeof(RedisModuleString *)); |
9811 | for (i = fctx->argc; i > pos; i--) { |
9812 | fctx->argv[i] = fctx->argv[i-1]; |
9813 | } |
9814 | fctx->argv[pos] = arg; |
9815 | fctx->argc++; |
9816 | |
9817 | return REDISMODULE_OK; |
9818 | } |
9819 | |
9820 | /* Modify the filtered command by replacing an existing argument with a new one. |
9821 | * The specified RedisModuleString argument may be used by Redis after the |
9822 | * filter context is destroyed, so it must not be auto-memory allocated, freed |
9823 | * or used elsewhere. |
9824 | */ |
9825 | int RM_CommandFilterArgReplace(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) |
9826 | { |
9827 | if (pos < 0 || pos >= fctx->argc) return REDISMODULE_ERR; |
9828 | |
9829 | decrRefCount(fctx->argv[pos]); |
9830 | fctx->argv[pos] = arg; |
9831 | |
9832 | return REDISMODULE_OK; |
9833 | } |
9834 | |
9835 | /* Modify the filtered command by deleting an argument at the specified |
9836 | * position. |
9837 | */ |
9838 | int RM_CommandFilterArgDelete(RedisModuleCommandFilterCtx *fctx, int pos) |
9839 | { |
9840 | int i; |
9841 | if (pos < 0 || pos >= fctx->argc) return REDISMODULE_ERR; |
9842 | |
9843 | decrRefCount(fctx->argv[pos]); |
9844 | for (i = pos; i < fctx->argc-1; i++) { |
9845 | fctx->argv[i] = fctx->argv[i+1]; |
9846 | } |
9847 | fctx->argc--; |
9848 | |
9849 | return REDISMODULE_OK; |
9850 | } |
9851 | |
9852 | /* For a given pointer allocated via RedisModule_Alloc() or |
9853 | * RedisModule_Realloc(), return the amount of memory allocated for it. |
9854 | * Note that this may be different (larger) than the memory we allocated |
9855 | * with the allocation calls, since sometimes the underlying allocator |
9856 | * will allocate more memory. |
9857 | */ |
9858 | size_t RM_MallocSize(void* ptr) { |
9859 | return zmalloc_size(ptr); |
9860 | } |
9861 | |
9862 | /* Similar to RM_MallocSize, the difference is that RM_MallocUsableSize |
9863 | * returns the usable size of memory by the module. */ |
9864 | size_t RM_MallocUsableSize(void *ptr) { |
9865 | return zmalloc_usable_size(ptr); |
9866 | } |
9867 | |
9868 | /* Same as RM_MallocSize, except it works on RedisModuleString pointers. |
9869 | */ |
9870 | size_t RM_MallocSizeString(RedisModuleString* str) { |
9871 | serverAssert(str->type == OBJ_STRING); |
9872 | return sizeof(*str) + getStringObjectSdsUsedMemory(str); |
9873 | } |
9874 | |
9875 | /* Same as RM_MallocSize, except it works on RedisModuleDict pointers. |
9876 | * Note that the returned value is only the overhead of the underlying structures, |
9877 | * it does not include the allocation size of the keys and values. |
9878 | */ |
9879 | size_t RM_MallocSizeDict(RedisModuleDict* dict) { |
9880 | size_t size = sizeof(RedisModuleDict) + sizeof(rax); |
9881 | size += dict->rax->numnodes * sizeof(raxNode); |
9882 | /* For more info about this weird line, see streamRadixTreeMemoryUsage */ |
9883 | size += dict->rax->numnodes * sizeof(long)*30; |
9884 | return size; |
9885 | } |
9886 | |
9887 | /* Return the a number between 0 to 1 indicating the amount of memory |
9888 | * currently used, relative to the Redis "maxmemory" configuration. |
9889 | * |
9890 | * * 0 - No memory limit configured. |
9891 | * * Between 0 and 1 - The percentage of the memory used normalized in 0-1 range. |
9892 | * * Exactly 1 - Memory limit reached. |
9893 | * * Greater 1 - More memory used than the configured limit. |
9894 | */ |
9895 | float RM_GetUsedMemoryRatio(){ |
9896 | float level; |
9897 | getMaxmemoryState(NULL, NULL, NULL, &level); |
9898 | return level; |
9899 | } |
9900 | |
9901 | /* -------------------------------------------------------------------------- |
9902 | * ## Scanning keyspace and hashes |
9903 | * -------------------------------------------------------------------------- */ |
9904 | |
9905 | typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata); |
9906 | typedef struct { |
9907 | RedisModuleCtx *ctx; |
9908 | void* user_data; |
9909 | RedisModuleScanCB fn; |
9910 | } ScanCBData; |
9911 | |
9912 | typedef struct RedisModuleScanCursor{ |
9913 | unsigned long cursor; |
9914 | int done; |
9915 | }RedisModuleScanCursor; |
9916 | |
9917 | static void moduleScanCallback(void *privdata, const dictEntry *de) { |
9918 | ScanCBData *data = privdata; |
9919 | sds key = dictGetKey(de); |
9920 | robj* val = dictGetVal(de); |
9921 | RedisModuleString *keyname = createObject(OBJ_STRING,sdsdup(key)); |
9922 | |
9923 | /* Setup the key handle. */ |
9924 | RedisModuleKey kp = {0}; |
9925 | moduleInitKey(&kp, data->ctx, keyname, val, REDISMODULE_READ); |
9926 | |
9927 | data->fn(data->ctx, keyname, &kp, data->user_data); |
9928 | |
9929 | moduleCloseKey(&kp); |
9930 | decrRefCount(keyname); |
9931 | } |
9932 | |
9933 | /* Create a new cursor to be used with RedisModule_Scan */ |
9934 | RedisModuleScanCursor *RM_ScanCursorCreate() { |
9935 | RedisModuleScanCursor* cursor = zmalloc(sizeof(*cursor)); |
9936 | cursor->cursor = 0; |
9937 | cursor->done = 0; |
9938 | return cursor; |
9939 | } |
9940 | |
9941 | /* Restart an existing cursor. The keys will be rescanned. */ |
9942 | void RM_ScanCursorRestart(RedisModuleScanCursor *cursor) { |
9943 | cursor->cursor = 0; |
9944 | cursor->done = 0; |
9945 | } |
9946 | |
9947 | /* Destroy the cursor struct. */ |
9948 | void RM_ScanCursorDestroy(RedisModuleScanCursor *cursor) { |
9949 | zfree(cursor); |
9950 | } |
9951 | |
9952 | /* Scan API that allows a module to scan all the keys and value in |
9953 | * the selected db. |
9954 | * |
9955 | * Callback for scan implementation. |
9956 | * |
9957 | * void scan_callback(RedisModuleCtx *ctx, RedisModuleString *keyname, |
9958 | * RedisModuleKey *key, void *privdata); |
9959 | * |
9960 | * - `ctx`: the redis module context provided to for the scan. |
9961 | * - `keyname`: owned by the caller and need to be retained if used after this |
9962 | * function. |
9963 | * - `key`: holds info on the key and value, it is provided as best effort, in |
9964 | * some cases it might be NULL, in which case the user should (can) use |
9965 | * RedisModule_OpenKey() (and CloseKey too). |
9966 | * when it is provided, it is owned by the caller and will be free when the |
9967 | * callback returns. |
9968 | * - `privdata`: the user data provided to RedisModule_Scan(). |
9969 | * |
9970 | * The way it should be used: |
9971 | * |
9972 | * RedisModuleScanCursor *c = RedisModule_ScanCursorCreate(); |
9973 | * while(RedisModule_Scan(ctx, c, callback, privateData)); |
9974 | * RedisModule_ScanCursorDestroy(c); |
9975 | * |
9976 | * It is also possible to use this API from another thread while the lock |
9977 | * is acquired during the actual call to RM_Scan: |
9978 | * |
9979 | * RedisModuleScanCursor *c = RedisModule_ScanCursorCreate(); |
9980 | * RedisModule_ThreadSafeContextLock(ctx); |
9981 | * while(RedisModule_Scan(ctx, c, callback, privateData)){ |
9982 | * RedisModule_ThreadSafeContextUnlock(ctx); |
9983 | * // do some background job |
9984 | * RedisModule_ThreadSafeContextLock(ctx); |
9985 | * } |
9986 | * RedisModule_ScanCursorDestroy(c); |
9987 | * |
9988 | * The function will return 1 if there are more elements to scan and |
9989 | * 0 otherwise, possibly setting errno if the call failed. |
9990 | * |
9991 | * It is also possible to restart an existing cursor using RM_ScanCursorRestart. |
9992 | * |
9993 | * IMPORTANT: This API is very similar to the Redis SCAN command from the |
9994 | * point of view of the guarantees it provides. This means that the API |
9995 | * may report duplicated keys, but guarantees to report at least one time |
9996 | * every key that was there from the start to the end of the scanning process. |
9997 | * |
9998 | * NOTE: If you do database changes within the callback, you should be aware |
9999 | * that the internal state of the database may change. For instance it is safe |
10000 | * to delete or modify the current key, but may not be safe to delete any |
10001 | * other key. |
10002 | * Moreover playing with the Redis keyspace while iterating may have the |
10003 | * effect of returning more duplicates. A safe pattern is to store the keys |
10004 | * names you want to modify elsewhere, and perform the actions on the keys |
10005 | * later when the iteration is complete. However this can cost a lot of |
10006 | * memory, so it may make sense to just operate on the current key when |
10007 | * possible during the iteration, given that this is safe. */ |
10008 | int RM_Scan(RedisModuleCtx *ctx, RedisModuleScanCursor *cursor, RedisModuleScanCB fn, void *privdata) { |
10009 | if (cursor->done) { |
10010 | errno = ENOENT; |
10011 | return 0; |
10012 | } |
10013 | int ret = 1; |
10014 | ScanCBData data = { ctx, privdata, fn }; |
10015 | cursor->cursor = dictScan(ctx->client->db->dict, cursor->cursor, moduleScanCallback, NULL, &data); |
10016 | if (cursor->cursor == 0) { |
10017 | cursor->done = 1; |
10018 | ret = 0; |
10019 | } |
10020 | errno = 0; |
10021 | return ret; |
10022 | } |
10023 | |
10024 | typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); |
10025 | typedef struct { |
10026 | RedisModuleKey *key; |
10027 | void* user_data; |
10028 | RedisModuleScanKeyCB fn; |
10029 | } ScanKeyCBData; |
10030 | |
10031 | static void moduleScanKeyCallback(void *privdata, const dictEntry *de) { |
10032 | ScanKeyCBData *data = privdata; |
10033 | sds key = dictGetKey(de); |
10034 | robj *o = data->key->value; |
10035 | robj *field = createStringObject(key, sdslen(key)); |
10036 | robj *value = NULL; |
10037 | if (o->type == OBJ_SET) { |
10038 | value = NULL; |
10039 | } else if (o->type == OBJ_HASH) { |
10040 | sds val = dictGetVal(de); |
10041 | value = createStringObject(val, sdslen(val)); |
10042 | } else if (o->type == OBJ_ZSET) { |
10043 | double *val = (double*)dictGetVal(de); |
10044 | value = createStringObjectFromLongDouble(*val, 0); |
10045 | } |
10046 | |
10047 | data->fn(data->key, field, value, data->user_data); |
10048 | decrRefCount(field); |
10049 | if (value) decrRefCount(value); |
10050 | } |
10051 | |
10052 | /* Scan api that allows a module to scan the elements in a hash, set or sorted set key |
10053 | * |
10054 | * Callback for scan implementation. |
10055 | * |
10056 | * void scan_callback(RedisModuleKey *key, RedisModuleString* field, RedisModuleString* value, void *privdata); |
10057 | * |
10058 | * - key - the redis key context provided to for the scan. |
10059 | * - field - field name, owned by the caller and need to be retained if used |
10060 | * after this function. |
10061 | * - value - value string or NULL for set type, owned by the caller and need to |
10062 | * be retained if used after this function. |
10063 | * - privdata - the user data provided to RedisModule_ScanKey. |
10064 | * |
10065 | * The way it should be used: |
10066 | * |
10067 | * RedisModuleScanCursor *c = RedisModule_ScanCursorCreate(); |
10068 | * RedisModuleKey *key = RedisModule_OpenKey(...) |
10069 | * while(RedisModule_ScanKey(key, c, callback, privateData)); |
10070 | * RedisModule_CloseKey(key); |
10071 | * RedisModule_ScanCursorDestroy(c); |
10072 | * |
10073 | * It is also possible to use this API from another thread while the lock is acquired during |
10074 | * the actual call to RM_ScanKey, and re-opening the key each time: |
10075 | * |
10076 | * RedisModuleScanCursor *c = RedisModule_ScanCursorCreate(); |
10077 | * RedisModule_ThreadSafeContextLock(ctx); |
10078 | * RedisModuleKey *key = RedisModule_OpenKey(...) |
10079 | * while(RedisModule_ScanKey(ctx, c, callback, privateData)){ |
10080 | * RedisModule_CloseKey(key); |
10081 | * RedisModule_ThreadSafeContextUnlock(ctx); |
10082 | * // do some background job |
10083 | * RedisModule_ThreadSafeContextLock(ctx); |
10084 | * RedisModuleKey *key = RedisModule_OpenKey(...) |
10085 | * } |
10086 | * RedisModule_CloseKey(key); |
10087 | * RedisModule_ScanCursorDestroy(c); |
10088 | * |
10089 | * The function will return 1 if there are more elements to scan and 0 otherwise, |
10090 | * possibly setting errno if the call failed. |
10091 | * It is also possible to restart an existing cursor using RM_ScanCursorRestart. |
10092 | * |
10093 | * NOTE: Certain operations are unsafe while iterating the object. For instance |
10094 | * while the API guarantees to return at least one time all the elements that |
10095 | * are present in the data structure consistently from the start to the end |
10096 | * of the iteration (see HSCAN and similar commands documentation), the more |
10097 | * you play with the elements, the more duplicates you may get. In general |
10098 | * deleting the current element of the data structure is safe, while removing |
10099 | * the key you are iterating is not safe. */ |
10100 | int RM_ScanKey(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleScanKeyCB fn, void *privdata) { |
10101 | if (key == NULL || key->value == NULL) { |
10102 | errno = EINVAL; |
10103 | return 0; |
10104 | } |
10105 | dict *ht = NULL; |
10106 | robj *o = key->value; |
10107 | if (o->type == OBJ_SET) { |
10108 | if (o->encoding == OBJ_ENCODING_HT) |
10109 | ht = o->ptr; |
10110 | } else if (o->type == OBJ_HASH) { |
10111 | if (o->encoding == OBJ_ENCODING_HT) |
10112 | ht = o->ptr; |
10113 | } else if (o->type == OBJ_ZSET) { |
10114 | if (o->encoding == OBJ_ENCODING_SKIPLIST) |
10115 | ht = ((zset *)o->ptr)->dict; |
10116 | } else { |
10117 | errno = EINVAL; |
10118 | return 0; |
10119 | } |
10120 | if (cursor->done) { |
10121 | errno = ENOENT; |
10122 | return 0; |
10123 | } |
10124 | int ret = 1; |
10125 | if (ht) { |
10126 | ScanKeyCBData data = { key, privdata, fn }; |
10127 | cursor->cursor = dictScan(ht, cursor->cursor, moduleScanKeyCallback, NULL, &data); |
10128 | if (cursor->cursor == 0) { |
10129 | cursor->done = 1; |
10130 | ret = 0; |
10131 | } |
10132 | } else if (o->type == OBJ_SET && o->encoding == OBJ_ENCODING_INTSET) { |
10133 | int pos = 0; |
10134 | int64_t ll; |
10135 | while(intsetGet(o->ptr,pos++,&ll)) { |
10136 | robj *field = createObject(OBJ_STRING,sdsfromlonglong(ll)); |
10137 | fn(key, field, NULL, privdata); |
10138 | decrRefCount(field); |
10139 | } |
10140 | cursor->cursor = 1; |
10141 | cursor->done = 1; |
10142 | ret = 0; |
10143 | } else if (o->type == OBJ_ZSET) { |
10144 | unsigned char *p = lpSeek(o->ptr,0); |
10145 | unsigned char *vstr; |
10146 | unsigned int vlen; |
10147 | long long vll; |
10148 | while(p) { |
10149 | vstr = lpGetValue(p,&vlen,&vll); |
10150 | robj *field = (vstr != NULL) ? |
10151 | createStringObject((char*)vstr,vlen) : |
10152 | createObject(OBJ_STRING,sdsfromlonglong(vll)); |
10153 | p = lpNext(o->ptr,p); |
10154 | vstr = lpGetValue(p,&vlen,&vll); |
10155 | robj *value = (vstr != NULL) ? |
10156 | createStringObject((char*)vstr,vlen) : |
10157 | createObject(OBJ_STRING,sdsfromlonglong(vll)); |
10158 | fn(key, field, value, privdata); |
10159 | p = lpNext(o->ptr,p); |
10160 | decrRefCount(field); |
10161 | decrRefCount(value); |
10162 | } |
10163 | cursor->cursor = 1; |
10164 | cursor->done = 1; |
10165 | ret = 0; |
10166 | } else if (o->type == OBJ_HASH) { |
10167 | unsigned char *p = lpFirst(o->ptr); |
10168 | unsigned char *vstr; |
10169 | int64_t vlen; |
10170 | unsigned char intbuf[LP_INTBUF_SIZE]; |
10171 | while(p) { |
10172 | vstr = lpGet(p,&vlen,intbuf); |
10173 | robj *field = createStringObject((char*)vstr,vlen); |
10174 | p = lpNext(o->ptr,p); |
10175 | vstr = lpGet(p,&vlen,intbuf); |
10176 | robj *value = createStringObject((char*)vstr,vlen); |
10177 | fn(key, field, value, privdata); |
10178 | p = lpNext(o->ptr,p); |
10179 | decrRefCount(field); |
10180 | decrRefCount(value); |
10181 | } |
10182 | cursor->cursor = 1; |
10183 | cursor->done = 1; |
10184 | ret = 0; |
10185 | } |
10186 | errno = 0; |
10187 | return ret; |
10188 | } |
10189 | |
10190 | |
10191 | /* -------------------------------------------------------------------------- |
10192 | * ## Module fork API |
10193 | * -------------------------------------------------------------------------- */ |
10194 | |
10195 | /* Create a background child process with the current frozen snapshot of the |
10196 | * main process where you can do some processing in the background without |
10197 | * affecting / freezing the traffic and no need for threads and GIL locking. |
10198 | * Note that Redis allows for only one concurrent fork. |
10199 | * When the child wants to exit, it should call RedisModule_ExitFromChild. |
10200 | * If the parent wants to kill the child it should call RedisModule_KillForkChild |
10201 | * The done handler callback will be executed on the parent process when the |
10202 | * child existed (but not when killed) |
10203 | * Return: -1 on failure, on success the parent process will get a positive PID |
10204 | * of the child, and the child process will get 0. |
10205 | */ |
10206 | int RM_Fork(RedisModuleForkDoneHandler cb, void *user_data) { |
10207 | pid_t childpid; |
10208 | |
10209 | if ((childpid = redisFork(CHILD_TYPE_MODULE)) == 0) { |
10210 | /* Child */ |
10211 | redisSetProcTitle("redis-module-fork" ); |
10212 | } else if (childpid == -1) { |
10213 | serverLog(LL_WARNING,"Can't fork for module: %s" , strerror(errno)); |
10214 | } else { |
10215 | /* Parent */ |
10216 | moduleForkInfo.done_handler = cb; |
10217 | moduleForkInfo.done_handler_user_data = user_data; |
10218 | serverLog(LL_VERBOSE, "Module fork started pid: %ld " , (long) childpid); |
10219 | } |
10220 | return childpid; |
10221 | } |
10222 | |
10223 | /* The module is advised to call this function from the fork child once in a while, |
10224 | * so that it can report progress and COW memory to the parent which will be |
10225 | * reported in INFO. |
10226 | * The `progress` argument should between 0 and 1, or -1 when not available. */ |
10227 | void RM_SendChildHeartbeat(double progress) { |
10228 | sendChildInfoGeneric(CHILD_INFO_TYPE_CURRENT_INFO, 0, progress, "Module fork" ); |
10229 | } |
10230 | |
10231 | /* Call from the child process when you want to terminate it. |
10232 | * retcode will be provided to the done handler executed on the parent process. |
10233 | */ |
10234 | int RM_ExitFromChild(int retcode) { |
10235 | sendChildCowInfo(CHILD_INFO_TYPE_MODULE_COW_SIZE, "Module fork" ); |
10236 | exitFromChild(retcode); |
10237 | return REDISMODULE_OK; |
10238 | } |
10239 | |
10240 | /* Kill the active module forked child, if there is one active and the |
10241 | * pid matches, and returns C_OK. Otherwise if there is no active module |
10242 | * child or the pid does not match, return C_ERR without doing anything. */ |
10243 | int TerminateModuleForkChild(int child_pid, int wait) { |
10244 | /* Module child should be active and pid should match. */ |
10245 | if (server.child_type != CHILD_TYPE_MODULE || |
10246 | server.child_pid != child_pid) return C_ERR; |
10247 | |
10248 | int statloc; |
10249 | serverLog(LL_VERBOSE,"Killing running module fork child: %ld" , |
10250 | (long) server.child_pid); |
10251 | if (kill(server.child_pid,SIGUSR1) != -1 && wait) { |
10252 | while(waitpid(server.child_pid, &statloc, 0) != |
10253 | server.child_pid); |
10254 | } |
10255 | /* Reset the buffer accumulating changes while the child saves. */ |
10256 | resetChildState(); |
10257 | moduleForkInfo.done_handler = NULL; |
10258 | moduleForkInfo.done_handler_user_data = NULL; |
10259 | return C_OK; |
10260 | } |
10261 | |
10262 | /* Can be used to kill the forked child process from the parent process. |
10263 | * child_pid would be the return value of RedisModule_Fork. */ |
10264 | int RM_KillForkChild(int child_pid) { |
10265 | /* Kill module child, wait for child exit. */ |
10266 | if (TerminateModuleForkChild(child_pid,1) == C_OK) |
10267 | return REDISMODULE_OK; |
10268 | else |
10269 | return REDISMODULE_ERR; |
10270 | } |
10271 | |
10272 | void ModuleForkDoneHandler(int exitcode, int bysignal) { |
10273 | serverLog(LL_NOTICE, |
10274 | "Module fork exited pid: %ld, retcode: %d, bysignal: %d" , |
10275 | (long) server.child_pid, exitcode, bysignal); |
10276 | if (moduleForkInfo.done_handler) { |
10277 | moduleForkInfo.done_handler(exitcode, bysignal, |
10278 | moduleForkInfo.done_handler_user_data); |
10279 | } |
10280 | |
10281 | moduleForkInfo.done_handler = NULL; |
10282 | moduleForkInfo.done_handler_user_data = NULL; |
10283 | } |
10284 | |
10285 | /* -------------------------------------------------------------------------- |
10286 | * ## Server hooks implementation |
10287 | * -------------------------------------------------------------------------- */ |
10288 | |
10289 | /* This must be synced with REDISMODULE_EVENT_* |
10290 | * We use -1 (MAX_UINT64) to denote that this event doesn't have |
10291 | * a data structure associated with it. We use MAX_UINT64 on purpose, |
10292 | * in order to pass the check in RedisModule_SubscribeToServerEvent. */ |
10293 | static uint64_t moduleEventVersions[] = { |
10294 | REDISMODULE_REPLICATIONINFO_VERSION, /* REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED */ |
10295 | -1, /* REDISMODULE_EVENT_PERSISTENCE */ |
10296 | REDISMODULE_FLUSHINFO_VERSION, /* REDISMODULE_EVENT_FLUSHDB */ |
10297 | -1, /* REDISMODULE_EVENT_LOADING */ |
10298 | REDISMODULE_CLIENTINFO_VERSION, /* REDISMODULE_EVENT_CLIENT_CHANGE */ |
10299 | -1, /* REDISMODULE_EVENT_SHUTDOWN */ |
10300 | -1, /* REDISMODULE_EVENT_REPLICA_CHANGE */ |
10301 | -1, /* REDISMODULE_EVENT_MASTER_LINK_CHANGE */ |
10302 | REDISMODULE_CRON_LOOP_VERSION, /* REDISMODULE_EVENT_CRON_LOOP */ |
10303 | REDISMODULE_MODULE_CHANGE_VERSION, /* REDISMODULE_EVENT_MODULE_CHANGE */ |
10304 | REDISMODULE_LOADING_PROGRESS_VERSION, /* REDISMODULE_EVENT_LOADING_PROGRESS */ |
10305 | REDISMODULE_SWAPDBINFO_VERSION, /* REDISMODULE_EVENT_SWAPDB */ |
10306 | -1, /* REDISMODULE_EVENT_REPL_BACKUP */ |
10307 | -1, /* REDISMODULE_EVENT_FORK_CHILD */ |
10308 | -1, /* REDISMODULE_EVENT_REPL_ASYNC_LOAD */ |
10309 | -1, /* REDISMODULE_EVENT_EVENTLOOP */ |
10310 | -1, /* REDISMODULE_EVENT_CONFIG */ |
10311 | }; |
10312 | |
10313 | /* Register to be notified, via a callback, when the specified server event |
10314 | * happens. The callback is called with the event as argument, and an additional |
10315 | * argument which is a void pointer and should be cased to a specific type |
10316 | * that is event-specific (but many events will just use NULL since they do not |
10317 | * have additional information to pass to the callback). |
10318 | * |
10319 | * If the callback is NULL and there was a previous subscription, the module |
10320 | * will be unsubscribed. If there was a previous subscription and the callback |
10321 | * is not null, the old callback will be replaced with the new one. |
10322 | * |
10323 | * The callback must be of this type: |
10324 | * |
10325 | * int (*RedisModuleEventCallback)(RedisModuleCtx *ctx, |
10326 | * RedisModuleEvent eid, |
10327 | * uint64_t subevent, |
10328 | * void *data); |
10329 | * |
10330 | * The 'ctx' is a normal Redis module context that the callback can use in |
10331 | * order to call other modules APIs. The 'eid' is the event itself, this |
10332 | * is only useful in the case the module subscribed to multiple events: using |
10333 | * the 'id' field of this structure it is possible to check if the event |
10334 | * is one of the events we registered with this callback. The 'subevent' field |
10335 | * depends on the event that fired. |
10336 | * |
10337 | * Finally the 'data' pointer may be populated, only for certain events, with |
10338 | * more relevant data. |
10339 | * |
10340 | * Here is a list of events you can use as 'eid' and related sub events: |
10341 | * |
10342 | * * RedisModuleEvent_ReplicationRoleChanged: |
10343 | * |
10344 | * This event is called when the instance switches from master |
10345 | * to replica or the other way around, however the event is |
10346 | * also called when the replica remains a replica but starts to |
10347 | * replicate with a different master. |
10348 | * |
10349 | * The following sub events are available: |
10350 | * |
10351 | * * `REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_MASTER` |
10352 | * * `REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_REPLICA` |
10353 | * |
10354 | * The 'data' field can be casted by the callback to a |
10355 | * `RedisModuleReplicationInfo` structure with the following fields: |
10356 | * |
10357 | * int master; // true if master, false if replica |
10358 | * char *masterhost; // master instance hostname for NOW_REPLICA |
10359 | * int masterport; // master instance port for NOW_REPLICA |
10360 | * char *replid1; // Main replication ID |
10361 | * char *replid2; // Secondary replication ID |
10362 | * uint64_t repl1_offset; // Main replication offset |
10363 | * uint64_t repl2_offset; // Offset of replid2 validity |
10364 | * |
10365 | * * RedisModuleEvent_Persistence |
10366 | * |
10367 | * This event is called when RDB saving or AOF rewriting starts |
10368 | * and ends. The following sub events are available: |
10369 | * |
10370 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START` |
10371 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_AOF_START` |
10372 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START` |
10373 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START` |
10374 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_ENDED` |
10375 | * * `REDISMODULE_SUBEVENT_PERSISTENCE_FAILED` |
10376 | * |
10377 | * The above events are triggered not just when the user calls the |
10378 | * relevant commands like BGSAVE, but also when a saving operation |
10379 | * or AOF rewriting occurs because of internal server triggers. |
10380 | * The SYNC_RDB_START sub events are happening in the foreground due to |
10381 | * SAVE command, FLUSHALL, or server shutdown, and the other RDB and |
10382 | * AOF sub events are executed in a background fork child, so any |
10383 | * action the module takes can only affect the generated AOF or RDB, |
10384 | * but will not be reflected in the parent process and affect connected |
10385 | * clients and commands. Also note that the AOF_START sub event may end |
10386 | * up saving RDB content in case of an AOF with rdb-preamble. |
10387 | * |
10388 | * * RedisModuleEvent_FlushDB |
10389 | * |
10390 | * The FLUSHALL, FLUSHDB or an internal flush (for instance |
10391 | * because of replication, after the replica synchronization) |
10392 | * happened. The following sub events are available: |
10393 | * |
10394 | * * `REDISMODULE_SUBEVENT_FLUSHDB_START` |
10395 | * * `REDISMODULE_SUBEVENT_FLUSHDB_END` |
10396 | * |
10397 | * The data pointer can be casted to a RedisModuleFlushInfo |
10398 | * structure with the following fields: |
10399 | * |
10400 | * int32_t async; // True if the flush is done in a thread. |
10401 | * // See for instance FLUSHALL ASYNC. |
10402 | * // In this case the END callback is invoked |
10403 | * // immediately after the database is put |
10404 | * // in the free list of the thread. |
10405 | * int32_t dbnum; // Flushed database number, -1 for all the DBs |
10406 | * // in the case of the FLUSHALL operation. |
10407 | * |
10408 | * The start event is called *before* the operation is initiated, thus |
10409 | * allowing the callback to call DBSIZE or other operation on the |
10410 | * yet-to-free keyspace. |
10411 | * |
10412 | * * RedisModuleEvent_Loading |
10413 | * |
10414 | * Called on loading operations: at startup when the server is |
10415 | * started, but also after a first synchronization when the |
10416 | * replica is loading the RDB file from the master. |
10417 | * The following sub events are available: |
10418 | * |
10419 | * * `REDISMODULE_SUBEVENT_LOADING_RDB_START` |
10420 | * * `REDISMODULE_SUBEVENT_LOADING_AOF_START` |
10421 | * * `REDISMODULE_SUBEVENT_LOADING_REPL_START` |
10422 | * * `REDISMODULE_SUBEVENT_LOADING_ENDED` |
10423 | * * `REDISMODULE_SUBEVENT_LOADING_FAILED` |
10424 | * |
10425 | * Note that AOF loading may start with an RDB data in case of |
10426 | * rdb-preamble, in which case you'll only receive an AOF_START event. |
10427 | * |
10428 | * * RedisModuleEvent_ClientChange |
10429 | * |
10430 | * Called when a client connects or disconnects. |
10431 | * The data pointer can be casted to a RedisModuleClientInfo |
10432 | * structure, documented in RedisModule_GetClientInfoById(). |
10433 | * The following sub events are available: |
10434 | * |
10435 | * * `REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED` |
10436 | * * `REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED` |
10437 | * |
10438 | * * RedisModuleEvent_Shutdown |
10439 | * |
10440 | * The server is shutting down. No subevents are available. |
10441 | * |
10442 | * * RedisModuleEvent_ReplicaChange |
10443 | * |
10444 | * This event is called when the instance (that can be both a |
10445 | * master or a replica) get a new online replica, or lose a |
10446 | * replica since it gets disconnected. |
10447 | * The following sub events are available: |
10448 | * |
10449 | * * `REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE` |
10450 | * * `REDISMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE` |
10451 | * |
10452 | * No additional information is available so far: future versions |
10453 | * of Redis will have an API in order to enumerate the replicas |
10454 | * connected and their state. |
10455 | * |
10456 | * * RedisModuleEvent_CronLoop |
10457 | * |
10458 | * This event is called every time Redis calls the serverCron() |
10459 | * function in order to do certain bookkeeping. Modules that are |
10460 | * required to do operations from time to time may use this callback. |
10461 | * Normally Redis calls this function 10 times per second, but |
10462 | * this changes depending on the "hz" configuration. |
10463 | * No sub events are available. |
10464 | * |
10465 | * The data pointer can be casted to a RedisModuleCronLoop |
10466 | * structure with the following fields: |
10467 | * |
10468 | * int32_t hz; // Approximate number of events per second. |
10469 | * |
10470 | * * RedisModuleEvent_MasterLinkChange |
10471 | * |
10472 | * This is called for replicas in order to notify when the |
10473 | * replication link becomes functional (up) with our master, |
10474 | * or when it goes down. Note that the link is not considered |
10475 | * up when we just connected to the master, but only if the |
10476 | * replication is happening correctly. |
10477 | * The following sub events are available: |
10478 | * |
10479 | * * `REDISMODULE_SUBEVENT_MASTER_LINK_UP` |
10480 | * * `REDISMODULE_SUBEVENT_MASTER_LINK_DOWN` |
10481 | * |
10482 | * * RedisModuleEvent_ModuleChange |
10483 | * |
10484 | * This event is called when a new module is loaded or one is unloaded. |
10485 | * The following sub events are available: |
10486 | * |
10487 | * * `REDISMODULE_SUBEVENT_MODULE_LOADED` |
10488 | * * `REDISMODULE_SUBEVENT_MODULE_UNLOADED` |
10489 | * |
10490 | * The data pointer can be casted to a RedisModuleModuleChange |
10491 | * structure with the following fields: |
10492 | * |
10493 | * const char* module_name; // Name of module loaded or unloaded. |
10494 | * int32_t module_version; // Module version. |
10495 | * |
10496 | * * RedisModuleEvent_LoadingProgress |
10497 | * |
10498 | * This event is called repeatedly called while an RDB or AOF file |
10499 | * is being loaded. |
10500 | * The following sub events are available: |
10501 | * |
10502 | * * `REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB` |
10503 | * * `REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF` |
10504 | * |
10505 | * The data pointer can be casted to a RedisModuleLoadingProgress |
10506 | * structure with the following fields: |
10507 | * |
10508 | * int32_t hz; // Approximate number of events per second. |
10509 | * int32_t progress; // Approximate progress between 0 and 1024, |
10510 | * // or -1 if unknown. |
10511 | * |
10512 | * * RedisModuleEvent_SwapDB |
10513 | * |
10514 | * This event is called when a SWAPDB command has been successfully |
10515 | * Executed. |
10516 | * For this event call currently there is no subevents available. |
10517 | * |
10518 | * The data pointer can be casted to a RedisModuleSwapDbInfo |
10519 | * structure with the following fields: |
10520 | * |
10521 | * int32_t dbnum_first; // Swap Db first dbnum |
10522 | * int32_t dbnum_second; // Swap Db second dbnum |
10523 | * |
10524 | * * RedisModuleEvent_ReplBackup |
10525 | * |
10526 | * WARNING: Replication Backup events are deprecated since Redis 7.0 and are never fired. |
10527 | * See RedisModuleEvent_ReplAsyncLoad for understanding how Async Replication Loading events |
10528 | * are now triggered when repl-diskless-load is set to swapdb. |
10529 | * |
10530 | * Called when repl-diskless-load config is set to swapdb, |
10531 | * And redis needs to backup the current database for the |
10532 | * possibility to be restored later. A module with global data and |
10533 | * maybe with aux_load and aux_save callbacks may need to use this |
10534 | * notification to backup / restore / discard its globals. |
10535 | * The following sub events are available: |
10536 | * |
10537 | * * `REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE` |
10538 | * * `REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE` |
10539 | * * `REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD` |
10540 | * |
10541 | * * RedisModuleEvent_ReplAsyncLoad |
10542 | * |
10543 | * Called when repl-diskless-load config is set to swapdb and a replication with a master of same |
10544 | * data set history (matching replication ID) occurs. |
10545 | * In which case redis serves current data set while loading new database in memory from socket. |
10546 | * Modules must have declared they support this mechanism in order to activate it, through |
10547 | * REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD flag. |
10548 | * The following sub events are available: |
10549 | * |
10550 | * * `REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED` |
10551 | * * `REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED` |
10552 | * * `REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED` |
10553 | * |
10554 | * * RedisModuleEvent_ForkChild |
10555 | * |
10556 | * Called when a fork child (AOFRW, RDBSAVE, module fork...) is born/dies |
10557 | * The following sub events are available: |
10558 | * |
10559 | * * `REDISMODULE_SUBEVENT_FORK_CHILD_BORN` |
10560 | * * `REDISMODULE_SUBEVENT_FORK_CHILD_DIED` |
10561 | * |
10562 | * * RedisModuleEvent_EventLoop |
10563 | * |
10564 | * Called on each event loop iteration, once just before the event loop goes |
10565 | * to sleep or just after it wakes up. |
10566 | * The following sub events are available: |
10567 | * |
10568 | * * `REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP` |
10569 | * * `REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP` |
10570 | * |
10571 | * * RedisModule_Event_Config |
10572 | * |
10573 | * Called when a configuration event happens |
10574 | * The following sub events are available: |
10575 | * |
10576 | * * `REDISMODULE_SUBEVENT_CONFIG_CHANGE` |
10577 | * |
10578 | * The data pointer can be casted to a RedisModuleConfigChange |
10579 | * structure with the following fields: |
10580 | * |
10581 | * const char **config_names; // An array of C string pointers containing the |
10582 | * // name of each modified configuration item |
10583 | * uint32_t num_changes; // The number of elements in the config_names array |
10584 | * |
10585 | * The function returns REDISMODULE_OK if the module was successfully subscribed |
10586 | * for the specified event. If the API is called from a wrong context or unsupported event |
10587 | * is given then REDISMODULE_ERR is returned. */ |
10588 | int RM_SubscribeToServerEvent(RedisModuleCtx *ctx, RedisModuleEvent event, RedisModuleEventCallback callback) { |
10589 | RedisModuleEventListener *el; |
10590 | |
10591 | /* Protect in case of calls from contexts without a module reference. */ |
10592 | if (ctx->module == NULL) return REDISMODULE_ERR; |
10593 | if (event.id >= _REDISMODULE_EVENT_NEXT) return REDISMODULE_ERR; |
10594 | if (event.dataver > moduleEventVersions[event.id]) return REDISMODULE_ERR; /* Module compiled with a newer redismodule.h than we support */ |
10595 | |
10596 | /* Search an event matching this module and event ID. */ |
10597 | listIter li; |
10598 | listNode *ln; |
10599 | listRewind(RedisModule_EventListeners,&li); |
10600 | while((ln = listNext(&li))) { |
10601 | el = ln->value; |
10602 | if (el->module == ctx->module && el->event.id == event.id) |
10603 | break; /* Matching event found. */ |
10604 | } |
10605 | |
10606 | /* Modify or remove the event listener if we already had one. */ |
10607 | if (ln) { |
10608 | if (callback == NULL) { |
10609 | listDelNode(RedisModule_EventListeners,ln); |
10610 | zfree(el); |
10611 | } else { |
10612 | el->callback = callback; /* Update the callback with the new one. */ |
10613 | } |
10614 | return REDISMODULE_OK; |
10615 | } |
10616 | |
10617 | /* No event found, we need to add a new one. */ |
10618 | el = zmalloc(sizeof(*el)); |
10619 | el->module = ctx->module; |
10620 | el->event = event; |
10621 | el->callback = callback; |
10622 | listAddNodeTail(RedisModule_EventListeners,el); |
10623 | return REDISMODULE_OK; |
10624 | } |
10625 | |
10626 | /** |
10627 | * For a given server event and subevent, return zero if the |
10628 | * subevent is not supported and non-zero otherwise. |
10629 | */ |
10630 | int RM_IsSubEventSupported(RedisModuleEvent event, int64_t subevent) { |
10631 | switch (event.id) { |
10632 | case REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED: |
10633 | return subevent < _REDISMODULE_EVENT_REPLROLECHANGED_NEXT; |
10634 | case REDISMODULE_EVENT_PERSISTENCE: |
10635 | return subevent < _REDISMODULE_SUBEVENT_PERSISTENCE_NEXT; |
10636 | case REDISMODULE_EVENT_FLUSHDB: |
10637 | return subevent < _REDISMODULE_SUBEVENT_FLUSHDB_NEXT; |
10638 | case REDISMODULE_EVENT_LOADING: |
10639 | return subevent < _REDISMODULE_SUBEVENT_LOADING_NEXT; |
10640 | case REDISMODULE_EVENT_CLIENT_CHANGE: |
10641 | return subevent < _REDISMODULE_SUBEVENT_CLIENT_CHANGE_NEXT; |
10642 | case REDISMODULE_EVENT_SHUTDOWN: |
10643 | return subevent < _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT; |
10644 | case REDISMODULE_EVENT_REPLICA_CHANGE: |
10645 | return subevent < _REDISMODULE_EVENT_REPLROLECHANGED_NEXT; |
10646 | case REDISMODULE_EVENT_MASTER_LINK_CHANGE: |
10647 | return subevent < _REDISMODULE_SUBEVENT_MASTER_NEXT; |
10648 | case REDISMODULE_EVENT_CRON_LOOP: |
10649 | return subevent < _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT; |
10650 | case REDISMODULE_EVENT_MODULE_CHANGE: |
10651 | return subevent < _REDISMODULE_SUBEVENT_MODULE_NEXT; |
10652 | case REDISMODULE_EVENT_LOADING_PROGRESS: |
10653 | return subevent < _REDISMODULE_SUBEVENT_LOADING_PROGRESS_NEXT; |
10654 | case REDISMODULE_EVENT_SWAPDB: |
10655 | return subevent < _REDISMODULE_SUBEVENT_SWAPDB_NEXT; |
10656 | case REDISMODULE_EVENT_REPL_ASYNC_LOAD: |
10657 | return subevent < _REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_NEXT; |
10658 | case REDISMODULE_EVENT_FORK_CHILD: |
10659 | return subevent < _REDISMODULE_SUBEVENT_FORK_CHILD_NEXT; |
10660 | case REDISMODULE_EVENT_EVENTLOOP: |
10661 | return subevent < _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT; |
10662 | case REDISMODULE_EVENT_CONFIG: |
10663 | return subevent < _REDISMODULE_SUBEVENT_CONFIG_NEXT; |
10664 | default: |
10665 | break; |
10666 | } |
10667 | return 0; |
10668 | } |
10669 | |
10670 | /* This is called by the Redis internals every time we want to fire an |
10671 | * event that can be intercepted by some module. The pointer 'data' is useful |
10672 | * in order to populate the event-specific structure when needed, in order |
10673 | * to return the structure with more information to the callback. |
10674 | * |
10675 | * 'eid' and 'subid' are just the main event ID and the sub event associated |
10676 | * with the event, depending on what exactly happened. */ |
10677 | void moduleFireServerEvent(uint64_t eid, int subid, void *data) { |
10678 | /* Fast path to return ASAP if there is nothing to do, avoiding to |
10679 | * setup the iterator and so forth: we want this call to be extremely |
10680 | * cheap if there are no registered modules. */ |
10681 | if (listLength(RedisModule_EventListeners) == 0) return; |
10682 | |
10683 | listIter li; |
10684 | listNode *ln; |
10685 | listRewind(RedisModule_EventListeners,&li); |
10686 | while((ln = listNext(&li))) { |
10687 | RedisModuleEventListener *el = ln->value; |
10688 | if (el->event.id == eid) { |
10689 | RedisModuleCtx ctx; |
10690 | if (eid == REDISMODULE_EVENT_CLIENT_CHANGE) { |
10691 | /* In the case of client changes, we're pushing the real client |
10692 | * so the event handler can mutate it if needed. For example, |
10693 | * to change its authentication state in a way that does not |
10694 | * depend on specific commands executed later. |
10695 | */ |
10696 | moduleCreateContext(&ctx,el->module,REDISMODULE_CTX_NONE); |
10697 | ctx.client = (client *) data; |
10698 | } else { |
10699 | moduleCreateContext(&ctx,el->module,REDISMODULE_CTX_TEMP_CLIENT); |
10700 | } |
10701 | |
10702 | void *moduledata = NULL; |
10703 | RedisModuleClientInfoV1 civ1; |
10704 | RedisModuleReplicationInfoV1 riv1; |
10705 | RedisModuleModuleChangeV1 mcv1; |
10706 | /* Start at DB zero by default when calling the handler. It's |
10707 | * up to the specific event setup to change it when it makes |
10708 | * sense. For instance for FLUSHDB events we select the correct |
10709 | * DB automatically. */ |
10710 | selectDb(ctx.client, 0); |
10711 | |
10712 | /* Event specific context and data pointer setup. */ |
10713 | if (eid == REDISMODULE_EVENT_CLIENT_CHANGE) { |
10714 | serverAssert(modulePopulateClientInfoStructure(&civ1,data, el->event.dataver) == REDISMODULE_OK); |
10715 | moduledata = &civ1; |
10716 | } else if (eid == REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED) { |
10717 | serverAssert(modulePopulateReplicationInfoStructure(&riv1,el->event.dataver) == REDISMODULE_OK); |
10718 | moduledata = &riv1; |
10719 | } else if (eid == REDISMODULE_EVENT_FLUSHDB) { |
10720 | moduledata = data; |
10721 | RedisModuleFlushInfoV1 *fi = data; |
10722 | if (fi->dbnum != -1) |
10723 | selectDb(ctx.client, fi->dbnum); |
10724 | } else if (eid == REDISMODULE_EVENT_MODULE_CHANGE) { |
10725 | RedisModule *m = data; |
10726 | if (m == el->module) { |
10727 | moduleFreeContext(&ctx); |
10728 | continue; |
10729 | } |
10730 | mcv1.version = REDISMODULE_MODULE_CHANGE_VERSION; |
10731 | mcv1.module_name = m->name; |
10732 | mcv1.module_version = m->ver; |
10733 | moduledata = &mcv1; |
10734 | } else if (eid == REDISMODULE_EVENT_LOADING_PROGRESS) { |
10735 | moduledata = data; |
10736 | } else if (eid == REDISMODULE_EVENT_CRON_LOOP) { |
10737 | moduledata = data; |
10738 | } else if (eid == REDISMODULE_EVENT_SWAPDB) { |
10739 | moduledata = data; |
10740 | } else if (eid == REDISMODULE_EVENT_CONFIG) { |
10741 | moduledata = data; |
10742 | } |
10743 | |
10744 | el->module->in_hook++; |
10745 | el->callback(&ctx,el->event,subid,moduledata); |
10746 | el->module->in_hook--; |
10747 | |
10748 | moduleFreeContext(&ctx); |
10749 | } |
10750 | } |
10751 | } |
10752 | |
10753 | /* Remove all the listeners for this module: this is used before unloading |
10754 | * a module. */ |
10755 | void moduleUnsubscribeAllServerEvents(RedisModule *module) { |
10756 | RedisModuleEventListener *el; |
10757 | listIter li; |
10758 | listNode *ln; |
10759 | listRewind(RedisModule_EventListeners,&li); |
10760 | |
10761 | while((ln = listNext(&li))) { |
10762 | el = ln->value; |
10763 | if (el->module == module) { |
10764 | listDelNode(RedisModule_EventListeners,ln); |
10765 | zfree(el); |
10766 | } |
10767 | } |
10768 | } |
10769 | |
10770 | void processModuleLoadingProgressEvent(int is_aof) { |
10771 | long long now = server.ustime; |
10772 | static long long next_event = 0; |
10773 | if (now >= next_event) { |
10774 | /* Fire the loading progress modules end event. */ |
10775 | int progress = -1; |
10776 | if (server.loading_total_bytes) |
10777 | progress = (server.loading_loaded_bytes<<10) / server.loading_total_bytes; |
10778 | RedisModuleLoadingProgressV1 fi = {REDISMODULE_LOADING_PROGRESS_VERSION, |
10779 | server.hz, |
10780 | progress}; |
10781 | moduleFireServerEvent(REDISMODULE_EVENT_LOADING_PROGRESS, |
10782 | is_aof? |
10783 | REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF: |
10784 | REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB, |
10785 | &fi); |
10786 | /* decide when the next event should fire. */ |
10787 | next_event = now + 1000000 / server.hz; |
10788 | } |
10789 | } |
10790 | |
10791 | /* When a module key is deleted (in dbAsyncDelete/dbSyncDelete/dbOverwrite), it |
10792 | * will be called to tell the module which key is about to be released. */ |
10793 | void moduleNotifyKeyUnlink(robj *key, robj *val, int dbid) { |
10794 | if (val->type == OBJ_MODULE) { |
10795 | moduleValue *mv = val->ptr; |
10796 | moduleType *mt = mv->type; |
10797 | /* We prefer to use the enhanced version. */ |
10798 | if (mt->unlink2 != NULL) { |
10799 | RedisModuleKeyOptCtx ctx = {key, NULL, dbid, -1}; |
10800 | mt->unlink2(&ctx,mv->value); |
10801 | } else if (mt->unlink != NULL) { |
10802 | mt->unlink(key,mv->value); |
10803 | } |
10804 | } |
10805 | } |
10806 | |
10807 | /* Return the free_effort of the module, it will automatically choose to call |
10808 | * `free_effort` or `free_effort2`, and the default return value is 1. |
10809 | * value of 0 means very high effort (always asynchronous freeing). */ |
10810 | size_t moduleGetFreeEffort(robj *key, robj *val, int dbid) { |
10811 | moduleValue *mv = val->ptr; |
10812 | moduleType *mt = mv->type; |
10813 | size_t effort = 1; |
10814 | /* We prefer to use the enhanced version. */ |
10815 | if (mt->free_effort2 != NULL) { |
10816 | RedisModuleKeyOptCtx ctx = {key, NULL, dbid, -1}; |
10817 | effort = mt->free_effort2(&ctx,mv->value); |
10818 | } else if (mt->free_effort != NULL) { |
10819 | effort = mt->free_effort(key,mv->value); |
10820 | } |
10821 | |
10822 | return effort; |
10823 | } |
10824 | |
10825 | /* Return the memory usage of the module, it will automatically choose to call |
10826 | * `mem_usage` or `mem_usage2`, and the default return value is 0. */ |
10827 | size_t moduleGetMemUsage(robj *key, robj *val, size_t sample_size, int dbid) { |
10828 | moduleValue *mv = val->ptr; |
10829 | moduleType *mt = mv->type; |
10830 | size_t size = 0; |
10831 | /* We prefer to use the enhanced version. */ |
10832 | if (mt->mem_usage2 != NULL) { |
10833 | RedisModuleKeyOptCtx ctx = {key, NULL, dbid, -1}; |
10834 | size = mt->mem_usage2(&ctx, mv->value, sample_size); |
10835 | } else if (mt->mem_usage != NULL) { |
10836 | size = mt->mem_usage(mv->value); |
10837 | } |
10838 | |
10839 | return size; |
10840 | } |
10841 | |
10842 | /* -------------------------------------------------------------------------- |
10843 | * Modules API internals |
10844 | * -------------------------------------------------------------------------- */ |
10845 | |
10846 | /* server.moduleapi dictionary type. Only uses plain C strings since |
10847 | * this gets queries from modules. */ |
10848 | |
10849 | uint64_t dictCStringKeyHash(const void *key) { |
10850 | return dictGenHashFunction((unsigned char*)key, strlen((char*)key)); |
10851 | } |
10852 | |
10853 | int dictCStringKeyCompare(dict *d, const void *key1, const void *key2) { |
10854 | UNUSED(d); |
10855 | return strcmp(key1,key2) == 0; |
10856 | } |
10857 | |
10858 | dictType moduleAPIDictType = { |
10859 | dictCStringKeyHash, /* hash function */ |
10860 | NULL, /* key dup */ |
10861 | NULL, /* val dup */ |
10862 | dictCStringKeyCompare, /* key compare */ |
10863 | NULL, /* key destructor */ |
10864 | NULL, /* val destructor */ |
10865 | NULL /* allow to expand */ |
10866 | }; |
10867 | |
10868 | int moduleRegisterApi(const char *funcname, void *funcptr) { |
10869 | return dictAdd(server.moduleapi, (char*)funcname, funcptr); |
10870 | } |
10871 | |
10872 | #define REGISTER_API(name) \ |
10873 | moduleRegisterApi("RedisModule_" #name, (void *)(unsigned long)RM_ ## name) |
10874 | |
10875 | /* Global initialization at Redis startup. */ |
10876 | void moduleRegisterCoreAPI(void); |
10877 | |
10878 | /* Currently, this function is just a placeholder for the module system |
10879 | * initialization steps that need to be run after server initialization. |
10880 | * A previous issue, selectDb() in createClient() requires that server.db has |
10881 | * been initialized, see #7323. */ |
10882 | void moduleInitModulesSystemLast(void) { |
10883 | } |
10884 | |
10885 | |
10886 | dictType sdsKeyValueHashDictType = { |
10887 | dictSdsCaseHash, /* hash function */ |
10888 | NULL, /* key dup */ |
10889 | NULL, /* val dup */ |
10890 | dictSdsKeyCaseCompare, /* key compare */ |
10891 | dictSdsDestructor, /* key destructor */ |
10892 | dictSdsDestructor, /* val destructor */ |
10893 | NULL /* allow to expand */ |
10894 | }; |
10895 | |
10896 | void moduleInitModulesSystem(void) { |
10897 | moduleUnblockedClients = listCreate(); |
10898 | server.loadmodule_queue = listCreate(); |
10899 | server.module_configs_queue = dictCreate(&sdsKeyValueHashDictType); |
10900 | modules = dictCreate(&modulesDictType); |
10901 | |
10902 | /* Set up the keyspace notification subscriber list and static client */ |
10903 | moduleKeyspaceSubscribers = listCreate(); |
10904 | |
10905 | /* Set up filter list */ |
10906 | moduleCommandFilters = listCreate(); |
10907 | |
10908 | moduleRegisterCoreAPI(); |
10909 | |
10910 | /* Create a pipe for module threads to be able to wake up the redis main thread. |
10911 | * Make the pipe non blocking. This is just a best effort aware mechanism |
10912 | * and we do not want to block not in the read nor in the write half. |
10913 | * Enable close-on-exec flag on pipes in case of the fork-exec system calls in |
10914 | * sentinels or redis servers. */ |
10915 | if (anetPipe(server.module_pipe, O_CLOEXEC|O_NONBLOCK, O_CLOEXEC|O_NONBLOCK) == -1) { |
10916 | serverLog(LL_WARNING, |
10917 | "Can't create the pipe for module threads: %s" , strerror(errno)); |
10918 | exit(1); |
10919 | } |
10920 | |
10921 | /* Create the timers radix tree. */ |
10922 | Timers = raxNew(); |
10923 | |
10924 | /* Setup the event listeners data structures. */ |
10925 | RedisModule_EventListeners = listCreate(); |
10926 | |
10927 | /* Making sure moduleEventVersions is synced with the number of events. */ |
10928 | serverAssert(sizeof(moduleEventVersions)/sizeof(moduleEventVersions[0]) == _REDISMODULE_EVENT_NEXT); |
10929 | |
10930 | /* Our thread-safe contexts GIL must start with already locked: |
10931 | * it is just unlocked when it's safe. */ |
10932 | pthread_mutex_lock(&moduleGIL); |
10933 | } |
10934 | |
10935 | void modulesCron(void) { |
10936 | /* Check number of temporary clients in the pool and free the unused ones |
10937 | * since the last cron. moduleTempClientMinCount tracks minimum count of |
10938 | * clients in the pool since the last cron. This is the number of clients |
10939 | * that we didn't use for the last cron period. */ |
10940 | |
10941 | /* Limit the max client count to be freed at once to avoid latency spikes.*/ |
10942 | int iteration = 50; |
10943 | /* We are freeing clients if we have more than 8 unused clients. Keeping |
10944 | * small amount of clients to avoid client allocation costs if temporary |
10945 | * clients are required after some idle period. */ |
10946 | const unsigned int min_client = 8; |
10947 | while (iteration > 0 && moduleTempClientCount > 0 && moduleTempClientMinCount > min_client) { |
10948 | client *c = moduleTempClients[--moduleTempClientCount]; |
10949 | freeClient(c); |
10950 | iteration--; |
10951 | moduleTempClientMinCount--; |
10952 | } |
10953 | moduleTempClientMinCount = moduleTempClientCount; |
10954 | |
10955 | /* Shrink moduleTempClients array itself if it is wasting some space */ |
10956 | if (moduleTempClientCap > 32 && moduleTempClientCap > moduleTempClientCount * 4) { |
10957 | moduleTempClientCap /= 4; |
10958 | moduleTempClients = zrealloc(moduleTempClients,sizeof(client*)*moduleTempClientCap); |
10959 | } |
10960 | } |
10961 | |
10962 | void moduleLoadQueueEntryFree(struct moduleLoadQueueEntry *loadmod) { |
10963 | if (!loadmod) return; |
10964 | sdsfree(loadmod->path); |
10965 | for (int i = 0; i < loadmod->argc; i++) { |
10966 | decrRefCount(loadmod->argv[i]); |
10967 | } |
10968 | zfree(loadmod->argv); |
10969 | zfree(loadmod); |
10970 | } |
10971 | |
10972 | /* Remove Module Configs from standardConfig array in config.c */ |
10973 | void moduleRemoveConfigs(RedisModule *module) { |
10974 | listIter li; |
10975 | listNode *ln; |
10976 | listRewind(module->module_configs, &li); |
10977 | while ((ln = listNext(&li))) { |
10978 | ModuleConfig *config = listNodeValue(ln); |
10979 | sds module_name = sdsnew(module->name); |
10980 | sds full_name = sdscat(sdscat(module_name, "." ), config->name); /* ModuleName.ModuleConfig */ |
10981 | removeConfig(full_name); |
10982 | sdsfree(full_name); |
10983 | } |
10984 | } |
10985 | |
10986 | /* Load all the modules in the server.loadmodule_queue list, which is |
10987 | * populated by `loadmodule` directives in the configuration file. |
10988 | * We can't load modules directly when processing the configuration file |
10989 | * because the server must be fully initialized before loading modules. |
10990 | * |
10991 | * The function aborts the server on errors, since to start with missing |
10992 | * modules is not considered sane: clients may rely on the existence of |
10993 | * given commands, loading AOF also may need some modules to exist, and |
10994 | * if this instance is a slave, it must understand commands from master. */ |
10995 | void moduleLoadFromQueue(void) { |
10996 | listIter li; |
10997 | listNode *ln; |
10998 | |
10999 | listRewind(server.loadmodule_queue,&li); |
11000 | while((ln = listNext(&li))) { |
11001 | struct moduleLoadQueueEntry *loadmod = ln->value; |
11002 | if (moduleLoad(loadmod->path,(void **)loadmod->argv,loadmod->argc, 0) |
11003 | == C_ERR) |
11004 | { |
11005 | serverLog(LL_WARNING, |
11006 | "Can't load module from %s: server aborting" , |
11007 | loadmod->path); |
11008 | exit(1); |
11009 | } |
11010 | moduleLoadQueueEntryFree(loadmod); |
11011 | listDelNode(server.loadmodule_queue, ln); |
11012 | } |
11013 | if (dictSize(server.module_configs_queue)) { |
11014 | serverLog(LL_WARNING, "Module Configuration detected without loadmodule directive or no ApplyConfig call: aborting" ); |
11015 | exit(1); |
11016 | } |
11017 | } |
11018 | |
11019 | void moduleFreeModuleStructure(struct RedisModule *module) { |
11020 | listRelease(module->types); |
11021 | listRelease(module->filters); |
11022 | listRelease(module->usedby); |
11023 | listRelease(module->using); |
11024 | listRelease(module->module_configs); |
11025 | sdsfree(module->name); |
11026 | moduleLoadQueueEntryFree(module->loadmod); |
11027 | zfree(module); |
11028 | } |
11029 | |
11030 | /* Free the command registered with the specified module. |
11031 | * On success C_OK is returned, otherwise C_ERR is returned. |
11032 | * |
11033 | * Note that caller needs to handle the deletion of the command table dict, |
11034 | * and after that needs to free the command->fullname and the command itself. |
11035 | */ |
11036 | int moduleFreeCommand(struct RedisModule *module, struct redisCommand *cmd) { |
11037 | if (cmd->proc != RedisModuleCommandDispatcher) |
11038 | return C_ERR; |
11039 | |
11040 | RedisModuleCommand *cp = cmd->module_cmd; |
11041 | if (cp->module != module) |
11042 | return C_ERR; |
11043 | |
11044 | /* Free everything except cmd->fullname and cmd itself. */ |
11045 | for (int j = 0; j < cmd->key_specs_num; j++) { |
11046 | if (cmd->key_specs[j].notes) |
11047 | zfree((char *)cmd->key_specs[j].notes); |
11048 | if (cmd->key_specs[j].begin_search_type == KSPEC_BS_KEYWORD) |
11049 | zfree((char *)cmd->key_specs[j].bs.keyword.keyword); |
11050 | } |
11051 | if (cmd->key_specs != cmd->key_specs_static) |
11052 | zfree(cmd->key_specs); |
11053 | for (int j = 0; cmd->tips && cmd->tips[j]; j++) |
11054 | zfree((char *)cmd->tips[j]); |
11055 | for (int j = 0; cmd->history && cmd->history[j].since; j++) { |
11056 | zfree((char *)cmd->history[j].since); |
11057 | zfree((char *)cmd->history[j].changes); |
11058 | } |
11059 | zfree((char *)cmd->summary); |
11060 | zfree((char *)cmd->since); |
11061 | zfree((char *)cmd->deprecated_since); |
11062 | zfree((char *)cmd->complexity); |
11063 | if (cmd->latency_histogram) { |
11064 | hdr_close(cmd->latency_histogram); |
11065 | cmd->latency_histogram = NULL; |
11066 | } |
11067 | zfree(cmd->args); |
11068 | zfree(cp); |
11069 | |
11070 | if (cmd->subcommands_dict) { |
11071 | dictEntry *de; |
11072 | dictIterator *di = dictGetSafeIterator(cmd->subcommands_dict); |
11073 | while ((de = dictNext(di)) != NULL) { |
11074 | struct redisCommand *sub = dictGetVal(de); |
11075 | if (moduleFreeCommand(module, sub) != C_OK) continue; |
11076 | |
11077 | serverAssert(dictDelete(cmd->subcommands_dict, sub->declared_name) == DICT_OK); |
11078 | sdsfree((sds)sub->declared_name); |
11079 | sdsfree(sub->fullname); |
11080 | zfree(sub); |
11081 | } |
11082 | dictReleaseIterator(di); |
11083 | dictRelease(cmd->subcommands_dict); |
11084 | } |
11085 | |
11086 | return C_OK; |
11087 | } |
11088 | |
11089 | void moduleUnregisterCommands(struct RedisModule *module) { |
11090 | /* Unregister all the commands registered by this module. */ |
11091 | dictIterator *di = dictGetSafeIterator(server.commands); |
11092 | dictEntry *de; |
11093 | while ((de = dictNext(di)) != NULL) { |
11094 | struct redisCommand *cmd = dictGetVal(de); |
11095 | if (moduleFreeCommand(module, cmd) != C_OK) continue; |
11096 | |
11097 | serverAssert(dictDelete(server.commands, cmd->fullname) == DICT_OK); |
11098 | serverAssert(dictDelete(server.orig_commands, cmd->fullname) == DICT_OK); |
11099 | sdsfree((sds)cmd->declared_name); |
11100 | sdsfree(cmd->fullname); |
11101 | zfree(cmd); |
11102 | } |
11103 | dictReleaseIterator(di); |
11104 | } |
11105 | |
11106 | /* We parse argv to add sds "NAME VALUE" pairs to the server.module_configs_queue list of configs. |
11107 | * We also increment the module_argv pointer to just after ARGS if there are args, otherwise |
11108 | * we set it to NULL */ |
11109 | int parseLoadexArguments(RedisModuleString ***module_argv, int *module_argc) { |
11110 | int args_specified = 0; |
11111 | RedisModuleString **argv = *module_argv; |
11112 | int argc = *module_argc; |
11113 | for (int i = 0; i < argc; i++) { |
11114 | char *arg_val = argv[i]->ptr; |
11115 | if (!strcasecmp(arg_val, "CONFIG" )) { |
11116 | if (i + 2 >= argc) { |
11117 | serverLog(LL_NOTICE, "CONFIG specified without name value pair" ); |
11118 | return REDISMODULE_ERR; |
11119 | } |
11120 | sds name = sdsdup(argv[i + 1]->ptr); |
11121 | sds value = sdsdup(argv[i + 2]->ptr); |
11122 | if (!dictReplace(server.module_configs_queue, name, value)) sdsfree(name); |
11123 | i += 2; |
11124 | } else if (!strcasecmp(arg_val, "ARGS" )) { |
11125 | args_specified = 1; |
11126 | i++; |
11127 | if (i >= argc) { |
11128 | *module_argv = NULL; |
11129 | *module_argc = 0; |
11130 | } else { |
11131 | *module_argv = argv + i; |
11132 | *module_argc = argc - i; |
11133 | } |
11134 | break; |
11135 | } else { |
11136 | serverLog(LL_NOTICE, "Syntax Error from arguments to loadex around %s." , arg_val); |
11137 | return REDISMODULE_ERR; |
11138 | } |
11139 | } |
11140 | if (!args_specified) { |
11141 | *module_argv = NULL; |
11142 | *module_argc = 0; |
11143 | } |
11144 | return REDISMODULE_OK; |
11145 | } |
11146 | |
11147 | /* Load a module and initialize it. On success C_OK is returned, otherwise |
11148 | * C_ERR is returned. */ |
11149 | int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loadex) { |
11150 | int (*onload)(void *, void **, int); |
11151 | void *handle; |
11152 | |
11153 | struct stat st; |
11154 | if (stat(path, &st) == 0) { |
11155 | /* This check is best effort */ |
11156 | if (!(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { |
11157 | serverLog(LL_WARNING, "Module %s failed to load: It does not have execute permissions." , path); |
11158 | return C_ERR; |
11159 | } |
11160 | } |
11161 | |
11162 | handle = dlopen(path,RTLD_NOW|RTLD_LOCAL); |
11163 | if (handle == NULL) { |
11164 | serverLog(LL_WARNING, "Module %s failed to load: %s" , path, dlerror()); |
11165 | return C_ERR; |
11166 | } |
11167 | onload = (int (*)(void *, void **, int))(unsigned long) dlsym(handle,"RedisModule_OnLoad" ); |
11168 | if (onload == NULL) { |
11169 | dlclose(handle); |
11170 | serverLog(LL_WARNING, |
11171 | "Module %s does not export RedisModule_OnLoad() " |
11172 | "symbol. Module not loaded." ,path); |
11173 | return C_ERR; |
11174 | } |
11175 | RedisModuleCtx ctx; |
11176 | moduleCreateContext(&ctx, NULL, REDISMODULE_CTX_TEMP_CLIENT); /* We pass NULL since we don't have a module yet. */ |
11177 | selectDb(ctx.client, 0); |
11178 | if (onload((void*)&ctx,module_argv,module_argc) == REDISMODULE_ERR) { |
11179 | serverLog(LL_WARNING, |
11180 | "Module %s initialization failed. Module not loaded" ,path); |
11181 | if (ctx.module) { |
11182 | moduleUnregisterCommands(ctx.module); |
11183 | moduleUnregisterSharedAPI(ctx.module); |
11184 | moduleUnregisterUsedAPI(ctx.module); |
11185 | moduleRemoveConfigs(ctx.module); |
11186 | moduleFreeModuleStructure(ctx.module); |
11187 | } |
11188 | moduleFreeContext(&ctx); |
11189 | dlclose(handle); |
11190 | return C_ERR; |
11191 | } |
11192 | |
11193 | /* Redis module loaded! Register it. */ |
11194 | dictAdd(modules,ctx.module->name,ctx.module); |
11195 | ctx.module->blocked_clients = 0; |
11196 | ctx.module->handle = handle; |
11197 | ctx.module->loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry)); |
11198 | ctx.module->loadmod->path = sdsnew(path); |
11199 | ctx.module->loadmod->argv = module_argc ? zmalloc(sizeof(robj*)*module_argc) : NULL; |
11200 | ctx.module->loadmod->argc = module_argc; |
11201 | for (int i = 0; i < module_argc; i++) { |
11202 | ctx.module->loadmod->argv[i] = module_argv[i]; |
11203 | incrRefCount(ctx.module->loadmod->argv[i]); |
11204 | } |
11205 | |
11206 | serverLog(LL_NOTICE,"Module '%s' loaded from %s" ,ctx.module->name,path); |
11207 | |
11208 | if (listLength(ctx.module->module_configs) && !ctx.module->configs_initialized) { |
11209 | serverLogRaw(LL_WARNING, "Module Configurations were not set, likely a missing LoadConfigs call. Unloading the module." ); |
11210 | moduleUnload(ctx.module->name); |
11211 | moduleFreeContext(&ctx); |
11212 | return C_ERR; |
11213 | } |
11214 | |
11215 | if (is_loadex && dictSize(server.module_configs_queue)) { |
11216 | serverLogRaw(LL_WARNING, "Loadex configurations were not applied, likely due to invalid arguments. Unloading the module." ); |
11217 | moduleUnload(ctx.module->name); |
11218 | moduleFreeContext(&ctx); |
11219 | return C_ERR; |
11220 | } |
11221 | |
11222 | /* Fire the loaded modules event. */ |
11223 | moduleFireServerEvent(REDISMODULE_EVENT_MODULE_CHANGE, |
11224 | REDISMODULE_SUBEVENT_MODULE_LOADED, |
11225 | ctx.module); |
11226 | |
11227 | moduleFreeContext(&ctx); |
11228 | return C_OK; |
11229 | } |
11230 | |
11231 | /* Unload the module registered with the specified name. On success |
11232 | * C_OK is returned, otherwise C_ERR is returned and errno is set |
11233 | * to the following values depending on the type of error: |
11234 | * |
11235 | * * ENONET: No such module having the specified name. |
11236 | * * EBUSY: The module exports a new data type and can only be reloaded. |
11237 | * * EPERM: The module exports APIs which are used by other module. |
11238 | * * EAGAIN: The module has blocked clients. |
11239 | * * EINPROGRESS: The module holds timer not fired. |
11240 | * * ECANCELED: Unload module error. */ |
11241 | int moduleUnload(sds name) { |
11242 | struct RedisModule *module = dictFetchValue(modules,name); |
11243 | |
11244 | if (module == NULL) { |
11245 | errno = ENOENT; |
11246 | return C_ERR; |
11247 | } else if (listLength(module->types)) { |
11248 | errno = EBUSY; |
11249 | return C_ERR; |
11250 | } else if (listLength(module->usedby)) { |
11251 | errno = EPERM; |
11252 | return C_ERR; |
11253 | } else if (module->blocked_clients) { |
11254 | errno = EAGAIN; |
11255 | return C_ERR; |
11256 | } else if (moduleHoldsTimer(module)) { |
11257 | errno = EINPROGRESS; |
11258 | return C_ERR; |
11259 | } |
11260 | |
11261 | /* Give module a chance to clean up. */ |
11262 | int (*onunload)(void *); |
11263 | onunload = (int (*)(void *))(unsigned long) dlsym(module->handle, "RedisModule_OnUnload" ); |
11264 | if (onunload) { |
11265 | RedisModuleCtx ctx; |
11266 | moduleCreateContext(&ctx, module, REDISMODULE_CTX_TEMP_CLIENT); |
11267 | int unload_status = onunload((void*)&ctx); |
11268 | moduleFreeContext(&ctx); |
11269 | |
11270 | if (unload_status == REDISMODULE_ERR) { |
11271 | serverLog(LL_WARNING, "Module %s OnUnload failed. Unload canceled." , name); |
11272 | errno = ECANCELED; |
11273 | return C_ERR; |
11274 | } |
11275 | } |
11276 | |
11277 | moduleFreeAuthenticatedClients(module); |
11278 | moduleUnregisterCommands(module); |
11279 | moduleUnregisterSharedAPI(module); |
11280 | moduleUnregisterUsedAPI(module); |
11281 | moduleUnregisterFilters(module); |
11282 | moduleRemoveConfigs(module); |
11283 | |
11284 | /* Remove any notification subscribers this module might have */ |
11285 | moduleUnsubscribeNotifications(module); |
11286 | moduleUnsubscribeAllServerEvents(module); |
11287 | |
11288 | /* Unload the dynamic library. */ |
11289 | if (dlclose(module->handle) == -1) { |
11290 | char *error = dlerror(); |
11291 | if (error == NULL) error = "Unknown error" ; |
11292 | serverLog(LL_WARNING,"Error when trying to close the %s module: %s" , |
11293 | module->name, error); |
11294 | } |
11295 | |
11296 | /* Fire the unloaded modules event. */ |
11297 | moduleFireServerEvent(REDISMODULE_EVENT_MODULE_CHANGE, |
11298 | REDISMODULE_SUBEVENT_MODULE_UNLOADED, |
11299 | module); |
11300 | |
11301 | /* Remove from list of modules. */ |
11302 | serverLog(LL_NOTICE,"Module %s unloaded" ,module->name); |
11303 | dictDelete(modules,module->name); |
11304 | module->name = NULL; /* The name was already freed by dictDelete(). */ |
11305 | moduleFreeModuleStructure(module); |
11306 | |
11307 | return C_OK; |
11308 | } |
11309 | |
11310 | void modulePipeReadable(aeEventLoop *el, int fd, void *privdata, int mask) { |
11311 | UNUSED(el); |
11312 | UNUSED(fd); |
11313 | UNUSED(mask); |
11314 | UNUSED(privdata); |
11315 | |
11316 | char buf[128]; |
11317 | while (read(fd, buf, sizeof(buf)) == sizeof(buf)); |
11318 | |
11319 | /* Handle event loop events if pipe was written from event loop API */ |
11320 | eventLoopHandleOneShotEvents(); |
11321 | } |
11322 | |
11323 | /* Helper function for the MODULE and HELLO command: send the list of the |
11324 | * loaded modules to the client. */ |
11325 | void addReplyLoadedModules(client *c) { |
11326 | dictIterator *di = dictGetIterator(modules); |
11327 | dictEntry *de; |
11328 | |
11329 | addReplyArrayLen(c,dictSize(modules)); |
11330 | while ((de = dictNext(di)) != NULL) { |
11331 | sds name = dictGetKey(de); |
11332 | struct RedisModule *module = dictGetVal(de); |
11333 | sds path = module->loadmod->path; |
11334 | addReplyMapLen(c,4); |
11335 | addReplyBulkCString(c,"name" ); |
11336 | addReplyBulkCBuffer(c,name,sdslen(name)); |
11337 | addReplyBulkCString(c,"ver" ); |
11338 | addReplyLongLong(c,module->ver); |
11339 | addReplyBulkCString(c,"path" ); |
11340 | addReplyBulkCBuffer(c,path,sdslen(path)); |
11341 | addReplyBulkCString(c,"args" ); |
11342 | addReplyArrayLen(c,module->loadmod->argc); |
11343 | for (int i = 0; i < module->loadmod->argc; i++) { |
11344 | addReplyBulk(c,module->loadmod->argv[i]); |
11345 | } |
11346 | } |
11347 | dictReleaseIterator(di); |
11348 | } |
11349 | |
11350 | /* Helper for genModulesInfoString(): given a list of modules, return |
11351 | * an SDS string in the form "[modulename|modulename2|...]" */ |
11352 | sds genModulesInfoStringRenderModulesList(list *l) { |
11353 | listIter li; |
11354 | listNode *ln; |
11355 | listRewind(l,&li); |
11356 | sds output = sdsnew("[" ); |
11357 | while((ln = listNext(&li))) { |
11358 | RedisModule *module = ln->value; |
11359 | output = sdscat(output,module->name); |
11360 | if (ln != listLast(l)) |
11361 | output = sdscat(output,"|" ); |
11362 | } |
11363 | output = sdscat(output,"]" ); |
11364 | return output; |
11365 | } |
11366 | |
11367 | /* Helper for genModulesInfoString(): render module options as an SDS string. */ |
11368 | sds genModulesInfoStringRenderModuleOptions(struct RedisModule *module) { |
11369 | sds output = sdsnew("[" ); |
11370 | if (module->options & REDISMODULE_OPTIONS_HANDLE_IO_ERRORS) |
11371 | output = sdscat(output,"handle-io-errors|" ); |
11372 | if (module->options & REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD) |
11373 | output = sdscat(output,"handle-repl-async-load|" ); |
11374 | if (module->options & REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED) |
11375 | output = sdscat(output,"no-implicit-signal-modified|" ); |
11376 | output = sdstrim(output,"|" ); |
11377 | output = sdscat(output,"]" ); |
11378 | return output; |
11379 | } |
11380 | |
11381 | |
11382 | /* Helper function for the INFO command: adds loaded modules as to info's |
11383 | * output. |
11384 | * |
11385 | * After the call, the passed sds info string is no longer valid and all the |
11386 | * references must be substituted with the new pointer returned by the call. */ |
11387 | sds genModulesInfoString(sds info) { |
11388 | dictIterator *di = dictGetIterator(modules); |
11389 | dictEntry *de; |
11390 | |
11391 | while ((de = dictNext(di)) != NULL) { |
11392 | sds name = dictGetKey(de); |
11393 | struct RedisModule *module = dictGetVal(de); |
11394 | |
11395 | sds usedby = genModulesInfoStringRenderModulesList(module->usedby); |
11396 | sds using = genModulesInfoStringRenderModulesList(module->using); |
11397 | sds options = genModulesInfoStringRenderModuleOptions(module); |
11398 | info = sdscatfmt(info, |
11399 | "module:name=%S,ver=%i,api=%i,filters=%i," |
11400 | "usedby=%S,using=%S,options=%S\r\n" , |
11401 | name, module->ver, module->apiver, |
11402 | (int)listLength(module->filters), usedby, using, options); |
11403 | sdsfree(usedby); |
11404 | sdsfree(using); |
11405 | sdsfree(options); |
11406 | } |
11407 | dictReleaseIterator(di); |
11408 | return info; |
11409 | } |
11410 | |
11411 | /* -------------------------------------------------------------------------- |
11412 | * Module Configurations API internals |
11413 | * -------------------------------------------------------------------------- */ |
11414 | |
11415 | /* Check if the configuration name is already registered */ |
11416 | int isModuleConfigNameRegistered(RedisModule *module, sds name) { |
11417 | listNode *match = listSearchKey(module->module_configs, (void *) name); |
11418 | return match != NULL; |
11419 | } |
11420 | |
11421 | /* Assert that the flags passed into the RM_RegisterConfig Suite are valid */ |
11422 | int moduleVerifyConfigFlags(unsigned int flags, configType type) { |
11423 | if ((flags & ~(REDISMODULE_CONFIG_DEFAULT |
11424 | | REDISMODULE_CONFIG_IMMUTABLE |
11425 | | REDISMODULE_CONFIG_SENSITIVE |
11426 | | REDISMODULE_CONFIG_HIDDEN |
11427 | | REDISMODULE_CONFIG_PROTECTED |
11428 | | REDISMODULE_CONFIG_DENY_LOADING |
11429 | | REDISMODULE_CONFIG_BITFLAGS |
11430 | | REDISMODULE_CONFIG_MEMORY))) { |
11431 | serverLogRaw(LL_WARNING, "Invalid flag(s) for configuration" ); |
11432 | return REDISMODULE_ERR; |
11433 | } |
11434 | if (type != NUMERIC_CONFIG && flags & REDISMODULE_CONFIG_MEMORY) { |
11435 | serverLogRaw(LL_WARNING, "Numeric flag provided for non-numeric configuration." ); |
11436 | return REDISMODULE_ERR; |
11437 | } |
11438 | if (type != ENUM_CONFIG && flags & REDISMODULE_CONFIG_BITFLAGS) { |
11439 | serverLogRaw(LL_WARNING, "Enum flag provided for non-enum configuration." ); |
11440 | return REDISMODULE_ERR; |
11441 | } |
11442 | return REDISMODULE_OK; |
11443 | } |
11444 | |
11445 | int moduleVerifyConfigName(sds name) { |
11446 | if (sdslen(name) == 0) { |
11447 | serverLogRaw(LL_WARNING, "Module config names cannot be an empty string." ); |
11448 | return REDISMODULE_ERR; |
11449 | } |
11450 | for (size_t i = 0 ; i < sdslen(name) ; ++i) { |
11451 | char curr_char = name[i]; |
11452 | if ((curr_char >= 'a' && curr_char <= 'z') || |
11453 | (curr_char >= 'A' && curr_char <= 'Z') || |
11454 | (curr_char >= '0' && curr_char <= '9') || |
11455 | (curr_char == '_') || (curr_char == '-')) |
11456 | { |
11457 | continue; |
11458 | } |
11459 | serverLog(LL_WARNING, "Invalid character %c in Module Config name %s." , curr_char, name); |
11460 | return REDISMODULE_ERR; |
11461 | } |
11462 | return REDISMODULE_OK; |
11463 | } |
11464 | |
11465 | /* This is a series of set functions for each type that act as dispatchers for |
11466 | * config.c to call module set callbacks. */ |
11467 | #define CONFIG_ERR_SIZE 256 |
11468 | static char configerr[CONFIG_ERR_SIZE]; |
11469 | static void propagateErrorString(RedisModuleString *err_in, const char **err) { |
11470 | if (err_in) { |
11471 | strncpy(configerr, err_in->ptr, CONFIG_ERR_SIZE); |
11472 | configerr[CONFIG_ERR_SIZE - 1] = '\0'; |
11473 | decrRefCount(err_in); |
11474 | *err = configerr; |
11475 | } |
11476 | } |
11477 | |
11478 | int setModuleBoolConfig(ModuleConfig *config, int val, const char **err) { |
11479 | RedisModuleString *error = NULL; |
11480 | int return_code = config->set_fn.set_bool(config->name, val, config->privdata, &error); |
11481 | propagateErrorString(error, err); |
11482 | return return_code == REDISMODULE_OK ? 1 : 0; |
11483 | } |
11484 | |
11485 | int setModuleStringConfig(ModuleConfig *config, sds strval, const char **err) { |
11486 | RedisModuleString *error = NULL; |
11487 | RedisModuleString *new = createStringObject(strval, sdslen(strval)); |
11488 | int return_code = config->set_fn.set_string(config->name, new, config->privdata, &error); |
11489 | propagateErrorString(error, err); |
11490 | decrRefCount(new); |
11491 | return return_code == REDISMODULE_OK ? 1 : 0; |
11492 | } |
11493 | |
11494 | int setModuleEnumConfig(ModuleConfig *config, int val, const char **err) { |
11495 | RedisModuleString *error = NULL; |
11496 | int return_code = config->set_fn.set_enum(config->name, val, config->privdata, &error); |
11497 | propagateErrorString(error, err); |
11498 | return return_code == REDISMODULE_OK ? 1 : 0; |
11499 | } |
11500 | |
11501 | int setModuleNumericConfig(ModuleConfig *config, long long val, const char **err) { |
11502 | RedisModuleString *error = NULL; |
11503 | int return_code = config->set_fn.set_numeric(config->name, val, config->privdata, &error); |
11504 | propagateErrorString(error, err); |
11505 | return return_code == REDISMODULE_OK ? 1 : 0; |
11506 | } |
11507 | |
11508 | /* This is a series of get functions for each type that act as dispatchers for |
11509 | * config.c to call module set callbacks. */ |
11510 | int getModuleBoolConfig(ModuleConfig *module_config) { |
11511 | return module_config->get_fn.get_bool(module_config->name, module_config->privdata); |
11512 | } |
11513 | |
11514 | sds getModuleStringConfig(ModuleConfig *module_config) { |
11515 | RedisModuleString *val = module_config->get_fn.get_string(module_config->name, module_config->privdata); |
11516 | return val ? sdsdup(val->ptr) : NULL; |
11517 | } |
11518 | |
11519 | int getModuleEnumConfig(ModuleConfig *module_config) { |
11520 | return module_config->get_fn.get_enum(module_config->name, module_config->privdata); |
11521 | } |
11522 | |
11523 | long long getModuleNumericConfig(ModuleConfig *module_config) { |
11524 | return module_config->get_fn.get_numeric(module_config->name, module_config->privdata); |
11525 | } |
11526 | |
11527 | /* This function takes a module and a list of configs stored as sds NAME VALUE pairs. |
11528 | * It attempts to call set on each of these configs. */ |
11529 | int loadModuleConfigs(RedisModule *module) { |
11530 | listIter li; |
11531 | listNode *ln; |
11532 | const char *err = NULL; |
11533 | listRewind(module->module_configs, &li); |
11534 | while ((ln = listNext(&li))) { |
11535 | ModuleConfig *module_config = listNodeValue(ln); |
11536 | sds config_name = sdscatfmt(sdsempty(), "%s.%s" , module->name, module_config->name); |
11537 | dictEntry *config_argument = dictFind(server.module_configs_queue, config_name); |
11538 | if (config_argument) { |
11539 | if (!performModuleConfigSetFromName(dictGetKey(config_argument), dictGetVal(config_argument), &err)) { |
11540 | serverLog(LL_WARNING, "Issue during loading of configuration %s : %s" , (sds) dictGetKey(config_argument), err); |
11541 | sdsfree(config_name); |
11542 | dictEmpty(server.module_configs_queue, NULL); |
11543 | return REDISMODULE_ERR; |
11544 | } |
11545 | } else { |
11546 | if (!performModuleConfigSetDefaultFromName(config_name, &err)) { |
11547 | serverLog(LL_WARNING, "Issue attempting to set default value of configuration %s : %s" , module_config->name, err); |
11548 | sdsfree(config_name); |
11549 | dictEmpty(server.module_configs_queue, NULL); |
11550 | return REDISMODULE_ERR; |
11551 | } |
11552 | } |
11553 | dictDelete(server.module_configs_queue, config_name); |
11554 | sdsfree(config_name); |
11555 | } |
11556 | module->configs_initialized = 1; |
11557 | return REDISMODULE_OK; |
11558 | } |
11559 | |
11560 | /* Add module_config to the list if the apply and privdata do not match one already in it. */ |
11561 | void addModuleConfigApply(list *module_configs, ModuleConfig *module_config) { |
11562 | if (!module_config->apply_fn) return; |
11563 | listIter li; |
11564 | listNode *ln; |
11565 | ModuleConfig *pending_apply; |
11566 | listRewind(module_configs, &li); |
11567 | while ((ln = listNext(&li))) { |
11568 | pending_apply = listNodeValue(ln); |
11569 | if (pending_apply->apply_fn == module_config->apply_fn && pending_apply->privdata == module_config->privdata) { |
11570 | return; |
11571 | } |
11572 | } |
11573 | listAddNodeTail(module_configs, module_config); |
11574 | } |
11575 | |
11576 | /* Call apply on all module configs specified in set, if an apply function was specified at registration time. */ |
11577 | int moduleConfigApplyConfig(list *module_configs, const char **err, const char **err_arg_name) { |
11578 | if (!listLength(module_configs)) return 1; |
11579 | listIter li; |
11580 | listNode *ln; |
11581 | ModuleConfig *module_config; |
11582 | RedisModuleString *error = NULL; |
11583 | RedisModuleCtx ctx; |
11584 | |
11585 | listRewind(module_configs, &li); |
11586 | while ((ln = listNext(&li))) { |
11587 | module_config = listNodeValue(ln); |
11588 | moduleCreateContext(&ctx, module_config->module, REDISMODULE_CTX_NONE); |
11589 | if (module_config->apply_fn(&ctx, module_config->privdata, &error)) { |
11590 | if (err_arg_name) *err_arg_name = module_config->name; |
11591 | propagateErrorString(error, err); |
11592 | moduleFreeContext(&ctx); |
11593 | return 0; |
11594 | } |
11595 | moduleFreeContext(&ctx); |
11596 | } |
11597 | return 1; |
11598 | } |
11599 | |
11600 | /* -------------------------------------------------------------------------- |
11601 | * ## Module Configurations API |
11602 | * -------------------------------------------------------------------------- */ |
11603 | |
11604 | /* Create a module config object. */ |
11605 | ModuleConfig *createModuleConfig(sds name, RedisModuleConfigApplyFunc apply_fn, void *privdata, RedisModule *module) { |
11606 | ModuleConfig *new_config = zmalloc(sizeof(ModuleConfig)); |
11607 | new_config->name = sdsdup(name); |
11608 | new_config->apply_fn = apply_fn; |
11609 | new_config->privdata = privdata; |
11610 | new_config->module = module; |
11611 | return new_config; |
11612 | } |
11613 | |
11614 | int moduleConfigValidityCheck(RedisModule *module, sds name, unsigned int flags, configType type) { |
11615 | if (moduleVerifyConfigFlags(flags, type) || moduleVerifyConfigName(name)) { |
11616 | errno = EINVAL; |
11617 | return REDISMODULE_ERR; |
11618 | } |
11619 | if (isModuleConfigNameRegistered(module, name)) { |
11620 | serverLog(LL_WARNING, "Configuration by the name: %s already registered" , name); |
11621 | errno = EALREADY; |
11622 | return REDISMODULE_ERR; |
11623 | } |
11624 | return REDISMODULE_OK; |
11625 | } |
11626 | |
11627 | unsigned int maskModuleConfigFlags(unsigned int flags) { |
11628 | unsigned int new_flags = 0; |
11629 | if (flags & REDISMODULE_CONFIG_DEFAULT) new_flags |= MODIFIABLE_CONFIG; |
11630 | if (flags & REDISMODULE_CONFIG_IMMUTABLE) new_flags |= IMMUTABLE_CONFIG; |
11631 | if (flags & REDISMODULE_CONFIG_HIDDEN) new_flags |= HIDDEN_CONFIG; |
11632 | if (flags & REDISMODULE_CONFIG_PROTECTED) new_flags |= PROTECTED_CONFIG; |
11633 | if (flags & REDISMODULE_CONFIG_DENY_LOADING) new_flags |= DENY_LOADING_CONFIG; |
11634 | return new_flags; |
11635 | } |
11636 | |
11637 | unsigned int maskModuleNumericConfigFlags(unsigned int flags) { |
11638 | unsigned int new_flags = 0; |
11639 | if (flags & REDISMODULE_CONFIG_MEMORY) new_flags |= MEMORY_CONFIG; |
11640 | return new_flags; |
11641 | } |
11642 | |
11643 | unsigned int maskModuleEnumConfigFlags(unsigned int flags) { |
11644 | unsigned int new_flags = 0; |
11645 | if (flags & REDISMODULE_CONFIG_BITFLAGS) new_flags |= MULTI_ARG_CONFIG; |
11646 | return new_flags; |
11647 | } |
11648 | |
11649 | /* Create a string config that Redis users can interact with via the Redis config file, |
11650 | * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. |
11651 | * |
11652 | * The actual config value is owned by the module, and the `getfn`, `setfn` and optional |
11653 | * `applyfn` callbacks that are provided to Redis in order to access or manipulate the |
11654 | * value. The `getfn` callback retrieves the value from the module, while the `setfn` |
11655 | * callback provides a value to be stored into the module config. |
11656 | * The optional `applyfn` callback is called after a `CONFIG SET` command modified one or |
11657 | * more configs using the `setfn` callback and can be used to atomically apply a config |
11658 | * after several configs were changed together. |
11659 | * If there are multiple configs with `applyfn` callbacks set by a single `CONFIG SET` |
11660 | * command, they will be deduplicated if their `applyfn` function and `privdata` pointers |
11661 | * are identical, and the callback will only be run once. |
11662 | * Both the `setfn` and `applyfn` can return an error if the provided value is invalid or |
11663 | * cannot be used. |
11664 | * The config also declares a type for the value that is validated by Redis and |
11665 | * provided to the module. The config system provides the following types: |
11666 | * |
11667 | * * Redis String: Binary safe string data. |
11668 | * * Enum: One of a finite number of string tokens, provided during registration. |
11669 | * * Numeric: 64 bit signed integer, which also supports min and max values. |
11670 | * * Bool: Yes or no value. |
11671 | * |
11672 | * The `setfn` callback is expected to return REDISMODULE_OK when the value is successfully |
11673 | * applied. It can also return REDISMODULE_ERR if the value can't be applied, and the |
11674 | * *err pointer can be set with a RedisModuleString error message to provide to the client. |
11675 | * This RedisModuleString will be freed by redis after returning from the set callback. |
11676 | * |
11677 | * All configs are registered with a name, a type, a default value, private data that is made |
11678 | * available in the callbacks, as well as several flags that modify the behavior of the config. |
11679 | * The name must only contain alphanumeric characters or dashes. The supported flags are: |
11680 | * |
11681 | * * REDISMODULE_CONFIG_DEFAULT: The default flags for a config. This creates a config that can be modified after startup. |
11682 | * * REDISMODULE_CONFIG_IMMUTABLE: This config can only be provided loading time. |
11683 | * * REDISMODULE_CONFIG_SENSITIVE: The value stored in this config is redacted from all logging. |
11684 | * * REDISMODULE_CONFIG_HIDDEN: The name is hidden from `CONFIG GET` with pattern matching. |
11685 | * * REDISMODULE_CONFIG_PROTECTED: This config will be only be modifiable based off the value of enable-protected-configs. |
11686 | * * REDISMODULE_CONFIG_DENY_LOADING: This config is not modifiable while the server is loading data. |
11687 | * * REDISMODULE_CONFIG_MEMORY: For numeric configs, this config will convert data unit notations into their byte equivalent. |
11688 | * * REDISMODULE_CONFIG_BITFLAGS: For enum configs, this config will allow multiple entries to be combined as bit flags. |
11689 | * |
11690 | * Default values are used on startup to set the value if it is not provided via the config file |
11691 | * or command line. Default values are also used to compare to on a config rewrite. |
11692 | * |
11693 | * Notes: |
11694 | * |
11695 | * 1. On string config sets that the string passed to the set callback will be freed after execution and the module must retain it. |
11696 | * 2. On string config gets the string will not be consumed and will be valid after execution. |
11697 | * |
11698 | * Example implementation: |
11699 | * |
11700 | * RedisModuleString *strval; |
11701 | * int adjustable = 1; |
11702 | * RedisModuleString *getStringConfigCommand(const char *name, void *privdata) { |
11703 | * return strval; |
11704 | * } |
11705 | * |
11706 | * int setStringConfigCommand(const char *name, RedisModuleString *new, void *privdata, RedisModuleString **err) { |
11707 | * if (adjustable) { |
11708 | * RedisModule_Free(strval); |
11709 | * RedisModule_RetainString(NULL, new); |
11710 | * strval = new; |
11711 | * return REDISMODULE_OK; |
11712 | * } |
11713 | * *err = RedisModule_CreateString(NULL, "Not adjustable.", 15); |
11714 | * return REDISMODULE_ERR; |
11715 | * } |
11716 | * ... |
11717 | * RedisModule_RegisterStringConfig(ctx, "string", NULL, REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL); |
11718 | * |
11719 | * If the registration fails, REDISMODULE_ERR is returned and one of the following |
11720 | * errno is set: |
11721 | * * EINVAL: The provided flags are invalid for the registration or the name of the config contains invalid characters. |
11722 | * * EALREADY: The provided configuration name is already used. */ |
11723 | int RM_RegisterStringConfig(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { |
11724 | RedisModule *module = ctx->module; |
11725 | sds config_name = sdsnew(name); |
11726 | if (moduleConfigValidityCheck(module, config_name, flags, NUMERIC_CONFIG)) { |
11727 | sdsfree(config_name); |
11728 | return REDISMODULE_ERR; |
11729 | } |
11730 | ModuleConfig *new_config = createModuleConfig(config_name, applyfn, privdata, module); |
11731 | sdsfree(config_name); |
11732 | new_config->get_fn.get_string = getfn; |
11733 | new_config->set_fn.set_string = setfn; |
11734 | listAddNodeTail(module->module_configs, new_config); |
11735 | flags = maskModuleConfigFlags(flags); |
11736 | addModuleStringConfig(module->name, name, flags, new_config, default_val ? sdsnew(default_val) : NULL); |
11737 | return REDISMODULE_OK; |
11738 | } |
11739 | |
11740 | /* Create a bool config that server clients can interact with via the |
11741 | * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See |
11742 | * RedisModule_RegisterStringConfig for detailed information about configs. */ |
11743 | int RM_RegisterBoolConfig(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { |
11744 | RedisModule *module = ctx->module; |
11745 | sds config_name = sdsnew(name); |
11746 | if (moduleConfigValidityCheck(module, config_name, flags, BOOL_CONFIG)) { |
11747 | sdsfree(config_name); |
11748 | return REDISMODULE_ERR; |
11749 | } |
11750 | ModuleConfig *new_config = createModuleConfig(config_name, applyfn, privdata, module); |
11751 | sdsfree(config_name); |
11752 | new_config->get_fn.get_bool = getfn; |
11753 | new_config->set_fn.set_bool = setfn; |
11754 | listAddNodeTail(module->module_configs, new_config); |
11755 | flags = maskModuleConfigFlags(flags); |
11756 | addModuleBoolConfig(module->name, name, flags, new_config, default_val); |
11757 | return REDISMODULE_OK; |
11758 | } |
11759 | |
11760 | /* |
11761 | * Create an enum config that server clients can interact with via the |
11762 | * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. |
11763 | * Enum configs are a set of string tokens to corresponding integer values, where |
11764 | * the string value is exposed to Redis clients but the value passed Redis and the |
11765 | * module is the integer value. These values are defined in enum_values, an array |
11766 | * of null-terminated c strings, and int_vals, an array of enum values who has an |
11767 | * index partner in enum_values. |
11768 | * Example Implementation: |
11769 | * const char *enum_vals[3] = {"first", "second", "third"}; |
11770 | * const int int_vals[3] = {0, 2, 4}; |
11771 | * int enum_val = 0; |
11772 | * |
11773 | * int getEnumConfigCommand(const char *name, void *privdata) { |
11774 | * return enum_val; |
11775 | * } |
11776 | * |
11777 | * int setEnumConfigCommand(const char *name, int val, void *privdata, const char **err) { |
11778 | * enum_val = val; |
11779 | * return REDISMODULE_OK; |
11780 | * } |
11781 | * ... |
11782 | * RedisModule_RegisterEnumConfig(ctx, "enum", 0, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 3, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL); |
11783 | * |
11784 | * Note that you can use REDISMODULE_CONFIG_BITFLAGS so that multiple enum string |
11785 | * can be combined into one integer as bit flags, in which case you may want to |
11786 | * sort your enums so that the preferred combinations are present first. |
11787 | * |
11788 | * See RedisModule_RegisterStringConfig for detailed general information about configs. */ |
11789 | int RM_RegisterEnumConfig(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { |
11790 | RedisModule *module = ctx->module; |
11791 | sds config_name = sdsnew(name); |
11792 | if (moduleConfigValidityCheck(module, config_name, flags, ENUM_CONFIG)) { |
11793 | sdsfree(config_name); |
11794 | return REDISMODULE_ERR; |
11795 | } |
11796 | ModuleConfig *new_config = createModuleConfig(config_name, applyfn, privdata, module); |
11797 | sdsfree(config_name); |
11798 | new_config->get_fn.get_enum = getfn; |
11799 | new_config->set_fn.set_enum = setfn; |
11800 | configEnum *enum_vals = zmalloc((num_enum_vals + 1) * sizeof(configEnum)); |
11801 | for (int i = 0; i < num_enum_vals; i++) { |
11802 | enum_vals[i].name = zstrdup(enum_values[i]); |
11803 | enum_vals[i].val = int_values[i]; |
11804 | } |
11805 | enum_vals[num_enum_vals].name = NULL; |
11806 | enum_vals[num_enum_vals].val = 0; |
11807 | listAddNodeTail(module->module_configs, new_config); |
11808 | flags = maskModuleConfigFlags(flags) | maskModuleEnumConfigFlags(flags); |
11809 | addModuleEnumConfig(module->name, name, flags, new_config, default_val, enum_vals); |
11810 | return REDISMODULE_OK; |
11811 | } |
11812 | |
11813 | /* |
11814 | * Create an integer config that server clients can interact with via the |
11815 | * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See |
11816 | * RedisModule_RegisterStringConfig for detailed information about configs. */ |
11817 | int RM_RegisterNumericConfig(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { |
11818 | RedisModule *module = ctx->module; |
11819 | sds config_name = sdsnew(name); |
11820 | if (moduleConfigValidityCheck(module, config_name, flags, NUMERIC_CONFIG)) { |
11821 | sdsfree(config_name); |
11822 | return REDISMODULE_ERR; |
11823 | } |
11824 | ModuleConfig *new_config = createModuleConfig(config_name, applyfn, privdata, module); |
11825 | sdsfree(config_name); |
11826 | new_config->get_fn.get_numeric = getfn; |
11827 | new_config->set_fn.set_numeric = setfn; |
11828 | listAddNodeTail(module->module_configs, new_config); |
11829 | unsigned int numeric_flags = maskModuleNumericConfigFlags(flags); |
11830 | flags = maskModuleConfigFlags(flags); |
11831 | addModuleNumericConfig(module->name, name, flags, new_config, default_val, numeric_flags, min, max); |
11832 | return REDISMODULE_OK; |
11833 | } |
11834 | |
11835 | /* Applies all pending configurations on the module load. This should be called |
11836 | * after all of the configurations have been registered for the module inside of RedisModule_OnLoad. |
11837 | * This API needs to be called when configurations are provided in either `MODULE LOADEX` |
11838 | * or provided as startup arguments. */ |
11839 | int RM_LoadConfigs(RedisModuleCtx *ctx) { |
11840 | if (!ctx || !ctx->module) { |
11841 | return REDISMODULE_ERR; |
11842 | } |
11843 | RedisModule *module = ctx->module; |
11844 | /* Load configs from conf file or arguments from loadex */ |
11845 | if (loadModuleConfigs(module)) return REDISMODULE_ERR; |
11846 | return REDISMODULE_OK; |
11847 | } |
11848 | |
11849 | /* Redis MODULE command. |
11850 | * |
11851 | * MODULE LIST |
11852 | * MODULE LOAD <path> [args...] |
11853 | * MODULE LOADEX <path> [[CONFIG NAME VALUE] [CONFIG NAME VALUE]] [ARGS ...] |
11854 | * MODULE UNLOAD <name> |
11855 | */ |
11856 | void moduleCommand(client *c) { |
11857 | char *subcmd = c->argv[1]->ptr; |
11858 | |
11859 | if (c->argc == 2 && !strcasecmp(subcmd,"help" )) { |
11860 | const char *help[] = { |
11861 | "LIST" , |
11862 | " Return a list of loaded modules." , |
11863 | "LOAD <path> [<arg> ...]" , |
11864 | " Load a module library from <path>, passing to it any optional arguments." , |
11865 | "LOADEX <path> [[CONFIG NAME VALUE] [CONFIG NAME VALUE]] [ARGS ...]" , |
11866 | " Load a module library from <path>, while passing it module configurations and optional arguments." , |
11867 | "UNLOAD <name>" , |
11868 | " Unload a module." , |
11869 | NULL |
11870 | }; |
11871 | addReplyHelp(c, help); |
11872 | } else if (!strcasecmp(subcmd,"load" ) && c->argc >= 3) { |
11873 | robj **argv = NULL; |
11874 | int argc = 0; |
11875 | |
11876 | if (c->argc > 3) { |
11877 | argc = c->argc - 3; |
11878 | argv = &c->argv[3]; |
11879 | } |
11880 | |
11881 | if (moduleLoad(c->argv[2]->ptr,(void **)argv,argc, 0) == C_OK) |
11882 | addReply(c,shared.ok); |
11883 | else |
11884 | addReplyError(c, |
11885 | "Error loading the extension. Please check the server logs." ); |
11886 | } else if (!strcasecmp(subcmd,"loadex" ) && c->argc >= 3) { |
11887 | robj **argv = NULL; |
11888 | int argc = 0; |
11889 | |
11890 | if (c->argc > 3) { |
11891 | argc = c->argc - 3; |
11892 | argv = &c->argv[3]; |
11893 | } |
11894 | /* If this is a loadex command we want to populate server.module_configs_queue with |
11895 | * sds NAME VALUE pairs. We also want to increment argv to just after ARGS, if supplied. */ |
11896 | if (parseLoadexArguments((RedisModuleString ***) &argv, &argc) == REDISMODULE_OK && |
11897 | moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 1) == C_OK) |
11898 | addReply(c,shared.ok); |
11899 | else { |
11900 | dictEmpty(server.module_configs_queue, NULL); |
11901 | addReplyError(c, |
11902 | "Error loading the extension. Please check the server logs." ); |
11903 | } |
11904 | |
11905 | } else if (!strcasecmp(subcmd,"unload" ) && c->argc == 3) { |
11906 | if (moduleUnload(c->argv[2]->ptr) == C_OK) |
11907 | addReply(c,shared.ok); |
11908 | else { |
11909 | char *errmsg; |
11910 | switch(errno) { |
11911 | case ENOENT: |
11912 | errmsg = "no such module with that name" ; |
11913 | break; |
11914 | case EBUSY: |
11915 | errmsg = "the module exports one or more module-side data " |
11916 | "types, can't unload" ; |
11917 | break; |
11918 | case EPERM: |
11919 | errmsg = "the module exports APIs used by other modules. " |
11920 | "Please unload them first and try again" ; |
11921 | break; |
11922 | case EAGAIN: |
11923 | errmsg = "the module has blocked clients. " |
11924 | "Please wait them unblocked and try again" ; |
11925 | break; |
11926 | case EINPROGRESS: |
11927 | errmsg = "the module holds timer that is not fired. " |
11928 | "Please stop the timer or wait until it fires." ; |
11929 | break; |
11930 | default: |
11931 | errmsg = "operation not possible." ; |
11932 | break; |
11933 | } |
11934 | addReplyErrorFormat(c,"Error unloading module: %s" ,errmsg); |
11935 | } |
11936 | } else if (!strcasecmp(subcmd,"list" ) && c->argc == 2) { |
11937 | addReplyLoadedModules(c); |
11938 | } else { |
11939 | addReplySubcommandSyntaxError(c); |
11940 | return; |
11941 | } |
11942 | } |
11943 | |
11944 | /* Return the number of registered modules. */ |
11945 | size_t moduleCount(void) { |
11946 | return dictSize(modules); |
11947 | } |
11948 | |
11949 | /* -------------------------------------------------------------------------- |
11950 | * ## Key eviction API |
11951 | * -------------------------------------------------------------------------- */ |
11952 | |
11953 | /* Set the key last access time for LRU based eviction. not relevant if the |
11954 | * servers's maxmemory policy is LFU based. Value is idle time in milliseconds. |
11955 | * returns REDISMODULE_OK if the LRU was updated, REDISMODULE_ERR otherwise. */ |
11956 | int RM_SetLRU(RedisModuleKey *key, mstime_t lru_idle) { |
11957 | if (!key->value) |
11958 | return REDISMODULE_ERR; |
11959 | if (objectSetLRUOrLFU(key->value, -1, lru_idle, lru_idle>=0 ? LRU_CLOCK() : 0, 1)) |
11960 | return REDISMODULE_OK; |
11961 | return REDISMODULE_ERR; |
11962 | } |
11963 | |
11964 | /* Gets the key last access time. |
11965 | * Value is idletime in milliseconds or -1 if the server's eviction policy is |
11966 | * LFU based. |
11967 | * returns REDISMODULE_OK if when key is valid. */ |
11968 | int RM_GetLRU(RedisModuleKey *key, mstime_t *lru_idle) { |
11969 | *lru_idle = -1; |
11970 | if (!key->value) |
11971 | return REDISMODULE_ERR; |
11972 | if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) |
11973 | return REDISMODULE_OK; |
11974 | *lru_idle = estimateObjectIdleTime(key->value); |
11975 | return REDISMODULE_OK; |
11976 | } |
11977 | |
11978 | /* Set the key access frequency. only relevant if the server's maxmemory policy |
11979 | * is LFU based. |
11980 | * The frequency is a logarithmic counter that provides an indication of |
11981 | * the access frequencyonly (must be <= 255). |
11982 | * returns REDISMODULE_OK if the LFU was updated, REDISMODULE_ERR otherwise. */ |
11983 | int RM_SetLFU(RedisModuleKey *key, long long lfu_freq) { |
11984 | if (!key->value) |
11985 | return REDISMODULE_ERR; |
11986 | if (objectSetLRUOrLFU(key->value, lfu_freq, -1, 0, 1)) |
11987 | return REDISMODULE_OK; |
11988 | return REDISMODULE_ERR; |
11989 | } |
11990 | |
11991 | /* Gets the key access frequency or -1 if the server's eviction policy is not |
11992 | * LFU based. |
11993 | * returns REDISMODULE_OK if when key is valid. */ |
11994 | int RM_GetLFU(RedisModuleKey *key, long long *lfu_freq) { |
11995 | *lfu_freq = -1; |
11996 | if (!key->value) |
11997 | return REDISMODULE_ERR; |
11998 | if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) |
11999 | *lfu_freq = LFUDecrAndReturn(key->value); |
12000 | return REDISMODULE_OK; |
12001 | } |
12002 | |
12003 | /* -------------------------------------------------------------------------- |
12004 | * ## Miscellaneous APIs |
12005 | * -------------------------------------------------------------------------- */ |
12006 | |
12007 | /** |
12008 | * Returns the full ContextFlags mask, using the return value |
12009 | * the module can check if a certain set of flags are supported |
12010 | * by the redis server version in use. |
12011 | * Example: |
12012 | * |
12013 | * int supportedFlags = RM_GetContextFlagsAll(); |
12014 | * if (supportedFlags & REDISMODULE_CTX_FLAGS_MULTI) { |
12015 | * // REDISMODULE_CTX_FLAGS_MULTI is supported |
12016 | * } else{ |
12017 | * // REDISMODULE_CTX_FLAGS_MULTI is not supported |
12018 | * } |
12019 | */ |
12020 | int RM_GetContextFlagsAll() { |
12021 | return _REDISMODULE_CTX_FLAGS_NEXT - 1; |
12022 | } |
12023 | |
12024 | /** |
12025 | * Returns the full KeyspaceNotification mask, using the return value |
12026 | * the module can check if a certain set of flags are supported |
12027 | * by the redis server version in use. |
12028 | * Example: |
12029 | * |
12030 | * int supportedFlags = RM_GetKeyspaceNotificationFlagsAll(); |
12031 | * if (supportedFlags & REDISMODULE_NOTIFY_LOADED) { |
12032 | * // REDISMODULE_NOTIFY_LOADED is supported |
12033 | * } else{ |
12034 | * // REDISMODULE_NOTIFY_LOADED is not supported |
12035 | * } |
12036 | */ |
12037 | int RM_GetKeyspaceNotificationFlagsAll() { |
12038 | return _REDISMODULE_NOTIFY_NEXT - 1; |
12039 | } |
12040 | |
12041 | /** |
12042 | * Return the redis version in format of 0x00MMmmpp. |
12043 | * Example for 6.0.7 the return value will be 0x00060007. |
12044 | */ |
12045 | int RM_GetServerVersion() { |
12046 | return REDIS_VERSION_NUM; |
12047 | } |
12048 | |
12049 | /** |
12050 | * Return the current redis-server runtime value of REDISMODULE_TYPE_METHOD_VERSION. |
12051 | * You can use that when calling RM_CreateDataType to know which fields of |
12052 | * RedisModuleTypeMethods are gonna be supported and which will be ignored. |
12053 | */ |
12054 | int RM_GetTypeMethodVersion() { |
12055 | return REDISMODULE_TYPE_METHOD_VERSION; |
12056 | } |
12057 | |
12058 | /* Replace the value assigned to a module type. |
12059 | * |
12060 | * The key must be open for writing, have an existing value, and have a moduleType |
12061 | * that matches the one specified by the caller. |
12062 | * |
12063 | * Unlike RM_ModuleTypeSetValue() which will free the old value, this function |
12064 | * simply swaps the old value with the new value. |
12065 | * |
12066 | * The function returns REDISMODULE_OK on success, REDISMODULE_ERR on errors |
12067 | * such as: |
12068 | * |
12069 | * 1. Key is not opened for writing. |
12070 | * 2. Key is not a module data type key. |
12071 | * 3. Key is a module datatype other than 'mt'. |
12072 | * |
12073 | * If old_value is non-NULL, the old value is returned by reference. |
12074 | */ |
12075 | int RM_ModuleTypeReplaceValue(RedisModuleKey *key, moduleType *mt, void *new_value, void **old_value) { |
12076 | if (!(key->mode & REDISMODULE_WRITE) || key->iter) |
12077 | return REDISMODULE_ERR; |
12078 | if (!key->value || key->value->type != OBJ_MODULE) |
12079 | return REDISMODULE_ERR; |
12080 | |
12081 | moduleValue *mv = key->value->ptr; |
12082 | if (mv->type != mt) |
12083 | return REDISMODULE_ERR; |
12084 | |
12085 | if (old_value) |
12086 | *old_value = mv->value; |
12087 | mv->value = new_value; |
12088 | |
12089 | return REDISMODULE_OK; |
12090 | } |
12091 | |
12092 | /* For a specified command, parse its arguments and return an array that |
12093 | * contains the indexes of all key name arguments. This function is |
12094 | * essentially a more efficient way to do `COMMAND GETKEYS`. |
12095 | * |
12096 | * The out_flags argument is optional, and can be set to NULL. |
12097 | * When provided it is filled with REDISMODULE_CMD_KEY_ flags in matching |
12098 | * indexes with the key indexes of the returned array. |
12099 | * |
12100 | * A NULL return value indicates the specified command has no keys, or |
12101 | * an error condition. Error conditions are indicated by setting errno |
12102 | * as follows: |
12103 | * |
12104 | * * ENOENT: Specified command does not exist. |
12105 | * * EINVAL: Invalid command arity specified. |
12106 | * |
12107 | * NOTE: The returned array is not a Redis Module object so it does not |
12108 | * get automatically freed even when auto-memory is used. The caller |
12109 | * must explicitly call RM_Free() to free it, same as the out_flags pointer if |
12110 | * used. |
12111 | */ |
12112 | int *RM_GetCommandKeysWithFlags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags) { |
12113 | UNUSED(ctx); |
12114 | struct redisCommand *cmd; |
12115 | int *res = NULL; |
12116 | |
12117 | /* Find command */ |
12118 | if ((cmd = lookupCommand(argv,argc)) == NULL) { |
12119 | errno = ENOENT; |
12120 | return NULL; |
12121 | } |
12122 | |
12123 | /* Bail out if command has no keys */ |
12124 | if (!doesCommandHaveKeys(cmd)) { |
12125 | errno = 0; |
12126 | return NULL; |
12127 | } |
12128 | |
12129 | if ((cmd->arity > 0 && cmd->arity != argc) || (argc < -cmd->arity)) { |
12130 | errno = EINVAL; |
12131 | return NULL; |
12132 | } |
12133 | |
12134 | getKeysResult result = GETKEYS_RESULT_INIT; |
12135 | getKeysFromCommand(cmd, argv, argc, &result); |
12136 | |
12137 | *num_keys = result.numkeys; |
12138 | if (!result.numkeys) { |
12139 | errno = 0; |
12140 | getKeysFreeResult(&result); |
12141 | return NULL; |
12142 | } |
12143 | |
12144 | /* The return value here expects an array of key positions */ |
12145 | unsigned long int size = sizeof(int) * result.numkeys; |
12146 | res = zmalloc(size); |
12147 | if (out_flags) |
12148 | *out_flags = zmalloc(size); |
12149 | for (int i = 0; i < result.numkeys; i++) { |
12150 | res[i] = result.keys[i].pos; |
12151 | if (out_flags) |
12152 | (*out_flags)[i] = moduleConvertKeySpecsFlags(result.keys[i].flags, 0); |
12153 | } |
12154 | |
12155 | return res; |
12156 | } |
12157 | |
12158 | /* Identical to RM_GetCommandKeysWithFlags when flags are not needed. */ |
12159 | int *RM_GetCommandKeys(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) { |
12160 | return RM_GetCommandKeysWithFlags(ctx, argv, argc, num_keys, NULL); |
12161 | } |
12162 | |
12163 | /* Return the name of the command currently running */ |
12164 | const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) { |
12165 | if (!ctx || !ctx->client || !ctx->client->cmd) |
12166 | return NULL; |
12167 | |
12168 | return (const char*)ctx->client->cmd->fullname; |
12169 | } |
12170 | |
12171 | /* -------------------------------------------------------------------------- |
12172 | * ## Defrag API |
12173 | * -------------------------------------------------------------------------- */ |
12174 | |
12175 | /* The defrag context, used to manage state during calls to the data type |
12176 | * defrag callback. |
12177 | */ |
12178 | typedef struct RedisModuleDefragCtx { |
12179 | long defragged; |
12180 | long long int endtime; |
12181 | unsigned long *cursor; |
12182 | struct redisObject *key; /* Optional name of key processed, NULL when unknown. */ |
12183 | int dbid; /* The dbid of the key being processed, -1 when unknown. */ |
12184 | } RedisModuleDefragCtx; |
12185 | |
12186 | /* Register a defrag callback for global data, i.e. anything that the module |
12187 | * may allocate that is not tied to a specific data type. |
12188 | */ |
12189 | int RM_RegisterDefragFunc(RedisModuleCtx *ctx, RedisModuleDefragFunc cb) { |
12190 | ctx->module->defrag_cb = cb; |
12191 | return REDISMODULE_OK; |
12192 | } |
12193 | |
12194 | /* When the data type defrag callback iterates complex structures, this |
12195 | * function should be called periodically. A zero (false) return |
12196 | * indicates the callback may continue its work. A non-zero value (true) |
12197 | * indicates it should stop. |
12198 | * |
12199 | * When stopped, the callback may use RM_DefragCursorSet() to store its |
12200 | * position so it can later use RM_DefragCursorGet() to resume defragging. |
12201 | * |
12202 | * When stopped and more work is left to be done, the callback should |
12203 | * return 1. Otherwise, it should return 0. |
12204 | * |
12205 | * NOTE: Modules should consider the frequency in which this function is called, |
12206 | * so it generally makes sense to do small batches of work in between calls. |
12207 | */ |
12208 | int RM_DefragShouldStop(RedisModuleDefragCtx *ctx) { |
12209 | return (ctx->endtime != 0 && ctx->endtime < ustime()); |
12210 | } |
12211 | |
12212 | /* Store an arbitrary cursor value for future re-use. |
12213 | * |
12214 | * This should only be called if RM_DefragShouldStop() has returned a non-zero |
12215 | * value and the defrag callback is about to exit without fully iterating its |
12216 | * data type. |
12217 | * |
12218 | * This behavior is reserved to cases where late defrag is performed. Late |
12219 | * defrag is selected for keys that implement the `free_effort` callback and |
12220 | * return a `free_effort` value that is larger than the defrag |
12221 | * 'active-defrag-max-scan-fields' configuration directive. |
12222 | * |
12223 | * Smaller keys, keys that do not implement `free_effort` or the global |
12224 | * defrag callback are not called in late-defrag mode. In those cases, a |
12225 | * call to this function will return REDISMODULE_ERR. |
12226 | * |
12227 | * The cursor may be used by the module to represent some progress into the |
12228 | * module's data type. Modules may also store additional cursor-related |
12229 | * information locally and use the cursor as a flag that indicates when |
12230 | * traversal of a new key begins. This is possible because the API makes |
12231 | * a guarantee that concurrent defragmentation of multiple keys will |
12232 | * not be performed. |
12233 | */ |
12234 | int RM_DefragCursorSet(RedisModuleDefragCtx *ctx, unsigned long cursor) { |
12235 | if (!ctx->cursor) |
12236 | return REDISMODULE_ERR; |
12237 | |
12238 | *ctx->cursor = cursor; |
12239 | return REDISMODULE_OK; |
12240 | } |
12241 | |
12242 | /* Fetch a cursor value that has been previously stored using RM_DefragCursorSet(). |
12243 | * |
12244 | * If not called for a late defrag operation, REDISMODULE_ERR will be returned and |
12245 | * the cursor should be ignored. See RM_DefragCursorSet() for more details on |
12246 | * defrag cursors. |
12247 | */ |
12248 | int RM_DefragCursorGet(RedisModuleDefragCtx *ctx, unsigned long *cursor) { |
12249 | if (!ctx->cursor) |
12250 | return REDISMODULE_ERR; |
12251 | |
12252 | *cursor = *ctx->cursor; |
12253 | return REDISMODULE_OK; |
12254 | } |
12255 | |
12256 | /* Defrag a memory allocation previously allocated by RM_Alloc, RM_Calloc, etc. |
12257 | * The defragmentation process involves allocating a new memory block and copying |
12258 | * the contents to it, like realloc(). |
12259 | * |
12260 | * If defragmentation was not necessary, NULL is returned and the operation has |
12261 | * no other effect. |
12262 | * |
12263 | * If a non-NULL value is returned, the caller should use the new pointer instead |
12264 | * of the old one and update any reference to the old pointer, which must not |
12265 | * be used again. |
12266 | */ |
12267 | void *RM_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr) { |
12268 | void *newptr = activeDefragAlloc(ptr); |
12269 | if (newptr) |
12270 | ctx->defragged++; |
12271 | |
12272 | return newptr; |
12273 | } |
12274 | |
12275 | /* Defrag a RedisModuleString previously allocated by RM_Alloc, RM_Calloc, etc. |
12276 | * See RM_DefragAlloc() for more information on how the defragmentation process |
12277 | * works. |
12278 | * |
12279 | * NOTE: It is only possible to defrag strings that have a single reference. |
12280 | * Typically this means strings retained with RM_RetainString or RM_HoldString |
12281 | * may not be defragmentable. One exception is command argvs which, if retained |
12282 | * by the module, will end up with a single reference (because the reference |
12283 | * on the Redis side is dropped as soon as the command callback returns). |
12284 | */ |
12285 | RedisModuleString *RM_DefragRedisModuleString(RedisModuleDefragCtx *ctx, RedisModuleString *str) { |
12286 | return activeDefragStringOb(str, &ctx->defragged); |
12287 | } |
12288 | |
12289 | |
12290 | /* Perform a late defrag of a module datatype key. |
12291 | * |
12292 | * Returns a zero value (and initializes the cursor) if no more needs to be done, |
12293 | * or a non-zero value otherwise. |
12294 | */ |
12295 | int moduleLateDefrag(robj *key, robj *value, unsigned long *cursor, long long endtime, long long *defragged, int dbid) { |
12296 | moduleValue *mv = value->ptr; |
12297 | moduleType *mt = mv->type; |
12298 | |
12299 | RedisModuleDefragCtx defrag_ctx = { 0, endtime, cursor, key, dbid}; |
12300 | |
12301 | /* Invoke callback. Note that the callback may be missing if the key has been |
12302 | * replaced with a different type since our last visit. |
12303 | */ |
12304 | int ret = 0; |
12305 | if (mt->defrag) |
12306 | ret = mt->defrag(&defrag_ctx, key, &mv->value); |
12307 | |
12308 | *defragged += defrag_ctx.defragged; |
12309 | if (!ret) { |
12310 | *cursor = 0; /* No more work to do */ |
12311 | return 0; |
12312 | } |
12313 | |
12314 | return 1; |
12315 | } |
12316 | |
12317 | /* Attempt to defrag a module data type value. Depending on complexity, |
12318 | * the operation may happen immediately or be scheduled for later. |
12319 | * |
12320 | * Returns 1 if the operation has been completed or 0 if it needs to |
12321 | * be scheduled for late defrag. |
12322 | */ |
12323 | int moduleDefragValue(robj *key, robj *value, long *defragged, int dbid) { |
12324 | moduleValue *mv = value->ptr; |
12325 | moduleType *mt = mv->type; |
12326 | |
12327 | /* Try to defrag moduleValue itself regardless of whether or not |
12328 | * defrag callbacks are provided. |
12329 | */ |
12330 | moduleValue *newmv = activeDefragAlloc(mv); |
12331 | if (newmv) { |
12332 | (*defragged)++; |
12333 | value->ptr = mv = newmv; |
12334 | } |
12335 | |
12336 | if (!mt->defrag) |
12337 | return 1; |
12338 | |
12339 | /* Use free_effort to determine complexity of module value, and if |
12340 | * necessary schedule it for defragLater instead of quick immediate |
12341 | * defrag. |
12342 | */ |
12343 | size_t effort = moduleGetFreeEffort(key, value, dbid); |
12344 | if (!effort) |
12345 | effort = SIZE_MAX; |
12346 | if (effort > server.active_defrag_max_scan_fields) { |
12347 | return 0; /* Defrag later */ |
12348 | } |
12349 | |
12350 | RedisModuleDefragCtx defrag_ctx = { 0, 0, NULL, key, dbid}; |
12351 | mt->defrag(&defrag_ctx, key, &mv->value); |
12352 | (*defragged) += defrag_ctx.defragged; |
12353 | return 1; |
12354 | } |
12355 | |
12356 | /* Call registered module API defrag functions */ |
12357 | long moduleDefragGlobals(void) { |
12358 | dictIterator *di = dictGetIterator(modules); |
12359 | dictEntry *de; |
12360 | long defragged = 0; |
12361 | |
12362 | while ((de = dictNext(di)) != NULL) { |
12363 | struct RedisModule *module = dictGetVal(de); |
12364 | if (!module->defrag_cb) |
12365 | continue; |
12366 | RedisModuleDefragCtx defrag_ctx = { 0, 0, NULL, NULL, -1}; |
12367 | module->defrag_cb(&defrag_ctx); |
12368 | defragged += defrag_ctx.defragged; |
12369 | } |
12370 | dictReleaseIterator(di); |
12371 | |
12372 | return defragged; |
12373 | } |
12374 | |
12375 | /* Returns the name of the key currently being processed. |
12376 | * There is no guarantee that the key name is always available, so this may return NULL. |
12377 | */ |
12378 | const RedisModuleString *RM_GetKeyNameFromDefragCtx(RedisModuleDefragCtx *ctx) { |
12379 | return ctx->key; |
12380 | } |
12381 | |
12382 | /* Returns the database id of the key currently being processed. |
12383 | * There is no guarantee that this info is always available, so this may return -1. |
12384 | */ |
12385 | int RM_GetDbIdFromDefragCtx(RedisModuleDefragCtx *ctx) { |
12386 | return ctx->dbid; |
12387 | } |
12388 | |
12389 | /* Register all the APIs we export. Keep this function at the end of the |
12390 | * file so that's easy to seek it to add new entries. */ |
12391 | void moduleRegisterCoreAPI(void) { |
12392 | server.moduleapi = dictCreate(&moduleAPIDictType); |
12393 | server.sharedapi = dictCreate(&moduleAPIDictType); |
12394 | REGISTER_API(Alloc); |
12395 | REGISTER_API(TryAlloc); |
12396 | REGISTER_API(Calloc); |
12397 | REGISTER_API(Realloc); |
12398 | REGISTER_API(Free); |
12399 | REGISTER_API(Strdup); |
12400 | REGISTER_API(CreateCommand); |
12401 | REGISTER_API(GetCommand); |
12402 | REGISTER_API(CreateSubcommand); |
12403 | REGISTER_API(SetCommandInfo); |
12404 | REGISTER_API(SetModuleAttribs); |
12405 | REGISTER_API(IsModuleNameBusy); |
12406 | REGISTER_API(WrongArity); |
12407 | REGISTER_API(ReplyWithLongLong); |
12408 | REGISTER_API(ReplyWithError); |
12409 | REGISTER_API(ReplyWithSimpleString); |
12410 | REGISTER_API(ReplyWithArray); |
12411 | REGISTER_API(ReplyWithMap); |
12412 | REGISTER_API(ReplyWithSet); |
12413 | REGISTER_API(ReplyWithAttribute); |
12414 | REGISTER_API(ReplyWithNullArray); |
12415 | REGISTER_API(ReplyWithEmptyArray); |
12416 | REGISTER_API(ReplySetArrayLength); |
12417 | REGISTER_API(ReplySetMapLength); |
12418 | REGISTER_API(ReplySetSetLength); |
12419 | REGISTER_API(ReplySetAttributeLength); |
12420 | REGISTER_API(ReplyWithString); |
12421 | REGISTER_API(ReplyWithEmptyString); |
12422 | REGISTER_API(ReplyWithVerbatimString); |
12423 | REGISTER_API(ReplyWithVerbatimStringType); |
12424 | REGISTER_API(ReplyWithStringBuffer); |
12425 | REGISTER_API(ReplyWithCString); |
12426 | REGISTER_API(ReplyWithNull); |
12427 | REGISTER_API(ReplyWithBool); |
12428 | REGISTER_API(ReplyWithCallReply); |
12429 | REGISTER_API(ReplyWithDouble); |
12430 | REGISTER_API(ReplyWithBigNumber); |
12431 | REGISTER_API(ReplyWithLongDouble); |
12432 | REGISTER_API(GetSelectedDb); |
12433 | REGISTER_API(SelectDb); |
12434 | REGISTER_API(KeyExists); |
12435 | REGISTER_API(OpenKey); |
12436 | REGISTER_API(CloseKey); |
12437 | REGISTER_API(KeyType); |
12438 | REGISTER_API(ValueLength); |
12439 | REGISTER_API(ListPush); |
12440 | REGISTER_API(ListPop); |
12441 | REGISTER_API(ListGet); |
12442 | REGISTER_API(ListSet); |
12443 | REGISTER_API(ListInsert); |
12444 | REGISTER_API(ListDelete); |
12445 | REGISTER_API(StringToLongLong); |
12446 | REGISTER_API(StringToULongLong); |
12447 | REGISTER_API(StringToDouble); |
12448 | REGISTER_API(StringToLongDouble); |
12449 | REGISTER_API(StringToStreamID); |
12450 | REGISTER_API(Call); |
12451 | REGISTER_API(CallReplyProto); |
12452 | REGISTER_API(FreeCallReply); |
12453 | REGISTER_API(CallReplyInteger); |
12454 | REGISTER_API(CallReplyDouble); |
12455 | REGISTER_API(CallReplyBigNumber); |
12456 | REGISTER_API(CallReplyVerbatim); |
12457 | REGISTER_API(CallReplyBool); |
12458 | REGISTER_API(CallReplySetElement); |
12459 | REGISTER_API(CallReplyMapElement); |
12460 | REGISTER_API(CallReplyAttributeElement); |
12461 | REGISTER_API(CallReplyAttribute); |
12462 | REGISTER_API(CallReplyType); |
12463 | REGISTER_API(CallReplyLength); |
12464 | REGISTER_API(CallReplyArrayElement); |
12465 | REGISTER_API(CallReplyStringPtr); |
12466 | REGISTER_API(CreateStringFromCallReply); |
12467 | REGISTER_API(CreateString); |
12468 | REGISTER_API(CreateStringFromLongLong); |
12469 | REGISTER_API(CreateStringFromULongLong); |
12470 | REGISTER_API(CreateStringFromDouble); |
12471 | REGISTER_API(CreateStringFromLongDouble); |
12472 | REGISTER_API(CreateStringFromString); |
12473 | REGISTER_API(CreateStringFromStreamID); |
12474 | REGISTER_API(CreateStringPrintf); |
12475 | REGISTER_API(FreeString); |
12476 | REGISTER_API(StringPtrLen); |
12477 | REGISTER_API(AutoMemory); |
12478 | REGISTER_API(Replicate); |
12479 | REGISTER_API(ReplicateVerbatim); |
12480 | REGISTER_API(DeleteKey); |
12481 | REGISTER_API(UnlinkKey); |
12482 | REGISTER_API(StringSet); |
12483 | REGISTER_API(StringDMA); |
12484 | REGISTER_API(StringTruncate); |
12485 | REGISTER_API(SetExpire); |
12486 | REGISTER_API(GetExpire); |
12487 | REGISTER_API(ResetDataset); |
12488 | REGISTER_API(DbSize); |
12489 | REGISTER_API(RandomKey); |
12490 | REGISTER_API(ZsetAdd); |
12491 | REGISTER_API(ZsetIncrby); |
12492 | REGISTER_API(ZsetScore); |
12493 | REGISTER_API(ZsetRem); |
12494 | REGISTER_API(ZsetRangeStop); |
12495 | REGISTER_API(ZsetFirstInScoreRange); |
12496 | REGISTER_API(ZsetLastInScoreRange); |
12497 | REGISTER_API(ZsetFirstInLexRange); |
12498 | REGISTER_API(ZsetLastInLexRange); |
12499 | REGISTER_API(ZsetRangeCurrentElement); |
12500 | REGISTER_API(ZsetRangeNext); |
12501 | REGISTER_API(ZsetRangePrev); |
12502 | REGISTER_API(ZsetRangeEndReached); |
12503 | REGISTER_API(HashSet); |
12504 | REGISTER_API(HashGet); |
12505 | REGISTER_API(StreamAdd); |
12506 | REGISTER_API(StreamDelete); |
12507 | REGISTER_API(StreamIteratorStart); |
12508 | REGISTER_API(StreamIteratorStop); |
12509 | REGISTER_API(StreamIteratorNextID); |
12510 | REGISTER_API(StreamIteratorNextField); |
12511 | REGISTER_API(StreamIteratorDelete); |
12512 | REGISTER_API(StreamTrimByLength); |
12513 | REGISTER_API(StreamTrimByID); |
12514 | REGISTER_API(IsKeysPositionRequest); |
12515 | REGISTER_API(KeyAtPos); |
12516 | REGISTER_API(KeyAtPosWithFlags); |
12517 | REGISTER_API(IsChannelsPositionRequest); |
12518 | REGISTER_API(ChannelAtPosWithFlags); |
12519 | REGISTER_API(GetClientId); |
12520 | REGISTER_API(GetClientUserNameById); |
12521 | REGISTER_API(GetContextFlags); |
12522 | REGISTER_API(AvoidReplicaTraffic); |
12523 | REGISTER_API(PoolAlloc); |
12524 | REGISTER_API(CreateDataType); |
12525 | REGISTER_API(ModuleTypeSetValue); |
12526 | REGISTER_API(ModuleTypeReplaceValue); |
12527 | REGISTER_API(ModuleTypeGetType); |
12528 | REGISTER_API(ModuleTypeGetValue); |
12529 | REGISTER_API(IsIOError); |
12530 | REGISTER_API(SetModuleOptions); |
12531 | REGISTER_API(SignalModifiedKey); |
12532 | REGISTER_API(SaveUnsigned); |
12533 | REGISTER_API(LoadUnsigned); |
12534 | REGISTER_API(SaveSigned); |
12535 | REGISTER_API(LoadSigned); |
12536 | REGISTER_API(SaveString); |
12537 | REGISTER_API(SaveStringBuffer); |
12538 | REGISTER_API(LoadString); |
12539 | REGISTER_API(LoadStringBuffer); |
12540 | REGISTER_API(SaveDouble); |
12541 | REGISTER_API(LoadDouble); |
12542 | REGISTER_API(SaveFloat); |
12543 | REGISTER_API(LoadFloat); |
12544 | REGISTER_API(SaveLongDouble); |
12545 | REGISTER_API(LoadLongDouble); |
12546 | REGISTER_API(SaveDataTypeToString); |
12547 | REGISTER_API(LoadDataTypeFromString); |
12548 | REGISTER_API(LoadDataTypeFromStringEncver); |
12549 | REGISTER_API(EmitAOF); |
12550 | REGISTER_API(Log); |
12551 | REGISTER_API(LogIOError); |
12552 | REGISTER_API(_Assert); |
12553 | REGISTER_API(LatencyAddSample); |
12554 | REGISTER_API(StringAppendBuffer); |
12555 | REGISTER_API(TrimStringAllocation); |
12556 | REGISTER_API(RetainString); |
12557 | REGISTER_API(HoldString); |
12558 | REGISTER_API(StringCompare); |
12559 | REGISTER_API(GetContextFromIO); |
12560 | REGISTER_API(GetKeyNameFromIO); |
12561 | REGISTER_API(GetKeyNameFromModuleKey); |
12562 | REGISTER_API(GetDbIdFromModuleKey); |
12563 | REGISTER_API(GetDbIdFromIO); |
12564 | REGISTER_API(GetKeyNameFromOptCtx); |
12565 | REGISTER_API(GetToKeyNameFromOptCtx); |
12566 | REGISTER_API(GetDbIdFromOptCtx); |
12567 | REGISTER_API(GetToDbIdFromOptCtx); |
12568 | REGISTER_API(GetKeyNameFromDefragCtx); |
12569 | REGISTER_API(GetDbIdFromDefragCtx); |
12570 | REGISTER_API(GetKeyNameFromDigest); |
12571 | REGISTER_API(GetDbIdFromDigest); |
12572 | REGISTER_API(BlockClient); |
12573 | REGISTER_API(UnblockClient); |
12574 | REGISTER_API(IsBlockedReplyRequest); |
12575 | REGISTER_API(IsBlockedTimeoutRequest); |
12576 | REGISTER_API(GetBlockedClientPrivateData); |
12577 | REGISTER_API(AbortBlock); |
12578 | REGISTER_API(Milliseconds); |
12579 | REGISTER_API(MonotonicMicroseconds); |
12580 | REGISTER_API(BlockedClientMeasureTimeStart); |
12581 | REGISTER_API(BlockedClientMeasureTimeEnd); |
12582 | REGISTER_API(GetThreadSafeContext); |
12583 | REGISTER_API(GetDetachedThreadSafeContext); |
12584 | REGISTER_API(FreeThreadSafeContext); |
12585 | REGISTER_API(ThreadSafeContextLock); |
12586 | REGISTER_API(ThreadSafeContextTryLock); |
12587 | REGISTER_API(ThreadSafeContextUnlock); |
12588 | REGISTER_API(DigestAddStringBuffer); |
12589 | REGISTER_API(DigestAddLongLong); |
12590 | REGISTER_API(DigestEndSequence); |
12591 | REGISTER_API(NotifyKeyspaceEvent); |
12592 | REGISTER_API(GetNotifyKeyspaceEvents); |
12593 | REGISTER_API(SubscribeToKeyspaceEvents); |
12594 | REGISTER_API(RegisterClusterMessageReceiver); |
12595 | REGISTER_API(SendClusterMessage); |
12596 | REGISTER_API(GetClusterNodeInfo); |
12597 | REGISTER_API(GetClusterNodesList); |
12598 | REGISTER_API(FreeClusterNodesList); |
12599 | REGISTER_API(CreateTimer); |
12600 | REGISTER_API(StopTimer); |
12601 | REGISTER_API(GetTimerInfo); |
12602 | REGISTER_API(GetMyClusterID); |
12603 | REGISTER_API(GetClusterSize); |
12604 | REGISTER_API(GetRandomBytes); |
12605 | REGISTER_API(GetRandomHexChars); |
12606 | REGISTER_API(BlockedClientDisconnected); |
12607 | REGISTER_API(SetDisconnectCallback); |
12608 | REGISTER_API(GetBlockedClientHandle); |
12609 | REGISTER_API(SetClusterFlags); |
12610 | REGISTER_API(CreateDict); |
12611 | REGISTER_API(FreeDict); |
12612 | REGISTER_API(DictSize); |
12613 | REGISTER_API(DictSetC); |
12614 | REGISTER_API(DictReplaceC); |
12615 | REGISTER_API(DictSet); |
12616 | REGISTER_API(DictReplace); |
12617 | REGISTER_API(DictGetC); |
12618 | REGISTER_API(DictGet); |
12619 | REGISTER_API(DictDelC); |
12620 | REGISTER_API(DictDel); |
12621 | REGISTER_API(DictIteratorStartC); |
12622 | REGISTER_API(DictIteratorStart); |
12623 | REGISTER_API(DictIteratorStop); |
12624 | REGISTER_API(DictIteratorReseekC); |
12625 | REGISTER_API(DictIteratorReseek); |
12626 | REGISTER_API(DictNextC); |
12627 | REGISTER_API(DictPrevC); |
12628 | REGISTER_API(DictNext); |
12629 | REGISTER_API(DictPrev); |
12630 | REGISTER_API(DictCompareC); |
12631 | REGISTER_API(DictCompare); |
12632 | REGISTER_API(ExportSharedAPI); |
12633 | REGISTER_API(GetSharedAPI); |
12634 | REGISTER_API(RegisterCommandFilter); |
12635 | REGISTER_API(UnregisterCommandFilter); |
12636 | REGISTER_API(CommandFilterArgsCount); |
12637 | REGISTER_API(CommandFilterArgGet); |
12638 | REGISTER_API(CommandFilterArgInsert); |
12639 | REGISTER_API(CommandFilterArgReplace); |
12640 | REGISTER_API(CommandFilterArgDelete); |
12641 | REGISTER_API(Fork); |
12642 | REGISTER_API(SendChildHeartbeat); |
12643 | REGISTER_API(ExitFromChild); |
12644 | REGISTER_API(KillForkChild); |
12645 | REGISTER_API(RegisterInfoFunc); |
12646 | REGISTER_API(InfoAddSection); |
12647 | REGISTER_API(InfoBeginDictField); |
12648 | REGISTER_API(InfoEndDictField); |
12649 | REGISTER_API(InfoAddFieldString); |
12650 | REGISTER_API(InfoAddFieldCString); |
12651 | REGISTER_API(InfoAddFieldDouble); |
12652 | REGISTER_API(InfoAddFieldLongLong); |
12653 | REGISTER_API(InfoAddFieldULongLong); |
12654 | REGISTER_API(GetServerInfo); |
12655 | REGISTER_API(FreeServerInfo); |
12656 | REGISTER_API(ServerInfoGetField); |
12657 | REGISTER_API(ServerInfoGetFieldC); |
12658 | REGISTER_API(ServerInfoGetFieldSigned); |
12659 | REGISTER_API(ServerInfoGetFieldUnsigned); |
12660 | REGISTER_API(ServerInfoGetFieldDouble); |
12661 | REGISTER_API(GetClientInfoById); |
12662 | REGISTER_API(GetClientNameById); |
12663 | REGISTER_API(SetClientNameById); |
12664 | REGISTER_API(PublishMessage); |
12665 | REGISTER_API(PublishMessageShard); |
12666 | REGISTER_API(SubscribeToServerEvent); |
12667 | REGISTER_API(SetLRU); |
12668 | REGISTER_API(GetLRU); |
12669 | REGISTER_API(SetLFU); |
12670 | REGISTER_API(GetLFU); |
12671 | REGISTER_API(BlockClientOnKeys); |
12672 | REGISTER_API(SignalKeyAsReady); |
12673 | REGISTER_API(GetBlockedClientReadyKey); |
12674 | REGISTER_API(GetUsedMemoryRatio); |
12675 | REGISTER_API(MallocSize); |
12676 | REGISTER_API(MallocUsableSize); |
12677 | REGISTER_API(MallocSizeString); |
12678 | REGISTER_API(MallocSizeDict); |
12679 | REGISTER_API(ScanCursorCreate); |
12680 | REGISTER_API(ScanCursorDestroy); |
12681 | REGISTER_API(ScanCursorRestart); |
12682 | REGISTER_API(Scan); |
12683 | REGISTER_API(ScanKey); |
12684 | REGISTER_API(CreateModuleUser); |
12685 | REGISTER_API(SetModuleUserACL); |
12686 | REGISTER_API(GetCurrentUserName); |
12687 | REGISTER_API(GetModuleUserFromUserName); |
12688 | REGISTER_API(ACLCheckCommandPermissions); |
12689 | REGISTER_API(ACLCheckKeyPermissions); |
12690 | REGISTER_API(ACLCheckChannelPermissions); |
12691 | REGISTER_API(ACLAddLogEntry); |
12692 | REGISTER_API(FreeModuleUser); |
12693 | REGISTER_API(DeauthenticateAndCloseClient); |
12694 | REGISTER_API(AuthenticateClientWithACLUser); |
12695 | REGISTER_API(AuthenticateClientWithUser); |
12696 | REGISTER_API(GetContextFlagsAll); |
12697 | REGISTER_API(GetKeyspaceNotificationFlagsAll); |
12698 | REGISTER_API(IsSubEventSupported); |
12699 | REGISTER_API(GetServerVersion); |
12700 | REGISTER_API(GetClientCertificate); |
12701 | REGISTER_API(RedactClientCommandArgument); |
12702 | REGISTER_API(GetCommandKeys); |
12703 | REGISTER_API(GetCommandKeysWithFlags); |
12704 | REGISTER_API(GetCurrentCommandName); |
12705 | REGISTER_API(GetTypeMethodVersion); |
12706 | REGISTER_API(RegisterDefragFunc); |
12707 | REGISTER_API(DefragAlloc); |
12708 | REGISTER_API(DefragRedisModuleString); |
12709 | REGISTER_API(DefragShouldStop); |
12710 | REGISTER_API(DefragCursorSet); |
12711 | REGISTER_API(DefragCursorGet); |
12712 | REGISTER_API(EventLoopAdd); |
12713 | REGISTER_API(EventLoopDel); |
12714 | REGISTER_API(EventLoopAddOneShot); |
12715 | REGISTER_API(Yield); |
12716 | REGISTER_API(RegisterBoolConfig); |
12717 | REGISTER_API(RegisterNumericConfig); |
12718 | REGISTER_API(RegisterStringConfig); |
12719 | REGISTER_API(RegisterEnumConfig); |
12720 | REGISTER_API(LoadConfigs); |
12721 | } |
12722 | |