// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x40, %rsp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
movl %eax, -0x2c(%rbp)
movq 0xeb1fd(%rip), %rax     # 0x113ac0
cmpq $0x0, 0x28(%rax)
je 0x28913
cmpl $0x0, 0xeb317(%rip)     # 0x113be8
jne 0x28913
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rax
movl 0x20(%rax), %eax
andl $0x800, %eax            # imm = 0x800
cmpl $0x0, %eax
jne 0x28913
movq -0x8(%rbp), %rdi
movq 0xeb1cd(%rip), %rsi     # 0x113ac0
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x30(%rax), %edx
movq -0x8(%rbp), %rax
movq 0x38(%rax), %rcx
movq -0x8(%rbp), %rax
movl 0x30(%rax), %r8d
callq 0x3f4b0
movq -0x8(%rbp), %rax
movl 0x90(%rax), %ecx
andl $0xffff3fff, %ecx       # imm = 0xFFFF3FFF
movl %ecx, 0x90(%rax)
leaq 0xeafc8(%rip), %rdi     # 0x1138f8
addq $0x5c0, %rdi            # imm = 0x5C0
callq 0x285b0
movq 0xeb515(%rip), %rax     # 0x113e58
movq %rax, -0x18(%rbp)
callq 0x252a0
movq %rax, -0x20(%rbp)
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rax
movq 0x8(%rax), %rax
movq -0x8(%rbp), %rdi
callq *%rax
callq 0x252a0
subq -0x20(%rbp), %rax
movq %rax, -0x28(%rbp)
movq 0xeb4e2(%rip), %rax     # 0x113e58
subq -0x18(%rbp), %rax
movq %rax, -0x18(%rbp)
cmpl $0x0, 0xeb263(%rip)     # 0x113be8
je 0x289a4
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x100, %eax            # imm = 0x100
cmpl $0x0, %eax
je 0x289a4
movl -0xc(%rbp), %eax
andl $-0x4, %eax
movl %eax, -0xc(%rbp)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x100, %eax            # imm = 0x100
cmpl $0x0, %eax
je 0x28a1e
cmpq $0x0, 0xeb728(%rip)     # 0x1140e8
je 0x28a1e
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x8000, %eax           # imm = 0x8000
cmpl $0x0, %eax
je 0x289ef
movq 0xeb70b(%rip), %rax     # 0x1140e8
movl 0x90(%rax), %ecx
orl $0x8000, %ecx           # imm = 0x8000
movl %ecx, 0x90(%rax)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x4000, %eax           # imm = 0x4000
cmpl $0x0, %eax
je 0x28a1c
movq 0xeb6de(%rip), %rax     # 0x1140e8
movl 0x90(%rax), %ecx
orl $0x4000, %ecx           # imm = 0x4000
movl %ecx, 0x90(%rax)
jmp 0x28a1e
movl -0xc(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x28a56
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rax
leaq 0x3a1e8(%rip), %rcx     # 0x62c20
cmpq %rcx, 0x8(%rax)
je 0x28a56
movq -0x8(%rbp), %rax
movq 0x38(%rax), %rdi
movq -0x8(%rbp), %rax
movl 0x30(%rax), %esi
movq -0x28(%rbp), %rdx
callq 0x72800
movl -0xc(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
je 0x28a89
movq -0x28(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rax
addq 0x40(%rax), %rcx
movq %rcx, 0x40(%rax)
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rax
movq 0x48(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x48(%rax)
movl -0xc(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x28b1c
movl $0x0, -0x30(%rbp)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x8000, %eax           # imm = 0x8000
cmpl $0x0, %eax
je 0x28abc
movl -0x30(%rbp), %eax
orl $0x2, %eax
movl %eax, -0x30(%rbp)
movq -0x8(%rbp), %rax
movl 0x90(%rax), %eax
andl $0x4000, %eax           # imm = 0x4000
cmpl $0x0, %eax
je 0x28ad9
movl -0x30(%rbp), %eax
orl $0x1, %eax
movl %eax, -0x30(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x28ae9
movl -0x30(%rbp), %eax
orl $0x3, %eax
movl %eax, -0x30(%rbp)
cmpl $0x0, -0x30(%rbp)
je 0x28b1a
movq -0x8(%rbp), %rax
movq 0x40(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x30(%rax), %esi
movq -0x8(%rbp), %rax
movq 0x38(%rax), %rdx
movq -0x8(%rbp), %rax
movl 0x30(%rax), %ecx
movl -0x30(%rbp), %r8d
callq 0x28790
jmp 0x28b1c
movq -0x8(%rbp), %rax
movl 0x90(%rax), %ecx
andl $0xffff3fff, %ecx       # imm = 0xFFFF3FFF
movl %ecx, 0x90(%rax)
movl -0x2c(%rbp), %ecx
andl $0xc000, %ecx           # imm = 0xC000
movq -0x8(%rbp), %rax
orl 0x90(%rax), %ecx
movl %ecx, 0x90(%rax)
cmpl $0x0, 0xeb36e(%rip)     # 0x113ec0
je 0x28bc4
movl $0x0, -0x34(%rbp)
movl -0x34(%rbp), %eax
cmpl 0xeb35c(%rip), %eax     # 0x113ec0
jge 0x28bb1
movq 0xeb34b(%rip), %rax     # 0x113eb8
movslq -0x34(%rbp), %rcx
shlq $0x5, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x40(%rbp), %rax
movl 0xc(%rax), %esi
movq -0x40(%rbp), %rax
movq (%rax), %rdx
movq -0x40(%rbp), %rax
movl 0x8(%rax), %ecx
movq -0x40(%rbp), %rax
movl 0x10(%rax), %r8d
callq 0x28790
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x28b5b
leaq 0xead40(%rip), %rdi     # 0x1138f8
addq $0x5c0, %rdi            # imm = 0x5C0
callq 0x28680
movq 0xeb075(%rip), %rax     # 0x113c40
addq $0x1, %rax
movq %rax, 0xeb06a(%rip)     # 0x113c40
addq $0x40, %rsp
popq %rbp
retq
nopl (%rax)