// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/cluster.c
// Function: clusterLoadConfig
int clusterLoadConfig(char *filename) {
    FILE *fp = fopen(filename,"r");
    struct stat sb;
    char *line;
    int maxline, j;

    if (fp == NULL) {
        if (errno == ENOENT) {
            return REDIS_ERR;
        } else {
            redisLog(REDIS_WARNING,
                "Loading the cluster node config from %s: %s",
                filename, strerror(errno));
            exit(1);
        }
    }

    /* Check if the file is zero-length: if so return REDIS_ERR to signal
     * we have to write the config. */
    if (fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {
        fclose(fp);
        return REDIS_ERR;
    }

    /* Parse the file. Note that single liens of the cluster config file can
     * be really long as they include all the hash slots of the node.
     * 集群配置文件中的行可能会非常长，
     * 因为它会在行里面记录所有哈希槽的节点。
     *
     * This means in the worst possible case, half of the Redis slots will be
     * present in a single line, possibly in importing or migrating state, so
     * together with the node ID of the sender/receiver.
     *
     * 在最坏情况下，一个行可能保存了半数的哈希槽数据，
     * 并且可能带有导入或导出状态，以及发送者和接受者的 ID 。
     *
     * To simplify we allocate 1024+REDIS_CLUSTER_SLOTS*128 bytes per line. 
     *
     * 为了简单起见，我们为每行分配 1024+REDIS_CLUSTER_SLOTS*128 字节的空间
     */
    maxline = 1024+REDIS_CLUSTER_SLOTS*128;
    line = zmalloc(maxline);
    while(fgets(line,maxline,fp) != NULL) {
        int argc;
        sds *argv;
        clusterNode *n, *master;
        char *p, *s;

        /* Skip blank lines, they can be created either by users manually
         * editing nodes.conf or by the config writing process if stopped
         * before the truncate() call. */
        if (line[0] == '\n') continue;

        /* Split the line into arguments for processing. */
        argv = sdssplitargs(line,&argc);
        if (argv == NULL) goto fmterr;

        /* Handle the special "vars" line. Don't pretend it is the last
         * line even if it actually is when generated by Redis. */
        if (strcasecmp(argv[0],"vars") == 0) {
            for (j = 1; j < argc; j += 2) {
                if (strcasecmp(argv[j],"currentEpoch") == 0) {
                    server.cluster->currentEpoch =
                            strtoull(argv[j+1],NULL,10);
                } else if (strcasecmp(argv[j],"lastVoteEpoch") == 0) {
                    server.cluster->lastVoteEpoch =
                            strtoull(argv[j+1],NULL,10);
                } else {
                    redisLog(REDIS_WARNING,
                        "Skipping unknown cluster config variable '%s'",
                        argv[j]);
                }
            }
            continue;
        }

        /* Create this node if it does not exist */
        // 检查节点是否已经存在
        n = clusterLookupNode(argv[0]);
        if (!n) {
            // 未存在则创建这个节点
            n = createClusterNode(argv[0],0);
            clusterAddNode(n);
        }
        /* Address and port */
        // 设置节点的 ip 和 port
        if ((p = strchr(argv[1],':')) == NULL) goto fmterr;
        *p = '\0';
        memcpy(n->ip,argv[1],strlen(argv[1])+1);
        n->port = atoi(p+1);

        /* Parse flags */
        // 分析节点的 flag
        p = s = argv[2];
        while(p) {
            p = strchr(s,',');
            if (p) *p = '\0';
            // 这是节点本身
            if (!strcasecmp(s,"myself")) {
                redisAssert(server.cluster->myself == NULL);
                myself = server.cluster->myself = n;
                n->flags |= REDIS_NODE_MYSELF;
            // 这是一个主节点
            } else if (!strcasecmp(s,"master")) {
                n->flags |= REDIS_NODE_MASTER;
            // 这是一个从节点
            } else if (!strcasecmp(s,"slave")) {
                n->flags |= REDIS_NODE_SLAVE;
            // 这是一个疑似下线节点
            } else if (!strcasecmp(s,"fail?")) {
                n->flags |= REDIS_NODE_PFAIL;
            // 这是一个已下线节点
            } else if (!strcasecmp(s,"fail")) {
                n->flags |= REDIS_NODE_FAIL;
                n->fail_time = mstime();
            // 等待向节点发送 PING
            } else if (!strcasecmp(s,"handshake")) {
                n->flags |= REDIS_NODE_HANDSHAKE;
            // 尚未获得这个节点的地址
            } else if (!strcasecmp(s,"noaddr")) {
                n->flags |= REDIS_NODE_NOADDR;
            // 无 flag
            } else if (!strcasecmp(s,"noflags")) {
                /* nothing to do */
            } else {
                redisPanic("Unknown flag in redis cluster config file");
            }
            if (p) s = p+1;
        }

        /* Get master if any. Set the master and populate master's
         * slave list. */
        // 如果有主节点的话，那么设置主节点
        if (argv[3][0] != '-') {
            master = clusterLookupNode(argv[3]);
            // 如果主节点不存在，那么添加它
            if (!master) {
                master = createClusterNode(argv[3],0);
                clusterAddNode(master);
            }
            // 设置主节点
            n->slaveof = master;
            // 将节点 n 加入到主节点 master 的从节点名单中
            clusterNodeAddSlave(master,n);
        }

        /* Set ping sent / pong received timestamps */
        // 设置最近一次发送 PING 命令以及接收 PING 命令回复的时间戳
        if (atoi(argv[4])) n->ping_sent = mstime();
        if (atoi(argv[5])) n->pong_received = mstime();

        /* Set configEpoch for this node. */
        // 设置配置纪元
        n->configEpoch = strtoull(argv[6],NULL,10);

        /* Populate hash slots served by this instance. */
        // 取出节点服务的槽
        for (j = 8; j < argc; j++) {
            int start, stop;

            // 正在导入或导出槽
            if (argv[j][0] == '[') {
                /* Here we handle migrating / importing slots */
                int slot;
                char direction;
                clusterNode *cn;

                p = strchr(argv[j],'-');
                redisAssert(p != NULL);
                *p = '\0';
                // 导入 or 导出？
                direction = p[1]; /* Either '>' or '<' */
                // 槽
                slot = atoi(argv[j]+1);
                p += 3;
                // 目标节点
                cn = clusterLookupNode(p);
                // 如果目标不存在，那么创建
                if (!cn) {
                    cn = createClusterNode(p,0);
                    clusterAddNode(cn);
                }
                // 根据方向，设定本节点要导入或者导出的槽的目标
                if (direction == '>') {
                    server.cluster->migrating_slots_to[slot] = cn;
                } else {
                    server.cluster->importing_slots_from[slot] = cn;
                }
                continue;

            // 没有导入或导出，这是一个区间范围的槽
            // 比如 0 - 10086
            } else if ((p = strchr(argv[j],'-')) != NULL) {
                *p = '\0';
                start = atoi(argv[j]);
                stop = atoi(p+1);

            // 没有导入或导出，这是单一个槽
            // 比如 10086
            } else {
                start = stop = atoi(argv[j]);
            }

            // 将槽载入节点
            while(start <= stop) clusterAddSlot(n, start++);
        }

        sdsfreesplitres(argv,argc);
    }
    zfree(line);
    fclose(fp);

    /* Config sanity check */
    redisAssert(server.cluster->myself != NULL);
    redisLog(REDIS_NOTICE,"Node configuration loaded, I'm %.40s", myself->name);

    /* Something that should never happen: currentEpoch smaller than
     * the max epoch found in the nodes configuration. However we handle this
     * as some form of protection against manual editing of critical files. */
    if (clusterGetMaxEpoch() > server.cluster->currentEpoch) {
        server.cluster->currentEpoch = clusterGetMaxEpoch();
    }
    return REDIS_OK;

fmterr:
    redisLog(REDIS_WARNING,
        "Unrecoverable error: corrupted cluster config file.");
    fclose(fp);
    exit(1);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %rdi, %r14
leaq 0x5239f(%rip), %rsi     # 0xa208a
callq 0x1fa60
testq %rax, %rax
je 0x4fd2b
movq %rax, %r12
movq %rax, %rdi
callq 0x1f070
leaq 0x28(%rsp), %rsi
movl %eax, %edi
callq 0x1f690
cmpl $-0x1, %eax
je 0x4fd63
cmpq $0x0, 0x58(%rsp)
jne 0x4fd63
movq %r12, %rdi
callq 0x1f9a0
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x502f5
callq 0x1f810
movl (%rax), %edi
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
cmpl $0x2, %edi
je 0x502f5
callq 0x1f630
leaq 0x4be98(%rip), %rsi     # 0x9bbe4
movl $0x3, %edi
movq %r14, %rdx
movq %rax, %rcx
xorl %eax, %eax
callq 0x23064
jmp 0x5035b
movl $0x200400, %edi         # imm = 0x200400
callq 0x29709
movq %rax, %rbp
movq %rax, %rdi
movl $0x200400, %esi         # imm = 0x200400
movq %r12, %rdx
callq 0x1f430
testq %rax, %rax
je 0x5028b
leaq 0x4be85(%rip), %r15     # 0x9bc15
movq %r12, 0x10(%rsp)
movq %rbp, 0x20(%rsp)
cmpb $0xa, (%rbp)
je 0x50272
movq %rbp, %rdi
leaq 0xc(%rsp), %rsi
callq 0x291c9
testq %rax, %rax
je 0x50340
movq %rax, %r13
movq (%rax), %rbx
movq %rbx, %rdi
leaq 0x4be46(%rip), %rsi     # 0x9bc10
callq 0x1f2e0
testl %eax, %eax
je 0x501c8
movq %rbx, %rdi
callq 0x50394
movq %rax, %rbx
testq %rax, %rax
jne 0x4fe23
movq (%r13), %rdi
xorl %esi, %esi
callq 0x503df
movq %rax, %rbx
leaq 0x7a1ac(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r14
leaq 0x8(%rbx), %rdi
movl $0x28, %esi
callq 0x28148
movq %r14, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0x222b6
movq 0x8(%r13), %rdi
movl $0x3a, %esi
callq 0x1f790
testq %rax, %rax
je 0x50340
movq %rax, %r14
movb $0x0, (%rax)
leaq 0x888(%rbx), %r15
movq %r13, %r12
movq 0x8(%r13), %r13
movq %r13, %rdi
callq 0x1f4f0
leaq 0x1(%rax), %rdx
movq %r15, %rdi
movq %r13, %rsi
callq 0x1fbd0
incq %r14
movq %r14, %rdi
callq 0x1f710
movl %eax, 0x8b8(%rbx)
movq %r12, 0x18(%rsp)
movq 0x10(%r12), %r13
testq %r13, %r13
leaq 0x4c9ed(%rip), %r14     # 0x9c877
je 0x4ffb9
movq %r13, %rdi
movl $0x2c, %esi
callq 0x1f790
movq %rax, %r15
testq %rax, %rax
je 0x4fea9
movb $0x0, (%r15)
movq %r13, %rdi
movq %r14, %rsi
callq 0x1f2e0
testl %eax, %eax
je 0x4ff52
movq %r13, %rdi
leaq 0x4cf41(%rip), %rsi     # 0x9ce07
callq 0x1f2e0
testl %eax, %eax
je 0x4ff7a
movq %r13, %rdi
leaq 0x4cf5d(%rip), %rsi     # 0x9ce3a
callq 0x1f2e0
testl %eax, %eax
je 0x4ff80
movq %r13, %rdi
leaq 0x4bd93(%rip), %rsi     # 0x9bc87
callq 0x1f2e0
testl %eax, %eax
je 0x4ff86
movq %r13, %rdi
leaq 0x4bd82(%rip), %rsi     # 0x9bc8d
callq 0x1f2e0
testl %eax, %eax
je 0x4ff8c
movq %r13, %rdi
leaq 0x4bd74(%rip), %rsi     # 0x9bc92
callq 0x1f2e0
testl %eax, %eax
je 0x4ff9e
movq %r13, %rdi
leaq 0x4bd6b(%rip), %rsi     # 0x9bc9c
callq 0x1f2e0
testl %eax, %eax
je 0x4ffa4
movq %r13, %rdi
leaq 0x4bd5f(%rip), %rsi     # 0x9bca3
callq 0x1f2e0
testl %eax, %eax
je 0x4ffa8
jmp 0x50365
leaq 0x7a04f(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
cmpq $0x0, (%rax)
jne 0x5031e
movq %rbx, (%rax)
movq %rbx, 0x8e6b4(%rip)     # 0xde628
orb $0x10, 0x30(%rbx)
jmp 0x4ffa8
orb $0x1, 0x30(%rbx)
jmp 0x4ffa8
orb $0x2, 0x30(%rbx)
jmp 0x4ffa8
orb $0x4, 0x30(%rbx)
jmp 0x4ffa8
orb $0x8, 0x30(%rbx)
callq 0x232a3
movq %rax, 0x868(%rbx)
jmp 0x4ffa8
orb $0x20, 0x30(%rbx)
jmp 0x4ffa8
orb $0x40, 0x30(%rbx)
leaq 0x1(%r15), %rax
testq %r15, %r15
cmovneq %rax, %r13
jne 0x4fe90
movq 0x18(%rsp), %r13
movq 0x18(%r13), %rdi
cmpb $0x2d, (%rdi)
leaq 0x4bc49(%rip), %r15     # 0x9bc15
movq 0x10(%rsp), %r12
je 0x50035
callq 0x50394
movq %rax, %r14
testq %rax, %rax
jne 0x50023
movq 0x18(%r13), %rdi
xorl %esi, %esi
callq 0x503df
movq %rax, %r14
leaq 0x79fb3(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r15
leaq 0x8(%r14), %rdi
movl $0x28, %esi
callq 0x28148
movq %r15, %rdi
leaq 0x4bbfd(%rip), %r15     # 0x9bc15
movq %rax, %rsi
movq %r14, %rdx
callq 0x222b6
movq %r14, 0x850(%rbx)
movq %r14, %rdi
movq %rbx, %rsi
callq 0x504e5
movq 0x20(%r13), %rdi
callq 0x1f710
testl %eax, %eax
je 0x5004e
callq 0x232a3
movq %rax, 0x858(%rbx)
movq 0x28(%r13), %rdi
callq 0x1f710
testl %eax, %eax
je 0x50067
callq 0x232a3
movq %rax, 0x860(%rbx)
movq 0x30(%r13), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1fa00
movq %rax, 0x38(%rbx)
movl 0xc(%rsp), %esi
cmpl $0x9, %esi
jl 0x501bb
movl $0x8, %r12d
movq (%r13,%r12,8), %r14
movb (%r14), %bpl
movq %r14, %rdi
movl $0x2d, %esi
callq 0x1f790
movq %rax, %r15
cmpb $0x5b, %bpl
jne 0x50149
testq %r15, %r15
je 0x50309
movb $0x0, (%r15)
movb 0x1(%r15), %bpl
movq (%r13,%r12,8), %rdi
incq %rdi
callq 0x1f710
movl %eax, %r13d
addq $0x3, %r15
movq %r15, %rdi
callq 0x50394
movq %rax, %r14
testq %rax, %rax
jne 0x50120
movq %r15, %rdi
xorl %esi, %esi
callq 0x503df
movq %rax, %r14
leaq 0x79eaf(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r15
leaq 0x8(%r14), %rdi
movl $0x28, %esi
callq 0x28148
movq %r15, %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x222b6
xorl %eax, %eax
cmpb $0x3e, %bpl
setne %al
movslq %r13d, %rcx
shll $0x11, %eax
leaq 0x79e72(%rip), %rdx     # 0xc9fa8
addq 0x7d0(%rdx), %rax
movq %r14, 0x28(%rax,%rcx,8)
movq 0x18(%rsp), %r13
jmp 0x50199
testq %r15, %r15
je 0x5016c
movb $0x0, (%r15)
movq (%r13,%r12,8), %rdi
callq 0x1f710
movl %eax, %r14d
incq %r15
movq %r15, %rdi
callq 0x1f710
jmp 0x50177
movq %r14, %rdi
callq 0x1f710
movl %eax, %r14d
movl %eax, %r15d
cmpl %eax, %r14d
jg 0x50199
incl %r15d
leal 0x1(%r14), %ebp
movq %rbx, %rdi
movl %r14d, %esi
callq 0x50552
movl %ebp, %r14d
cmpl %ebp, %r15d
jne 0x50182
incq %r12
movslq 0xc(%rsp), %rsi
cmpq %rsi, %r12
jl 0x5008e
movq 0x10(%rsp), %r12
movq 0x20(%rsp), %rbp
leaq 0x4ba5a(%rip), %r15     # 0x9bc15
movq %r13, %rdi
callq 0x28f0a
jmp 0x50272
cmpl $0x2, 0xc(%rsp)
jl 0x50272
movl $0x1, %r14d
movq (%r13,%r14,8), %rbx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x1f2e0
testl %eax, %eax
je 0x50218
movq %rbx, %rdi
leaq 0x4ba2b(%rip), %rsi     # 0x9bc22
callq 0x1f2e0
testl %eax, %eax
je 0x5023d
movl $0x3, %edi
leaq 0x4ba24(%rip), %rsi     # 0x9bc30
movq %rbx, %rdx
xorl %eax, %eax
callq 0x23064
jmp 0x50263
movq 0x8(%r13,%r14,8), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1fa00
leaq 0x79d78(%rip), %rcx     # 0xc9fa8
movq 0x7d0(%rcx), %rcx
movq %rax, 0x8(%rcx)
jmp 0x50263
movq 0x8(%r13,%r14,8), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1fa00
leaq 0x79d53(%rip), %rcx     # 0xc9fa8
movq 0x7d0(%rcx), %rcx
movq %rax, 0x60070(%rcx)
addq $0x2, %r14
cmpl %r14d, 0xc(%rsp)
jg 0x501d9
movq %rbp, %rdi
movl $0x200400, %esi         # imm = 0x200400
movq %r12, %rdx
callq 0x1f430
testq %rax, %rax
jne 0x4fd9a
movq %rbp, %rdi
callq 0x2984b
movq %r12, %rdi
callq 0x1f9a0
leaq 0x79d06(%rip), %r14     # 0xc9fa8
movq 0x7d0(%r14), %rax
cmpq $0x0, (%rax)
je 0x5037f
movq 0x8e36e(%rip), %rdx     # 0xde628
addq $0x8, %rdx
leaq 0x4ba31(%rip), %rsi     # 0x9bcf6
xorl %ebx, %ebx
movl $0x2, %edi
xorl %eax, %eax
callq 0x23064
callq 0x4fc68
movq 0x7d0(%r14), %rcx
cmpq 0x8(%rcx), %rax
jbe 0x502f5
callq 0x4fc68
movq 0x7d0(%r14), %rcx
movq %rax, 0x8(%rcx)
movl %ebx, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x48f3c(%rip), %rdi     # 0x9924c
leaq 0x4b966(%rip), %rsi     # 0x9bc7d
movl $0x111, %edx            # imm = 0x111
jmp 0x50331
leaq 0x4b939(%rip), %rdi     # 0x9bc5e
leaq 0x4b951(%rip), %rsi     # 0x9bc7d
movl $0xcc, %edx
callq 0x4d037
movl $0x1, %edi
callq 0x1f3b0
leaq 0x4b9d4(%rip), %rsi     # 0x9bd1b
movl $0x3, %edi
xorl %eax, %eax
callq 0x23064
movq %r12, %rdi
callq 0x1f9a0
movl $0x1, %edi
callq 0x1f2b0
leaq 0x4b93f(%rip), %rdi     # 0x9bcab
leaq 0x4b90a(%rip), %rsi     # 0x9bc7d
movl $0xe6, %edx
callq 0x4d0e5
jmp 0x50336
leaq 0x4b951(%rip), %rdi     # 0x9bcd7
leaq 0x4b8f0(%rip), %rsi     # 0x9bc7d
movl $0x13e, %edx            # imm = 0x13E
jmp 0x50331