I have a set of records that I would save inside a transaction. But when I call EXEC it seems I never called MULTI , but I does. Here is the rew code. nothing happen between the two routines. tb_insert_into_redis(...) is the head and tb_insert_into_redis_rec(...) is the recursive. EXEC answer me "I should call MULTI before" ,but I did.


static int tb_insert_into_redis_rec(ptbParseResult tbpr,  ptbNode new_child,
    struct hashtable *parent_collection, struct hashtable *new_inserted,int status  )
{
    size_t i;
    char *tmp;
    RedisModuleCallReply *rep;
    ptbNode tn=new_child;
    if (!hcontains(new_inserted,tn->par->id )&& !hcontains(parent_collection,tn->par->id)   )
            if (!hadd(parent_collection,tn->par->id,tn->par)) return TB_EXIT_FAILURE;

        tmp=tb_R_node_to_string(new_child,tbpr->s,status,
                                                                0,
                                                                NULL,
                                                                0,
                                                                NULL,
                                                                0,
                                                                0);

    rep=RedisModule_Call(tbpr->ctx,"SET","sb",tb_get_key(tbpr->ctx,
                                                             tbpr->parent_tbi->tb->key, tn->id),
                                                            tmp, tbpr->s->e-tbpr->s->s);

        if (!hadd(new_inserted,tn->id,tn)) return TB_EXIT_FAILURE;
        if (RedisModule_CallReplyType(rep)==REDISMODULE_REPLY_ERROR)
        {
            rep=RedisModule_Call(tbpr->ctx,"DISCARD","");

            return TB_QUERY_FAILURE;
        }
    int c=TB_QUERY_SUCCESS;
    for (i=0;i<new_child->nattrs;i++)
        if ((c=tb_insert_into_redis_rec(tbpr,new_child->attrs[i],parent_collection, new_inserted,status))
            & (TB_QUERY_FAILURE|TB_EXIT_FAILURE))
            return c;
    for (i=0;i<new_child->nchs;i++)
        if ((c=tb_insert_into_redis_rec(tbpr,new_child->chs[i],parent_collection, new_inserted,status))
            & (TB_QUERY_FAILURE|TB_EXIT_FAILURE))
            return c;
    return c;

}
static int tb_insert_branch_into_redis(ptbParseResult tbpr, ptbSeekIndexes ItemsToUpdate,int status)
{
    struct hashtable *parent_collection=NULL;
        struct hashtable *new_inserted=NULL;
    parent_collection=hCreator(30);
        new_inserted=hCreator(30);
    int c=TB_QUERY_SUCCESS ;
    size_t i;
        if (!parent_collection)return TB_EXIT_FAILURE;
    if (!new_inserted) 
    {
        hdistructor(parent_collection);     
        return TB_EXIT_FAILURE;
    }
    RedisModuleCallReply *rep=RedisModule_Call(tbpr->ctx,"MULTI","");
        if (RedisModule_CallReplyType(rep)==REDISMODULE_REPLY_ERROR)
    {
        c=TB_QUERY_FAILURE;
        goto ESCAPE;
    }


    for (i=0;i<ItemsToUpdate->n;i++)
    {
        if ((c=tb_insert_into_redis_rec(tbpr,
                        ItemsToUpdate->indexes[i],
                        parent_collection,
                        new_inserted,
                        status))
            & (TB_QUERY_FAILURE | TB_EXIT_FAILURE))
            goto ESCAPE;
    }

    ptbNode tn;
    char *tmp;
    while((tn=foreach(parent_collection)))
    {
        tmp=tb_R_node_to_string(tn,tbpr->s,status,0,NULL,0,NULL,0,0);
        rep=RedisModule_Call(tbpr->ctx,"SET","sb",tb_get_key(tbpr->ctx,
                                                             tbpr->parent_tbi->tb->key, tn->id),
                                                            tmp, tbpr->s->e-tbpr->s->s);
    }

    c=tb_set_DB(tbpr->ctx,sd.tb->key,sd.tb) ;

ESCAPE:
    if (c&TB_QUERY_SUCCESS)
        rep=RedisModule_Call(tbpr->ctx,"EXEC","");
    else
        rep=RedisModule_Call(tbpr->ctx,"DISCARD","");

    hdistructor(parent_collection);
        hdistructor(new_inserted);

    return c;

}

Comment From: itamarhaber

Hi Jurhas,

Looks like you're building an interesting module - good luck!

Each time RedisModule_Call is used, Redis simulates a client call internally to serve it. Because this isn't a real client what you get is basically the equivalent of opening a connection for each command. The error you're getting is because the context in which you've called MULTI is no longer used when you issue command calls.

This isn't really an issue in this case because MULTI/EXEC are client-side semantics designed to ensure that the server processes a block of commands atomically. When the context of execution is inside a module, however, everything done is in a "transaction" because the module's command is blocking the server until it finishes so using, MULTI has no meaning. This is similar to transactions and Lua and to fully understand the topic I recommend that you read the relevant documentation page at: http://redis.io/topics/transactions

