├── .editorconfig ├── .gitignore ├── API.md ├── LICENSE ├── README-es.md ├── README-zh_CN.md ├── README.md ├── gen.es6 ├── gen.go └── rm ├── callback.go ├── callbacks.h ├── cmd_flag.go ├── decl.go ├── decl.h ├── hw_wrapper.h ├── mod.go ├── redismodule.h ├── rm.go ├── rm.h ├── run.go ├── types.go ├── varargs.h └── wrapper.h /.editorconfig: -------------------------------------------------------------------------------- 1 | # See: http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 4 11 | 12 | # Tab indentation (no size specified) 13 | [Makefile] 14 | indent_style = tab 15 | 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.go] 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.[568vq] 14 | [568vq].out 15 | 16 | *.cgo1.go 17 | *.cgo2.c 18 | _cgo_defun.c 19 | _cgo_gotypes.go 20 | _cgo_export.* 21 | 22 | _testmain.go 23 | 24 | *.exe 25 | *.test 26 | *.prof 27 | ### OSX template 28 | *.DS_Store 29 | .AppleDouble 30 | .LSOverride 31 | 32 | # Icon must end with two \r 33 | Icon 34 | 35 | # Thumbnails 36 | ._* 37 | 38 | # Files that might appear in the root of a volume 39 | .DocumentRevisions-V100 40 | .fseventsd 41 | .Spotlight-V100 42 | .TemporaryItems 43 | .Trashes 44 | .VolumeIcon.icns 45 | .com.apple.timemachine.donotpresent 46 | 47 | # Directories potentially created on remote AFP share 48 | .AppleDB 49 | .AppleDesktop 50 | Network Trash Folder 51 | Temporary Items 52 | .apdisk 53 | ### JetBrains template 54 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 55 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 56 | 57 | # User-specific stuff: 58 | .idea/workspace.xml 59 | .idea/tasks.xml 60 | .idea/dictionaries 61 | .idea/vcs.xml 62 | .idea/jsLibraryMappings.xml 63 | 64 | # Sensitive or high-churn files: 65 | .idea/dataSources.ids 66 | .idea/dataSources.xml 67 | .idea/dataSources.local.xml 68 | .idea/sqlDataSources.xml 69 | .idea/dynamic.xml 70 | .idea/uiDesigner.xml 71 | 72 | # Gradle: 73 | .idea/gradle.xml 74 | .idea/libraries 75 | 76 | # Mongo Explorer plugin: 77 | .idea/mongoSettings.xml 78 | 79 | ## File-based project format: 80 | *.iws 81 | 82 | ## Plugin-specific files: 83 | 84 | # IntelliJ 85 | /out/ 86 | 87 | # mpeltonen/sbt-idea plugin 88 | .idea_modules/ 89 | 90 | # JIRA plugin 91 | atlassian-ide-plugin.xml 92 | 93 | # Crashlytics plugin (for Android Studio and IntelliJ) 94 | com_crashlytics_export_strings.xml 95 | crashlytics.properties 96 | crashlytics-build.properties 97 | fabric.properties 98 | 99 | 100 | .idea 101 | ignored 102 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # Modules API reference 2 | 3 | ## `RM_Alloc` 4 | 5 | void *RM_Alloc(size_t bytes); 6 | 7 | Use like malloc(). Memory allocated with this function is reported in 8 | Redis INFO memory, used for keys eviction according to maxmemory settings 9 | and in general is taken into account as memory allocated by Redis. 10 | You should avoid to use malloc(). 11 | 12 | ## `RM_Realloc` 13 | 14 | void* RM_Realloc(void *ptr, size_t bytes); 15 | 16 | Use like realloc() for memory obtained with `RedisModule_Alloc()`. 17 | 18 | ## `RM_Free` 19 | 20 | void RM_Free(void *ptr); 21 | 22 | Use like free() for memory obtained by `RedisModule_Alloc()` and 23 | `RedisModule_Realloc()`. However you should never try to free with 24 | `RedisModule_Free()` memory allocated with malloc() inside your module. 25 | 26 | ## `RM_Strdup` 27 | 28 | char *RM_Strdup(const char *str); 29 | 30 | Like strdup() but returns memory allocated with `RedisModule_Alloc()`. 31 | 32 | ## `RM_PoolAlloc` 33 | 34 | void *RM_PoolAlloc(RedisModuleCtx *ctx, size_t bytes); 35 | 36 | Return heap allocated memory that will be freed automatically when the 37 | module callback function returns. Mostly suitable for small allocations 38 | that are short living and must be released when the callback returns 39 | anyway. The returned memory is aligned to the architecture word size 40 | if at least word size bytes are requested, otherwise it is just 41 | aligned to the next power of two, so for example a 3 bytes request is 42 | 4 bytes aligned while a 2 bytes request is 2 bytes aligned. 43 | 44 | There is no realloc style function since when this is needed to use the 45 | pool allocator is not a good idea. 46 | 47 | The function returns NULL if `bytes` is 0. 48 | 49 | ## `RM_GetApi` 50 | 51 | int RM_GetApi(const char *funcname, void **targetPtrPtr); 52 | 53 | Lookup the requested module API and store the function pointer into the 54 | target pointer. The function returns `REDISMODULE_ERR` if there is no such 55 | named API, otherwise `REDISMODULE_OK`. 56 | 57 | This function is not meant to be used by modules developer, it is only 58 | used implicitly by including redismodule.h. 59 | 60 | ## `RM_IsKeysPositionRequest` 61 | 62 | int RM_IsKeysPositionRequest(RedisModuleCtx *ctx); 63 | 64 | Return non-zero if a module command, that was declared with the 65 | flag "getkeys-api", is called in a special way to get the keys positions 66 | and not to get executed. Otherwise zero is returned. 67 | 68 | ## `RM_KeyAtPos` 69 | 70 | void RM_KeyAtPos(RedisModuleCtx *ctx, int pos); 71 | 72 | When a module command is called in order to obtain the position of 73 | keys, since it was flagged as "getkeys-api" during the registration, 74 | the command implementation checks for this special call using the 75 | `RedisModule_IsKeysPositionRequest()` API and uses this function in 76 | order to report keys, like in the following example: 77 | 78 | if (`RedisModule_IsKeysPositionRequest(ctx))` { 79 | `RedisModule_KeyAtPos(ctx`,1); 80 | `RedisModule_KeyAtPos(ctx`,2); 81 | } 82 | 83 | Note: in the example below the get keys API would not be needed since 84 | keys are at fixed positions. This interface is only used for commands 85 | with a more complex structure. 86 | 87 | ## `RM_CreateCommand` 88 | 89 | int RM_CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); 90 | 91 | Register a new command in the Redis server, that will be handled by 92 | calling the function pointer 'func' using the RedisModule calling 93 | convention. The function returns `REDISMODULE_ERR` if the specified command 94 | name is already busy or a set of invalid flags were passed, otherwise 95 | `REDISMODULE_OK` is returned and the new command is registered. 96 | 97 | This function must be called during the initialization of the module 98 | inside the `RedisModule_OnLoad()` function. Calling this function outside 99 | of the initialization function is not defined. 100 | 101 | The command function type is the following: 102 | 103 | int MyCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 104 | 105 | And is supposed to always return `REDISMODULE_OK`. 106 | 107 | The set of flags 'strflags' specify the behavior of the command, and should 108 | be passed as a C string compoesd of space separated words, like for 109 | example "write deny-oom". The set of flags are: 110 | 111 | * **"write"**: The command may modify the data set (it may also read 112 | from it). 113 | * **"readonly"**: The command returns data from keys but never writes. 114 | * **"admin"**: The command is an administrative command (may change 115 | replication or perform similar tasks). 116 | * **"deny-oom"**: The command may use additional memory and should be 117 | denied during out of memory conditions. 118 | * **"deny-script"**: Don't allow this command in Lua scripts. 119 | * **"allow-loading"**: Allow this command while the server is loading data. 120 | Only commands not interacting with the data set 121 | should be allowed to run in this mode. If not sure 122 | don't use this flag. 123 | * **"pubsub"**: The command publishes things on Pub/Sub channels. 124 | * **"random"**: The command may have different outputs even starting 125 | from the same input arguments and key values. 126 | * **"allow-stale"**: The command is allowed to run on slaves that don't 127 | serve stale data. Don't use if you don't know what 128 | this means. 129 | * **"no-monitor"**: Don't propoagate the command on monitor. Use this if 130 | the command has sensible data among the arguments. 131 | * **"fast"**: The command time complexity is not greater 132 | than O(log(N)) where N is the size of the collection or 133 | anything else representing the normal scalability 134 | issue with the command. 135 | * **"getkeys-api"**: The command implements the interface to return 136 | the arguments that are keys. Used when start/stop/step 137 | is not enough because of the command syntax. 138 | * **"no-cluster"**: The command should not register in Redis Cluster 139 | since is not designed to work with it because, for 140 | example, is unable to report the position of the 141 | keys, programmatically creates key names, or any 142 | other reason. 143 | 144 | ## `RM_SetModuleAttribs` 145 | 146 | void RM_SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); 147 | 148 | Called by `RM_Init()` to setup the `ctx->module` structure. 149 | 150 | This is an internal function, Redis modules developers don't need 151 | to use it. 152 | 153 | ## `RM_AutoMemory` 154 | 155 | void RM_AutoMemory(RedisModuleCtx *ctx); 156 | 157 | Enable automatic memory management. See API.md for more information. 158 | 159 | The function must be called as the first function of a command implementation 160 | that wants to use automatic memory. 161 | 162 | ## `RM_CreateString` 163 | 164 | RedisModuleString *RM_CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len); 165 | 166 | Create a new module string object. The returned string must be freed 167 | with `RedisModule_FreeString()`, unless automatic memory is enabled. 168 | 169 | The string is created by copying the `len` bytes starting 170 | at `ptr`. No reference is retained to the passed buffer. 171 | 172 | ## `RM_CreateStringFromLongLong` 173 | 174 | RedisModuleString *RM_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll); 175 | 176 | Like `RedisModule_CreatString()`, but creates a string starting from a long long 177 | integer instead of taking a buffer and its length. 178 | 179 | The returned string must be released with `RedisModule_FreeString()` or by 180 | enabling automatic memory management. 181 | 182 | ## `RM_CreateStringFromString` 183 | 184 | RedisModuleString *RM_CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str); 185 | 186 | Like `RedisModule_CreatString()`, but creates a string starting from an existing 187 | RedisModuleString. 188 | 189 | The returned string must be released with `RedisModule_FreeString()` or by 190 | enabling automatic memory management. 191 | 192 | ## `RM_FreeString` 193 | 194 | void RM_FreeString(RedisModuleCtx *ctx, RedisModuleString *str); 195 | 196 | Free a module string object obtained with one of the Redis modules API calls 197 | that return new string objects. 198 | 199 | It is possible to call this function even when automatic memory management 200 | is enabled. In that case the string will be released ASAP and removed 201 | from the pool of string to release at the end. 202 | 203 | ## `RM_StringPtrLen` 204 | 205 | const char *RM_StringPtrLen(RedisModuleString *str, size_t *len); 206 | 207 | Given a string module object, this function returns the string pointer 208 | and length of the string. The returned pointer and length should only 209 | be used for read only accesses and never modified. 210 | 211 | ## `RM_StringToLongLong` 212 | 213 | int RM_StringToLongLong(RedisModuleString *str, long long *ll); 214 | 215 | Convert the string into a long long integer, storing it at `*ll`. 216 | Returns `REDISMODULE_OK` on success. If the string can't be parsed 217 | as a valid, strict long long (no spaces before/after), `REDISMODULE_ERR` 218 | is returned. 219 | 220 | ## `RM_StringToDouble` 221 | 222 | int RM_StringToDouble(RedisModuleString *str, double *d); 223 | 224 | Convert the string into a double, storing it at `*d`. 225 | Returns `REDISMODULE_OK` on success or `REDISMODULE_ERR` if the string is 226 | not a valid string representation of a double value. 227 | 228 | ## `RM_WrongArity` 229 | 230 | int RM_WrongArity(RedisModuleCtx *ctx); 231 | 232 | Send an error about the number of arguments given to the command, 233 | citing the command name in the error message. 234 | 235 | Example: 236 | 237 | if (argc != 3) return `RedisModule_WrongArity(ctx)`; 238 | 239 | ## `RM_ReplyWithLongLong` 240 | 241 | int RM_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); 242 | 243 | Send an integer reply to the client, with the specified long long value. 244 | The function always returns `REDISMODULE_OK`. 245 | 246 | ## `RM_ReplyWithError` 247 | 248 | int RM_ReplyWithError(RedisModuleCtx *ctx, const char *err); 249 | 250 | Reply with the error 'err'. 251 | 252 | Note that 'err' must contain all the error, including 253 | the initial error code. The function only provides the initial "-", so 254 | the usage is, for example: 255 | 256 | `RM_ReplyWithError(ctx`,"ERR Wrong Type"); 257 | 258 | and not just: 259 | 260 | `RM_ReplyWithError(ctx`,"Wrong Type"); 261 | 262 | The function always returns `REDISMODULE_OK`. 263 | 264 | ## `RM_ReplyWithSimpleString` 265 | 266 | int RM_ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); 267 | 268 | Reply with a simple string (+... \r\n in RESP protocol). This replies 269 | are suitable only when sending a small non-binary string with small 270 | overhead, like "OK" or similar replies. 271 | 272 | The function always returns `REDISMODULE_OK`. 273 | 274 | ## `RM_ReplyWithArray` 275 | 276 | int RM_ReplyWithArray(RedisModuleCtx *ctx, long len); 277 | 278 | Reply with an array type of 'len' elements. However 'len' other calls 279 | to `ReplyWith*` style functions must follow in order to emit the elements 280 | of the array. 281 | 282 | When producing arrays with a number of element that is not known beforehand 283 | the function can be called with the special count 284 | `REDISMODULE_POSTPONED_ARRAY_LEN`, and the actual number of elements can be 285 | later set with `RedisModule_ReplySetArrayLength()` (which will set the 286 | latest "open" count if there are multiple ones). 287 | 288 | The function always returns `REDISMODULE_OK`. 289 | 290 | ## `RM_ReplySetArrayLength` 291 | 292 | void RM_ReplySetArrayLength(RedisModuleCtx *ctx, long len); 293 | 294 | When `RedisModule_ReplyWithArray()` is used with the argument 295 | `REDISMODULE_POSTPONED_ARRAY_LEN`, because we don't know beforehand the number 296 | of items we are going to output as elements of the array, this function 297 | will take care to set the array length. 298 | 299 | Since it is possible to have multiple array replies pending with unknown 300 | length, this function guarantees to always set the latest array length 301 | that was created in a postponed way. 302 | 303 | For example in order to output an array like [1,[10,20,30]] we 304 | could write: 305 | 306 | `RedisModule_ReplyWithArray(ctx`,`REDISMODULE_POSTPONED_ARRAY_LEN`); 307 | `RedisModule_ReplyWithLongLong(ctx`,1); 308 | `RedisModule_ReplyWithArray(ctx`,`REDISMODULE_POSTPONED_ARRAY_LEN`); 309 | `RedisModule_ReplyWithLongLong(ctx`,10); 310 | `RedisModule_ReplyWithLongLong(ctx`,20); 311 | `RedisModule_ReplyWithLongLong(ctx`,30); 312 | `RedisModule_ReplySetArrayLength(ctx`,3); // Set len of 10,20,30 array. 313 | `RedisModule_ReplySetArrayLength(ctx`,2); // Set len of top array 314 | 315 | Note that in the above example there is no reason to postpone the array 316 | length, since we produce a fixed number of elements, but in the practice 317 | the code may use an interator or other ways of creating the output so 318 | that is not easy to calculate in advance the number of elements. 319 | 320 | ## `RM_ReplyWithStringBuffer` 321 | 322 | int RM_ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len); 323 | 324 | Reply with a bulk string, taking in input a C buffer pointer and length. 325 | 326 | The function always returns `REDISMODULE_OK`. 327 | 328 | ## `RM_ReplyWithString` 329 | 330 | int RM_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str); 331 | 332 | Reply with a bulk string, taking in input a RedisModuleString object. 333 | 334 | The function always returns `REDISMODULE_OK`. 335 | 336 | ## `RM_ReplyWithNull` 337 | 338 | int RM_ReplyWithNull(RedisModuleCtx *ctx); 339 | 340 | Reply to the client with a NULL. In the RESP protocol a NULL is encoded 341 | as the string "$-1\r\n". 342 | 343 | The function always returns `REDISMODULE_OK`. 344 | 345 | ## `RM_ReplyWithCallReply` 346 | 347 | int RM_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); 348 | 349 | Reply exactly what a Redis command returned us with `RedisModule_Call()`. 350 | This function is useful when we use `RedisModule_Call()` in order to 351 | execute some command, as we want to reply to the client exactly the 352 | same reply we obtained by the command. 353 | 354 | The function always returns `REDISMODULE_OK`. 355 | 356 | ## `RM_ReplyWithDouble` 357 | 358 | int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d); 359 | 360 | Send a string reply obtained converting the double 'd' into a bulk string. 361 | This function is basically equivalent to converting a double into 362 | a string into a C buffer, and then calling the function 363 | `RedisModule_ReplyWithStringBuffer()` with the buffer and length. 364 | 365 | The function always returns `REDISMODULE_OK`. 366 | 367 | ## `RM_Replicate` 368 | 369 | int RM_Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); 370 | 371 | Replicate the specified command and arguments to slaves and AOF, as effect 372 | of execution of the calling command implementation. 373 | 374 | The replicated commands are always wrapped into the MULTI/EXEC that 375 | contains all the commands replicated in a given module command 376 | execution. However the commands replicated with `RedisModule_Call()` 377 | are the first items, the ones replicated with `RedisModule_Replicate()` 378 | will all follow before the EXEC. 379 | 380 | Modules should try to use one interface or the other. 381 | 382 | This command follows exactly the same interface of `RedisModule_Call()`, 383 | so a set of format specifiers must be passed, followed by arguments 384 | matching the provided format specifiers. 385 | 386 | Please refer to `RedisModule_Call()` for more information. 387 | 388 | The command returns `REDISMODULE_ERR` if the format specifiers are invalid 389 | or the command name does not belong to a known command. 390 | 391 | ## `RM_ReplicateVerbatim` 392 | 393 | int RM_ReplicateVerbatim(RedisModuleCtx *ctx); 394 | 395 | This function will replicate the command exactly as it was invoked 396 | by the client. Note that this function will not wrap the command into 397 | a MULTI/EXEC stanza, so it should not be mixed with other replication 398 | commands. 399 | 400 | Basically this form of replication is useful when you want to propagate 401 | the command to the slaves and AOF file exactly as it was called, since 402 | the command can just be re-executed to deterministically re-create the 403 | new state starting from the old one. 404 | 405 | The function always returns `REDISMODULE_OK`. 406 | 407 | ## `RM_GetClientId` 408 | 409 | unsigned long long RM_GetClientId(RedisModuleCtx *ctx); 410 | 411 | Return the ID of the current client calling the currently active module 412 | command. The returned ID has a few guarantees: 413 | 414 | 1. The ID is different for each different client, so if the same client 415 | executes a module command multiple times, it can be recognized as 416 | having the same ID, otherwise the ID will be different. 417 | 2. The ID increases monotonically. Clients connecting to the server later 418 | are guaranteed to get IDs greater than any past ID previously seen. 419 | 420 | Valid IDs are from 1 to 2^64-1. If 0 is returned it means there is no way 421 | to fetch the ID in the context the function was currently called. 422 | 423 | ## `RM_GetSelectedDb` 424 | 425 | int RM_GetSelectedDb(RedisModuleCtx *ctx); 426 | 427 | Return the currently selected DB. 428 | 429 | ## `RM_SelectDb` 430 | 431 | int RM_SelectDb(RedisModuleCtx *ctx, int newid); 432 | 433 | Change the currently selected DB. Returns an error if the id 434 | is out of range. 435 | 436 | Note that the client will retain the currently selected DB even after 437 | the Redis command implemented by the module calling this function 438 | returns. 439 | 440 | If the module command wishes to change something in a different DB and 441 | returns back to the original one, it should call `RedisModule_GetSelectedDb()` 442 | before in order to restore the old DB number before returning. 443 | 444 | ## `RM_OpenKey` 445 | 446 | void *RM_OpenKey(RedisModuleCtx *ctx, robj *keyname, int mode); 447 | 448 | Return an handle representing a Redis key, so that it is possible 449 | to call other APIs with the key handle as argument to perform 450 | operations on the key. 451 | 452 | The return value is the handle repesenting the key, that must be 453 | closed with `RM_CloseKey()`. 454 | 455 | If the key does not exist and WRITE mode is requested, the handle 456 | is still returned, since it is possible to perform operations on 457 | a yet not existing key (that will be created, for example, after 458 | a list push operation). If the mode is just READ instead, and the 459 | key does not exist, NULL is returned. However it is still safe to 460 | call `RedisModule_CloseKey()` and `RedisModule_KeyType()` on a NULL 461 | value. 462 | 463 | ## `RM_CloseKey` 464 | 465 | void RM_CloseKey(RedisModuleKey *key); 466 | 467 | Close a key handle. 468 | 469 | ## `RM_KeyType` 470 | 471 | int RM_KeyType(RedisModuleKey *key); 472 | 473 | Return the type of the key. If the key pointer is NULL then 474 | `REDISMODULE_KEYTYPE_EMPTY` is returned. 475 | 476 | ## `RM_ValueLength` 477 | 478 | size_t RM_ValueLength(RedisModuleKey *key); 479 | 480 | Return the length of the value associated with the key. 481 | For strings this is the length of the string. For all the other types 482 | is the number of elements (just counting keys for hashes). 483 | 484 | If the key pointer is NULL or the key is empty, zero is returned. 485 | 486 | ## `RM_DeleteKey` 487 | 488 | int RM_DeleteKey(RedisModuleKey *key); 489 | 490 | If the key is open for writing, remove it, and setup the key to 491 | accept new writes as an empty key (that will be created on demand). 492 | On success `REDISMODULE_OK` is returned. If the key is not open for 493 | writing `REDISMODULE_ERR` is returned. 494 | 495 | ## `RM_GetExpire` 496 | 497 | mstime_t RM_GetExpire(RedisModuleKey *key); 498 | 499 | Return the key expire value, as milliseconds of remaining TTL. 500 | If no TTL is associated with the key or if the key is empty, 501 | `REDISMODULE_NO_EXPIRE` is returned. 502 | 503 | ## `RM_SetExpire` 504 | 505 | int RM_SetExpire(RedisModuleKey *key, mstime_t expire); 506 | 507 | Set a new expire for the key. If the special expire 508 | `REDISMODULE_NO_EXPIRE` is set, the expire is cancelled if there was 509 | one (the same as the PERSIST command). 510 | 511 | Note that the expire must be provided as a positive integer representing 512 | the number of milliseconds of TTL the key should have. 513 | 514 | The function returns `REDISMODULE_OK` on success or `REDISMODULE_ERR` if 515 | the key was not open for writing or is an empty key. 516 | 517 | ## `RM_StringSet` 518 | 519 | int RM_StringSet(RedisModuleKey *key, RedisModuleString *str); 520 | 521 | If the key is open for writing, set the specified string 'str' as the 522 | value of the key, deleting the old value if any. 523 | On success `REDISMODULE_OK` is returned. If the key is not open for 524 | writing or there is an active iterator, `REDISMODULE_ERR` is returned. 525 | 526 | ## `RM_StringDMA` 527 | 528 | char *RM_StringDMA(RedisModuleKey *key, size_t *len, int mode); 529 | 530 | Prepare the key associated string value for DMA access, and returns 531 | a pointer and size (by reference), that the user can use to read or 532 | modify the string in-place accessing it directly via pointer. 533 | 534 | The 'mode' is composed by bitwise OR-ing the following flags: 535 | 536 | `REDISMODULE_READ` -- Read access 537 | `REDISMODULE_WRITE` -- Write access 538 | 539 | If the DMA is not requested for writing, the pointer returned should 540 | only be accessed in a read-only fashion. 541 | 542 | On error (wrong type) NULL is returned. 543 | 544 | DMA access rules: 545 | 546 | 1. No other key writing function should be called since the moment 547 | the pointer is obtained, for all the time we want to use DMA access 548 | to read or modify the string. 549 | 550 | 2. Each time `RM_StringTruncate()` is called, to continue with the DMA 551 | access, `RM_StringDMA()` should be called again to re-obtain 552 | a new pointer and length. 553 | 554 | 3. If the returned pointer is not NULL, but the length is zero, no 555 | byte can be touched (the string is empty, or the key itself is empty) 556 | so a `RM_StringTruncate()` call should be used if there is to enlarge 557 | the string, and later call StringDMA() again to get the pointer. 558 | 559 | ## `RM_StringTruncate` 560 | 561 | int RM_StringTruncate(RedisModuleKey *key, size_t newlen); 562 | 563 | If the string is open for writing and is of string type, resize it, padding 564 | with zero bytes if the new length is greater than the old one. 565 | 566 | After this call, `RM_StringDMA()` must be called again to continue 567 | DMA access with the new pointer. 568 | 569 | The function returns `REDISMODULE_OK` on success, and `REDISMODULE_ERR` on 570 | error, that is, the key is not open for writing, is not a string 571 | or resizing for more than 512 MB is requested. 572 | 573 | If the key is empty, a string key is created with the new string value 574 | unless the new length value requested is zero. 575 | 576 | ## `RM_ListPush` 577 | 578 | int RM_ListPush(RedisModuleKey *key, int where, RedisModuleString *ele); 579 | 580 | Push an element into a list, on head or tail depending on 'where' argumnet. 581 | If the key pointer is about an empty key opened for writing, the key 582 | is created. On error (key opened for read-only operations or of the wrong 583 | type) `REDISMODULE_ERR` is returned, otherwise `REDISMODULE_OK` is returned. 584 | 585 | ## `RM_ListPop` 586 | 587 | RedisModuleString *RM_ListPop(RedisModuleKey *key, int where); 588 | 589 | Pop an element from the list, and returns it as a module string object 590 | that the user should be free with `RM_FreeString()` or by enabling 591 | automatic memory. 'where' specifies if the element should be popped from 592 | head or tail. The command returns NULL if: 593 | 1) The list is empty. 594 | 2) The key was not open for writing. 595 | 3) The key is not a list. 596 | 597 | ## `RM_ZsetAddFlagsToCoreFlags` 598 | 599 | int RM_ZsetAddFlagsToCoreFlags(int flags); 600 | 601 | Conversion from/to public flags of the Modules API and our private flags, 602 | so that we have everything decoupled. 603 | 604 | ## `RM_ZsetAddFlagsFromCoreFlags` 605 | 606 | int RM_ZsetAddFlagsFromCoreFlags(int flags); 607 | 608 | See previous function comment. 609 | 610 | ## `RM_ZsetAdd` 611 | 612 | int RM_ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); 613 | 614 | Add a new element into a sorted set, with the specified 'score'. 615 | If the element already exists, the score is updated. 616 | 617 | A new sorted set is created at value if the key is an empty open key 618 | setup for writing. 619 | 620 | Additional flags can be passed to the function via a pointer, the flags 621 | are both used to receive input and to communicate state when the function 622 | returns. 'flagsptr' can be NULL if no special flags are used. 623 | 624 | The input flags are: 625 | 626 | `REDISMODULE_ZADD_XX`: Element must already exist. Do nothing otherwise. 627 | `REDISMODULE_ZADD_NX`: Element must not exist. Do nothing otherwise. 628 | 629 | The output flags are: 630 | 631 | `REDISMODULE_ZADD_ADDED`: The new element was added to the sorted set. 632 | `REDISMODULE_ZADD_UPDATED`: The score of the element was updated. 633 | `REDISMODULE_ZADD_NOP`: No operation was performed because XX or NX flags. 634 | 635 | On success the function returns `REDISMODULE_OK`. On the following errors 636 | `REDISMODULE_ERR` is returned: 637 | 638 | * The key was not opened for writing. 639 | * The key is of the wrong type. 640 | * 'score' double value is not a number (NaN). 641 | 642 | ## `RM_ZsetIncrby` 643 | 644 | int RM_ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); 645 | 646 | This function works exactly like `RM_ZsetAdd()`, but instead of setting 647 | a new score, the score of the existing element is incremented, or if the 648 | element does not already exist, it is added assuming the old score was 649 | zero. 650 | 651 | The input and output flags, and the return value, have the same exact 652 | meaning, with the only difference that this function will return 653 | `REDISMODULE_ERR` even when 'score' is a valid double number, but adding it 654 | to the existing score resuts into a NaN (not a number) condition. 655 | 656 | This function has an additional field 'newscore', if not NULL is filled 657 | with the new score of the element after the increment, if no error 658 | is returned. 659 | 660 | ## `RM_ZsetRem` 661 | 662 | int RM_ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted); 663 | 664 | Remove the specified element from the sorted set. 665 | The function returns `REDISMODULE_OK` on success, and `REDISMODULE_ERR` 666 | on one of the following conditions: 667 | 668 | * The key was not opened for writing. 669 | * The key is of the wrong type. 670 | 671 | The return value does NOT indicate the fact the element was really 672 | removed (since it existed) or not, just if the function was executed 673 | with success. 674 | 675 | In order to know if the element was removed, the additional argument 676 | 'deleted' must be passed, that populates the integer by reference 677 | setting it to 1 or 0 depending on the outcome of the operation. 678 | The 'deleted' argument can be NULL if the caller is not interested 679 | to know if the element was really removed. 680 | 681 | Empty keys will be handled correctly by doing nothing. 682 | 683 | ## `RM_ZsetScore` 684 | 685 | int RM_ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score); 686 | 687 | On success retrieve the double score associated at the sorted set element 688 | 'ele' and returns `REDISMODULE_OK`. Otherwise `REDISMODULE_ERR` is returned 689 | to signal one of the following conditions: 690 | 691 | * There is no such element 'ele' in the sorted set. 692 | * The key is not a sorted set. 693 | * The key is an open empty key. 694 | 695 | ## `RM_ZsetRangeStop` 696 | 697 | void RM_ZsetRangeStop(RedisModuleKey *key); 698 | 699 | Stop a sorted set iteration. 700 | 701 | ## `RM_ZsetRangeEndReached` 702 | 703 | int RM_ZsetRangeEndReached(RedisModuleKey *key); 704 | 705 | Return the "End of range" flag value to signal the end of the iteration. 706 | 707 | ## `RM_ZsetFirstInScoreRange` 708 | 709 | int RM_ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); 710 | 711 | Setup a sorted set iterator seeking the first element in the specified 712 | range. Returns `REDISMODULE_OK` if the iterator was correctly initialized 713 | otherwise `REDISMODULE_ERR` is returned in the following conditions: 714 | 715 | 1. The value stored at key is not a sorted set or the key is empty. 716 | 717 | The range is specified according to the two double values 'min' and 'max'. 718 | Both can be infinite using the following two macros: 719 | 720 | `REDISMODULE_POSITIVE_INFINITE` for positive infinite value 721 | `REDISMODULE_NEGATIVE_INFINITE` for negative infinite value 722 | 723 | 'minex' and 'maxex' parameters, if true, respectively setup a range 724 | where the min and max value are exclusive (not included) instead of 725 | inclusive. 726 | 727 | ## `RM_ZsetLastInScoreRange` 728 | 729 | int RM_ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); 730 | 731 | Exactly like `RedisModule_ZsetFirstInScoreRange()` but the last element of 732 | the range is selected for the start of the iteration instead. 733 | 734 | ## `RM_ZsetFirstInLexRange` 735 | 736 | int RM_ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); 737 | 738 | Setup a sorted set iterator seeking the first element in the specified 739 | lexicographical range. Returns `REDISMODULE_OK` if the iterator was correctly 740 | initialized otherwise `REDISMODULE_ERR` is returned in the 741 | following conditions: 742 | 743 | 1. The value stored at key is not a sorted set or the key is empty. 744 | 2. The lexicographical range 'min' and 'max' format is invalid. 745 | 746 | 'min' and 'max' should be provided as two RedisModuleString objects 747 | in the same format as the parameters passed to the ZRANGEBYLEX command. 748 | The function does not take ownership of the objects, so they can be released 749 | ASAP after the iterator is setup. 750 | 751 | ## `RM_ZsetLastInLexRange` 752 | 753 | int RM_ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); 754 | 755 | Exactly like `RedisModule_ZsetFirstInLexRange()` but the last element of 756 | the range is selected for the start of the iteration instead. 757 | 758 | ## `RM_ZsetRangeCurrentElement` 759 | 760 | RedisModuleString *RM_ZsetRangeCurrentElement(RedisModuleKey *key, double *score); 761 | 762 | Return the current sorted set element of an active sorted set iterator 763 | or NULL if the range specified in the iterator does not include any 764 | element. 765 | 766 | ## `RM_ZsetRangeNext` 767 | 768 | int RM_ZsetRangeNext(RedisModuleKey *key); 769 | 770 | Go to the next element of the sorted set iterator. Returns 1 if there was 771 | a next element, 0 if we are already at the latest element or the range 772 | does not include any item at all. 773 | 774 | ## `RM_ZsetRangePrev` 775 | 776 | int RM_ZsetRangePrev(RedisModuleKey *key); 777 | 778 | Go to the previous element of the sorted set iterator. Returns 1 if there was 779 | a previous element, 0 if we are already at the first element or the range 780 | does not include any item at all. 781 | 782 | ## `RM_HashSet` 783 | 784 | int RM_HashSet(RedisModuleKey *key, int flags, ...); 785 | 786 | Set the field of the specified hash field to the specified value. 787 | If the key is an empty key open for writing, it is created with an empty 788 | hash value, in order to set the specified field. 789 | 790 | The function is variadic and the user must specify pairs of field 791 | names and values, both as RedisModuleString pointers (unless the 792 | CFIELD option is set, see later). 793 | 794 | Example to set the hash argv[1] to the value argv[2]: 795 | 796 | `RedisModule_HashSet(key`,`REDISMODULE_HASH_NONE`,argv[1],argv[2],NULL); 797 | 798 | The function can also be used in order to delete fields (if they exist) 799 | by setting them to the specified value of `REDISMODULE_HASH_DELETE`: 800 | 801 | `RedisModule_HashSet(key`,`REDISMODULE_HASH_NONE`,argv[1], 802 | `REDISMODULE_HASH_DELETE`,NULL); 803 | 804 | The behavior of the command changes with the specified flags, that can be 805 | set to `REDISMODULE_HASH_NONE` if no special behavior is needed. 806 | 807 | `REDISMODULE_HASH_NX`: The operation is performed only if the field was not 808 | already existing in the hash. 809 | `REDISMODULE_HASH_XX`: The operation is performed only if the field was 810 | already existing, so that a new value could be 811 | associated to an existing filed, but no new fields 812 | are created. 813 | `REDISMODULE_HASH_CFIELDS`: The field names passed are null terminated C 814 | strings instead of RedisModuleString objects. 815 | 816 | Unless NX is specified, the command overwrites the old field value with 817 | the new one. 818 | 819 | When using `REDISMODULE_HASH_CFIELDS`, field names are reported using 820 | normal C strings, so for example to delete the field "foo" the following 821 | code can be used: 822 | 823 | `RedisModule_HashSet(key`,`REDISMODULE_HASH_CFIELDS`,"foo", 824 | `REDISMODULE_HASH_DELETE`,NULL); 825 | 826 | Return value: 827 | 828 | The number of fields updated (that may be less than the number of fields 829 | specified because of the XX or NX options). 830 | 831 | In the following case the return value is always zero: 832 | 833 | * The key was not open for writing. 834 | * The key was associated with a non Hash value. 835 | 836 | ## `RM_HashGet` 837 | 838 | int RM_HashGet(RedisModuleKey *key, int flags, ...); 839 | 840 | Get fields from an hash value. This function is called using a variable 841 | number of arguments, alternating a field name (as a StringRedisModule 842 | pointer) with a pointer to a StringRedisModule pointer, that is set to the 843 | value of the field if the field exist, or NULL if the field did not exist. 844 | At the end of the field/value-ptr pairs, NULL must be specified as last 845 | argument to signal the end of the arguments in the variadic function. 846 | 847 | This is an example usage: 848 | 849 | RedisModuleString *first, *second; 850 | `RedisModule_HashGet(mykey`,`REDISMODULE_HASH_NONE`,argv[1],&first, 851 | argv[2],&second,NULL); 852 | 853 | As with `RedisModule_HashSet()` the behavior of the command can be specified 854 | passing flags different than `REDISMODULE_HASH_NONE`: 855 | 856 | `REDISMODULE_HASH_CFIELD`: field names as null terminated C strings. 857 | 858 | `REDISMODULE_HASH_EXISTS`: instead of setting the value of the field 859 | expecting a RedisModuleString pointer to pointer, the function just 860 | reports if the field esists or not and expects an integer pointer 861 | as the second element of each pair. 862 | 863 | Example of `REDISMODULE_HASH_CFIELD`: 864 | 865 | RedisModuleString *username, *hashedpass; 866 | `RedisModule_HashGet(mykey`,"username",&username,"hp",&hashedpass, NULL); 867 | 868 | Example of `REDISMODULE_HASH_EXISTS`: 869 | 870 | int exists; 871 | `RedisModule_HashGet(mykey`,argv[1],&exists,NULL); 872 | 873 | The function returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` if 874 | the key is not an hash value. 875 | 876 | Memory management: 877 | 878 | The returned RedisModuleString objects should be released with 879 | `RedisModule_FreeString()`, or by enabling automatic memory management. 880 | 881 | ## `RM_FreeCallReply_Rec` 882 | 883 | void RM_FreeCallReply_Rec(RedisModuleCallReply *reply, int freenested); 884 | 885 | Free a Call reply and all the nested replies it contains if it's an 886 | array. 887 | 888 | ## `RM_FreeCallReply` 889 | 890 | void RM_FreeCallReply(RedisModuleCallReply *reply); 891 | 892 | Wrapper for the recursive free reply function. This is needed in order 893 | to have the first level function to return on nested replies, but only 894 | if called by the module API. 895 | 896 | ## `RM_CallReplyType` 897 | 898 | int RM_CallReplyType(RedisModuleCallReply *reply); 899 | 900 | Return the reply type. 901 | 902 | ## `RM_CallReplyLength` 903 | 904 | size_t RM_CallReplyLength(RedisModuleCallReply *reply); 905 | 906 | Return the reply type length, where applicable. 907 | 908 | ## `RM_CallReplyArrayElement` 909 | 910 | RedisModuleCallReply *RM_CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); 911 | 912 | Return the 'idx'-th nested call reply element of an array reply, or NULL 913 | if the reply type is wrong or the index is out of range. 914 | 915 | ## `RM_CallReplyInteger` 916 | 917 | long long RM_CallReplyInteger(RedisModuleCallReply *reply); 918 | 919 | Return the long long of an integer reply. 920 | 921 | ## `RM_CallReplyStringPtr` 922 | 923 | const char *RM_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); 924 | 925 | Return the pointer and length of a string or error reply. 926 | 927 | ## `RM_CreateStringFromCallReply` 928 | 929 | RedisModuleString *RM_CreateStringFromCallReply(RedisModuleCallReply *reply); 930 | 931 | Return a new string object from a call reply of type string, error or 932 | integer. Otherwise (wrong reply type) return NULL. 933 | 934 | ## `RM_Call` 935 | 936 | RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); 937 | 938 | Exported API to call any Redis command from modules. 939 | On success a RedisModuleCallReply object is returned, otherwise 940 | NULL is returned and errno is set to the following values: 941 | 942 | EINVAL: command non existing, wrong arity, wrong format specifier. 943 | EPERM: operation in Cluster instance with key in non local slot. 944 | 945 | ## `RM_CallReplyProto` 946 | 947 | const char *RM_CallReplyProto(RedisModuleCallReply *reply, size_t *len); 948 | 949 | Return a pointer, and a length, to the protocol returned by the command 950 | that returned the reply object. 951 | 952 | ## `RM_CreateDataType` 953 | 954 | moduleType *RM_CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, moduleTypeLoadFunc rdb_load, moduleTypeSaveFunc rdb_save, moduleTypeRewriteFunc aof_rewrite, moduleTypeDigestFunc digest, moduleTypeFreeFunc free); 955 | 956 | Register a new data type exported by the module. The parameters are the 957 | following. Please for in depth documentation check the modules API 958 | documentation, especially the INTRO.md file. 959 | 960 | * **name**: A 9 characters data type name that MUST be unique in the Redis 961 | Modules ecosystem. Be creative... and there will be no collisions. Use 962 | the charset A-Z a-z 9-0, plus the two "-_" characters. A good 963 | idea is to use, for example `-`. For example 964 | "tree-AntZ" may mean "Tree data structure by @antirez". To use both 965 | lower case and upper case letters helps in order to prevent collisions. 966 | * **encver**: Encoding version, which is, the version of the serialization 967 | that a module used in order to persist data. As long as the "name" 968 | matches, the RDB loading will be dispatched to the type callbacks 969 | whatever 'encver' is used, however the module can understand if 970 | the encoding it must load are of an older version of the module. 971 | For example the module "tree-AntZ" initially used encver=0. Later 972 | after an upgrade, it started to serialize data in a different format 973 | and to register the type with encver=1. However this module may 974 | still load old data produced by an older version if the rdb_load 975 | callback is able to check the encver value and act accordingly. 976 | The encver must be a positive value between 0 and 1023. 977 | * **rdb_load**: A callback function pointer that loads data from RDB files. 978 | * **rdb_save**: A callback function pointer that saves data to RDB files. 979 | * **aof_rewrite**: A callback function pointer that rewrites data as commands. 980 | * **digest**: A callback function pointer that is used for `DEBUG DIGEST`. 981 | * **free**: A callback function pointer that can free a type value. 982 | 983 | Note: the module name "AAAAAAAAA" is reserved and produces an error, it 984 | happens to be pretty lame as well. 985 | 986 | If there is already a module registering a type with the same name, 987 | and if the module name or encver is invalid, NULL is returned. 988 | Otherwise the new type is registered into Redis, and a reference of 989 | type RedisModuleType is returned: the caller of the function should store 990 | this reference into a gobal variable to make future use of it in the 991 | modules type API, since a single module may register multiple types. 992 | Example code fragment: 993 | 994 | static RedisModuleType *BalancedTreeType; 995 | 996 | int `RedisModule_OnLoad(RedisModuleCtx` *ctx) { 997 | // some code here ... 998 | BalancedTreeType = `RM_CreateDataType(`...); 999 | } 1000 | 1001 | ## `RM_ModuleTypeSetValue` 1002 | 1003 | int RM_ModuleTypeSetValue(RedisModuleKey *key, moduleType *mt, void *value); 1004 | 1005 | If the key is open for writing, set the specified module type object 1006 | as the value of the key, deleting the old value if any. 1007 | On success `REDISMODULE_OK` is returned. If the key is not open for 1008 | writing or there is an active iterator, `REDISMODULE_ERR` is returned. 1009 | 1010 | ## `RM_ModuleTypeGetType` 1011 | 1012 | moduleType *RM_ModuleTypeGetType(RedisModuleKey *key); 1013 | 1014 | Assuming `RedisModule_KeyType()` returned `REDISMODULE_KEYTYPE_MODULE` on 1015 | the key, returns the moduel type pointer of the value stored at key. 1016 | 1017 | If the key is NULL, is not associated with a module type, or is empty, 1018 | then NULL is returned instead. 1019 | 1020 | ## `RM_ModuleTypeGetValue` 1021 | 1022 | void *RM_ModuleTypeGetValue(RedisModuleKey *key); 1023 | 1024 | Assuming `RedisModule_KeyType()` returned `REDISMODULE_KEYTYPE_MODULE` on 1025 | the key, returns the module type low-level value stored at key, as 1026 | it was set by the user via `RedisModule_ModuleTypeSet()`. 1027 | 1028 | If the key is NULL, is not associated with a module type, or is empty, 1029 | then NULL is returned instead. 1030 | 1031 | ## `RM_SaveUnsigned` 1032 | 1033 | void RM_SaveUnsigned(RedisModuleIO *io, uint64_t value); 1034 | 1035 | Save an unsigned 64 bit value into the RDB file. This function should only 1036 | be called in the context of the rdb_save method of modules implementing new 1037 | data types. 1038 | 1039 | ## `RM_LoadUnsigned` 1040 | 1041 | uint64_t RM_LoadUnsigned(RedisModuleIO *io); 1042 | 1043 | Load an unsigned 64 bit value from the RDB file. This function should only 1044 | be called in the context of the rdb_load method of modules implementing 1045 | new data types. 1046 | 1047 | ## `RM_SaveSigned` 1048 | 1049 | void RM_SaveSigned(RedisModuleIO *io, int64_t value); 1050 | 1051 | Like `RedisModule_SaveUnsigned()` but for signed 64 bit values. 1052 | 1053 | ## `RM_LoadSigned` 1054 | 1055 | int64_t RM_LoadSigned(RedisModuleIO *io); 1056 | 1057 | Like `RedisModule_LoadUnsigned()` but for signed 64 bit values. 1058 | 1059 | ## `RM_SaveString` 1060 | 1061 | void RM_SaveString(RedisModuleIO *io, RedisModuleString *s); 1062 | 1063 | In the context of the rdb_save method of a module type, saves a 1064 | string into the RDB file taking as input a RedisModuleString. 1065 | 1066 | The string can be later loaded with `RedisModule_LoadString()` or 1067 | other Load family functions expecting a serialized string inside 1068 | the RDB file. 1069 | 1070 | ## `RM_SaveStringBuffer` 1071 | 1072 | void RM_SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len); 1073 | 1074 | Like `RedisModule_SaveString()` but takes a raw C pointer and length 1075 | as input. 1076 | 1077 | ## `RM_LoadString` 1078 | 1079 | RedisModuleString *RM_LoadString(RedisModuleIO *io); 1080 | 1081 | In the context of the rdb_load method of a module data type, loads a string 1082 | from the RDB file, that was previously saved with `RedisModule_SaveString()` 1083 | functions family. 1084 | 1085 | The returned string is a newly allocated RedisModuleString object, and 1086 | the user should at some point free it with a call to `RedisModule_FreeString()`. 1087 | 1088 | If the data structure does not store strings as RedisModuleString objects, 1089 | the similar function `RedisModule_LoadStringBuffer()` could be used instead. 1090 | 1091 | ## `RM_LoadStringBuffer` 1092 | 1093 | char *RM_LoadStringBuffer(RedisModuleIO *io, size_t *lenptr); 1094 | 1095 | Like `RedisModule_LoadString()` but returns an heap allocated string that 1096 | was allocated with `RedisModule_Alloc()`, and can be resized or freed with 1097 | `RedisModule_Realloc()` or `RedisModule_Free()`. 1098 | 1099 | The size of the string is stored at '*lenptr' if not NULL. 1100 | The returned string is not automatically NULL termianted, it is loaded 1101 | exactly as it was stored inisde the RDB file. 1102 | 1103 | ## `RM_SaveDouble` 1104 | 1105 | void RM_SaveDouble(RedisModuleIO *io, double value); 1106 | 1107 | In the context of the rdb_save method of a module data type, saves a double 1108 | value to the RDB file. The double can be a valid number, a NaN or infinity. 1109 | It is possible to load back the value with `RedisModule_LoadDouble()`. 1110 | 1111 | ## `RM_LoadDouble` 1112 | 1113 | double RM_LoadDouble(RedisModuleIO *io); 1114 | 1115 | In the context of the rdb_save method of a module data type, loads back the 1116 | double value saved by `RedisModule_SaveDouble()`. 1117 | 1118 | ## `RM_EmitAOF` 1119 | 1120 | void RM_EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); 1121 | 1122 | Emits a command into the AOF during the AOF rewriting process. This function 1123 | is only called in the context of the aof_rewrite method of data types exported 1124 | by a module. The command works exactly like `RedisModule_Call()` in the way 1125 | the parameters are passed, but it does not return anything as the error 1126 | handling is performed by Redis itself. 1127 | 1128 | ## `RM_Log` 1129 | 1130 | void RM_Log(RedisModuleCtx *ctx, const char *levelstr, const char *fmt, ...); 1131 | 1132 | Produces a log message to the standard Redis log, the format accepts 1133 | printf-alike specifiers, while level is a string describing the log 1134 | level to use when emitting the log, and must be one of the following: 1135 | 1136 | * "debug" 1137 | * "verbose" 1138 | * "notice" 1139 | * "warning" 1140 | 1141 | If the specified log level is invalid, verbose is used by default. 1142 | There is a fixed limit to the length of the log line this function is able 1143 | to emit, this limti is not specified but is guaranteed to be more than 1144 | a few lines of text. 1145 | 1146 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README-es.md: -------------------------------------------------------------------------------- 1 | # Módulo Go Redis 2 | go-rm te permitirá escribir módulos Redis, utilizando Golang. 3 | 4 | Leer en | [中文](./README-zh_CN.md) | [English](./README.md) | [Spanish](./README-es.md) 5 | 6 | ## Demostración 7 | 8 | ```bash 9 | # Asegurate de tener la última versión de Redis 10 | # Por ejemplo, con brew puedes descargarla utilizando: 11 | # brew reinstall redis --HEAD 12 | 13 | # Para compilar el módulo 14 | go build -v -buildmode=c-shared github.com/redismodule/rxhash/cmd/rxhash 15 | 16 | # Para iniciar redis-server y cargar nuestro módulo, con logging en modo de depuración: 17 | redis-server --loadmodule rxhash --loglevel debug 18 | ``` 19 | 20 | __Conectarse a redis-server__ 21 | 22 | ``` 23 | # Test hgetset 24 | redis-cli hset a a 1 25 | #> (integer) 1 26 | redis-cli hgetset a a 2 27 | #> "1" 28 | redis-cli hget a a 29 | #> "2" 30 | # Return nil if field not exists 31 | redis-cli hgetset a b 2 32 | #> (nil) 33 | redis-cli hgetset a b 3 34 | #> "2" 35 | ``` 36 | 37 | Vaya, funciona, ahora puedes distribuir este módulo Redis a tus amigos. :P 38 | 39 | ## ¿Cómo escribir un módulo Redis? 40 | 41 | Implementar un módulo Redis es tan fácil como crear una aplicación de consola en Go, esto es todo lo que necesitas para implementar el comando de arriba, el código fuente está [aquí](https://github.com/wenerme/go-rm/blob/master/modules/hashex/hashex.go). 42 | 43 | ```go 44 | package main 45 | 46 | import "github.com/wenerme/go-rm/rm" 47 | 48 | func main() { 49 | // En caso de que alguien intente llamar esto. 50 | rm.Run() 51 | } 52 | 53 | func init() { 54 | rm.Mod = CreateMyMod() 55 | } 56 | func CreateMyMod() *rm.Module { 57 | mod := rm.NewMod() 58 | mod.Name = "hashex" 59 | mod.Version = 1 60 | mod.Commands = []rm.Command{CreateCommand_HGETSET()} 61 | return mod 62 | } 63 | func CreateCommand_HGETSET() rm.Command { 64 | return rm.Command{ 65 | Usage: "HGETSET key field value", 66 | Desc: `Sets the 'field' in Hash 'key' to 'value' and returns the previous value, if any. 67 | Reply: String, the previous value or NULL if 'field' didn't exist. `, 68 | Name: "hgetset", 69 | Flags: "write fast deny-oom", 70 | FirstKey:1, LastKey:1, KeyStep:1, 71 | Action: func(cmd rm.CmdContext) int { 72 | ctx, args := cmd.Ctx, cmd.Args 73 | if len(cmd.Args) != 4 { 74 | return ctx.WrongArity() 75 | } 76 | ctx.AutoMemory() 77 | key, ok := openHashKey(ctx, args[1]) 78 | if !ok { 79 | return rm.ERR 80 | } 81 | // obtener el valor actual del elemento hash 82 | var val rm.String; 83 | key.HashGet(rm.HASH_NONE, cmd.Args[2], (*uintptr)(&val)) 84 | // definir el nuevo valor 85 | key.HashSet(rm.HASH_NONE, cmd.Args[2], cmd.Args[3]) 86 | if val.IsNull() { 87 | ctx.ReplyWithNull() 88 | } else { 89 | ctx.ReplyWithString(val) 90 | } 91 | return rm.OK 92 | }, 93 | } 94 | } 95 | // abrir la clave y asegurarse de que se trata de un hash y no está vacía 96 | func openHashKey(ctx rm.Ctx, k rm.String) (rm.Key, bool) { 97 | key := ctx.OpenKey(k, rm.READ | rm.WRITE) 98 | if key.KeyType() != rm.KEYTYPE_EMPTY && key.KeyType() != rm.KEYTYPE_HASH { 99 | ctx.ReplyWithError(rm.ERRORMSG_WRONGTYPE) 100 | return rm.Key(0), false 101 | } 102 | return key, true 103 | } 104 | ``` 105 | 106 | ## Fantasía 107 | 108 | * Un módulo de gestión de módulos, provee 109 | * mod.search 110 | * Búsqueda de módulos en repositorios (¿GitHub?) 111 | * La estructura del repositorio sería así: 112 | ``` 113 | /namespace 114 | /module-name 115 | /bin 116 | /darwin_amd64 117 | module-name.so 118 | module-name.sha 119 | /linux_amd64 120 | module-name.go 121 | ``` 122 | * mod.get 123 | * Descargar el módulo a ~/.redismodule 124 | * Dado que el módulo está escrito en Go, podemos compilarlo para casi cualquier plataforma 125 | * Podemos utilizar el tag/commit para versionar el binario, entonces también sería posible descargar versiones anteriores 126 | * mod.install 127 | * Instalar el módulo descargado 128 | * ... 129 | * Un módulo para gestión de cluster 130 | * Facilitaría la creación/gestión/monitoreo de un cluster basado en Redis 3 131 | * Un tipo de dato JSON, para demostrar la forma de agregar un nuevo tipo de datos a Redis. 132 | * json.fmt key template 133 | * json.path key path \[pretty] 134 | * json.get key \[pretty] 135 | * json.set key value 136 | * Esto validaría el JSON 137 | 138 | ## Dificultades 139 | * El código C no puede llamar a funciones Go, entonces cada callback es pregenerado 140 | * 200 comandos como máximo 141 | * 5 tipos de datos como máximo 142 | * Los límites son fáciles de cambiar, sólo necesitan un valor máximo apropiado 143 | * Go no puede llamar a var_args, la llamada a esta función también es pregenerada 144 | * HashSet/HashGet acepta hasta 20 argumentos 145 | * Los límites son fáciles de cambiar, sólo necesitan un valor máximo apropiado 146 | 147 | ## TODO 148 | 149 | * Encontrar límites apropiados para tipos de datos y var_args 150 | -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 | # Go Redis module 2 | go-rm 旨在通过 Golang 来实现 redis 模块. 3 | 4 | 语言 | [中文](./README-zh_CN.md) | [English](./README.md) | [Spanish](./README-es.md) 5 | 6 | ## 现有模块 7 | 8 | * [redismodule](https://github.com/redismodule) 9 | * [rxhash](https://github.com/redismodule/rxhash) 10 | 11 | 12 | ## 演示 13 | 14 | ```bash 15 | # 确保你安装了最新的 redis, 不是最新版,而是 github 上的最新编译版本 16 | # 如果你能够使用 brew 命令,那么你可以通过以下方式来安装 17 | # brew reinstall redis --HEAD 18 | 19 | # 构建 redis 模块 20 | go build -v -buildmode=c-shared github.com/redismodule/rxhash/cmd/rxhash 21 | 22 | # 启动 redis-server 并加载刚刚编译的模块,使用 debug 日志级别 23 | redis-server --loadmodule rxhash --loglevel debug 24 | ``` 25 | 26 | __客户端__ 27 | 28 | ``` 29 | # Test hgetset 30 | redis-cli hset a a 1 31 | #> (integer) 1 32 | redis-cli hgetset a a 2 33 | #> "1" 34 | redis-cli hget a a 35 | #> "2" 36 | # Return nil if field not exists 37 | redis-cli hgetset a b 2 38 | #> (nil) 39 | redis-cli hgetset a b 3 40 | #> "2" 41 | ``` 42 | 43 | ## 如何实现一个 Redis 模块 44 | 45 | 实现一个 Redis 模块非常简单,就像是写一个 cli 程序一样,以下代码实现了上面演示的功能,源代码在[这里](https://github.com/wenerme/go-rm/blob/master/modules/hashex/hashex.go). 46 | 47 | ```go 48 | package main 49 | 50 | import "github.com/wenerme/go-rm/rm" 51 | 52 | func main() { 53 | // In case someone try to run this 54 | rm.Run() 55 | } 56 | 57 | func init() { 58 | rm.Mod = CreateMyMod() 59 | } 60 | func CreateMyMod() *rm.Module { 61 | mod := rm.NewMod() 62 | mod.Name = "hashex" 63 | mod.Version = 1 64 | mod.Commands = []rm.Command{CreateCommand_HGETSET()} 65 | return mod 66 | } 67 | func CreateCommand_HGETSET() rm.Command { 68 | return rm.Command{ 69 | Usage: "HGETSET key field value", 70 | Desc: `Sets the 'field' in Hash 'key' to 'value' and returns the previous value, if any. 71 | Reply: String, the previous value or NULL if 'field' didn't exist. `, 72 | Name: "hgetset", 73 | Flags: "write fast deny-oom", 74 | FirstKey:1, LastKey:1, KeyStep:1, 75 | Action: func(cmd rm.CmdContext) int { 76 | ctx, args := cmd.Ctx, cmd.Args 77 | if len(cmd.Args) != 4 { 78 | return ctx.WrongArity() 79 | } 80 | ctx.AutoMemory() 81 | key, ok := openHashKey(ctx, args[1]) 82 | if !ok { 83 | return rm.ERR 84 | } 85 | // get the current value of the hash element 86 | var val rm.String; 87 | key.HashGet(rm.HASH_NONE, cmd.Args[2], (*uintptr)(&val)) 88 | // set the element to the new value 89 | key.HashSet(rm.HASH_NONE, cmd.Args[2], cmd.Args[3]) 90 | if val.IsNull() { 91 | ctx.ReplyWithNull() 92 | } else { 93 | ctx.ReplyWithString(val) 94 | } 95 | return rm.OK 96 | }, 97 | } 98 | } 99 | // open the key and make sure it is indeed a Hash and not empty 100 | func openHashKey(ctx rm.Ctx, k rm.String) (rm.Key, bool) { 101 | key := ctx.OpenKey(k, rm.READ | rm.WRITE) 102 | if key.KeyType() != rm.KEYTYPE_EMPTY && key.KeyType() != rm.KEYTYPE_HASH { 103 | ctx.ReplyWithError(rm.ERRORMSG_WRONGTYPE) 104 | return rm.Key(0), false 105 | } 106 | return key, true 107 | } 108 | ``` 109 | 110 | ## 幻想 111 | 112 | * 实现一个用于管理模块的命令,提供下述命令 113 | * mod.search 114 | * 从仓库(github?)搜索模块 115 | * 仓库的结构类似于这样 116 | ``` 117 | /namespace 118 | /module-name 119 | /bin 120 | /darwin_amd64 121 | module-name.so 122 | module-name.sha 123 | /linux_amd64 124 | module-name.go 125 | ``` 126 | * mod.get 127 | * 下载模块到 ~/.redismodule 128 | * 因为模块是用 Go 写的,因此大多数平台都能使用 129 | * 可以使用 tag 或者是提交 id 来标识版本 130 | * mod.install 131 | * 调用 redis 的命令来安装模块 132 | * ... 133 | * 集群管理模块 134 | * 用于简化 redis 3 的集群 创建/管理/监控 135 | * 实现一个 json 数据类型,用于演示如果添加新的 redis 类型,支持以下命令 136 | * json.fmt key template 137 | * json.path key path \[pretty] 138 | * json.get key \[pretty] 139 | * json.set key value 140 | * 该操作会验证 value 是否为 json 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Redis module 2 | go-rm will let you write redis module in golang. 3 | 4 | Read in | [中文](./README-zh_CN.md) | [English](./README.md) | [Spanish](./README-es.md) 5 | 6 | ## Modules 7 | 8 | * [redismodule](https://github.com/redismodule) 9 | * [rxhash](https://github.com/redismodule/rxhash) 10 | 11 | ## Demo 12 | 13 | ```bash 14 | # Ensure you installed the newest redis 15 | # for example by using brew you can 16 | # brew reinstall redis --HEAD 17 | 18 | # Build redis module 19 | go build -v -buildmode=c-shared github.com/redismodule/rxhash/cmd/rxhash 20 | 21 | # Start redis-server and load our module with debug log 22 | redis-server --loadmodule rxhash --loglevel debug 23 | ``` 24 | 25 | __Connect to out redis-server__ 26 | 27 | ```bash 28 | # Test hgetset 29 | redis-cli hset a a 1 30 | #> (integer) 1 31 | redis-cli hgetset a a 2 32 | #> "1" 33 | redis-cli hget a a 34 | #> "2" 35 | # Return nil if field not exists 36 | redis-cli hgetset a b 2 37 | #> (nil) 38 | redis-cli hgetset a b 3 39 | #> "2" 40 | ``` 41 | 42 | Wow, it works, now you can distribute this redis module to you friends. :P 43 | 44 | ## How to write a module 45 | 46 | Implement a redis module is as easy as you write a cli app in go, this is all you need to implement above command. 47 | 48 | ```go 49 | package main 50 | 51 | import "github.com/wenerme/go-rm/rm" 52 | 53 | func main() { 54 | // In case someone try to run this 55 | rm.Run() 56 | } 57 | 58 | func init() { 59 | rm.Mod = CreateMyMod() 60 | } 61 | func CreateMyMod() *rm.Module { 62 | mod := rm.NewMod() 63 | mod.Name = "hashex" 64 | mod.Version = 1 65 | mod.Commands = []rm.Command{CreateCommand_HGETSET()} 66 | return mod 67 | } 68 | func CreateCommand_HGETSET() rm.Command { 69 | return rm.Command{ 70 | Usage: "HGETSET key field value", 71 | Desc: `Sets the 'field' in Hash 'key' to 'value' and returns the previous value, if any. 72 | Reply: String, the previous value or NULL if 'field' didn't exist. `, 73 | Name: "hgetset", 74 | Flags: "write fast deny-oom", 75 | FirstKey:1, LastKey:1, KeyStep:1, 76 | Action: func(cmd rm.CmdContext) int { 77 | ctx, args := cmd.Ctx, cmd.Args 78 | if len(cmd.Args) != 4 { 79 | return ctx.WrongArity() 80 | } 81 | ctx.AutoMemory() 82 | key, ok := openHashKey(ctx, args[1]) 83 | if !ok { 84 | return rm.ERR 85 | } 86 | // get the current value of the hash element 87 | var val rm.String; 88 | key.HashGet(rm.HASH_NONE, cmd.Args[2], (*uintptr)(&val)) 89 | // set the element to the new value 90 | key.HashSet(rm.HASH_NONE, cmd.Args[2], cmd.Args[3]) 91 | if val.IsNull() { 92 | ctx.ReplyWithNull() 93 | } else { 94 | ctx.ReplyWithString(val) 95 | } 96 | return rm.OK 97 | }, 98 | } 99 | } 100 | // open the key and make sure it is indeed a Hash and not empty 101 | func openHashKey(ctx rm.Ctx, k rm.String) (rm.Key, bool) { 102 | key := ctx.OpenKey(k, rm.READ | rm.WRITE) 103 | if key.KeyType() != rm.KEYTYPE_EMPTY && key.KeyType() != rm.KEYTYPE_HASH { 104 | ctx.ReplyWithError(rm.ERRORMSG_WRONGTYPE) 105 | return rm.Key(0), false 106 | } 107 | return key, true 108 | } 109 | ``` 110 | 111 | ## Fantasy 112 | 113 | * A module management module, supplies 114 | * mod.search 115 | * Search module from repository(github?) 116 | * Repository structure like this 117 | ``` 118 | /namespace 119 | /module-name 120 | /bin 121 | /darwin_amd64 122 | module-name.so 123 | module-name.sha 124 | /linux_amd64 125 | module-name.go 126 | ``` 127 | * mod.get 128 | * Download module to ~/.redismodule 129 | * Because module is write in go, so we can build for almost any platform 130 | * We can use tag/commit to version the binary, so we can download the old version too 131 | * mod.install 132 | * Install downloaded module by calling redis command 133 | * ... 134 | * A cluster management module 135 | * Easy to create/manage/monitor redis3 cluster 136 | * A json data type to demonstration how to add new data type in redis. 137 | * json.fmt key template 138 | * json.path key path \[pretty] 139 | * json.get key \[pretty] 140 | * json.set key value 141 | * this will validate the json format 142 | 143 | ## Pitfall 144 | * C can not call Go function, so every callback is pre-generated 145 | * 200 commands at most 146 | * 5 data type at most 147 | * limits are easy to change, just need a proper max value 148 | * Go can not call var_args, function call is pre-generated 149 | * HashSet/HashGet can accept 20 args at most 150 | * limits are easy to change, just need a proper max value 151 | * Don't know what happens when unload a golang shared module 152 | * Single module 153 | * Multi module 154 | * Is there runtime are shared ? 155 | * Module write in go can not report it's memory usage to redis, max memory limits is useless 156 | * If a module write in go also include a third party write in other language, the memory usage is unknown 157 | * Module can only accept command, seems there is no way to call redis initiative. 158 | 159 | ## TODO 160 | 161 | * Find a proper limits for data types and var_args 162 | -------------------------------------------------------------------------------- /gen.es6: -------------------------------------------------------------------------------- 1 | let argc = 21; 2 | 3 | function GenerateHashSetVar(name, ret, call) { 4 | let s = ` 5 | int HashSetVar(RedisModuleKey *key, int flags,int argc, intptr_t argv[]){ 6 | switch(argc){ 7 | `; 8 | 9 | for (var i = 0; i < argc; i++) { 10 | s += `case ${i}: return RedisModule_HashSet(key, flags`; 11 | for (var j = 0; j < i; j++) { 12 | s += `,argv[${j}]` 13 | } 14 | s += `);\n` 15 | } 16 | 17 | s += ` 18 | default: 19 | return REDISMODULE_ERR; 20 | } 21 | }`; 22 | return s 23 | } 24 | 25 | function GenerateHashGetVar(name, ret, call) { 26 | let s = ` 27 | int HashGetVar(RedisModuleKey *key, int flags,int argc, intptr_t argv[]){ 28 | switch(argc){ 29 | `; 30 | 31 | for (var i = 0; i < argc; i++) { 32 | s += `case ${i}: return RedisModule_HashGet(key, flags`; 33 | for (var j = 0; j < i; j++) { 34 | s += `,argv[${j}]` 35 | } 36 | s += `);\n` 37 | } 38 | 39 | s += ` 40 | default: 41 | return REDISMODULE_ERR; 42 | } 43 | }`; 44 | return s 45 | } 46 | 47 | 48 | function GenerateCallVar(name, ret, call) { 49 | let s = ` 50 | RedisModuleCallReply * CallVar(RedisModuleCtx *key, const char *cmdname, const char *fmt, const int argc,const intptr_t argv[]){ 51 | switch(argc){ 52 | `; 53 | 54 | for (var i = 0; i < argc; i++) { 55 | s += `case ${i}: return RedisModule_Call(key, cmdname, fmt`; 56 | for (var j = 0; j < i; j++) { 57 | s += `,argv[${j}]` 58 | } 59 | s += `);\n` 60 | } 61 | 62 | s += ` 63 | default: 64 | errno=EINVAL; 65 | return NULL; 66 | } 67 | }`; 68 | return s; 69 | } 70 | 71 | const all = [ 72 | GenerateCallVar(), 73 | '/* Hash */', 74 | GenerateHashSetVar(), 75 | GenerateHashGetVar(), 76 | ]; 77 | 78 | // console.log(GenerateHashSetVar()) 79 | // console.log(GenerateHashGetVar()) 80 | // console.log(GenerateCallVar()) 81 | const fs = require('fs'); 82 | let f = fs.readFileSync('rm/varargs.h').toString(); 83 | 84 | // region Generated 85 | 86 | f = f.replace(/(?<=region Generated)(.*)(?=\n[^\n]+endregion)/s, all.join('\n')); 87 | 88 | 89 | fs.writeFileSync('rm/varargs.h', f); 90 | -------------------------------------------------------------------------------- /gen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/bradfitz/iter" 7 | "github.com/ngaut/log" 8 | "github.com/urfave/cli" 9 | "io/ioutil" 10 | "os" 11 | "reflect" 12 | "regexp" 13 | "strings" 14 | "text/template" 15 | ) 16 | 17 | func main() { 18 | app := cli.NewApp() 19 | app.Name = "gen" 20 | app.Commands = []cli.Command{ 21 | { 22 | Name: "callback", 23 | Usage: "Generate Callbacks", 24 | Action: GenerateCallback, 25 | }, 26 | { 27 | Name: "wrapper", 28 | Flags: []cli.Flag{ 29 | cli.StringFlag{ 30 | Name: "t", 31 | Usage: `Generate wrapper c or go`, 32 | Value: "c", 33 | }, 34 | cli.StringFlag{ 35 | Name: "f", 36 | Usage: `Generated filename`, 37 | }, 38 | }, 39 | Action: GenerateWrapper, 40 | }, 41 | } 42 | //app.Run(strings.Split("gen wrapper -t go -f ./rm/wrapper.go", " ")) 43 | app.Run(strings.Split("gen callback", " ")) 44 | //app.RunAndExitOnError() 45 | //b, err := ioutil.ReadFile("./API.md") 46 | //if err != nil { 47 | // panic(err) 48 | //} 49 | // 50 | //b, err = json.Marshal(ParseApi(string(b))) 51 | //if err != nil { 52 | // panic(err) 53 | //} 54 | //ioutil.WriteFile("api.json", b, os.ModePerm) 55 | } 56 | 57 | var callbackTemplate = ` 58 | #ifndef GO_RM_CALLBACK_H 59 | #define GO_RM_CALLBACK_H 60 | 61 | #include "./decl.h" 62 | 63 | {{range $k, $v := .CallTypes}} 64 | 65 | // {{.Name}} - {{.Type}} 66 | inline int {{.Name}}_size(){return {{.Number}};} 67 | {{/*定义回调函数*/ -}} 68 | 69 | {{range $i, $_ := N .Number}} 70 | {{- with $v -}} 71 | 72 | {{.Ret}} cb_{{.Name}}_{{$i}}({{.ParamString}}){ 73 | {{- if ne .Ret "void"}}return {{end}} 74 | {{- /*调用实际方法*/ -}} 75 | {{.Name}}_call({{$i}},{{.ParamName}});{{- "" -}} 76 | } 77 | {{end}} 78 | {{- end}} 79 | 80 | 81 | {{- /*定义变量*/ -}} 82 | 83 | const {{.Type}} cb_{{.Name}}[] = { 84 | {{range $i, $_ := N .Number}} 85 | {{- with $v -}} 86 | cb_{{.Name}}_{{$i}},{{if neednl $i }}{{"\n"}}{{end}} 87 | {{- end}} 88 | {{- end}} 89 | }; 90 | 91 | {{- end}} 92 | #endif 93 | ` 94 | 95 | type CallbackCtx struct { 96 | CmdFuncNumber int 97 | ModTypeNumber int 98 | CallTypes []*CallType 99 | } 100 | 101 | type CallType struct { 102 | Name string 103 | Type string 104 | Ret string 105 | ParamString string 106 | ParamName string 107 | Number int 108 | } 109 | 110 | func GenerateCallback(ctx *cli.Context) error { 111 | tpl := MustTemplate(callbackTemplate, template.FuncMap{ 112 | "neednl": func(i int) bool { 113 | return i%15 == 0 && i != 0 114 | }}) 115 | 116 | buf := bytes.NewBufferString("") 117 | callbackCtx := CallbackCtx{ 118 | CmdFuncNumber: 60, 119 | ModTypeNumber: 6, 120 | // mt_rdb_load RedisModuleTypeLoadFunc 121 | // mt_rdb_save RedisModuleTypeSaveFunc 122 | // mt_aof_rewrite RedisModuleTypeRewriteFunc 123 | // mt_digest RedisModuleTypeDigestFunc 124 | // mt_free RedisModuleTypeFreeFunc 125 | 126 | // typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 127 | // typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); 128 | // typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); 129 | // typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); 130 | // typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); 131 | // typedef void (*RedisModuleTypeFreeFunc)(void *value); 132 | CallTypes: []*CallType{ 133 | { 134 | Name: "cmd_func", 135 | Type: "RedisModuleCmdFunc", 136 | ParamString: "RedisModuleCtx *ctx, RedisModuleString **argv, int argc", 137 | ParamName: "ctx, argv, argc", 138 | Ret: "int", 139 | Number: 200, 140 | }, 141 | { 142 | Name: "mt_rdb_load", 143 | Type: "RedisModuleTypeLoadFunc", 144 | ParamString: "RedisModuleIO *rdb, int encver", 145 | ParamName: "rdb, encver", 146 | Ret: "void*", 147 | }, 148 | { 149 | Name: "mt_rdb_save", 150 | Type: "RedisModuleTypeSaveFunc", 151 | ParamString: "RedisModuleIO *rdb, void *value", 152 | ParamName: "rdb, value", 153 | Ret: "void", 154 | }, 155 | { 156 | Name: "mt_aof_rewrite", 157 | Type: "RedisModuleTypeRewriteFunc", 158 | ParamString: "RedisModuleIO *aof, RedisModuleString *key, void *value", 159 | ParamName: "aof, key, value", 160 | Ret: "void", 161 | }, 162 | { 163 | Name: "mt_digest", 164 | Type: "RedisModuleTypeDigestFunc", 165 | ParamString: "RedisModuleDigest *digest, void *value", 166 | ParamName: "digest, value", 167 | Ret: "void", 168 | }, 169 | { 170 | Name: "mt_free", 171 | Type: "RedisModuleTypeFreeFunc", 172 | ParamString: "void *value", 173 | ParamName: "value", 174 | Ret: "void", 175 | }, 176 | }, 177 | } 178 | for _, c := range callbackCtx.CallTypes { 179 | if c.Number != 0 { 180 | continue 181 | } 182 | if c.Name[:2] == "mt" { 183 | c.Number = 5 184 | } 185 | } 186 | err := tpl.Execute(buf, callbackCtx) 187 | if err != nil { 188 | log.Fatalf("Execute template failed: %v", err) 189 | return err 190 | } 191 | return ioutil.WriteFile("./rm/callbacks.h", buf.Bytes(), os.ModePerm) 192 | } 193 | 194 | var wrapperHeaderTemplate = ` 195 | #ifndef GO_RM_WRAPPER_H 196 | #define GO_RM_WRAPPER_H 197 | 198 | #include "./redismodule.h" 199 | #include "./hw_wrapper.h" 200 | 201 | // Generated wrapper 202 | 203 | {{range $i, $v := .Apis}} 204 | {{if show_api $v -}} 205 | {{commented .Desc}} 206 | {{.Ret}} {{.Name}}( 207 | {{- range $j, $arg := .ArgInfos -}} 208 | {{.Type}} {{.Name}}{{if not (last $j $v.ArgInfos)}},{{end}} 209 | {{- end -}} 210 | ){ 211 | {{- if need_ret $v}}return {{end -}} 212 | RedisModule_{{.Name}}( 213 | {{- range $j, $arg := .ArgInfos -}} 214 | {{$arg.Name}}{{if not (last $j $v.ArgInfos)}},{{end}} 215 | {{- end -}} 216 | );} 217 | {{- end}} 218 | {{end}} 219 | 220 | #endif 221 | ` 222 | 223 | var wrapperGoTemplate = ` 224 | package rm 225 | 226 | //#include "./rm.h" 227 | import "C" 228 | import ( 229 | "unsafe" 230 | ) 231 | 232 | {{range $i, $v := .Apis}} 233 | {{if show_api $v -}} 234 | {{commented .Desc}} 235 | // {{.Sig}} 236 | func {{.Name}}( 237 | {{- range $j, $arg := .ArgInfos -}} 238 | {{.Name}} {{gotype .Type}}{{if not (last $j $v.ArgInfos)}},{{end}} 239 | {{- end -}} 240 | )( 241 | {{- if need_ret $v}}{{gotype .Ret}}{{end -}} 242 | ){ 243 | {{- if need_ret $v}}return {{end -}} 244 | {{- /* 类型转换 */ -}} 245 | {{- if need_ret $v}}{{gotype .Ret}}({{end -}} 246 | {{- /* 方法调用 */ -}} 247 | C.{{.Name}}( 248 | {{- range $j, $arg := .ArgInfos -}} 249 | {{.Name}}{{if not (last $j $v.ArgInfos)}},{{end}} 250 | {{- end -}} 251 | 252 | ) 253 | {{- if need_ret $v}}){{end -}} 254 | } 255 | {{- end}} 256 | {{end}} 257 | ` 258 | 259 | type WrapperCtx struct { 260 | Apis []ApiInfo 261 | } 262 | 263 | func GenerateWrapper(ctx *cli.Context) error { 264 | tplString := wrapperHeaderTemplate 265 | fn := "./rm/wrapper.h" 266 | switch ctx.String("t") { 267 | case "go": 268 | fn = "./rm/wrapper.go" 269 | tplString = wrapperGoTemplate 270 | } 271 | if ctx.String("f") != "" { 272 | fn = ctx.String("f") 273 | } 274 | 275 | tpl := MustTemplate(tplString, template.FuncMap{ 276 | "need_ret": func(i ApiInfo) bool { 277 | return i.Ret != "void" 278 | }, 279 | "show_api": func(i ApiInfo) bool { 280 | switch i.Name { 281 | case "ZsetAddFlagsToCoreFlags": 282 | case "ZsetAddFlagsFromCoreFlags": 283 | case "FreeCallReply_Rec": 284 | default: 285 | return true 286 | } 287 | return false 288 | }, 289 | }) 290 | b, err := ioutil.ReadFile("./API.md") 291 | if err != nil { 292 | return err 293 | } 294 | apis := ParseApi(string(b)) 295 | context := WrapperCtx{ 296 | Apis: apis, 297 | } 298 | str := MustExecute(tpl, context) 299 | return ioutil.WriteFile(fn, []byte(str), os.ModePerm) 300 | } 301 | 302 | type ApiInfo struct { 303 | Sig string 304 | Ret string 305 | Name string 306 | Args string 307 | Desc string 308 | ArgInfos []ArgInfo 309 | } 310 | type ArgInfo struct { 311 | Type string 312 | Name string 313 | } 314 | 315 | func ParseApi(md string) []ApiInfo { 316 | apis := make([]ApiInfo, 0) 317 | parts := regexp.MustCompile(`(?m)^##.*$`).Split(md, -1) 318 | sig := regexp.MustCompile(`(?m)^\s*$\s+([^;]+);\s*$^\s*$`) 319 | // void *RM_Alloc(size_t bytes); 320 | sigPattern := regexp.MustCompile(`(.*?)RM_([^(]+)\((.*?)\);`) 321 | for i, v := range parts { 322 | if i == 0 { 323 | continue 324 | } 325 | f := strings.TrimSpace(sig.FindString(v)) 326 | match := sigPattern.FindStringSubmatch(f) 327 | apis = append(apis, ApiInfo{ 328 | Sig: match[0], 329 | Ret: TypeMap(match[1]), 330 | Name: match[2], 331 | Args: match[3], 332 | Desc: strings.TrimSpace(sig.ReplaceAllString(v, "")), 333 | ArgInfos: ParseArgs(match[3]), 334 | }) 335 | } 336 | return apis 337 | } 338 | 339 | func ParseArgs(args string) []ArgInfo { 340 | infos := make([]ArgInfo, 0) 341 | parts := regexp.MustCompile(`\s*,\s*`).Split(args, -1) 342 | namePattern := regexp.MustCompile(`(\w+)$`) 343 | 344 | for _, v := range parts { 345 | if v == "..." { 346 | continue 347 | } 348 | name := namePattern.FindStringSubmatch(v)[0] 349 | t := strings.TrimSpace(namePattern.ReplaceAllLiteralString(v, "")) 350 | infos = append(infos, ArgInfo{ 351 | Name: name, 352 | Type: TypeMap(t), 353 | }) 354 | } 355 | return infos 356 | } 357 | 358 | func TypeMap(t string) string { 359 | a := strings.TrimSpace(t) 360 | a = strings.Replace(a, " *", "*", -1) 361 | switch a { 362 | case "robj*": 363 | a = "RedisModuleString*" 364 | default: 365 | // moduleType 366 | if strings.HasPrefix(a, "moduleType") { 367 | // RedisModuleTypeSaveFunc 368 | a = "RedisModule" + a[len("module"):] 369 | } 370 | } 371 | return a 372 | } 373 | func GoTypeMap(f string) string { 374 | a := f 375 | a = strings.TrimSpace(strings.TrimPrefix(a, "const")) 376 | t := a 377 | switch a { 378 | case "void*": 379 | t = "unsafe.Pointer" 380 | case "RedisModuleString*": 381 | t = "String" 382 | case "size_t": 383 | t = "int" 384 | case "size_t*": 385 | t = "*int" 386 | case "int*": 387 | t = "*int" 388 | case "RedisModuleCtx*": 389 | t = "Ctx" 390 | case "char*": 391 | t = "string" 392 | case "void**": 393 | t = "/* TODO void** */unsafe.Pointer" 394 | case "RedisModuleCmdFunc": 395 | t = "CmdFunc" 396 | case "RedisModuleCallReply*": 397 | t = "CallReply" 398 | case "RedisModuleKey*": 399 | t = "Key" 400 | case "RedisModuleIO*": 401 | t = "IO" 402 | case "RedisModuleType*": 403 | t = "/* TODO RedisModuleType* */unsafe.Pointer" 404 | case "mstime_t": 405 | t = "uint64" 406 | case "long long*": 407 | t = "*int64" 408 | case "double": 409 | t = "float64" 410 | case "double*": 411 | t = "*float64" 412 | case "unsigned long long": 413 | fallthrough 414 | case "uint64_t": 415 | t = "uint64" 416 | case "long long": 417 | fallthrough 418 | case "long": 419 | fallthrough 420 | case "int64_t": 421 | t = "int64" 422 | case "RedisModuleTypeLoadFunc": 423 | case "RedisModuleTypeSaveFunc": 424 | case "RedisModuleTypeRewriteFunc": 425 | case "RedisModuleTypeDigestFunc": 426 | case "RedisModuleTypeFreeFunc": 427 | case "int": 428 | default: 429 | fmt.Fprintf(os.Stderr, "No go type map found for %s(%v)\n", t, []byte(t)) 430 | } 431 | 432 | return t 433 | } 434 | 435 | func MustTemplate(content string, funcs template.FuncMap) *template.Template { 436 | tpl := template.New("tpl") 437 | tpl.Funcs(template.FuncMap{ 438 | "N": iter.N, 439 | "gotype": GoTypeMap, 440 | "last": func(x int, a interface{}) bool { 441 | return x == reflect.ValueOf(a).Len()-1 442 | }, 443 | "commented": func(s string) string { 444 | return regexp.MustCompile(`(?m)^`).ReplaceAllString(s, "// ") 445 | }, 446 | }) 447 | tpl.Funcs(funcs) 448 | 449 | template.Must(tpl.Parse(content)) 450 | return tpl 451 | } 452 | func MustExecute(tpl *template.Template, data interface{}) string { 453 | buf := bytes.NewBufferString("") 454 | err := tpl.Execute(buf, data) 455 | if err != nil { 456 | panic(err) 457 | } 458 | return buf.String() 459 | } 460 | -------------------------------------------------------------------------------- /rm/callback.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | var commands = make([]Command, 0) 4 | var moduleTypes = make([]DataType, 0) 5 | 6 | func getCommand(id int) *Command { 7 | return &commands[id] 8 | } 9 | func getDataType(id int) *DataType { 10 | return &moduleTypes[id] 11 | } 12 | func commandId(cmd Command) int { 13 | id := len(commands) 14 | commands = append(commands, cmd) 15 | return id 16 | } 17 | 18 | func dataTypeId(mt DataType) int { 19 | id := len(moduleTypes) 20 | moduleTypes = append(moduleTypes, mt) 21 | return id 22 | } 23 | -------------------------------------------------------------------------------- /rm/callbacks.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GO_RM_CALLBACK_H 3 | #define GO_RM_CALLBACK_H 4 | 5 | #include "./decl.h" 6 | 7 | 8 | 9 | // cmd_func - RedisModuleCmdFunc 10 | inline int cmd_func_size(){return 200;} 11 | int cb_cmd_func_0(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(0,ctx, argv, argc);} 12 | int cb_cmd_func_1(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(1,ctx, argv, argc);} 13 | int cb_cmd_func_2(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(2,ctx, argv, argc);} 14 | int cb_cmd_func_3(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(3,ctx, argv, argc);} 15 | int cb_cmd_func_4(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(4,ctx, argv, argc);} 16 | int cb_cmd_func_5(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(5,ctx, argv, argc);} 17 | int cb_cmd_func_6(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(6,ctx, argv, argc);} 18 | int cb_cmd_func_7(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(7,ctx, argv, argc);} 19 | int cb_cmd_func_8(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(8,ctx, argv, argc);} 20 | int cb_cmd_func_9(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(9,ctx, argv, argc);} 21 | int cb_cmd_func_10(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(10,ctx, argv, argc);} 22 | int cb_cmd_func_11(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(11,ctx, argv, argc);} 23 | int cb_cmd_func_12(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(12,ctx, argv, argc);} 24 | int cb_cmd_func_13(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(13,ctx, argv, argc);} 25 | int cb_cmd_func_14(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(14,ctx, argv, argc);} 26 | int cb_cmd_func_15(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(15,ctx, argv, argc);} 27 | int cb_cmd_func_16(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(16,ctx, argv, argc);} 28 | int cb_cmd_func_17(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(17,ctx, argv, argc);} 29 | int cb_cmd_func_18(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(18,ctx, argv, argc);} 30 | int cb_cmd_func_19(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(19,ctx, argv, argc);} 31 | int cb_cmd_func_20(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(20,ctx, argv, argc);} 32 | int cb_cmd_func_21(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(21,ctx, argv, argc);} 33 | int cb_cmd_func_22(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(22,ctx, argv, argc);} 34 | int cb_cmd_func_23(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(23,ctx, argv, argc);} 35 | int cb_cmd_func_24(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(24,ctx, argv, argc);} 36 | int cb_cmd_func_25(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(25,ctx, argv, argc);} 37 | int cb_cmd_func_26(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(26,ctx, argv, argc);} 38 | int cb_cmd_func_27(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(27,ctx, argv, argc);} 39 | int cb_cmd_func_28(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(28,ctx, argv, argc);} 40 | int cb_cmd_func_29(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(29,ctx, argv, argc);} 41 | int cb_cmd_func_30(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(30,ctx, argv, argc);} 42 | int cb_cmd_func_31(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(31,ctx, argv, argc);} 43 | int cb_cmd_func_32(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(32,ctx, argv, argc);} 44 | int cb_cmd_func_33(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(33,ctx, argv, argc);} 45 | int cb_cmd_func_34(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(34,ctx, argv, argc);} 46 | int cb_cmd_func_35(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(35,ctx, argv, argc);} 47 | int cb_cmd_func_36(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(36,ctx, argv, argc);} 48 | int cb_cmd_func_37(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(37,ctx, argv, argc);} 49 | int cb_cmd_func_38(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(38,ctx, argv, argc);} 50 | int cb_cmd_func_39(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(39,ctx, argv, argc);} 51 | int cb_cmd_func_40(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(40,ctx, argv, argc);} 52 | int cb_cmd_func_41(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(41,ctx, argv, argc);} 53 | int cb_cmd_func_42(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(42,ctx, argv, argc);} 54 | int cb_cmd_func_43(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(43,ctx, argv, argc);} 55 | int cb_cmd_func_44(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(44,ctx, argv, argc);} 56 | int cb_cmd_func_45(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(45,ctx, argv, argc);} 57 | int cb_cmd_func_46(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(46,ctx, argv, argc);} 58 | int cb_cmd_func_47(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(47,ctx, argv, argc);} 59 | int cb_cmd_func_48(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(48,ctx, argv, argc);} 60 | int cb_cmd_func_49(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(49,ctx, argv, argc);} 61 | int cb_cmd_func_50(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(50,ctx, argv, argc);} 62 | int cb_cmd_func_51(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(51,ctx, argv, argc);} 63 | int cb_cmd_func_52(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(52,ctx, argv, argc);} 64 | int cb_cmd_func_53(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(53,ctx, argv, argc);} 65 | int cb_cmd_func_54(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(54,ctx, argv, argc);} 66 | int cb_cmd_func_55(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(55,ctx, argv, argc);} 67 | int cb_cmd_func_56(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(56,ctx, argv, argc);} 68 | int cb_cmd_func_57(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(57,ctx, argv, argc);} 69 | int cb_cmd_func_58(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(58,ctx, argv, argc);} 70 | int cb_cmd_func_59(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(59,ctx, argv, argc);} 71 | int cb_cmd_func_60(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(60,ctx, argv, argc);} 72 | int cb_cmd_func_61(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(61,ctx, argv, argc);} 73 | int cb_cmd_func_62(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(62,ctx, argv, argc);} 74 | int cb_cmd_func_63(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(63,ctx, argv, argc);} 75 | int cb_cmd_func_64(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(64,ctx, argv, argc);} 76 | int cb_cmd_func_65(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(65,ctx, argv, argc);} 77 | int cb_cmd_func_66(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(66,ctx, argv, argc);} 78 | int cb_cmd_func_67(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(67,ctx, argv, argc);} 79 | int cb_cmd_func_68(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(68,ctx, argv, argc);} 80 | int cb_cmd_func_69(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(69,ctx, argv, argc);} 81 | int cb_cmd_func_70(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(70,ctx, argv, argc);} 82 | int cb_cmd_func_71(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(71,ctx, argv, argc);} 83 | int cb_cmd_func_72(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(72,ctx, argv, argc);} 84 | int cb_cmd_func_73(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(73,ctx, argv, argc);} 85 | int cb_cmd_func_74(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(74,ctx, argv, argc);} 86 | int cb_cmd_func_75(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(75,ctx, argv, argc);} 87 | int cb_cmd_func_76(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(76,ctx, argv, argc);} 88 | int cb_cmd_func_77(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(77,ctx, argv, argc);} 89 | int cb_cmd_func_78(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(78,ctx, argv, argc);} 90 | int cb_cmd_func_79(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(79,ctx, argv, argc);} 91 | int cb_cmd_func_80(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(80,ctx, argv, argc);} 92 | int cb_cmd_func_81(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(81,ctx, argv, argc);} 93 | int cb_cmd_func_82(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(82,ctx, argv, argc);} 94 | int cb_cmd_func_83(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(83,ctx, argv, argc);} 95 | int cb_cmd_func_84(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(84,ctx, argv, argc);} 96 | int cb_cmd_func_85(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(85,ctx, argv, argc);} 97 | int cb_cmd_func_86(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(86,ctx, argv, argc);} 98 | int cb_cmd_func_87(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(87,ctx, argv, argc);} 99 | int cb_cmd_func_88(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(88,ctx, argv, argc);} 100 | int cb_cmd_func_89(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(89,ctx, argv, argc);} 101 | int cb_cmd_func_90(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(90,ctx, argv, argc);} 102 | int cb_cmd_func_91(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(91,ctx, argv, argc);} 103 | int cb_cmd_func_92(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(92,ctx, argv, argc);} 104 | int cb_cmd_func_93(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(93,ctx, argv, argc);} 105 | int cb_cmd_func_94(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(94,ctx, argv, argc);} 106 | int cb_cmd_func_95(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(95,ctx, argv, argc);} 107 | int cb_cmd_func_96(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(96,ctx, argv, argc);} 108 | int cb_cmd_func_97(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(97,ctx, argv, argc);} 109 | int cb_cmd_func_98(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(98,ctx, argv, argc);} 110 | int cb_cmd_func_99(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(99,ctx, argv, argc);} 111 | int cb_cmd_func_100(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(100,ctx, argv, argc);} 112 | int cb_cmd_func_101(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(101,ctx, argv, argc);} 113 | int cb_cmd_func_102(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(102,ctx, argv, argc);} 114 | int cb_cmd_func_103(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(103,ctx, argv, argc);} 115 | int cb_cmd_func_104(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(104,ctx, argv, argc);} 116 | int cb_cmd_func_105(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(105,ctx, argv, argc);} 117 | int cb_cmd_func_106(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(106,ctx, argv, argc);} 118 | int cb_cmd_func_107(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(107,ctx, argv, argc);} 119 | int cb_cmd_func_108(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(108,ctx, argv, argc);} 120 | int cb_cmd_func_109(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(109,ctx, argv, argc);} 121 | int cb_cmd_func_110(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(110,ctx, argv, argc);} 122 | int cb_cmd_func_111(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(111,ctx, argv, argc);} 123 | int cb_cmd_func_112(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(112,ctx, argv, argc);} 124 | int cb_cmd_func_113(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(113,ctx, argv, argc);} 125 | int cb_cmd_func_114(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(114,ctx, argv, argc);} 126 | int cb_cmd_func_115(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(115,ctx, argv, argc);} 127 | int cb_cmd_func_116(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(116,ctx, argv, argc);} 128 | int cb_cmd_func_117(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(117,ctx, argv, argc);} 129 | int cb_cmd_func_118(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(118,ctx, argv, argc);} 130 | int cb_cmd_func_119(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(119,ctx, argv, argc);} 131 | int cb_cmd_func_120(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(120,ctx, argv, argc);} 132 | int cb_cmd_func_121(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(121,ctx, argv, argc);} 133 | int cb_cmd_func_122(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(122,ctx, argv, argc);} 134 | int cb_cmd_func_123(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(123,ctx, argv, argc);} 135 | int cb_cmd_func_124(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(124,ctx, argv, argc);} 136 | int cb_cmd_func_125(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(125,ctx, argv, argc);} 137 | int cb_cmd_func_126(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(126,ctx, argv, argc);} 138 | int cb_cmd_func_127(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(127,ctx, argv, argc);} 139 | int cb_cmd_func_128(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(128,ctx, argv, argc);} 140 | int cb_cmd_func_129(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(129,ctx, argv, argc);} 141 | int cb_cmd_func_130(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(130,ctx, argv, argc);} 142 | int cb_cmd_func_131(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(131,ctx, argv, argc);} 143 | int cb_cmd_func_132(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(132,ctx, argv, argc);} 144 | int cb_cmd_func_133(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(133,ctx, argv, argc);} 145 | int cb_cmd_func_134(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(134,ctx, argv, argc);} 146 | int cb_cmd_func_135(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(135,ctx, argv, argc);} 147 | int cb_cmd_func_136(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(136,ctx, argv, argc);} 148 | int cb_cmd_func_137(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(137,ctx, argv, argc);} 149 | int cb_cmd_func_138(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(138,ctx, argv, argc);} 150 | int cb_cmd_func_139(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(139,ctx, argv, argc);} 151 | int cb_cmd_func_140(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(140,ctx, argv, argc);} 152 | int cb_cmd_func_141(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(141,ctx, argv, argc);} 153 | int cb_cmd_func_142(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(142,ctx, argv, argc);} 154 | int cb_cmd_func_143(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(143,ctx, argv, argc);} 155 | int cb_cmd_func_144(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(144,ctx, argv, argc);} 156 | int cb_cmd_func_145(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(145,ctx, argv, argc);} 157 | int cb_cmd_func_146(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(146,ctx, argv, argc);} 158 | int cb_cmd_func_147(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(147,ctx, argv, argc);} 159 | int cb_cmd_func_148(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(148,ctx, argv, argc);} 160 | int cb_cmd_func_149(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(149,ctx, argv, argc);} 161 | int cb_cmd_func_150(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(150,ctx, argv, argc);} 162 | int cb_cmd_func_151(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(151,ctx, argv, argc);} 163 | int cb_cmd_func_152(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(152,ctx, argv, argc);} 164 | int cb_cmd_func_153(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(153,ctx, argv, argc);} 165 | int cb_cmd_func_154(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(154,ctx, argv, argc);} 166 | int cb_cmd_func_155(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(155,ctx, argv, argc);} 167 | int cb_cmd_func_156(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(156,ctx, argv, argc);} 168 | int cb_cmd_func_157(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(157,ctx, argv, argc);} 169 | int cb_cmd_func_158(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(158,ctx, argv, argc);} 170 | int cb_cmd_func_159(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(159,ctx, argv, argc);} 171 | int cb_cmd_func_160(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(160,ctx, argv, argc);} 172 | int cb_cmd_func_161(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(161,ctx, argv, argc);} 173 | int cb_cmd_func_162(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(162,ctx, argv, argc);} 174 | int cb_cmd_func_163(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(163,ctx, argv, argc);} 175 | int cb_cmd_func_164(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(164,ctx, argv, argc);} 176 | int cb_cmd_func_165(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(165,ctx, argv, argc);} 177 | int cb_cmd_func_166(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(166,ctx, argv, argc);} 178 | int cb_cmd_func_167(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(167,ctx, argv, argc);} 179 | int cb_cmd_func_168(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(168,ctx, argv, argc);} 180 | int cb_cmd_func_169(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(169,ctx, argv, argc);} 181 | int cb_cmd_func_170(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(170,ctx, argv, argc);} 182 | int cb_cmd_func_171(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(171,ctx, argv, argc);} 183 | int cb_cmd_func_172(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(172,ctx, argv, argc);} 184 | int cb_cmd_func_173(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(173,ctx, argv, argc);} 185 | int cb_cmd_func_174(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(174,ctx, argv, argc);} 186 | int cb_cmd_func_175(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(175,ctx, argv, argc);} 187 | int cb_cmd_func_176(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(176,ctx, argv, argc);} 188 | int cb_cmd_func_177(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(177,ctx, argv, argc);} 189 | int cb_cmd_func_178(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(178,ctx, argv, argc);} 190 | int cb_cmd_func_179(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(179,ctx, argv, argc);} 191 | int cb_cmd_func_180(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(180,ctx, argv, argc);} 192 | int cb_cmd_func_181(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(181,ctx, argv, argc);} 193 | int cb_cmd_func_182(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(182,ctx, argv, argc);} 194 | int cb_cmd_func_183(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(183,ctx, argv, argc);} 195 | int cb_cmd_func_184(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(184,ctx, argv, argc);} 196 | int cb_cmd_func_185(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(185,ctx, argv, argc);} 197 | int cb_cmd_func_186(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(186,ctx, argv, argc);} 198 | int cb_cmd_func_187(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(187,ctx, argv, argc);} 199 | int cb_cmd_func_188(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(188,ctx, argv, argc);} 200 | int cb_cmd_func_189(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(189,ctx, argv, argc);} 201 | int cb_cmd_func_190(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(190,ctx, argv, argc);} 202 | int cb_cmd_func_191(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(191,ctx, argv, argc);} 203 | int cb_cmd_func_192(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(192,ctx, argv, argc);} 204 | int cb_cmd_func_193(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(193,ctx, argv, argc);} 205 | int cb_cmd_func_194(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(194,ctx, argv, argc);} 206 | int cb_cmd_func_195(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(195,ctx, argv, argc);} 207 | int cb_cmd_func_196(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(196,ctx, argv, argc);} 208 | int cb_cmd_func_197(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(197,ctx, argv, argc);} 209 | int cb_cmd_func_198(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(198,ctx, argv, argc);} 210 | int cb_cmd_func_199(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){return cmd_func_call(199,ctx, argv, argc);} 211 | const RedisModuleCmdFunc cb_cmd_func[] = { 212 | cb_cmd_func_0,cb_cmd_func_1,cb_cmd_func_2,cb_cmd_func_3,cb_cmd_func_4,cb_cmd_func_5,cb_cmd_func_6,cb_cmd_func_7,cb_cmd_func_8,cb_cmd_func_9,cb_cmd_func_10,cb_cmd_func_11,cb_cmd_func_12,cb_cmd_func_13,cb_cmd_func_14,cb_cmd_func_15, 213 | cb_cmd_func_16,cb_cmd_func_17,cb_cmd_func_18,cb_cmd_func_19,cb_cmd_func_20,cb_cmd_func_21,cb_cmd_func_22,cb_cmd_func_23,cb_cmd_func_24,cb_cmd_func_25,cb_cmd_func_26,cb_cmd_func_27,cb_cmd_func_28,cb_cmd_func_29,cb_cmd_func_30, 214 | cb_cmd_func_31,cb_cmd_func_32,cb_cmd_func_33,cb_cmd_func_34,cb_cmd_func_35,cb_cmd_func_36,cb_cmd_func_37,cb_cmd_func_38,cb_cmd_func_39,cb_cmd_func_40,cb_cmd_func_41,cb_cmd_func_42,cb_cmd_func_43,cb_cmd_func_44,cb_cmd_func_45, 215 | cb_cmd_func_46,cb_cmd_func_47,cb_cmd_func_48,cb_cmd_func_49,cb_cmd_func_50,cb_cmd_func_51,cb_cmd_func_52,cb_cmd_func_53,cb_cmd_func_54,cb_cmd_func_55,cb_cmd_func_56,cb_cmd_func_57,cb_cmd_func_58,cb_cmd_func_59,cb_cmd_func_60, 216 | cb_cmd_func_61,cb_cmd_func_62,cb_cmd_func_63,cb_cmd_func_64,cb_cmd_func_65,cb_cmd_func_66,cb_cmd_func_67,cb_cmd_func_68,cb_cmd_func_69,cb_cmd_func_70,cb_cmd_func_71,cb_cmd_func_72,cb_cmd_func_73,cb_cmd_func_74,cb_cmd_func_75, 217 | cb_cmd_func_76,cb_cmd_func_77,cb_cmd_func_78,cb_cmd_func_79,cb_cmd_func_80,cb_cmd_func_81,cb_cmd_func_82,cb_cmd_func_83,cb_cmd_func_84,cb_cmd_func_85,cb_cmd_func_86,cb_cmd_func_87,cb_cmd_func_88,cb_cmd_func_89,cb_cmd_func_90, 218 | cb_cmd_func_91,cb_cmd_func_92,cb_cmd_func_93,cb_cmd_func_94,cb_cmd_func_95,cb_cmd_func_96,cb_cmd_func_97,cb_cmd_func_98,cb_cmd_func_99,cb_cmd_func_100,cb_cmd_func_101,cb_cmd_func_102,cb_cmd_func_103,cb_cmd_func_104,cb_cmd_func_105, 219 | cb_cmd_func_106,cb_cmd_func_107,cb_cmd_func_108,cb_cmd_func_109,cb_cmd_func_110,cb_cmd_func_111,cb_cmd_func_112,cb_cmd_func_113,cb_cmd_func_114,cb_cmd_func_115,cb_cmd_func_116,cb_cmd_func_117,cb_cmd_func_118,cb_cmd_func_119,cb_cmd_func_120, 220 | cb_cmd_func_121,cb_cmd_func_122,cb_cmd_func_123,cb_cmd_func_124,cb_cmd_func_125,cb_cmd_func_126,cb_cmd_func_127,cb_cmd_func_128,cb_cmd_func_129,cb_cmd_func_130,cb_cmd_func_131,cb_cmd_func_132,cb_cmd_func_133,cb_cmd_func_134,cb_cmd_func_135, 221 | cb_cmd_func_136,cb_cmd_func_137,cb_cmd_func_138,cb_cmd_func_139,cb_cmd_func_140,cb_cmd_func_141,cb_cmd_func_142,cb_cmd_func_143,cb_cmd_func_144,cb_cmd_func_145,cb_cmd_func_146,cb_cmd_func_147,cb_cmd_func_148,cb_cmd_func_149,cb_cmd_func_150, 222 | cb_cmd_func_151,cb_cmd_func_152,cb_cmd_func_153,cb_cmd_func_154,cb_cmd_func_155,cb_cmd_func_156,cb_cmd_func_157,cb_cmd_func_158,cb_cmd_func_159,cb_cmd_func_160,cb_cmd_func_161,cb_cmd_func_162,cb_cmd_func_163,cb_cmd_func_164,cb_cmd_func_165, 223 | cb_cmd_func_166,cb_cmd_func_167,cb_cmd_func_168,cb_cmd_func_169,cb_cmd_func_170,cb_cmd_func_171,cb_cmd_func_172,cb_cmd_func_173,cb_cmd_func_174,cb_cmd_func_175,cb_cmd_func_176,cb_cmd_func_177,cb_cmd_func_178,cb_cmd_func_179,cb_cmd_func_180, 224 | cb_cmd_func_181,cb_cmd_func_182,cb_cmd_func_183,cb_cmd_func_184,cb_cmd_func_185,cb_cmd_func_186,cb_cmd_func_187,cb_cmd_func_188,cb_cmd_func_189,cb_cmd_func_190,cb_cmd_func_191,cb_cmd_func_192,cb_cmd_func_193,cb_cmd_func_194,cb_cmd_func_195, 225 | cb_cmd_func_196,cb_cmd_func_197,cb_cmd_func_198,cb_cmd_func_199, 226 | }; 227 | 228 | // mt_rdb_load - RedisModuleTypeLoadFunc 229 | inline int mt_rdb_load_size(){return 5;} 230 | void* cb_mt_rdb_load_0(RedisModuleIO *rdb, int encver){return mt_rdb_load_call(0,rdb, encver);} 231 | void* cb_mt_rdb_load_1(RedisModuleIO *rdb, int encver){return mt_rdb_load_call(1,rdb, encver);} 232 | void* cb_mt_rdb_load_2(RedisModuleIO *rdb, int encver){return mt_rdb_load_call(2,rdb, encver);} 233 | void* cb_mt_rdb_load_3(RedisModuleIO *rdb, int encver){return mt_rdb_load_call(3,rdb, encver);} 234 | void* cb_mt_rdb_load_4(RedisModuleIO *rdb, int encver){return mt_rdb_load_call(4,rdb, encver);} 235 | const RedisModuleTypeLoadFunc cb_mt_rdb_load[] = { 236 | cb_mt_rdb_load_0,cb_mt_rdb_load_1,cb_mt_rdb_load_2,cb_mt_rdb_load_3,cb_mt_rdb_load_4, 237 | }; 238 | 239 | // mt_rdb_save - RedisModuleTypeSaveFunc 240 | inline int mt_rdb_save_size(){return 5;} 241 | void cb_mt_rdb_save_0(RedisModuleIO *rdb, void *value){mt_rdb_save_call(0,rdb, value);} 242 | void cb_mt_rdb_save_1(RedisModuleIO *rdb, void *value){mt_rdb_save_call(1,rdb, value);} 243 | void cb_mt_rdb_save_2(RedisModuleIO *rdb, void *value){mt_rdb_save_call(2,rdb, value);} 244 | void cb_mt_rdb_save_3(RedisModuleIO *rdb, void *value){mt_rdb_save_call(3,rdb, value);} 245 | void cb_mt_rdb_save_4(RedisModuleIO *rdb, void *value){mt_rdb_save_call(4,rdb, value);} 246 | const RedisModuleTypeSaveFunc cb_mt_rdb_save[] = { 247 | cb_mt_rdb_save_0,cb_mt_rdb_save_1,cb_mt_rdb_save_2,cb_mt_rdb_save_3,cb_mt_rdb_save_4, 248 | }; 249 | 250 | // mt_aof_rewrite - RedisModuleTypeRewriteFunc 251 | inline int mt_aof_rewrite_size(){return 5;} 252 | void cb_mt_aof_rewrite_0(RedisModuleIO *aof, RedisModuleString *key, void *value){mt_aof_rewrite_call(0,aof, key, value);} 253 | void cb_mt_aof_rewrite_1(RedisModuleIO *aof, RedisModuleString *key, void *value){mt_aof_rewrite_call(1,aof, key, value);} 254 | void cb_mt_aof_rewrite_2(RedisModuleIO *aof, RedisModuleString *key, void *value){mt_aof_rewrite_call(2,aof, key, value);} 255 | void cb_mt_aof_rewrite_3(RedisModuleIO *aof, RedisModuleString *key, void *value){mt_aof_rewrite_call(3,aof, key, value);} 256 | void cb_mt_aof_rewrite_4(RedisModuleIO *aof, RedisModuleString *key, void *value){mt_aof_rewrite_call(4,aof, key, value);} 257 | const RedisModuleTypeRewriteFunc cb_mt_aof_rewrite[] = { 258 | cb_mt_aof_rewrite_0,cb_mt_aof_rewrite_1,cb_mt_aof_rewrite_2,cb_mt_aof_rewrite_3,cb_mt_aof_rewrite_4, 259 | }; 260 | 261 | // mt_digest - RedisModuleTypeDigestFunc 262 | inline int mt_digest_size(){return 5;} 263 | void cb_mt_digest_0(RedisModuleDigest *digest, void *value){mt_digest_call(0,digest, value);} 264 | void cb_mt_digest_1(RedisModuleDigest *digest, void *value){mt_digest_call(1,digest, value);} 265 | void cb_mt_digest_2(RedisModuleDigest *digest, void *value){mt_digest_call(2,digest, value);} 266 | void cb_mt_digest_3(RedisModuleDigest *digest, void *value){mt_digest_call(3,digest, value);} 267 | void cb_mt_digest_4(RedisModuleDigest *digest, void *value){mt_digest_call(4,digest, value);} 268 | const RedisModuleTypeDigestFunc cb_mt_digest[] = { 269 | cb_mt_digest_0,cb_mt_digest_1,cb_mt_digest_2,cb_mt_digest_3,cb_mt_digest_4, 270 | }; 271 | 272 | // mt_free - RedisModuleTypeFreeFunc 273 | inline int mt_free_size(){return 5;} 274 | void cb_mt_free_0(void *value){mt_free_call(0,value);} 275 | void cb_mt_free_1(void *value){mt_free_call(1,value);} 276 | void cb_mt_free_2(void *value){mt_free_call(2,value);} 277 | void cb_mt_free_3(void *value){mt_free_call(3,value);} 278 | void cb_mt_free_4(void *value){mt_free_call(4,value);} 279 | const RedisModuleTypeFreeFunc cb_mt_free[] = { 280 | cb_mt_free_0,cb_mt_free_1,cb_mt_free_2,cb_mt_free_3,cb_mt_free_4, 281 | }; 282 | #endif 283 | -------------------------------------------------------------------------------- /rm/cmd_flag.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | ) 7 | 8 | // Flags for create command 9 | type CmdFlag string 10 | 11 | const ( 12 | // The command may modify the data set (it may also read from it). 13 | CF_WRITE CmdFlag = "write" 14 | 15 | // The command returns data from keys but never writes. 16 | CF_READONLY = "readonly" 17 | 18 | // The command is an administrative command (may change replication or perform similar tasks). 19 | CF_ADMIN = "admin" 20 | 21 | // The command may use additional memory and should be denied during out of memory conditions. 22 | CF_DENY_OOM = "deny-oom" 23 | 24 | // Don't allow this command in Lua scripts. 25 | CF_DENY_SCRIPT = "deny-script" 26 | 27 | // Allow this command while the server is loading data. 28 | // Only commands not interacting with the data set 29 | // should be allowed to run in this mode. If not sure 30 | // don't use this flag. 31 | CF_ALLOW_LOADING = "allow-loading" 32 | 33 | // The command publishes things on Pub/Sub channels. 34 | CF_PUBSUB = "pubsub" 35 | 36 | // The command may have different outputs even starting from the same input arguments and key values. 37 | CF_RANDOM = "random" 38 | 39 | // The command is allowed to run on slaves that don't 40 | // serve stale data. Don't use if you don't know what 41 | // this means. 42 | CF_ALLOW_STALE = "allow-stale" 43 | 44 | // Don't propoagate the command on monitor. Use this if the command has sensible data among the arguments. 45 | // The command time complexity is not greater 46 | CF_NO_MONITOR = "no-monitor" 47 | 48 | //The command time complexity is not greater 49 | //than O(log(N)) where N is the size of the collection or 50 | //anything else representing the normal scalability 51 | //issue with the command. 52 | CF_FAST = "fast" 53 | 54 | //The command implements the interface to return 55 | //the arguments that are keys. Used when start/stop/step 56 | //is not enough because of the command syntax. 57 | CF_GETKEYS_API = "getkeys-api" 58 | 59 | //The command should not register in Redis Cluster 60 | //since is not designed to work with it because, for 61 | //example, is unable to report the position of the 62 | //keys, programmatically creates key names, or any 63 | //other reason. 64 | CF_NO_CLUSTER = "no-cluster" 65 | ) 66 | 67 | func BuildCommandFlag(f ...CmdFlag) string { 68 | buf := bytes.NewBufferString("") 69 | for _, v := range f { 70 | buf.WriteString(string(v)) 71 | buf.WriteRune(' ') 72 | } 73 | flags := strings.TrimRight(buf.String(), " ") 74 | return flags 75 | } 76 | -------------------------------------------------------------------------------- /rm/decl.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | /* 4 | #include 5 | #include 6 | */ 7 | import "C" 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "github.com/wenerme/letsgo/cutil" 12 | "unsafe" 13 | ) 14 | 15 | //export RedisModule_OnLoad 16 | func RedisModule_OnLoad(ctx uintptr, argv uintptr, argc int) C.int { 17 | return C.int(Ctx(ctx).Load(Mod, toStringSlice(argv, argc))) 18 | } 19 | 20 | //export redis_module_on_unload 21 | func redis_module_on_unload() { 22 | if Mod != nil && Mod.OnUnload != nil { 23 | Mod.OnUnload() 24 | } 25 | } 26 | 27 | //export cmd_func_call 28 | func cmd_func_call(id C.int, ctx uintptr, argv uintptr, argc int) C.int { 29 | args := toStringSlice(argv, argc) 30 | c := Ctx(ctx) 31 | cmd := getCommand(int(id)) 32 | if IsDebugEnabled() { 33 | buf := bytes.NewBufferString(fmt.Sprintf("CmdFuncCall(%v): %v", id, cmd.Name)) 34 | for i := 0; i < argc; i++ { 35 | buf.WriteString(" ") 36 | buf.WriteString(args[i].String()) 37 | } 38 | c.LogDebug(buf.String()) 39 | } 40 | return C.int(cmd.Action(CmdContext{Ctx: c, Args: args})) 41 | } 42 | 43 | func toStringSlice(argv uintptr, argc int) []String { 44 | args := make([]String, argc) 45 | size := int(unsafe.Sizeof(C.uintptr_t(0))) 46 | for i := 0; i < argc; i++ { 47 | ptr := unsafe.Pointer(argv + uintptr(size*i)) 48 | args[i] = String(uintptr(*(*C.uintptr_t)(ptr))) 49 | } 50 | return args 51 | } 52 | 53 | // typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 54 | // typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); 55 | // typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); 56 | // typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); 57 | // typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); 58 | // typedef void (*RedisModuleTypeFreeFunc)(void *value); 59 | 60 | //export mt_rdb_load_call 61 | func mt_rdb_load_call(id int, rdb uintptr, encver int) uintptr { 62 | dt := getDataType(id) 63 | if dt.RdbLoad != nil { 64 | return cutil.PtrToUintptr(dt.RdbLoad(IO(rdb), encver)) 65 | } 66 | return 0 67 | } 68 | 69 | //export mt_rdb_save_call 70 | func mt_rdb_save_call(id int, rdb uintptr, value uintptr) { 71 | dt := getDataType(id) 72 | if dt.RdbSave != nil { 73 | dt.RdbSave(IO(rdb), unsafe.Pointer(value)) 74 | } 75 | } 76 | 77 | //export mt_aof_rewrite_call 78 | func mt_aof_rewrite_call(id int, aof uintptr, key uintptr, value uintptr) { 79 | dt := getDataType(id) 80 | if dt.AofRewrite != nil { 81 | dt.AofRewrite(IO(aof), String(key), unsafe.Pointer(value)) 82 | } 83 | } 84 | 85 | //export mt_digest_call 86 | func mt_digest_call(id int, digest uintptr, value uintptr) { 87 | dt := getDataType(id) 88 | if dt.Digest != nil { 89 | dt.Digest(Digest(digest), unsafe.Pointer(value)) 90 | } 91 | } 92 | 93 | //export mt_free_call 94 | func mt_free_call(id int, value uintptr) { 95 | dt := getDataType(id) 96 | if dt.Free != nil { 97 | dt.Free(unsafe.Pointer(value)) 98 | } 99 | } 100 | 101 | func init() { 102 | // Preserve import "C" 103 | _ = C.int(0) 104 | } 105 | -------------------------------------------------------------------------------- /rm/decl.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_RM_DECL_H 2 | #define GO_RM_DECL_H 3 | 4 | #include "./redismodule.h" 5 | 6 | extern int RedisModule_OnLoad(RedisModuleCtx *ctx); 7 | 8 | extern int cmd_func_call(int id, RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 9 | 10 | extern void *mt_rdb_load_call(int id, RedisModuleIO *rdb, int encver); 11 | extern void mt_rdb_save_call(int id, RedisModuleIO *rdb, void *value); 12 | extern void mt_aof_rewrite_call(int id, RedisModuleIO *aof, RedisModuleString *key, void *value); 13 | extern void mt_digest_call(int id, RedisModuleDigest *digest, void *value); 14 | extern void mt_free_call(int id, void *value); 15 | 16 | extern void redis_module_on_unload(); 17 | void __attribute__((destructor)) OnUnload_Hack(void) { 18 | redis_module_on_unload(); 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /rm/hw_wrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_RM_HW_WRAPPER_H 2 | #define GO_RM_HW_WRAPPER_H 3 | 4 | #include "./redismodule.h" 5 | 6 | // Hand write wrapper because these function not defined in API.md 7 | 8 | //void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); 9 | void LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt){ 10 | RedisModule_LogIOError(io,levelstr,fmt,0); 11 | } 12 | 13 | //int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); 14 | int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len){ 15 | return RedisModule_StringAppendBuffer(ctx,str,buf,len); 16 | } 17 | 18 | //void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str); 19 | void RetainString(RedisModuleCtx *ctx, RedisModuleString *str){ 20 | return RedisModule_RetainString(ctx,str); 21 | } 22 | 23 | // int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b); 24 | int StringCompare(RedisModuleString *a, RedisModuleString *b){ 25 | return RedisModule_StringCompare(a,b); 26 | } 27 | 28 | //RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io); 29 | RedisModuleCtx * GetContextFromIO(RedisModuleIO *io){ 30 | return RedisModule_GetContextFromIO(io); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /rm/mod.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | import ( 4 | "strconv" 5 | "time" 6 | ) 7 | 8 | // Redis module definition 9 | type Module struct { 10 | Name string 11 | Version int 12 | SemVer string 13 | Commands []Command `json:",omitempty"` 14 | DataTypes []DataType `json:",omitempty"` 15 | 16 | BeforeInit func(Ctx, []String) error `json:"-"` 17 | AfterInit func(Ctx, []String) error `json:"-"` 18 | // When module unload 19 | // ! Very unstable, try to avoid this 20 | OnUnload func() `json:"-"` 21 | 22 | // Compilation date 23 | Compiled time.Time 24 | // List of all authors who contributed 25 | //Authors []Author 26 | // Copyright of the binary if any 27 | Copyright string `json:",omitempty"` 28 | // Name of Author (Note: Use App.Authors, this is deprecated) 29 | Author string `json:",omitempty"` 30 | Website string `json:",omitempty"` 31 | // Email of Author (Note: Use App.Authors, this is deprecated) 32 | Email string `json:",omitempty"` 33 | // Long description for this module 34 | Desc string `json:",omitempty"` 35 | // Will log more things 36 | Debug bool 37 | } 38 | 39 | // Is debug enabled 40 | func IsDebugEnabled() bool { 41 | // TODO Check redis log level 42 | return true 43 | } 44 | 45 | type Command struct { 46 | Usage string 47 | Desc string 48 | Name string 49 | Action CmdFunc `json:"-"` 50 | // Use BuildCommandFLags to generate this flags 51 | Flags string 52 | FirstKey int 53 | LastKey int 54 | KeyStep int 55 | } 56 | 57 | func NewMod() *Module { 58 | return &Module{} 59 | } 60 | 61 | // This module will be loaded 62 | var Mod *Module 63 | 64 | func init() { 65 | if Mod != nil { 66 | if Mod.SemVer == "" { 67 | Mod.SemVer = strconv.Itoa(Mod.Version) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /rm/redismodule.h: -------------------------------------------------------------------------------- 1 | #ifndef REDISMODULE_H 2 | #define REDISMODULE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* ---------------- Defines common between core and modules --------------- */ 9 | 10 | /* Error status return values. */ 11 | #define REDISMODULE_OK 0 12 | #define REDISMODULE_ERR 1 13 | 14 | /* API versions. */ 15 | #define REDISMODULE_APIVER_1 1 16 | 17 | /* API flags and constants */ 18 | #define REDISMODULE_READ (1<<0) 19 | #define REDISMODULE_WRITE (1<<1) 20 | 21 | #define REDISMODULE_LIST_HEAD 0 22 | #define REDISMODULE_LIST_TAIL 1 23 | 24 | /* Key types. */ 25 | #define REDISMODULE_KEYTYPE_EMPTY 0 26 | #define REDISMODULE_KEYTYPE_STRING 1 27 | #define REDISMODULE_KEYTYPE_LIST 2 28 | #define REDISMODULE_KEYTYPE_HASH 3 29 | #define REDISMODULE_KEYTYPE_SET 4 30 | #define REDISMODULE_KEYTYPE_ZSET 5 31 | #define REDISMODULE_KEYTYPE_MODULE 6 32 | 33 | /* Reply types. */ 34 | #define REDISMODULE_REPLY_UNKNOWN -1 35 | #define REDISMODULE_REPLY_STRING 0 36 | #define REDISMODULE_REPLY_ERROR 1 37 | #define REDISMODULE_REPLY_INTEGER 2 38 | #define REDISMODULE_REPLY_ARRAY 3 39 | #define REDISMODULE_REPLY_NULL 4 40 | 41 | /* Postponed array length. */ 42 | #define REDISMODULE_POSTPONED_ARRAY_LEN -1 43 | 44 | /* Expire */ 45 | #define REDISMODULE_NO_EXPIRE -1 46 | 47 | /* Sorted set API flags. */ 48 | #define REDISMODULE_ZADD_XX (1<<0) 49 | #define REDISMODULE_ZADD_NX (1<<1) 50 | #define REDISMODULE_ZADD_ADDED (1<<2) 51 | #define REDISMODULE_ZADD_UPDATED (1<<3) 52 | #define REDISMODULE_ZADD_NOP (1<<4) 53 | 54 | /* Hash API flags. */ 55 | #define REDISMODULE_HASH_NONE 0 56 | #define REDISMODULE_HASH_NX (1<<0) 57 | #define REDISMODULE_HASH_XX (1<<1) 58 | #define REDISMODULE_HASH_CFIELDS (1<<2) 59 | #define REDISMODULE_HASH_EXISTS (1<<3) 60 | 61 | /* A special pointer that we can use between the core and the module to signal 62 | * field deletion, and that is impossible to be a valid pointer. */ 63 | #define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1) 64 | 65 | /* Error messages. */ 66 | #define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value" 67 | 68 | #define REDISMODULE_POSITIVE_INFINITE (1.0/0.0) 69 | #define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0) 70 | 71 | /* ------------------------- End of common defines ------------------------ */ 72 | 73 | #ifndef REDISMODULE_CORE 74 | 75 | typedef long long mstime_t; 76 | 77 | /* Incomplete structures for compiler checks but opaque access. */ 78 | typedef struct RedisModuleCtx RedisModuleCtx; 79 | typedef struct RedisModuleKey RedisModuleKey; 80 | typedef struct RedisModuleString RedisModuleString; 81 | typedef struct RedisModuleCallReply RedisModuleCallReply; 82 | typedef struct RedisModuleIO RedisModuleIO; 83 | typedef struct RedisModuleType RedisModuleType; 84 | typedef struct RedisModuleDigest RedisModuleDigest; 85 | 86 | typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 87 | 88 | typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); 89 | typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); 90 | typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); 91 | typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); 92 | typedef void (*RedisModuleTypeFreeFunc)(void *value); 93 | 94 | #define REDISMODULE_GET_API(name) \ 95 | RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name)) 96 | 97 | #define REDISMODULE_API_FUNC(x) (*x) 98 | 99 | 100 | void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes); 101 | void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes); 102 | void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr); 103 | void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size); 104 | char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str); 105 | int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *); 106 | int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); 107 | int REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver); 108 | int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx); 109 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll); 110 | int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx); 111 | int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid); 112 | void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); 113 | void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp); 114 | int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp); 115 | size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp); 116 | int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele); 117 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where); 118 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); 119 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len); 120 | void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply); 121 | int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply); 122 | long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply); 123 | size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply); 124 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx); 125 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len); 126 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll); 127 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str); 128 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...); 129 | void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str); 130 | const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len); 131 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err); 132 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg); 133 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len); 134 | void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len); 135 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len); 136 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str); 137 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx); 138 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d); 139 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply); 140 | int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll); 141 | int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d); 142 | void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx); 143 | int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); 144 | int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx); 145 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len); 146 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply); 147 | int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key); 148 | int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str); 149 | char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode); 150 | int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen); 151 | mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key); 152 | int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire); 153 | int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); 154 | int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); 155 | int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score); 156 | int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted); 157 | void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key); 158 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex); 159 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex); 160 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); 161 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); 162 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score); 163 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key); 164 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key); 165 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key); 166 | int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...); 167 | int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...); 168 | int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx); 169 | void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos); 170 | unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx); 171 | void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes); 172 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeLoadFunc rdb_load, RedisModuleTypeSaveFunc rdb_save, RedisModuleTypeRewriteFunc aof_rewrite, RedisModuleTypeDigestFunc digest, RedisModuleTypeFreeFunc free); 173 | int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value); 174 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key); 175 | void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key); 176 | void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value); 177 | uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io); 178 | void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value); 179 | int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io); 180 | void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); 181 | void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s); 182 | void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len); 183 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io); 184 | char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr); 185 | void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value); 186 | double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io); 187 | void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value); 188 | float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io); 189 | void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); 190 | void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); 191 | int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); 192 | void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str); 193 | int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b); 194 | RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io); 195 | 196 | /* This is included inline inside each Redis module. */ 197 | static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused)); 198 | static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) { 199 | void *getapifuncptr = ((void**)ctx)[0]; 200 | RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr; 201 | REDISMODULE_GET_API(Alloc); 202 | REDISMODULE_GET_API(Calloc); 203 | REDISMODULE_GET_API(Free); 204 | REDISMODULE_GET_API(Realloc); 205 | REDISMODULE_GET_API(Strdup); 206 | REDISMODULE_GET_API(CreateCommand); 207 | REDISMODULE_GET_API(SetModuleAttribs); 208 | REDISMODULE_GET_API(WrongArity); 209 | REDISMODULE_GET_API(ReplyWithLongLong); 210 | REDISMODULE_GET_API(ReplyWithError); 211 | REDISMODULE_GET_API(ReplyWithSimpleString); 212 | REDISMODULE_GET_API(ReplyWithArray); 213 | REDISMODULE_GET_API(ReplySetArrayLength); 214 | REDISMODULE_GET_API(ReplyWithStringBuffer); 215 | REDISMODULE_GET_API(ReplyWithString); 216 | REDISMODULE_GET_API(ReplyWithNull); 217 | REDISMODULE_GET_API(ReplyWithCallReply); 218 | REDISMODULE_GET_API(ReplyWithDouble); 219 | REDISMODULE_GET_API(ReplySetArrayLength); 220 | REDISMODULE_GET_API(GetSelectedDb); 221 | REDISMODULE_GET_API(SelectDb); 222 | REDISMODULE_GET_API(OpenKey); 223 | REDISMODULE_GET_API(CloseKey); 224 | REDISMODULE_GET_API(KeyType); 225 | REDISMODULE_GET_API(ValueLength); 226 | REDISMODULE_GET_API(ListPush); 227 | REDISMODULE_GET_API(ListPop); 228 | REDISMODULE_GET_API(StringToLongLong); 229 | REDISMODULE_GET_API(StringToDouble); 230 | REDISMODULE_GET_API(Call); 231 | REDISMODULE_GET_API(CallReplyProto); 232 | REDISMODULE_GET_API(FreeCallReply); 233 | REDISMODULE_GET_API(CallReplyInteger); 234 | REDISMODULE_GET_API(CallReplyType); 235 | REDISMODULE_GET_API(CallReplyLength); 236 | REDISMODULE_GET_API(CallReplyArrayElement); 237 | REDISMODULE_GET_API(CallReplyStringPtr); 238 | REDISMODULE_GET_API(CreateStringFromCallReply); 239 | REDISMODULE_GET_API(CreateString); 240 | REDISMODULE_GET_API(CreateStringFromLongLong); 241 | REDISMODULE_GET_API(CreateStringFromString); 242 | REDISMODULE_GET_API(CreateStringPrintf); 243 | REDISMODULE_GET_API(FreeString); 244 | REDISMODULE_GET_API(StringPtrLen); 245 | REDISMODULE_GET_API(AutoMemory); 246 | REDISMODULE_GET_API(Replicate); 247 | REDISMODULE_GET_API(ReplicateVerbatim); 248 | REDISMODULE_GET_API(DeleteKey); 249 | REDISMODULE_GET_API(StringSet); 250 | REDISMODULE_GET_API(StringDMA); 251 | REDISMODULE_GET_API(StringTruncate); 252 | REDISMODULE_GET_API(GetExpire); 253 | REDISMODULE_GET_API(SetExpire); 254 | REDISMODULE_GET_API(ZsetAdd); 255 | REDISMODULE_GET_API(ZsetIncrby); 256 | REDISMODULE_GET_API(ZsetScore); 257 | REDISMODULE_GET_API(ZsetRem); 258 | REDISMODULE_GET_API(ZsetRangeStop); 259 | REDISMODULE_GET_API(ZsetFirstInScoreRange); 260 | REDISMODULE_GET_API(ZsetLastInScoreRange); 261 | REDISMODULE_GET_API(ZsetFirstInLexRange); 262 | REDISMODULE_GET_API(ZsetLastInLexRange); 263 | REDISMODULE_GET_API(ZsetRangeCurrentElement); 264 | REDISMODULE_GET_API(ZsetRangeNext); 265 | REDISMODULE_GET_API(ZsetRangePrev); 266 | REDISMODULE_GET_API(ZsetRangeEndReached); 267 | REDISMODULE_GET_API(HashSet); 268 | REDISMODULE_GET_API(HashGet); 269 | REDISMODULE_GET_API(IsKeysPositionRequest); 270 | REDISMODULE_GET_API(KeyAtPos); 271 | REDISMODULE_GET_API(GetClientId); 272 | REDISMODULE_GET_API(PoolAlloc); 273 | REDISMODULE_GET_API(CreateDataType); 274 | REDISMODULE_GET_API(ModuleTypeSetValue); 275 | REDISMODULE_GET_API(ModuleTypeGetType); 276 | REDISMODULE_GET_API(ModuleTypeGetValue); 277 | REDISMODULE_GET_API(SaveUnsigned); 278 | REDISMODULE_GET_API(LoadUnsigned); 279 | REDISMODULE_GET_API(SaveSigned); 280 | REDISMODULE_GET_API(LoadSigned); 281 | REDISMODULE_GET_API(SaveString); 282 | REDISMODULE_GET_API(SaveStringBuffer); 283 | REDISMODULE_GET_API(LoadString); 284 | REDISMODULE_GET_API(LoadStringBuffer); 285 | REDISMODULE_GET_API(SaveDouble); 286 | REDISMODULE_GET_API(LoadDouble); 287 | REDISMODULE_GET_API(SaveFloat); 288 | REDISMODULE_GET_API(LoadFloat); 289 | REDISMODULE_GET_API(EmitAOF); 290 | REDISMODULE_GET_API(Log); 291 | REDISMODULE_GET_API(LogIOError); 292 | REDISMODULE_GET_API(StringAppendBuffer); 293 | REDISMODULE_GET_API(RetainString); 294 | REDISMODULE_GET_API(StringCompare); 295 | REDISMODULE_GET_API(GetContextFromIO); 296 | 297 | RedisModule_SetModuleAttribs(ctx,name,ver,apiver); 298 | return REDISMODULE_OK; 299 | } 300 | 301 | #else 302 | 303 | /* Things only defined for the modules core, not exported to modules 304 | * including this file. */ 305 | #define RedisModuleString robj 306 | 307 | #endif /* REDISMODULE_CORE */ 308 | #endif /* REDISMOUDLE_H */ 309 | -------------------------------------------------------------------------------- /rm/rm.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_RM_RM_H 2 | #define GO_RM_RM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "./redismodule.h" 8 | #include "./callbacks.h" 9 | #include "./wrapper.h" 10 | #include "./varargs.h" 11 | 12 | int ReplyWithOK(RedisModuleCtx* ctx){return RedisModule_ReplyWithSimpleString(ctx,"OK");} 13 | int ModuleTypeSetValuePtr(RedisModuleKey* key,RedisModuleType* mt,uintptr_t value){return RedisModule_ModuleTypeSetValue(key,mt,(void*)(value));} 14 | 15 | int CreateCommandCallID(RedisModuleCtx *ctx,int id, const char *name, const char *strflags, int firstkey, int lastkey, int keystep) { 16 | return RedisModule_CreateCommand(ctx, name, cb_cmd_func[id], strflags, firstkey, lastkey, keystep); 17 | } 18 | 19 | uintptr_t CreateDataTypeCallID(RedisModuleCtx* ctx,int id,const char* name,int encver){ 20 | RedisModuleTypeLoadFunc rdb_load =cb_mt_rdb_load[id]; 21 | RedisModuleTypeSaveFunc rdb_save =cb_mt_rdb_save[id]; 22 | RedisModuleTypeRewriteFunc aof_rewrite =cb_mt_aof_rewrite[id]; 23 | RedisModuleTypeDigestFunc digest =cb_mt_digest[id]; 24 | RedisModuleTypeFreeFunc free =cb_mt_free[id]; 25 | return (uintptr_t)CreateDataType(ctx,name,encver,rdb_load,rdb_save,aof_rewrite,digest,free); 26 | } 27 | 28 | #define LOG_DEBUG "debug" 29 | #define LOG_VERBOSE "verbose" 30 | #define LOG_NOTICE "notice" 31 | #define LOG_WARNING "warning" 32 | 33 | void CtxLog(RedisModuleCtx *ctx, int level, const char *fmt) { 34 | char *l; 35 | switch (level) { 36 | default: 37 | case 0: 38 | l = LOG_DEBUG; 39 | break; 40 | case 1: 41 | l = LOG_VERBOSE; 42 | break; 43 | case 2: 44 | l = LOG_NOTICE; 45 | break; 46 | case 3: 47 | l = LOG_WARNING; 48 | break; 49 | } 50 | RedisModule_Log(ctx, l, fmt); 51 | } 52 | 53 | int get_errno(){ 54 | return errno; 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /rm/run.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/urfave/cli" 6 | "os" 7 | "strings" 8 | "text/template" 9 | ) 10 | 11 | // Handler main invoke 12 | func Run() { 13 | app := cli.NewApp() 14 | app.Name = Mod.Name 15 | app.Email = Mod.Email 16 | app.Author = Mod.Author 17 | app.Copyright = Mod.Copyright 18 | app.Version = Mod.SemVer 19 | app.Action = func(ctx *cli.Context) error { 20 | tpl, err := template.New("info").Parse(`{{"" -}} 21 | Redis module {{.Name}} version {{.Version}} semver {{.SemVer}} 22 | {{- if .Author}} created by {{.Author}} 23 | {{- if .Email}} <{{.Email}}>{{end -}} 24 | {{- end}} 25 | Include Command({{len .Commands}}){{"{"}}{{range $_,$v := .Commands}} {{$v.Name}} {{end}}} 26 | Include DataType({{len .DataTypes}}){{"{"}}{{range $_,$v := .DataTypes}} {{$v.Name}} {{end}}} 27 | {{- if .Website}} 28 | Know more from {{.Website}}{{end}} 29 | 30 | This should be build by 31 | 32 | go build -v -buildmode=c-shared 33 | 34 | Then you can load this redismodule by 35 | 36 | redis-server --loadmodule {{.Name}} --loglevel debug 37 | 38 | `) 39 | if err != nil { 40 | return err 41 | } 42 | err = tpl.Execute(os.Stdout, Mod) 43 | if err != nil { 44 | return err 45 | } 46 | return nil 47 | } 48 | app.Commands = []cli.Command{ 49 | { 50 | Name: "info", 51 | Action: func(ctx *cli.Context) error { 52 | b, err := json.MarshalIndent(Mod, " ", " ") 53 | if err != nil { 54 | return err 55 | } 56 | os.Stdout.Write(b) 57 | os.Stdout.Sync() 58 | return nil 59 | }, 60 | }, 61 | } 62 | if false { 63 | // Test info output 64 | app.Run(strings.Split("redismodule info", " ")) 65 | } 66 | app.RunAndExitOnError() 67 | } 68 | -------------------------------------------------------------------------------- /rm/types.go: -------------------------------------------------------------------------------- 1 | package rm 2 | 3 | // #include 4 | // inline intptr_t PtrToInt(void* ptr){return (intptr_t)ptr;} 5 | import ( 6 | "fmt" 7 | "github.com/wenerme/letsgo/cutil" 8 | "os" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | type Ctx uintptr 14 | type CallReply struct { 15 | uintptr 16 | errono syscall.Errno 17 | } 18 | type String uintptr 19 | type Key uintptr 20 | type IO uintptr 21 | type Digest uintptr 22 | type ModuleType uintptr 23 | 24 | type CmdFunc func(args CmdContext) int 25 | 26 | type ZsetKey Key 27 | type HashKey Key 28 | type ListKey Key 29 | type StringKey Key 30 | 31 | func CreateString(ptr unsafe.Pointer) String { 32 | return String(cutil.PtrToUintptr(ptr)) 33 | } 34 | func CreateCallReply(ptr unsafe.Pointer) CallReply { 35 | return CallReply{cutil.PtrToUintptr(ptr), getErrno()} 36 | } 37 | func CreateCallReplyError(errno syscall.Errno) CallReply { 38 | return CallReply{0, errno} 39 | } 40 | func NullString() String { 41 | return CreateString(NullPointer()) 42 | } 43 | func NullPointer() unsafe.Pointer { 44 | return unsafe.Pointer(uintptr(0)) 45 | } 46 | 47 | type DataType struct { 48 | Desc string 49 | // A 9 characters data type name that MUST be unique in the Redis 50 | // Modules ecosystem. Be creative... and there will be no collisions. Use 51 | // the charset A-Z a-z 9-0, plus the two "-_" characters. A good 52 | // idea is to use, for example `-`. For example 53 | // "tree-AntZ" may mean "Tree data structure by @antirez". To use both 54 | // lower case and upper case letters helps in order to prevent collisions. 55 | // 56 | // Note: the module name "AAAAAAAAA" is reserved and produces an error, it 57 | // happens to be pretty lame as well. 58 | Name string 59 | // Encoding version, which is, the version of the serialization 60 | // that a module used in order to persist data. As long as the "name" 61 | // matches, the RDB loading will be dispatched to the type callbacks 62 | // whatever 'encver' is used, however the module can understand if 63 | // the encoding it must load are of an older version of the module. 64 | // For example the module "tree-AntZ" initially used encver=0. Later 65 | // after an upgrade, it started to serialize data in a different format 66 | // and to register the type with encver=1. However this module may 67 | // still load old data produced by an older version if the rdb_load 68 | // callback is able to check the encver value and act accordingly. 69 | // The encver must be a positive value between 0 and 1023. 70 | EncVer int 71 | // A callback function pointer that loads data from RDB files. 72 | RdbLoad func(rdb IO, encver int) unsafe.Pointer `json:"-"` 73 | // A callback function pointer that saves data to RDB files. 74 | RdbSave func(rdb IO, value unsafe.Pointer) `json:"-"` 75 | // A callback function pointer that rewrites data as commands. 76 | AofRewrite func(aof IO, key String, value unsafe.Pointer) `json:"-"` 77 | // A callback function pointer that is used for `DEBUG DIGEST`. 78 | Digest func(digest Digest, value unsafe.Pointer) `json:"-"` 79 | // A callback function pointer that can free a type value. 80 | Free func(value unsafe.Pointer) `json:"-"` 81 | } 82 | type LogLevel int 83 | 84 | const ( 85 | LOG_DEBUG LogLevel = iota 86 | LOG_VERBOSE 87 | LOG_NOTICE 88 | LOG_WARNING 89 | ) 90 | 91 | type CmdContext struct { 92 | Ctx Ctx 93 | Args []String 94 | } 95 | 96 | func init() { 97 | //LogDebug("Init Go Redis module") 98 | } 99 | 100 | var LogDebug = func(format string, args ...interface{}) { 101 | fmt.Fprintf(os.Stdout, format+"\n", args...) 102 | } 103 | var LogError = func(format string, args ...interface{}) { 104 | fmt.Fprintf(os.Stderr, format+"\n", args...) 105 | } 106 | 107 | func (v String) ptr() unsafe.Pointer { 108 | return unsafe.Pointer(v) 109 | } 110 | func (v Ctx) ptr() unsafe.Pointer { 111 | return unsafe.Pointer(v) 112 | } 113 | func (v CallReply) ptr() unsafe.Pointer { 114 | return unsafe.Pointer(v.uintptr) 115 | } 116 | func (v IO) ptr() unsafe.Pointer { 117 | return unsafe.Pointer(v) 118 | } 119 | func (v Key) ptr() unsafe.Pointer { 120 | return unsafe.Pointer(v) 121 | } 122 | func (v ModuleType) ptr() unsafe.Pointer { 123 | return unsafe.Pointer(v) 124 | } 125 | func (v String) IsNull() bool { 126 | return uintptr(v) == 0 127 | } 128 | func (v Ctx) IsNull() bool { 129 | return uintptr(v) == 0 130 | } 131 | func (v CallReply) IsNull() bool { 132 | return uintptr(v.uintptr) == 0 133 | } 134 | func (v CallReply) IsErrno() (bool, syscall.Errno) { 135 | return v.errono != 0, v.errono 136 | } 137 | func (v IO) IsNull() bool { 138 | return uintptr(v) == 0 139 | } 140 | func (v Key) IsNull() bool { 141 | return uintptr(v) == 0 142 | } 143 | func (v ModuleType) IsNull() bool { 144 | return uintptr(v) == 0 145 | } 146 | -------------------------------------------------------------------------------- /rm/varargs.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_RM_VARARGS_H 2 | #define GO_RM_VARARGS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "./redismodule.h" 8 | #include "./wrapper.h" 9 | 10 | /** 11 | * This header file contains varargs call dispatcher's. 12 | * Go don't support call C's varargs method,to generate a lot methods 13 | * to simulate the varargs effect. 14 | * 15 | * cmd/cgo: cannot call functions with variable-argument lists. 16 | * https://github.com/golang/go/issues/975 17 | */ 18 | 19 | // Generated by gen.es6 20 | // region Generated 21 | RedisModuleCallReply * CallVar(RedisModuleCtx *key, const char *cmdname, const char *fmt, const int argc,const intptr_t argv[]){ 22 | switch(argc){ 23 | case 0: return RedisModule_Call(key, cmdname, fmt); 24 | case 1: return RedisModule_Call(key, cmdname, fmt,argv[0]); 25 | case 2: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1]); 26 | case 3: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2]); 27 | case 4: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3]); 28 | case 5: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4]); 29 | case 6: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]); 30 | case 7: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6]); 31 | case 8: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7]); 32 | case 9: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8]); 33 | case 10: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9]); 34 | case 11: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10]); 35 | case 12: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11]); 36 | case 13: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12]); 37 | case 14: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13]); 38 | case 15: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14]); 39 | case 16: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15]); 40 | case 17: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16]); 41 | case 18: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17]); 42 | case 19: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18]); 43 | case 20: return RedisModule_Call(key, cmdname, fmt,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18],argv[19]); 44 | 45 | default: 46 | errno=EINVAL; 47 | return NULL; 48 | } 49 | } 50 | /* Hash */ 51 | 52 | int HashSetVar(RedisModuleKey *key, int flags,int argc, intptr_t argv[]){ 53 | switch(argc){ 54 | case 0: return RedisModule_HashSet(key, flags); 55 | case 1: return RedisModule_HashSet(key, flags,argv[0]); 56 | case 2: return RedisModule_HashSet(key, flags,argv[0],argv[1]); 57 | case 3: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2]); 58 | case 4: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3]); 59 | case 5: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4]); 60 | case 6: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]); 61 | case 7: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6]); 62 | case 8: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7]); 63 | case 9: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8]); 64 | case 10: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9]); 65 | case 11: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10]); 66 | case 12: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11]); 67 | case 13: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12]); 68 | case 14: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13]); 69 | case 15: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14]); 70 | case 16: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15]); 71 | case 17: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16]); 72 | case 18: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17]); 73 | case 19: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18]); 74 | case 20: return RedisModule_HashSet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18],argv[19]); 75 | 76 | default: 77 | return REDISMODULE_ERR; 78 | } 79 | } 80 | 81 | int HashGetVar(RedisModuleKey *key, int flags,int argc, intptr_t argv[]){ 82 | switch(argc){ 83 | case 0: return RedisModule_HashGet(key, flags); 84 | case 1: return RedisModule_HashGet(key, flags,argv[0]); 85 | case 2: return RedisModule_HashGet(key, flags,argv[0],argv[1]); 86 | case 3: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2]); 87 | case 4: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3]); 88 | case 5: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4]); 89 | case 6: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]); 90 | case 7: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6]); 91 | case 8: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7]); 92 | case 9: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8]); 93 | case 10: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9]); 94 | case 11: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10]); 95 | case 12: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11]); 96 | case 13: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12]); 97 | case 14: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13]); 98 | case 15: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14]); 99 | case 16: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15]); 100 | case 17: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16]); 101 | case 18: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17]); 102 | case 19: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18]); 103 | case 20: return RedisModule_HashGet(key, flags,argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],argv[7],argv[8],argv[9],argv[10],argv[11],argv[12],argv[13],argv[14],argv[15],argv[16],argv[17],argv[18],argv[19]); 104 | 105 | default: 106 | return REDISMODULE_ERR; 107 | } 108 | } 109 | // endregion 110 | #endif 111 | -------------------------------------------------------------------------------- /rm/wrapper.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GO_RM_WRAPPER_H 3 | #define GO_RM_WRAPPER_H 4 | 5 | #include "./redismodule.h" 6 | #include "./hw_wrapper.h" 7 | 8 | 9 | // Use like malloc(). Memory allocated with this function is reported in 10 | // Redis INFO memory, used for keys eviction according to maxmemory settings 11 | // and in general is taken into account as memory allocated by Redis. 12 | // You should avoid to use malloc(). 13 | void* Alloc(size_t bytes){return RedisModule_Alloc(bytes);} 14 | 15 | // Use like realloc() for memory obtained with `RedisModule_Alloc()`. 16 | void* Realloc(void* ptr,size_t bytes){return RedisModule_Realloc(ptr,bytes);} 17 | 18 | // Use like free() for memory obtained by `RedisModule_Alloc()` and 19 | // `RedisModule_Realloc()`. However you should never try to free with 20 | // `RedisModule_Free()` memory allocated with malloc() inside your module. 21 | void Free(void* ptr){RedisModule_Free(ptr);} 22 | 23 | // Like strdup() but returns memory allocated with `RedisModule_Alloc()`. 24 | char* Strdup(const char* str){return RedisModule_Strdup(str);} 25 | 26 | // Return heap allocated memory that will be freed automatically when the 27 | // module callback function returns. Mostly suitable for small allocations 28 | // that are short living and must be released when the callback returns 29 | // anyway. The returned memory is aligned to the architecture word size 30 | // if at least word size bytes are requested, otherwise it is just 31 | // aligned to the next power of two, so for example a 3 bytes request is 32 | // 4 bytes aligned while a 2 bytes request is 2 bytes aligned. 33 | // 34 | // There is no realloc style function since when this is needed to use the 35 | // pool allocator is not a good idea. 36 | // 37 | // The function returns NULL if `bytes` is 0. 38 | void* PoolAlloc(RedisModuleCtx* ctx,size_t bytes){return RedisModule_PoolAlloc(ctx,bytes);} 39 | 40 | // Lookup the requested module API and store the function pointer into the 41 | // target pointer. The function returns `REDISMODULE_ERR` if there is no such 42 | // named API, otherwise `REDISMODULE_OK`. 43 | // 44 | // This function is not meant to be used by modules developer, it is only 45 | // used implicitly by including redismodule.h. 46 | int GetApi(const char* funcname,void** targetPtrPtr){return RedisModule_GetApi(funcname,targetPtrPtr);} 47 | 48 | // Return non-zero if a module command, that was declared with the 49 | // flag "getkeys-api", is called in a special way to get the keys positions 50 | // and not to get executed. Otherwise zero is returned. 51 | int IsKeysPositionRequest(RedisModuleCtx* ctx){return RedisModule_IsKeysPositionRequest(ctx);} 52 | 53 | // When a module command is called in order to obtain the position of 54 | // keys, since it was flagged as "getkeys-api" during the registration, 55 | // the command implementation checks for this special call using the 56 | // `RedisModule_IsKeysPositionRequest()` API and uses this function in 57 | // order to report keys, like in the following example: 58 | // 59 | // if (`RedisModule_IsKeysPositionRequest(ctx))` { 60 | // `RedisModule_KeyAtPos(ctx`,1); 61 | // `RedisModule_KeyAtPos(ctx`,2); 62 | // } 63 | // 64 | // Note: in the example below the get keys API would not be needed since 65 | // keys are at fixed positions. This interface is only used for commands 66 | // with a more complex structure. 67 | void KeyAtPos(RedisModuleCtx* ctx,int pos){RedisModule_KeyAtPos(ctx,pos);} 68 | 69 | // And is supposed to always return `REDISMODULE_OK`. 70 | // 71 | // The set of flags 'strflags' specify the behavior of the command, and should 72 | // be passed as a C string compoesd of space separated words, like for 73 | // example "write deny-oom". The set of flags are: 74 | // 75 | // * **"write"**: The command may modify the data set (it may also read 76 | // from it). 77 | // * **"readonly"**: The command returns data from keys but never writes. 78 | // * **"admin"**: The command is an administrative command (may change 79 | // replication or perform similar tasks). 80 | // * **"deny-oom"**: The command may use additional memory and should be 81 | // denied during out of memory conditions. 82 | // * **"deny-script"**: Don't allow this command in Lua scripts. 83 | // * **"allow-loading"**: Allow this command while the server is loading data. 84 | // Only commands not interacting with the data set 85 | // should be allowed to run in this mode. If not sure 86 | // don't use this flag. 87 | // * **"pubsub"**: The command publishes things on Pub/Sub channels. 88 | // * **"random"**: The command may have different outputs even starting 89 | // from the same input arguments and key values. 90 | // * **"allow-stale"**: The command is allowed to run on slaves that don't 91 | // serve stale data. Don't use if you don't know what 92 | // this means. 93 | // * **"no-monitor"**: Don't propoagate the command on monitor. Use this if 94 | // the command has sensible data among the arguments. 95 | // * **"fast"**: The command time complexity is not greater 96 | // than O(log(N)) where N is the size of the collection or 97 | // anything else representing the normal scalability 98 | // issue with the command. 99 | // * **"getkeys-api"**: The command implements the interface to return 100 | // the arguments that are keys. Used when start/stop/step 101 | // is not enough because of the command syntax. 102 | // * **"no-cluster"**: The command should not register in Redis Cluster 103 | // since is not designed to work with it because, for 104 | // example, is unable to report the position of the 105 | // keys, programmatically creates key names, or any 106 | // other reason. 107 | int CreateCommand(RedisModuleCtx* ctx,const char* name,RedisModuleCmdFunc cmdfunc,const char* strflags,int firstkey,int lastkey,int keystep){return RedisModule_CreateCommand(ctx,name,cmdfunc,strflags,firstkey,lastkey,keystep);} 108 | 109 | // Called by `RM_Init()` to setup the `ctx->module` structure. 110 | // 111 | // This is an internal function, Redis modules developers don't need 112 | // to use it. 113 | void SetModuleAttribs(RedisModuleCtx* ctx,const char* name,int ver,int apiver){RedisModule_SetModuleAttribs(ctx,name,ver,apiver);} 114 | 115 | // Enable automatic memory management. See API.md for more information. 116 | // 117 | // The function must be called as the first function of a command implementation 118 | // that wants to use automatic memory. 119 | void AutoMemory(RedisModuleCtx* ctx){RedisModule_AutoMemory(ctx);} 120 | 121 | // Create a new module string object. The returned string must be freed 122 | // with `RedisModule_FreeString()`, unless automatic memory is enabled. 123 | // 124 | // The string is created by copying the `len` bytes starting 125 | // at `ptr`. No reference is retained to the passed buffer. 126 | RedisModuleString* CreateString(RedisModuleCtx* ctx,const char* ptr,size_t len){return RedisModule_CreateString(ctx,ptr,len);} 127 | 128 | // Like `RedisModule_CreatString()`, but creates a string starting from a long long 129 | // integer instead of taking a buffer and its length. 130 | // 131 | // The returned string must be released with `RedisModule_FreeString()` or by 132 | // enabling automatic memory management. 133 | RedisModuleString* CreateStringFromLongLong(RedisModuleCtx* ctx,long long ll){return RedisModule_CreateStringFromLongLong(ctx,ll);} 134 | 135 | // Like `RedisModule_CreatString()`, but creates a string starting from an existing 136 | // RedisModuleString. 137 | // 138 | // The returned string must be released with `RedisModule_FreeString()` or by 139 | // enabling automatic memory management. 140 | RedisModuleString* CreateStringFromString(RedisModuleCtx* ctx,const RedisModuleString* str){return RedisModule_CreateStringFromString(ctx,str);} 141 | 142 | // Free a module string object obtained with one of the Redis modules API calls 143 | // that return new string objects. 144 | // 145 | // It is possible to call this function even when automatic memory management 146 | // is enabled. In that case the string will be released ASAP and removed 147 | // from the pool of string to release at the end. 148 | void FreeString(RedisModuleCtx* ctx,RedisModuleString* str){RedisModule_FreeString(ctx,str);} 149 | 150 | // Given a string module object, this function returns the string pointer 151 | // and length of the string. The returned pointer and length should only 152 | // be used for read only accesses and never modified. 153 | const char* StringPtrLen(RedisModuleString* str,size_t* len){return RedisModule_StringPtrLen(str,len);} 154 | 155 | // Convert the string into a long long integer, storing it at `*ll`. 156 | // Returns `REDISMODULE_OK` on success. If the string can't be parsed 157 | // as a valid, strict long long (no spaces before/after), `REDISMODULE_ERR` 158 | // is returned. 159 | int StringToLongLong(RedisModuleString* str,long long* ll){return RedisModule_StringToLongLong(str,ll);} 160 | 161 | // Convert the string into a double, storing it at `*d`. 162 | // Returns `REDISMODULE_OK` on success or `REDISMODULE_ERR` if the string is 163 | // not a valid string representation of a double value. 164 | int StringToDouble(RedisModuleString* str,double* d){return RedisModule_StringToDouble(str,d);} 165 | 166 | // 167 | int WrongArity(RedisModuleCtx* ctx){return RedisModule_WrongArity(ctx);} 168 | 169 | // Send an integer reply to the client, with the specified long long value. 170 | // The function always returns `REDISMODULE_OK`. 171 | int ReplyWithLongLong(RedisModuleCtx* ctx,long long ll){return RedisModule_ReplyWithLongLong(ctx,ll);} 172 | 173 | // The function always returns `REDISMODULE_OK`. 174 | int ReplyWithError(RedisModuleCtx* ctx,const char* err){return RedisModule_ReplyWithError(ctx,err);} 175 | 176 | // Reply with a simple string (+... \r\n in RESP protocol). This replies 177 | // are suitable only when sending a small non-binary string with small 178 | // overhead, like "OK" or similar replies. 179 | // 180 | // The function always returns `REDISMODULE_OK`. 181 | int ReplyWithSimpleString(RedisModuleCtx* ctx,const char* msg){return RedisModule_ReplyWithSimpleString(ctx,msg);} 182 | 183 | // Reply with an array type of 'len' elements. However 'len' other calls 184 | // to `ReplyWith*` style functions must follow in order to emit the elements 185 | // of the array. 186 | // 187 | // When producing arrays with a number of element that is not known beforehand 188 | // the function can be called with the special count 189 | // `REDISMODULE_POSTPONED_ARRAY_LEN`, and the actual number of elements can be 190 | // later set with `RedisModule_ReplySetArrayLength()` (which will set the 191 | // latest "open" count if there are multiple ones). 192 | // 193 | // The function always returns `REDISMODULE_OK`. 194 | int ReplyWithArray(RedisModuleCtx* ctx,long len){return RedisModule_ReplyWithArray(ctx,len);} 195 | 196 | // When `RedisModule_ReplyWithArray()` is used with the argument 197 | // `REDISMODULE_POSTPONED_ARRAY_LEN`, because we don't know beforehand the number 198 | // of items we are going to output as elements of the array, this function 199 | // will take care to set the array length. 200 | // 201 | // Since it is possible to have multiple array replies pending with unknown 202 | // length, this function guarantees to always set the latest array length 203 | // that was created in a postponed way. 204 | // 205 | // For example in order to output an array like [1,[10,20,30]] we 206 | // could write: 207 | // 208 | // `RedisModule_ReplyWithArray(ctx`,`REDISMODULE_POSTPONED_ARRAY_LEN`); 209 | // `RedisModule_ReplyWithLongLong(ctx`,1); 210 | // `RedisModule_ReplyWithArray(ctx`,`REDISMODULE_POSTPONED_ARRAY_LEN`); 211 | // `RedisModule_ReplyWithLongLong(ctx`,10); 212 | // `RedisModule_ReplyWithLongLong(ctx`,20); 213 | // `RedisModule_ReplyWithLongLong(ctx`,30); 214 | // `RedisModule_ReplySetArrayLength(ctx`,3); // Set len of 10,20,30 array. 215 | // `RedisModule_ReplySetArrayLength(ctx`,2); // Set len of top array 216 | // 217 | // Note that in the above example there is no reason to postpone the array 218 | // length, since we produce a fixed number of elements, but in the practice 219 | // the code may use an interator or other ways of creating the output so 220 | // that is not easy to calculate in advance the number of elements. 221 | void ReplySetArrayLength(RedisModuleCtx* ctx,long len){RedisModule_ReplySetArrayLength(ctx,len);} 222 | 223 | // Reply with a bulk string, taking in input a C buffer pointer and length. 224 | // 225 | // The function always returns `REDISMODULE_OK`. 226 | int ReplyWithStringBuffer(RedisModuleCtx* ctx,const char* buf,size_t len){return RedisModule_ReplyWithStringBuffer(ctx,buf,len);} 227 | 228 | // Reply with a bulk string, taking in input a RedisModuleString object. 229 | // 230 | // The function always returns `REDISMODULE_OK`. 231 | int ReplyWithString(RedisModuleCtx* ctx,RedisModuleString* str){return RedisModule_ReplyWithString(ctx,str);} 232 | 233 | // Reply to the client with a NULL. In the RESP protocol a NULL is encoded 234 | // as the string "$-1\r\n". 235 | // 236 | // The function always returns `REDISMODULE_OK`. 237 | int ReplyWithNull(RedisModuleCtx* ctx){return RedisModule_ReplyWithNull(ctx);} 238 | 239 | // Reply exactly what a Redis command returned us with `RedisModule_Call()`. 240 | // This function is useful when we use `RedisModule_Call()` in order to 241 | // execute some command, as we want to reply to the client exactly the 242 | // same reply we obtained by the command. 243 | // 244 | // The function always returns `REDISMODULE_OK`. 245 | int ReplyWithCallReply(RedisModuleCtx* ctx,RedisModuleCallReply* reply){return RedisModule_ReplyWithCallReply(ctx,reply);} 246 | 247 | // Send a string reply obtained converting the double 'd' into a bulk string. 248 | // This function is basically equivalent to converting a double into 249 | // a string into a C buffer, and then calling the function 250 | // `RedisModule_ReplyWithStringBuffer()` with the buffer and length. 251 | // 252 | // The function always returns `REDISMODULE_OK`. 253 | int ReplyWithDouble(RedisModuleCtx* ctx,double d){return RedisModule_ReplyWithDouble(ctx,d);} 254 | 255 | // Replicate the specified command and arguments to slaves and AOF, as effect 256 | // of execution of the calling command implementation. 257 | // 258 | // The replicated commands are always wrapped into the MULTI/EXEC that 259 | // contains all the commands replicated in a given module command 260 | // execution. However the commands replicated with `RedisModule_Call()` 261 | // are the first items, the ones replicated with `RedisModule_Replicate()` 262 | // will all follow before the EXEC. 263 | // 264 | // Modules should try to use one interface or the other. 265 | // 266 | // This command follows exactly the same interface of `RedisModule_Call()`, 267 | // so a set of format specifiers must be passed, followed by arguments 268 | // matching the provided format specifiers. 269 | // 270 | // Please refer to `RedisModule_Call()` for more information. 271 | // 272 | // The command returns `REDISMODULE_ERR` if the format specifiers are invalid 273 | // or the command name does not belong to a known command. 274 | int Replicate(RedisModuleCtx* ctx,const char* cmdname,const char* fmt){return RedisModule_Replicate(ctx,cmdname,fmt);} 275 | 276 | // This function will replicate the command exactly as it was invoked 277 | // by the client. Note that this function will not wrap the command into 278 | // a MULTI/EXEC stanza, so it should not be mixed with other replication 279 | // commands. 280 | // 281 | // Basically this form of replication is useful when you want to propagate 282 | // the command to the slaves and AOF file exactly as it was called, since 283 | // the command can just be re-executed to deterministically re-create the 284 | // new state starting from the old one. 285 | // 286 | // The function always returns `REDISMODULE_OK`. 287 | int ReplicateVerbatim(RedisModuleCtx* ctx){return RedisModule_ReplicateVerbatim(ctx);} 288 | 289 | // Return the ID of the current client calling the currently active module 290 | // command. The returned ID has a few guarantees: 291 | // 292 | // 1. The ID is different for each different client, so if the same client 293 | // executes a module command multiple times, it can be recognized as 294 | // having the same ID, otherwise the ID will be different. 295 | // 2. The ID increases monotonically. Clients connecting to the server later 296 | // are guaranteed to get IDs greater than any past ID previously seen. 297 | // 298 | // Valid IDs are from 1 to 2^64-1. If 0 is returned it means there is no way 299 | // to fetch the ID in the context the function was currently called. 300 | unsigned long long GetClientId(RedisModuleCtx* ctx){return RedisModule_GetClientId(ctx);} 301 | 302 | // Return the currently selected DB. 303 | int GetSelectedDb(RedisModuleCtx* ctx){return RedisModule_GetSelectedDb(ctx);} 304 | 305 | // Change the currently selected DB. Returns an error if the id 306 | // is out of range. 307 | // 308 | // Note that the client will retain the currently selected DB even after 309 | // the Redis command implemented by the module calling this function 310 | // returns. 311 | // 312 | // If the module command wishes to change something in a different DB and 313 | // returns back to the original one, it should call `RedisModule_GetSelectedDb()` 314 | // before in order to restore the old DB number before returning. 315 | int SelectDb(RedisModuleCtx* ctx,int newid){return RedisModule_SelectDb(ctx,newid);} 316 | 317 | // Return an handle representing a Redis key, so that it is possible 318 | // to call other APIs with the key handle as argument to perform 319 | // operations on the key. 320 | // 321 | // The return value is the handle repesenting the key, that must be 322 | // closed with `RM_CloseKey()`. 323 | // 324 | // If the key does not exist and WRITE mode is requested, the handle 325 | // is still returned, since it is possible to perform operations on 326 | // a yet not existing key (that will be created, for example, after 327 | // a list push operation). If the mode is just READ instead, and the 328 | // key does not exist, NULL is returned. However it is still safe to 329 | // call `RedisModule_CloseKey()` and `RedisModule_KeyType()` on a NULL 330 | // value. 331 | void* OpenKey(RedisModuleCtx* ctx,RedisModuleString* keyname,int mode){return RedisModule_OpenKey(ctx,keyname,mode);} 332 | 333 | // Close a key handle. 334 | void CloseKey(RedisModuleKey* key){RedisModule_CloseKey(key);} 335 | 336 | // Return the type of the key. If the key pointer is NULL then 337 | // `REDISMODULE_KEYTYPE_EMPTY` is returned. 338 | int KeyType(RedisModuleKey* key){return RedisModule_KeyType(key);} 339 | 340 | // Return the length of the value associated with the key. 341 | // For strings this is the length of the string. For all the other types 342 | // is the number of elements (just counting keys for hashes). 343 | // 344 | // If the key pointer is NULL or the key is empty, zero is returned. 345 | size_t ValueLength(RedisModuleKey* key){return RedisModule_ValueLength(key);} 346 | 347 | // If the key is open for writing, remove it, and setup the key to 348 | // accept new writes as an empty key (that will be created on demand). 349 | // On success `REDISMODULE_OK` is returned. If the key is not open for 350 | // writing `REDISMODULE_ERR` is returned. 351 | int DeleteKey(RedisModuleKey* key){return RedisModule_DeleteKey(key);} 352 | 353 | // Return the key expire value, as milliseconds of remaining TTL. 354 | // If no TTL is associated with the key or if the key is empty, 355 | // `REDISMODULE_NO_EXPIRE` is returned. 356 | mstime_t GetExpire(RedisModuleKey* key){return RedisModule_GetExpire(key);} 357 | 358 | // Set a new expire for the key. If the special expire 359 | // `REDISMODULE_NO_EXPIRE` is set, the expire is cancelled if there was 360 | // one (the same as the PERSIST command). 361 | // 362 | // Note that the expire must be provided as a positive integer representing 363 | // the number of milliseconds of TTL the key should have. 364 | // 365 | // The function returns `REDISMODULE_OK` on success or `REDISMODULE_ERR` if 366 | // the key was not open for writing or is an empty key. 367 | int SetExpire(RedisModuleKey* key,mstime_t expire){return RedisModule_SetExpire(key,expire);} 368 | 369 | // If the key is open for writing, set the specified string 'str' as the 370 | // value of the key, deleting the old value if any. 371 | // On success `REDISMODULE_OK` is returned. If the key is not open for 372 | // writing or there is an active iterator, `REDISMODULE_ERR` is returned. 373 | int StringSet(RedisModuleKey* key,RedisModuleString* str){return RedisModule_StringSet(key,str);} 374 | 375 | // Prepare the key associated string value for DMA access, and returns 376 | // a pointer and size (by reference), that the user can use to read or 377 | // modify the string in-place accessing it directly via pointer. 378 | // 379 | // The 'mode' is composed by bitwise OR-ing the following flags: 380 | // 381 | // `REDISMODULE_READ` -- Read access 382 | // `REDISMODULE_WRITE` -- Write access 383 | // 384 | // If the DMA is not requested for writing, the pointer returned should 385 | // only be accessed in a read-only fashion. 386 | // 387 | // On error (wrong type) NULL is returned. 388 | // 389 | // DMA access rules: 390 | // 391 | // 1. No other key writing function should be called since the moment 392 | // the pointer is obtained, for all the time we want to use DMA access 393 | // to read or modify the string. 394 | // 395 | // 2. Each time `RM_StringTruncate()` is called, to continue with the DMA 396 | // access, `RM_StringDMA()` should be called again to re-obtain 397 | // a new pointer and length. 398 | // 399 | // 3. If the returned pointer is not NULL, but the length is zero, no 400 | // byte can be touched (the string is empty, or the key itself is empty) 401 | // so a `RM_StringTruncate()` call should be used if there is to enlarge 402 | // the string, and later call StringDMA() again to get the pointer. 403 | char* StringDMA(RedisModuleKey* key,size_t* len,int mode){return RedisModule_StringDMA(key,len,mode);} 404 | 405 | // If the string is open for writing and is of string type, resize it, padding 406 | // with zero bytes if the new length is greater than the old one. 407 | // 408 | // After this call, `RM_StringDMA()` must be called again to continue 409 | // DMA access with the new pointer. 410 | // 411 | // The function returns `REDISMODULE_OK` on success, and `REDISMODULE_ERR` on 412 | // error, that is, the key is not open for writing, is not a string 413 | // or resizing for more than 512 MB is requested. 414 | // 415 | // If the key is empty, a string key is created with the new string value 416 | // unless the new length value requested is zero. 417 | int StringTruncate(RedisModuleKey* key,size_t newlen){return RedisModule_StringTruncate(key,newlen);} 418 | 419 | // Push an element into a list, on head or tail depending on 'where' argumnet. 420 | // If the key pointer is about an empty key opened for writing, the key 421 | // is created. On error (key opened for read-only operations or of the wrong 422 | // type) `REDISMODULE_ERR` is returned, otherwise `REDISMODULE_OK` is returned. 423 | int ListPush(RedisModuleKey* key,int where,RedisModuleString* ele){return RedisModule_ListPush(key,where,ele);} 424 | 425 | // Pop an element from the list, and returns it as a module string object 426 | // that the user should be free with `RM_FreeString()` or by enabling 427 | // automatic memory. 'where' specifies if the element should be popped from 428 | // head or tail. The command returns NULL if: 429 | // 1) The list is empty. 430 | // 2) The key was not open for writing. 431 | // 3) The key is not a list. 432 | RedisModuleString* ListPop(RedisModuleKey* key,int where){return RedisModule_ListPop(key,where);} 433 | 434 | 435 | 436 | 437 | 438 | // Add a new element into a sorted set, with the specified 'score'. 439 | // If the element already exists, the score is updated. 440 | // 441 | // A new sorted set is created at value if the key is an empty open key 442 | // setup for writing. 443 | // 444 | // Additional flags can be passed to the function via a pointer, the flags 445 | // are both used to receive input and to communicate state when the function 446 | // returns. 'flagsptr' can be NULL if no special flags are used. 447 | // 448 | // The input flags are: 449 | // 450 | // `REDISMODULE_ZADD_XX`: Element must already exist. Do nothing otherwise. 451 | // `REDISMODULE_ZADD_NX`: Element must not exist. Do nothing otherwise. 452 | // 453 | // The output flags are: 454 | // 455 | // `REDISMODULE_ZADD_ADDED`: The new element was added to the sorted set. 456 | // `REDISMODULE_ZADD_UPDATED`: The score of the element was updated. 457 | // `REDISMODULE_ZADD_NOP`: No operation was performed because XX or NX flags. 458 | // 459 | // On success the function returns `REDISMODULE_OK`. On the following errors 460 | // `REDISMODULE_ERR` is returned: 461 | // 462 | // * The key was not opened for writing. 463 | // * The key is of the wrong type. 464 | // * 'score' double value is not a number (NaN). 465 | int ZsetAdd(RedisModuleKey* key,double score,RedisModuleString* ele,int* flagsptr){return RedisModule_ZsetAdd(key,score,ele,flagsptr);} 466 | 467 | // This function works exactly like `RM_ZsetAdd()`, but instead of setting 468 | // a new score, the score of the existing element is incremented, or if the 469 | // element does not already exist, it is added assuming the old score was 470 | // zero. 471 | // 472 | // The input and output flags, and the return value, have the same exact 473 | // meaning, with the only difference that this function will return 474 | // `REDISMODULE_ERR` even when 'score' is a valid double number, but adding it 475 | // to the existing score resuts into a NaN (not a number) condition. 476 | // 477 | // This function has an additional field 'newscore', if not NULL is filled 478 | // with the new score of the element after the increment, if no error 479 | // is returned. 480 | int ZsetIncrby(RedisModuleKey* key,double score,RedisModuleString* ele,int* flagsptr,double* newscore){return RedisModule_ZsetIncrby(key,score,ele,flagsptr,newscore);} 481 | 482 | // Remove the specified element from the sorted set. 483 | // The function returns `REDISMODULE_OK` on success, and `REDISMODULE_ERR` 484 | // on one of the following conditions: 485 | // 486 | // * The key was not opened for writing. 487 | // * The key is of the wrong type. 488 | // 489 | // The return value does NOT indicate the fact the element was really 490 | // removed (since it existed) or not, just if the function was executed 491 | // with success. 492 | // 493 | // In order to know if the element was removed, the additional argument 494 | // 'deleted' must be passed, that populates the integer by reference 495 | // setting it to 1 or 0 depending on the outcome of the operation. 496 | // The 'deleted' argument can be NULL if the caller is not interested 497 | // to know if the element was really removed. 498 | // 499 | // Empty keys will be handled correctly by doing nothing. 500 | int ZsetRem(RedisModuleKey* key,RedisModuleString* ele,int* deleted){return RedisModule_ZsetRem(key,ele,deleted);} 501 | 502 | // On success retrieve the double score associated at the sorted set element 503 | // 'ele' and returns `REDISMODULE_OK`. Otherwise `REDISMODULE_ERR` is returned 504 | // to signal one of the following conditions: 505 | // 506 | // * There is no such element 'ele' in the sorted set. 507 | // * The key is not a sorted set. 508 | // * The key is an open empty key. 509 | int ZsetScore(RedisModuleKey* key,RedisModuleString* ele,double* score){return RedisModule_ZsetScore(key,ele,score);} 510 | 511 | // Stop a sorted set iteration. 512 | void ZsetRangeStop(RedisModuleKey* key){RedisModule_ZsetRangeStop(key);} 513 | 514 | // Return the "End of range" flag value to signal the end of the iteration. 515 | int ZsetRangeEndReached(RedisModuleKey* key){return RedisModule_ZsetRangeEndReached(key);} 516 | 517 | // Setup a sorted set iterator seeking the first element in the specified 518 | // range. Returns `REDISMODULE_OK` if the iterator was correctly initialized 519 | // otherwise `REDISMODULE_ERR` is returned in the following conditions: 520 | // 521 | // 1. The value stored at key is not a sorted set or the key is empty. 522 | // 523 | // The range is specified according to the two double values 'min' and 'max'. 524 | // Both can be infinite using the following two macros: 525 | // 526 | // `REDISMODULE_POSITIVE_INFINITE` for positive infinite value 527 | // `REDISMODULE_NEGATIVE_INFINITE` for negative infinite value 528 | // 529 | // 'minex' and 'maxex' parameters, if true, respectively setup a range 530 | // where the min and max value are exclusive (not included) instead of 531 | // inclusive. 532 | int ZsetFirstInScoreRange(RedisModuleKey* key,double min,double max,int minex,int maxex){return RedisModule_ZsetFirstInScoreRange(key,min,max,minex,maxex);} 533 | 534 | // Exactly like `RedisModule_ZsetFirstInScoreRange()` but the last element of 535 | // the range is selected for the start of the iteration instead. 536 | int ZsetLastInScoreRange(RedisModuleKey* key,double min,double max,int minex,int maxex){return RedisModule_ZsetLastInScoreRange(key,min,max,minex,maxex);} 537 | 538 | // Setup a sorted set iterator seeking the first element in the specified 539 | // lexicographical range. Returns `REDISMODULE_OK` if the iterator was correctly 540 | // initialized otherwise `REDISMODULE_ERR` is returned in the 541 | // following conditions: 542 | // 543 | // 1. The value stored at key is not a sorted set or the key is empty. 544 | // 2. The lexicographical range 'min' and 'max' format is invalid. 545 | // 546 | // 'min' and 'max' should be provided as two RedisModuleString objects 547 | // in the same format as the parameters passed to the ZRANGEBYLEX command. 548 | // The function does not take ownership of the objects, so they can be released 549 | // ASAP after the iterator is setup. 550 | int ZsetFirstInLexRange(RedisModuleKey* key,RedisModuleString* min,RedisModuleString* max){return RedisModule_ZsetFirstInLexRange(key,min,max);} 551 | 552 | // Exactly like `RedisModule_ZsetFirstInLexRange()` but the last element of 553 | // the range is selected for the start of the iteration instead. 554 | int ZsetLastInLexRange(RedisModuleKey* key,RedisModuleString* min,RedisModuleString* max){return RedisModule_ZsetLastInLexRange(key,min,max);} 555 | 556 | // Return the current sorted set element of an active sorted set iterator 557 | // or NULL if the range specified in the iterator does not include any 558 | // element. 559 | RedisModuleString* ZsetRangeCurrentElement(RedisModuleKey* key,double* score){return RedisModule_ZsetRangeCurrentElement(key,score);} 560 | 561 | // Go to the next element of the sorted set iterator. Returns 1 if there was 562 | // a next element, 0 if we are already at the latest element or the range 563 | // does not include any item at all. 564 | int ZsetRangeNext(RedisModuleKey* key){return RedisModule_ZsetRangeNext(key);} 565 | 566 | // Go to the previous element of the sorted set iterator. Returns 1 if there was 567 | // a previous element, 0 if we are already at the first element or the range 568 | // does not include any item at all. 569 | int ZsetRangePrev(RedisModuleKey* key){return RedisModule_ZsetRangePrev(key);} 570 | 571 | // Return value: 572 | // 573 | // The number of fields updated (that may be less than the number of fields 574 | // specified because of the XX or NX options). 575 | // 576 | // In the following case the return value is always zero: 577 | // 578 | // * The key was not open for writing. 579 | // * The key was associated with a non Hash value. 580 | int HashSet(RedisModuleKey* key,int flags){return RedisModule_HashSet(key,flags);} 581 | 582 | // Get fields from an hash value. This function is called using a variable 583 | // number of arguments, alternating a field name (as a StringRedisModule 584 | // pointer) with a pointer to a StringRedisModule pointer, that is set to the 585 | // value of the field if the field exist, or NULL if the field did not exist. 586 | // At the end of the field/value-ptr pairs, NULL must be specified as last 587 | // argument to signal the end of the arguments in the variadic function. 588 | // 589 | // This is an example usage: 590 | // 591 | // RedisModuleString *first, *second; 592 | // `RedisModule_HashGet(mykey`,`REDISMODULE_HASH_NONE`,argv[1],&first, 593 | // argv[2],&second,NULL); 594 | // 595 | // As with `RedisModule_HashSet()` the behavior of the command can be specified 596 | // passing flags different than `REDISMODULE_HASH_NONE`: 597 | // 598 | // `REDISMODULE_HASH_CFIELD`: field names as null terminated C strings. 599 | // 600 | // `REDISMODULE_HASH_EXISTS`: instead of setting the value of the field 601 | // expecting a RedisModuleString pointer to pointer, the function just 602 | // reports if the field esists or not and expects an integer pointer 603 | // as the second element of each pair. 604 | // 605 | // Example of `REDISMODULE_HASH_CFIELD`: 606 | // 607 | // RedisModuleString *username, *hashedpass; 608 | // `RedisModule_HashGet(mykey`,"username",&username,"hp",&hashedpass, NULL); 609 | // 610 | // Example of `REDISMODULE_HASH_EXISTS`: 611 | // 612 | // int exists; 613 | // `RedisModule_HashGet(mykey`,argv[1],&exists,NULL); 614 | // 615 | // The function returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` if 616 | // the key is not an hash value. 617 | // 618 | // Memory management: 619 | // 620 | // The returned RedisModuleString objects should be released with 621 | // `RedisModule_FreeString()`, or by enabling automatic memory management. 622 | int HashGet(RedisModuleKey* key,int flags){return RedisModule_HashGet(key,flags);} 623 | 624 | 625 | 626 | // Wrapper for the recursive free reply function. This is needed in order 627 | // to have the first level function to return on nested replies, but only 628 | // if called by the module API. 629 | void FreeCallReply(RedisModuleCallReply* reply){RedisModule_FreeCallReply(reply);} 630 | 631 | // Return the reply type. 632 | int CallReplyType(RedisModuleCallReply* reply){return RedisModule_CallReplyType(reply);} 633 | 634 | // Return the reply type length, where applicable. 635 | size_t CallReplyLength(RedisModuleCallReply* reply){return RedisModule_CallReplyLength(reply);} 636 | 637 | // Return the 'idx'-th nested call reply element of an array reply, or NULL 638 | // if the reply type is wrong or the index is out of range. 639 | RedisModuleCallReply* CallReplyArrayElement(RedisModuleCallReply* reply,size_t idx){return RedisModule_CallReplyArrayElement(reply,idx);} 640 | 641 | // Return the long long of an integer reply. 642 | long long CallReplyInteger(RedisModuleCallReply* reply){return RedisModule_CallReplyInteger(reply);} 643 | 644 | // Return the pointer and length of a string or error reply. 645 | const char* CallReplyStringPtr(RedisModuleCallReply* reply,size_t* len){return RedisModule_CallReplyStringPtr(reply,len);} 646 | 647 | // Return a new string object from a call reply of type string, error or 648 | // integer. Otherwise (wrong reply type) return NULL. 649 | RedisModuleString* CreateStringFromCallReply(RedisModuleCallReply* reply){return RedisModule_CreateStringFromCallReply(reply);} 650 | 651 | // Exported API to call any Redis command from modules. 652 | // On success a RedisModuleCallReply object is returned, otherwise 653 | // NULL is returned and errno is set to the following values: 654 | // 655 | // EINVAL: command non existing, wrong arity, wrong format specifier. 656 | // EPERM: operation in Cluster instance with key in non local slot. 657 | RedisModuleCallReply* Call(RedisModuleCtx* ctx,const char* cmdname,const char* fmt){return RedisModule_Call(ctx,cmdname,fmt);} 658 | 659 | // Return a pointer, and a length, to the protocol returned by the command 660 | // that returned the reply object. 661 | const char* CallReplyProto(RedisModuleCallReply* reply,size_t* len){return RedisModule_CallReplyProto(reply,len);} 662 | 663 | // int `RedisModule_OnLoad(RedisModuleCtx` *ctx) { 664 | // // some code here ... 665 | // BalancedTreeType = `RM_CreateDataType(`...); 666 | // } 667 | RedisModuleType* CreateDataType(RedisModuleCtx* ctx,const char* name,int encver,RedisModuleTypeLoadFunc rdb_load,RedisModuleTypeSaveFunc rdb_save,RedisModuleTypeRewriteFunc aof_rewrite,RedisModuleTypeDigestFunc digest,RedisModuleTypeFreeFunc free){return RedisModule_CreateDataType(ctx,name,encver,rdb_load,rdb_save,aof_rewrite,digest,free);} 668 | 669 | // If the key is open for writing, set the specified module type object 670 | // as the value of the key, deleting the old value if any. 671 | // On success `REDISMODULE_OK` is returned. If the key is not open for 672 | // writing or there is an active iterator, `REDISMODULE_ERR` is returned. 673 | int ModuleTypeSetValue(RedisModuleKey* key,RedisModuleType* mt,void* value){return RedisModule_ModuleTypeSetValue(key,mt,value);} 674 | 675 | // Assuming `RedisModule_KeyType()` returned `REDISMODULE_KEYTYPE_MODULE` on 676 | // the key, returns the moduel type pointer of the value stored at key. 677 | // 678 | // If the key is NULL, is not associated with a module type, or is empty, 679 | // then NULL is returned instead. 680 | RedisModuleType* ModuleTypeGetType(RedisModuleKey* key){return RedisModule_ModuleTypeGetType(key);} 681 | 682 | // Assuming `RedisModule_KeyType()` returned `REDISMODULE_KEYTYPE_MODULE` on 683 | // the key, returns the module type low-level value stored at key, as 684 | // it was set by the user via `RedisModule_ModuleTypeSet()`. 685 | // 686 | // If the key is NULL, is not associated with a module type, or is empty, 687 | // then NULL is returned instead. 688 | void* ModuleTypeGetValue(RedisModuleKey* key){return RedisModule_ModuleTypeGetValue(key);} 689 | 690 | // Save an unsigned 64 bit value into the RDB file. This function should only 691 | // be called in the context of the rdb_save method of modules implementing new 692 | // data types. 693 | void SaveUnsigned(RedisModuleIO* io,uint64_t value){RedisModule_SaveUnsigned(io,value);} 694 | 695 | // Load an unsigned 64 bit value from the RDB file. This function should only 696 | // be called in the context of the rdb_load method of modules implementing 697 | // new data types. 698 | uint64_t LoadUnsigned(RedisModuleIO* io){return RedisModule_LoadUnsigned(io);} 699 | 700 | // Like `RedisModule_SaveUnsigned()` but for signed 64 bit values. 701 | void SaveSigned(RedisModuleIO* io,int64_t value){RedisModule_SaveSigned(io,value);} 702 | 703 | // Like `RedisModule_LoadUnsigned()` but for signed 64 bit values. 704 | int64_t LoadSigned(RedisModuleIO* io){return RedisModule_LoadSigned(io);} 705 | 706 | // In the context of the rdb_save method of a module type, saves a 707 | // string into the RDB file taking as input a RedisModuleString. 708 | // 709 | // The string can be later loaded with `RedisModule_LoadString()` or 710 | // other Load family functions expecting a serialized string inside 711 | // the RDB file. 712 | void SaveString(RedisModuleIO* io,RedisModuleString* s){RedisModule_SaveString(io,s);} 713 | 714 | // Like `RedisModule_SaveString()` but takes a raw C pointer and length 715 | // as input. 716 | void SaveStringBuffer(RedisModuleIO* io,const char* str,size_t len){RedisModule_SaveStringBuffer(io,str,len);} 717 | 718 | // In the context of the rdb_load method of a module data type, loads a string 719 | // from the RDB file, that was previously saved with `RedisModule_SaveString()` 720 | // functions family. 721 | // 722 | // The returned string is a newly allocated RedisModuleString object, and 723 | // the user should at some point free it with a call to `RedisModule_FreeString()`. 724 | // 725 | // If the data structure does not store strings as RedisModuleString objects, 726 | // the similar function `RedisModule_LoadStringBuffer()` could be used instead. 727 | RedisModuleString* LoadString(RedisModuleIO* io){return RedisModule_LoadString(io);} 728 | 729 | // Like `RedisModule_LoadString()` but returns an heap allocated string that 730 | // was allocated with `RedisModule_Alloc()`, and can be resized or freed with 731 | // `RedisModule_Realloc()` or `RedisModule_Free()`. 732 | // 733 | // The size of the string is stored at '*lenptr' if not NULL. 734 | // The returned string is not automatically NULL termianted, it is loaded 735 | // exactly as it was stored inisde the RDB file. 736 | char* LoadStringBuffer(RedisModuleIO* io,size_t* lenptr){return RedisModule_LoadStringBuffer(io,lenptr);} 737 | 738 | // In the context of the rdb_save method of a module data type, saves a double 739 | // value to the RDB file. The double can be a valid number, a NaN or infinity. 740 | // It is possible to load back the value with `RedisModule_LoadDouble()`. 741 | void SaveDouble(RedisModuleIO* io,double value){RedisModule_SaveDouble(io,value);} 742 | 743 | // In the context of the rdb_save method of a module data type, loads back the 744 | // double value saved by `RedisModule_SaveDouble()`. 745 | double LoadDouble(RedisModuleIO* io){return RedisModule_LoadDouble(io);} 746 | 747 | // Emits a command into the AOF during the AOF rewriting process. This function 748 | // is only called in the context of the aof_rewrite method of data types exported 749 | // by a module. The command works exactly like `RedisModule_Call()` in the way 750 | // the parameters are passed, but it does not return anything as the error 751 | // handling is performed by Redis itself. 752 | void EmitAOF(RedisModuleIO* io,const char* cmdname,const char* fmt){RedisModule_EmitAOF(io,cmdname,fmt);} 753 | 754 | // Produces a log message to the standard Redis log, the format accepts 755 | // printf-alike specifiers, while level is a string describing the log 756 | // level to use when emitting the log, and must be one of the following: 757 | // 758 | // * "debug" 759 | // * "verbose" 760 | // * "notice" 761 | // * "warning" 762 | // 763 | // If the specified log level is invalid, verbose is used by default. 764 | // There is a fixed limit to the length of the log line this function is able 765 | // to emit, this limti is not specified but is guaranteed to be more than 766 | // a few lines of text. 767 | void Log(RedisModuleCtx* ctx,const char* levelstr,const char* fmt){RedisModule_Log(ctx,levelstr,fmt);} 768 | 769 | 770 | #endif 771 | --------------------------------------------------------------------------------