// File: /workspace/github_c_makefile_star2_O3/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 0x529cf(%rip), %rsi     # 0xa211a
callq 0x1fa60
testq %rax, %rax
je 0x4f78b
movq %rax, %r12
movq %rax, %rdi
callq 0x1f070
leaq 0x28(%rsp), %rsi
movl %eax, %edi
callq 0x1f690
cmpl $-0x1, %eax
je 0x4f7c3
cmpq $0x0, 0x58(%rsp)
jne 0x4f7c3
movq %r12, %rdi
callq 0x1f9a0
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x4fd3d
callq 0x1f810
movl (%rax), %edi
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
cmpl $0x2, %edi
je 0x4fd3d
callq 0x1f630
leaq 0x4c478(%rip), %rsi     # 0x9bc24
movl $0x3, %edi
movq %r14, %rdx
movq %rax, %rcx
xorl %eax, %eax
callq 0x23223
jmp 0x4fda3
movl $0x200400, %edi         # imm = 0x200400
callq 0x299b5
movq %rax, %rbp
movq %rax, %rdi
movl $0x200400, %esi         # imm = 0x200400
movq %r12, %rdx
callq 0x1f430
testq %rax, %rax
je 0x4fcd3
movq %r12, 0x10(%rsp)
movq %rbp, 0x20(%rsp)
cmpb $0xa, (%rbp)
je 0x4fcba
movq %rbp, %rdi
leaq 0xc(%rsp), %rsi
callq 0x294d6
testq %rax, %rax
je 0x4fd88
movq %rax, %r13
movq (%rax), %rbx
movq %rbx, %rdi
leaq 0x4c42d(%rip), %rsi     # 0x9bc50
callq 0x1f2e0
testl %eax, %eax
je 0x4fc0c
movq %rbx, %rdi
callq 0x4fddc
movq %rax, %rbx
testq %rax, %rax
jne 0x4f87c
movq (%r13), %rdi
xorl %esi, %esi
callq 0x4fe27
movq %rax, %rbx
leaq 0x7a753(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r14
leaq 0x8(%rbx), %rdi
movl $0x28, %esi
callq 0x283f4
movq %r14, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0x2249c
movq 0x8(%r13), %rdi
movl $0x3a, %esi
callq 0x1f790
testq %rax, %rax
je 0x4fd88
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), %r15
testq %r15, %r15
leaq 0x4cfd4(%rip), %r14     # 0x9c8b7
je 0x4fa0f
movq %r15, %rdi
movl $0x2c, %esi
callq 0x1f790
movq %rax, %r13
testq %rax, %rax
je 0x4f903
movb $0x0, (%r13)
movq %r15, %rdi
movq %r14, %rsi
callq 0x1f2e0
testl %eax, %eax
je 0x4f9ac
movq %r15, %rdi
leaq 0x4d527(%rip), %rsi     # 0x9ce47
callq 0x1f2e0
testl %eax, %eax
je 0x4f9d4
movq %r15, %rdi
leaq 0x4d543(%rip), %rsi     # 0x9ce7a
callq 0x1f2e0
testl %eax, %eax
je 0x4f9da
movq %r15, %rdi
leaq 0x4c379(%rip), %rsi     # 0x9bcc7
callq 0x1f2e0
testl %eax, %eax
je 0x4f9e0
movq %r15, %rdi
leaq 0x4c368(%rip), %rsi     # 0x9bccd
callq 0x1f2e0
testl %eax, %eax
je 0x4f9e6
movq %r15, %rdi
leaq 0x4c35a(%rip), %rsi     # 0x9bcd2
callq 0x1f2e0
testl %eax, %eax
je 0x4f9f8
movq %r15, %rdi
leaq 0x4c351(%rip), %rsi     # 0x9bcdc
callq 0x1f2e0
testl %eax, %eax
je 0x4f9fe
movq %r15, %rdi
leaq 0x4c345(%rip), %rsi     # 0x9bce3
callq 0x1f2e0
testl %eax, %eax
je 0x4fa02
jmp 0x4fdad
leaq 0x7a5f5(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
cmpq $0x0, (%rax)
jne 0x4fd66
movq %rbx, (%rax)
movq %rbx, 0x8ec5a(%rip)     # 0xde628
orb $0x10, 0x30(%rbx)
jmp 0x4fa02
orb $0x1, 0x30(%rbx)
jmp 0x4fa02
orb $0x2, 0x30(%rbx)
jmp 0x4fa02
orb $0x4, 0x30(%rbx)
jmp 0x4fa02
orb $0x8, 0x30(%rbx)
callq 0x23461
movq %rax, 0x868(%rbx)
jmp 0x4fa02
orb $0x20, 0x30(%rbx)
jmp 0x4fa02
orb $0x40, 0x30(%rbx)
leaq 0x1(%r13), %r15
testq %r13, %r13
jne 0x4f8e9
movq 0x18(%rsp), %r13
movq 0x18(%r13), %rdi
cmpb $0x2d, (%rdi)
movq 0x10(%rsp), %r12
je 0x4fa7d
callq 0x4fddc
movq %rax, %r14
testq %rax, %rax
jne 0x4fa6b
movq 0x18(%r13), %rdi
xorl %esi, %esi
callq 0x4fe27
movq %rax, %r14
leaq 0x7a564(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r15
leaq 0x8(%r14), %rdi
movl $0x28, %esi
callq 0x283f4
movq %r15, %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x2249c
movq %r14, 0x850(%rbx)
movq %r14, %rdi
movq %rbx, %rsi
callq 0x4ff2d
movq 0x20(%r13), %rdi
callq 0x1f710
testl %eax, %eax
je 0x4fa96
callq 0x23461
movq %rax, 0x858(%rbx)
movq 0x28(%r13), %rdi
callq 0x1f710
testl %eax, %eax
je 0x4faaf
callq 0x23461
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 0x4fbff
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 0x4fb8c
testq %r15, %r15
je 0x4fd51
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 0x4fddc
movq %rax, %r14
testq %rax, %rax
jne 0x4fb68
movq %r15, %rdi
xorl %esi, %esi
callq 0x4fe27
movq %rax, %r14
leaq 0x7a467(%rip), %rax     # 0xc9fa8
movq 0x7d0(%rax), %rax
movq 0x18(%rax), %r15
leaq 0x8(%r14), %rdi
movl $0x28, %esi
callq 0x283f4
movq %r15, %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x2249c
xorl %eax, %eax
cmpb $0x3e, %bpl
setne %al
movslq %r13d, %rcx
shll $0x11, %eax
leaq 0x7a42a(%rip), %rdx     # 0xc9fa8
addq 0x7d0(%rdx), %rax
movq %r14, 0x28(%rax,%rcx,8)
jmp 0x4fbdf
testq %r15, %r15
je 0x4fbb7
movb $0x0, (%r15)
movq (%r13,%r12,8), %rdi
callq 0x1f710
movl %eax, %r13d
incq %r15
movq %r15, %rdi
callq 0x1f710
cmpl %eax, %r13d
jg 0x4fbdf
movl %eax, %r14d
jmp 0x4fbc5
movq %r14, %rdi
callq 0x1f710
movl %eax, %r14d
movl %eax, %r13d
incl %r14d
leal 0x1(%r13), %ebp
movq %rbx, %rdi
movl %r13d, %esi
callq 0x4ff93
movl %ebp, %r13d
cmpl %ebp, %r14d
jne 0x4fbc8
incq %r12
movslq 0xc(%rsp), %rsi
cmpq %rsi, %r12
movq 0x18(%rsp), %r13
jl 0x4fad6
movq 0x10(%rsp), %r12
movq 0x20(%rsp), %rbp
movq %r13, %rdi
callq 0x2921e
jmp 0x4fcba
cmpl $0x2, 0xc(%rsp)
jl 0x4fcba
movl $0x1, %r14d
movq (%r13,%r14,8), %rbx
movq %rbx, %rdi
leaq 0x4c029(%rip), %rsi     # 0x9bc55
callq 0x1f2e0
testl %eax, %eax
je 0x4fc60
movq %rbx, %rdi
leaq 0x4c023(%rip), %rsi     # 0x9bc62
callq 0x1f2e0
testl %eax, %eax
je 0x4fc85
movl $0x3, %edi
leaq 0x4c01c(%rip), %rsi     # 0x9bc70
movq %rbx, %rdx
xorl %eax, %eax
callq 0x23223
jmp 0x4fcab
movq 0x8(%r13,%r14,8), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1fa00
leaq 0x7a330(%rip), %rcx     # 0xc9fa8
movq 0x7d0(%rcx), %rcx
movq %rax, 0x8(%rcx)
jmp 0x4fcab
movq 0x8(%r13,%r14,8), %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x1fa00
leaq 0x7a30b(%rip), %rcx     # 0xc9fa8
movq 0x7d0(%rcx), %rcx
movq %rax, 0x60070(%rcx)
addq $0x2, %r14
cmpl %r14d, 0xc(%rsp)
jg 0x4fc1d
movq %rbp, %rdi
movl $0x200400, %esi         # imm = 0x200400
movq %r12, %rdx
callq 0x1f430
testq %rax, %rax
jne 0x4f7f3
movq %rbp, %rdi
callq 0x29af7
movq %r12, %rdi
callq 0x1f9a0
leaq 0x7a2be(%rip), %r14     # 0xc9fa8
movq 0x7d0(%r14), %rax
cmpq $0x0, (%rax)
je 0x4fdc7
movq 0x8e926(%rip), %rdx     # 0xde628
addq $0x8, %rdx
leaq 0x4c029(%rip), %rsi     # 0x9bd36
xorl %ebx, %ebx
movl $0x2, %edi
xorl %eax, %eax
callq 0x23223
callq 0x4f6c8
movq 0x7d0(%r14), %rcx
cmpq 0x8(%rcx), %rax
jbe 0x4fd3d
callq 0x4f6c8
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 0x4953d(%rip), %rdi     # 0x99295
leaq 0x4bf5e(%rip), %rsi     # 0x9bcbd
movl $0x111, %edx            # imm = 0x111
jmp 0x4fd79
leaq 0x4bf31(%rip), %rdi     # 0x9bc9e
leaq 0x4bf49(%rip), %rsi     # 0x9bcbd
movl $0xcc, %edx
callq 0x4ca32
movl $0x1, %edi
callq 0x1f3b0
leaq 0x4bfcc(%rip), %rsi     # 0x9bd5b
movl $0x3, %edi
xorl %eax, %eax
callq 0x23223
movq %r12, %rdi
callq 0x1f9a0
movl $0x1, %edi
callq 0x1f2b0
leaq 0x4bf37(%rip), %rdi     # 0x9bceb
leaq 0x4bf02(%rip), %rsi     # 0x9bcbd
movl $0xe6, %edx
callq 0x4cae0
jmp 0x4fd7e
leaq 0x4bf49(%rip), %rdi     # 0x9bd17
leaq 0x4bee8(%rip), %rsi     # 0x9bcbd
movl $0x13e, %edx            # imm = 0x13E
jmp 0x4fd79