On Wed, Nov 16, 2016 at 4:39 PM, jurhas notifications@github.com wrote:

I have a set of records that I would save inside a transaction. But when I call EXEC it seems I never called MULTI , but I does. Here is the rew code. nothing happen between the two routines. tb_insert_into_redis(...) is the head and tb_insert_into_redis_rec(...) is the recursive. EXEC answer me "I should call MULTI before" ,but I did.

static int tb_insert_into_redis_rec(ptbParseResult tbpr, ptbNode new_child, struct hashtable parent_collection, struct hashtable new_inserted,int status ) { size_t i; char tmp; RedisModuleCallReply rep; ptbNode tn=new_child; if (!hcontains(new_inserted,tn->par->id )&& !hcontains(parent_collection,tn->par->id) ) if (!hadd(parent_collection,tn->par->id,tn->par)) return TB_EXIT_FAILURE;

tmp=tb_R_node_to_string(new_child,tbpr->s,status, 0, NULL, 0, NULL, 0, 0);

rep=RedisModule_Call(tbpr->ctx,"SET","sb",tb_get_key(tbpr->ctx, tbpr->parent_tbi->tb->key, tn->id), tmp, tbpr->s->e-tbpr->s->s);

``` if (!hadd(new_inserted,tn->id,tn)) return TB_EXIT_FAILURE; if (RedisModule_CallReplyType(rep)==REDISMODULE_REPLY_ERROR) { rep=RedisModule_Call(tbpr->ctx,"DISCARD","");

    return TB_QUERY_FAILURE;
}

```

int c=TB_QUERY_SUCCESS; for (i=0;inattrs;i++) if ((c=tb_insert_into_redis_rec(tbpr,new_child->attrs[i],parent_collection, new_inserted,status)) & (TB_QUERY_FAILURE|TB_EXIT_FAILURE)) return c; for (i=0;inchs;i++) if ((c=tb_insert_into_redis_rec(tbpr,new_child->chs[i],parent_collection, new_inserted,status)) & (TB_QUERY_FAILURE|TB_EXIT_FAILURE)) return c; return c;

} static int tb_insert_branch_into_redis(ptbParseResult tbpr, ptbSeekIndexes ItemsToUpdate,int status) { struct hashtable parent_collection=NULL; struct hashtable new_inserted=NULL; parent_collection=hCreator(30); new_inserted=hCreator(30); int c=TB_QUERY_SUCCESS ; size_t i; if (!parent_collection)return TB_EXIT_FAILURE; if (!new_inserted) { hdistructor(parent_collection);
return TB_EXIT_FAILURE; } RedisModuleCallReply *rep=RedisModule_Call(tbpr->ctx,"MULTI",""); if (RedisModule_CallReplyType(rep)==REDISMODULE_REPLY_ERROR) { c=TB_QUERY_FAILURE; goto ESCAPE; }

for (i=0;in;i++) { if ((c=tb_insert_into_redis_rec(tbpr, ItemsToUpdate->indexes[i], parent_collection, new_inserted, status)) & (TB_QUERY_FAILURE || TB_EXIT_FAILURE)) goto ESCAPE; }

ptbNode tn; char *tmp; while((tn=foreach(parent_collection))) { tmp=tb_R_node_to_string(tn,tbpr->s,status,0,NULL,0,NULL,0,0); rep=RedisModule_Call(tbpr->ctx,"SET","sb",tb_get_key(tbpr->ctx, tbpr->parent_tbi->tb->key, tn->id), tmp, tbpr->s->e-tbpr->s->s); }

if (tb_set_DB(tbpr->ctx,sd.tb->key,sd.tb) & TB_QUERY_FAILURE) return TB_QUERY_FAILURE;

ESCAPE: if (c&TB_QUERY_SUCCESS) rep=RedisModule_Call(tbpr->ctx,"EXEC",""); else rep=RedisModule_Call(tbpr->ctx,"DISCARD","");

hdistructor(parent_collection); hdistructor(new_inserted);

return c;

}

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/antirez/redis/issues/3613, or mute the thread https://github.com/notifications/unsubscribe-auth/AFx1_ET77L23312iIxV_oqjazgSM3cHQks5q-xWHgaJpZM4Kz8N7 .

Itamar Haber | Chief Developer Advocate _Redis http://www.redislabs.com/_Labs http://www.redislabs.com/ ~/redis

Mobile: +972 (54) 567 9692 Email: itamar@redislabs.com Twitter: @itamarhaber https://twitter.com/itamarhaber Skype: itamar.haber

Blog http://redislabs.com/blog/ | Twitter https://twitter.com/redislabs | LinkedIn https://www.linkedin.com/company/redis-labs-inc

http://www.redislabs.com/