// File: /workspace/github_c_makefile_star2_O3/nilyang[P]redis-tdd-annotation/src/redis.c
// Function: call
void call(redisClient *c, int flags) {
    // start 记录命令开始执行的时间
    long long dirty, start, duration;
    // 记录命令开始执行前的 FLAG
    int client_old_flags = c->flags;

    /* Sent the command to clients in MONITOR mode, only if the commands are
     * not generated from reading an AOF. */
    // 如果可以的话，将命令发送到 MONITOR
    if (listLength(server.monitors) &&
        !server.loading &&
        !(c->cmd->flags & REDIS_CMD_SKIP_MONITOR))
    {
        replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc);
    }

    /* Call the command. */
    c->flags &= ~(REDIS_FORCE_AOF|REDIS_FORCE_REPL);
    redisOpArrayInit(&server.also_propagate);
    // 保留旧 dirty 计数器值
    dirty = server.dirty;
    // 计算命令开始执行的时间
    start = ustime();
    // 执行实现函数
    c->cmd->proc(c);
    // 计算命令执行耗费的时间
    duration = ustime()-start;
    // 计算命令执行之后的 dirty 值
    dirty = server.dirty-dirty;

    /* When EVAL is called loading the AOF we don't want commands called
     * from Lua to go into the slowlog or to populate statistics. */
    // 不将从 Lua 中发出的命令放入 SLOWLOG ，也不进行统计
    if (server.loading && c->flags & REDIS_LUA_CLIENT)
        flags &= ~(REDIS_CALL_SLOWLOG | REDIS_CALL_STATS);

    /* If the caller is Lua, we want to force the EVAL caller to propagate
     * the script if the command flag or client flag are forcing the
     * propagation. */
    // 如果调用者是 Lua ，那么根据命令 FLAG 和客户端 FLAG
    // 打开传播（propagate)标志
    if (c->flags & REDIS_LUA_CLIENT && server.lua_caller) {
        if (c->flags & REDIS_FORCE_REPL)
            server.lua_caller->flags |= REDIS_FORCE_REPL;
        if (c->flags & REDIS_FORCE_AOF)
            server.lua_caller->flags |= REDIS_FORCE_AOF;
    }

    /* Log the command into the Slow log if needed, and populate the
     * per-command statistics that we show in INFO commandstats. */
    // 如果有需要，将命令放到 SLOWLOG 里面
    if (flags & REDIS_CALL_SLOWLOG && c->cmd->proc != execCommand)
        slowlogPushEntryIfNeeded(c->argv,c->argc,duration);
    // 更新命令的统计信息
    if (flags & REDIS_CALL_STATS) {
        c->cmd->microseconds += duration;
        c->cmd->calls++;
    }

    /* Propagate the command into the AOF and replication link */
    // 将命令复制到 AOF 和 slave 节点
    if (flags & REDIS_CALL_PROPAGATE) {
        int flags = REDIS_PROPAGATE_NONE;

        // 强制 REPL 传播
        if (c->flags & REDIS_FORCE_REPL) flags |= REDIS_PROPAGATE_REPL;

        // 强制 AOF 传播
        if (c->flags & REDIS_FORCE_AOF) flags |= REDIS_PROPAGATE_AOF;

        // 如果数据库有被修改，那么启用 REPL 和 AOF 传播
        if (dirty)
            flags |= (REDIS_PROPAGATE_REPL | REDIS_PROPAGATE_AOF);

        if (flags != REDIS_PROPAGATE_NONE)
            propagate(c->cmd,c->db->id,c->argv,c->argc,flags);
    }

    /* Restore the old FORCE_AOF/REPL flags, since call can be executed
     * recursively. */
    // 将客户端的 FLAG 恢复到命令执行之前
    // 因为 call 可能会递归执行
    c->flags &= ~(REDIS_FORCE_AOF|REDIS_FORCE_REPL);
    c->flags |= client_old_flags & (REDIS_FORCE_AOF|REDIS_FORCE_REPL);

    /* Handle the alsoPropagate() API to handle commands that want to propagate
     * multiple separated commands. */
    // 传播额外的命令
    if (server.also_propagate.numops) {
        int j;
        redisOp *rop;

        for (j = 0; j < server.also_propagate.numops; j++) {
            rop = &server.also_propagate.ops[j];
            propagate(rop->cmd, rop->dbid, rop->argv, rop->argc, rop->target);
        }
        redisOpArrayFree(&server.also_propagate);
    }
    server.stat_numcommands++;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movl %esi, %ebp
movq %rdi, %rbx
movl 0x90(%rdi), %r15d
movq 0xa4416(%rip), %rsi     # 0xca170
cmpq $0x0, 0x28(%rsi)
movl %r15d, %eax
je 0x25d9a
cmpl $0x0, 0xa452d(%rip)     # 0xca298
movl %r15d, %eax
jne 0x25d9a
movq 0x40(%rbx), %rax
testb $0x8, 0x21(%rax)
movl %r15d, %eax
jne 0x25d9a
movq 0x8(%rbx), %rax
movl 0x30(%rax), %edx
movq 0x38(%rbx), %rcx
movl 0x30(%rbx), %r8d
movq %rbx, %rdi
callq 0x339e1
movl 0x90(%rbx), %eax
andl $0xffff3fff, %eax       # imm = 0xFFFF3FFF
movl %eax, 0x90(%rbx)
movq $0x0, 0xa47b8(%rip) # 0xca568
movl $0x0, 0xa47b6(%rip)     # 0xca570
movq 0xa4747(%rip), %rax     # 0xca508
movq %rax, (%rsp)
leaq 0x8(%rsp), %r14
movq %r14, %rdi
xorl %esi, %esi
callq 0x1f2f0
movq (%r14), %r13
movq 0x8(%r14), %r12
movq 0x40(%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
leaq 0x8(%rsp), %r14
movq %r14, %rdi
xorl %esi, %esi
callq 0x1f2f0
movq (%r14), %rax
subq %r13, %rax
movq 0x8(%r14), %r14
subq %r12, %r14
imulq $0xf4240, %rax, %rax    # imm = 0xF4240
movl 0x90(%rbx), %ecx
movl %ebp, %r13d
andl $-0x4, %r13d
btl $0x8, %ecx
cmovael %ebp, %r13d
cmpl $0x0, 0xa4474(%rip)     # 0xca298
cmovel %ebp, %r13d
movq 0xa46d9(%rip), %rbp     # 0xca508
movl %ecx, %esi
shrl $0x8, %esi
movq 0xa495d(%rip), %rdx     # 0xca798
testq %rdx, %rdx
setne %dil
andb %sil, %dil
cmpb $0x1, %dil
jne 0x25e6a
testw %cx, %cx
jns 0x25e5d
orb $-0x80, 0x91(%rdx)
movl 0x90(%rbx), %ecx
btl $0xe, %ecx
jae 0x25e6a
orb $0x40, 0x91(%rdx)
addq %rax, %r14
testb $0x1, %r13b
je 0x25e93
movq 0x40(%rbx), %rax
movq 0x8(%rax), %rax
cmpq 0xa006e(%rip), %rax     # 0xc5ef0
je 0x25e93
movq 0x38(%rbx), %rdi
movl 0x30(%rbx), %esi
movq %r14, %rdx
callq 0x562e5
testb $0x2, %r13b
je 0x25eb9
movq 0x40(%rbx), %rax
movdqu 0x40(%rax), %xmm0
movq %r14, %xmm1
shufpd $0x2, 0x6e170(%rip), %xmm1 # xmm1 = xmm1[0],mem[1]
paddq %xmm0, %xmm1
movdqu %xmm1, 0x40(%rax)
movl 0x90(%rbx), %eax
testb $0x4, %r13b
je 0x25efd
movl %eax, %ecx
shrl $0xe, %ecx
andl $0x3, %ecx
cmpq (%rsp), %rbp
movl $0x3, %r8d
cmovel %ecx, %r8d
testl %r8d, %r8d
je 0x25efd
movq 0x40(%rbx), %rdi
movq 0x8(%rbx), %rax
movl 0x30(%rax), %esi
movq 0x38(%rbx), %rdx
movl 0x30(%rbx), %ecx
callq 0x25c59
movl 0x90(%rbx), %eax
andl $0xffff3fff, %eax       # imm = 0xFFFF3FFF
andl $0xc000, %r15d          # imm = 0xC000
orl %eax, %r15d
movl %r15d, 0x90(%rbx)
cmpl $0x0, 0xa4656(%rip)     # 0xca570
je 0x25f67
jle 0x25f5b
movl $0x18, %ebx
xorl %r14d, %r14d
movq 0xa463b(%rip), %rax     # 0xca568
movq (%rax,%rbx), %rdi
movl -0xc(%rax,%rbx), %esi
movq -0x18(%rax,%rbx), %rdx
movl -0x10(%rax,%rbx), %ecx
movl -0x8(%rax,%rbx), %r8d
callq 0x25c59
incq %r14
movslq 0xa461e(%rip), %rax     # 0xca570
addq $0x20, %rbx
cmpq %rax, %r14
jl 0x25f26
leaq 0xa4606(%rip), %rdi     # 0xca568
callq 0x25bbc
incq 0xa4382(%rip)           # 0xca2f0
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq