// File: /workspace/github_c_makefile_star2_O2/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
pushq %rax
movl %esi, %r13d
movq %rdi, %rbx
movl 0x90(%rdi), %r12d
movq 0xa24bd(%rip), %rsi     # 0xc7170
cmpq $0x0, 0x28(%rsi)
movl %r12d, %eax
je 0x24cf3
cmpl $0x0, 0xa25d4(%rip)     # 0xc7298
movl %r12d, %eax
jne 0x24cf3
movq 0x40(%rbx), %rax
testb $0x8, 0x21(%rax)
movl %r12d, %eax
jne 0x24cf3
movq 0x8(%rbx), %rax
movl 0x30(%rax), %edx
movq 0x38(%rbx), %rcx
movl 0x30(%rbx), %r8d
movq %rbx, %rdi
callq 0x3186b
movl 0x90(%rbx), %eax
andl $0xffff3fff, %eax       # imm = 0xFFFF3FFF
movl %eax, 0x90(%rbx)
andq $0x0, 0xa2862(%rip)     # 0xc7568
andl $0x0, 0xa2863(%rip)     # 0xc7570
movq 0xa27f4(%rip), %rax     # 0xc7508
movq %rax, (%rsp)
callq 0x22820
movq %rax, %r15
movq 0x40(%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
callq 0x22820
movq %rax, %r14
movl 0x90(%rbx), %eax
movl %r13d, %ebp
andl $-0x4, %ebp
btl $0x8, %eax
cmovael %r13d, %ebp
cmpl $0x0, 0xa254b(%rip)     # 0xc7298
cmovel %r13d, %ebp
movq 0xa27b0(%rip), %r13     # 0xc7508
movl %eax, %edx
shrl $0x8, %edx
movq 0xa2a34(%rip), %rcx     # 0xc7798
testq %rcx, %rcx
setne %sil
andb %dl, %sil
cmpb $0x1, %sil
jne 0x24d93
testw %ax, %ax
jns 0x24d86
orb $-0x80, 0x91(%rcx)
movl 0x90(%rbx), %eax
btl $0xe, %eax
jae 0x24d93
orb $0x40, 0x91(%rcx)
subq %r15, %r14
testb $0x1, %bpl
je 0x24dbc
movq 0x40(%rbx), %rax
movq 0x8(%rax), %rax
cmpq 0x9e145(%rip), %rax     # 0xc2ef0
je 0x24dbc
movq 0x38(%rbx), %rdi
movl 0x30(%rbx), %esi
movq %r14, %rdx
callq 0x51e76
testb $0x2, %bpl
je 0x24de2
movq 0x40(%rbx), %rax
movdqu 0x40(%rax), %xmm0
movq %r14, %xmm1
shufpd $0x2, 0x65407(%rip), %xmm1 # xmm1 = xmm1[0],mem[1]
paddq %xmm0, %xmm1
movdqu %xmm1, 0x40(%rax)
movl 0x90(%rbx), %eax
testb $0x4, %bpl
je 0x24e24
movl %eax, %ecx
shrl $0xe, %ecx
andl $0x3, %ecx
cmpq (%rsp), %r13
pushq $0x3
popq %r8
cmovel %ecx, %r8d
testl %r8d, %r8d
je 0x24e24
movq 0x40(%rbx), %rdi
movq 0x8(%rbx), %rax
movl 0x30(%rax), %esi
movq 0x38(%rbx), %rdx
movl 0x30(%rbx), %ecx
callq 0x24c05
movl 0x90(%rbx), %eax
andl $0xffff3fff, %eax       # imm = 0xFFFF3FFF
andl $0xc000, %r12d          # imm = 0xC000
orl %eax, %r12d
movl %r12d, 0x90(%rbx)
movl 0xa2730(%rip), %eax     # 0xc7570
testl %eax, %eax
je 0x24e8e
pushq $0x18
popq %rbx
xorl %r14d, %r14d
cltq
cmpq %rax, %r14
jge 0x24e82
movq 0xa2710(%rip), %rax     # 0xc7568
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 0x24c05
incq %r14
movl 0xa26f4(%rip), %eax     # 0xc7570
addq $0x20, %rbx
jmp 0x24e4a
leaq 0xa26df(%rip), %rdi     # 0xc7568
callq 0x24b7c
incq 0xa245b(%rip)           # 0xc72f0
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq