Hi,
Recently, I'm reading codes about Modules, it is a big change of 4.0, there are so many APIs that we can do lots of extensions with Modules.
When I read the API RM_Call() with "!" flag and RM_Replicate(), I remember redis.call() and redis.replicate_commands() in Lua scripting, also wrapped into the MULTI/EXEC.
Then I read samples in modules directory:
modules/helloworld.c
int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
RedisModule_AutoMemory(ctx);
RedisModule_Replicate(ctx,"ECHO","c","foo");
/* Using the "!" modifier we replicate the command if it
* modified the dataset in some way. */
RedisModule_Call(ctx,"INCR","c!","foo");
RedisModule_Call(ctx,"INCR","c!","bar");
RedisModule_ReplyWithLongLong(ctx,0);
return REDISMODULE_OK;
}
It works well, but when I try to call them in MULTI/EXEC, something strange happened:
$redis-cli
127.0.0.1:6379> module load modules/helloworld.so
OK
127.0.0.1:6379> hello.repl1
(integer) 0
127.0.0.1:6379> multi
OK
127.0.0.1:6379> hello.repl1
QUEUED
127.0.0.1:6379> exec
1) (integer) 0
$cat appendonly.aof
*1
$5
MULTI
*1
$5
MULTI
*2
$4
INCR
$3
foo
*2
$4
INCR
$3
bar
*2
$4
ECHO
$3
foo
*1
$4
EXEC
*1
$4
exec
There are nested MULTI contexts..., also happened when we execute a Lua script with redis.replicate_commands() in MULTI/EXEC.
To make matters worse, if we queue other write commands in MULTI/EXEC with replicate things, that will break atomicity of transaction, because EXEC has already been generated by redis.replicate_commands() or RM_Replicate() before the real EXEC we want!
I just did a little change, see #4340 .
Another question, commands in RedisModule_Replicate() are not executed by the caller, just replicate to slaves and aof file, is that designed purposely or a bug?