// File: /workspace/github_c_makefile_star2_O1/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 0xa4618(%rip), %rsi     # 0xca170
cmpq $0x0, 0x28(%rsi)
je 0x25b89
cmpl $0x0, 0xa4732(%rip)     # 0xca298
jne 0x25b89
movq 0x40(%rbx), %rax
testb $0x8, 0x21(%rax)
jne 0x25b89
movq 0x8(%rbx), %rax
movl 0x30(%rax), %edx
movq 0x38(%rbx), %rcx
movl 0x30(%rbx), %r8d
movq %rbx, %rdi
callq 0x33565
andb $0x3f, 0x91(%rbx)
movq $0x0, 0xa49cd(%rip) # 0xca568
movl $0x0, 0xa49cb(%rip)     # 0xca570
movq 0xa495c(%rip), %rax     # 0xca508
movq %rax, (%rsp)
leaq 0x8(%rsp), %r14
movq %r14, %rdi
xorl %esi, %esi
callq 0x1f2f0
movq (%r14), %r12
movq 0x8(%r14), %r13
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 %r12, %rax
movq 0x8(%r14), %r14
cmpl $0x0, 0xa46a8(%rip)     # 0xca298
je 0x25c01
movl %ebp, %ecx
andl $-0x4, %ecx
testb $0x1, 0x91(%rbx)
cmovnel %ecx, %ebp
imulq $0xf4240, %rax, %rax    # imm = 0xF4240
subq %r13, %r14
movq 0xa48f6(%rip), %r13     # 0xca508
movl 0x90(%rbx), %edx
movl %edx, %esi
shrl $0x8, %esi
movq 0xa4b74(%rip), %rcx     # 0xca798
testq %rcx, %rcx
setne %dil
andb %sil, %dil
cmpb $0x1, %dil
jne 0x25c50
testw %dx, %dx
jns 0x25c40
orb $-0x80, 0x91(%rcx)
testb $0x40, 0x91(%rbx)
je 0x25c50
orb $0x40, 0x91(%rcx)
addq %rax, %r14
testb $0x1, %bpl
je 0x25c79
movq 0x40(%rbx), %rax
movq 0x8(%rax), %rax
cmpq 0xa0288(%rip), %rax     # 0xc5ef0
je 0x25c79
movq 0x38(%rbx), %rdi
movl 0x30(%rbx), %esi
movq %r14, %rdx
callq 0x56880
testb $0x2, %bpl
je 0x25c8b
movq 0x40(%rbx), %rax
addq %r14, 0x40(%rax)
incq 0x48(%rax)
testb $0x4, %bpl
je 0x25cc7
movl 0x90(%rbx), %eax
shrl $0xe, %eax
andl $0x3, %eax
cmpq (%rsp), %r13
movl $0x3, %r8d
cmovel %eax, %r8d
testl %r8d, %r8d
je 0x25cc7
movq 0x40(%rbx), %rdi
movq 0x8(%rbx), %rax
movl 0x30(%rax), %esi
movq 0x38(%rbx), %rdx
movl 0x30(%rbx), %ecx
callq 0x25a57
movl $0xffff3fff, %eax       # imm = 0xFFFF3FFF
andl 0x90(%rbx), %eax
andl $0xc000, %r15d          # imm = 0xC000
orl %eax, %r15d
movl %r15d, 0x90(%rbx)
cmpl $0x0, 0xa4886(%rip)     # 0xca570
je 0x25d3e
cmpl $0x0, 0xa487d(%rip)     # 0xca570
jle 0x25d32
movl $0x18, %ebx
xorl %r14d, %r14d
movq 0xa4864(%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 0x25a57
incq %r14
movslq 0xa4847(%rip), %rax     # 0xca570
addq $0x20, %rbx
cmpq %rax, %r14
jl 0x25cfd
leaq 0xa482f(%rip), %rdi     # 0xca568
callq 0x259ba
incq 0xa45ab(%rip)           # 0xca2f0
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq