// File: /workspace/github_c_makefile_star2_O2/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, %rbx
leaq 0x41360(%rip), %rsi     # 0x8cbd3
callq 0x1fa60
testq %rax, %rax
je 0x4b8ab
movq %rax, %r14
movq %rax, %rdi
callq 0x1f070
leaq 0x28(%rsp), %rsi
movl %eax, %edi
callq 0x1f690
cmpl $-0x1, %eax
je 0x4b8d2
cmpq $0x0, 0x58(%rsp)
jne 0x4b8d2
movq %r14, %rdi
callq 0x1f9a0
jmp 0x4b8bb
callq 0x1f810
movl (%rax), %edi
cmpl $0x2, %edi
jne 0x4be23
pushq $-0x1
popq %rbx
movl %ebx, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x200400, %edi         # imm = 0x200400
callq 0x2828d
movq %rax, %r13
leaq 0x7b6c2(%rip), %r12     # 0xc6fa8
movq %r14, 0x18(%rsp)
movq %rax, 0x20(%rsp)
movq %r13, %rdi
movl $0x200400, %esi         # imm = 0x200400
movq %r14, %rdx
callq 0x1f430
testq %rax, %rax
je 0x4bd44
cmpb $0xa, (%r13)
je 0x4b8f0
movq %r13, %rdi
leaq 0xc(%rsp), %rsi
callq 0x27ee8
testq %rax, %rax
je 0x4bde6
movq %rax, %rbp
movq (%rax), %rbx
movq %rbx, %rdi
leaq 0x462da(%rip), %rsi     # 0x91c10
callq 0x1f2e0
testl %eax, %eax
je 0x4bca3
movq %rbx, %rdi
callq 0x4be56
movq %rax, %r13
testq %rax, %rax
jne 0x4b969
movq (%rbp), %rdi
xorl %esi, %esi
callq 0x4be9f
movq %rax, %r13
movq %rax, %rdi
callq 0x4bf5b
movq 0x8(%rbp), %rdi
pushq $0x3a
popq %rsi
callq 0x1f790
testq %rax, %rax
je 0x4bde6
movq %rax, %rbx
movb $0x0, (%rax)
leaq 0x888(%r13), %r12
movq %rbp, %r14
movq 0x8(%rbp), %rbp
movq %rbp, %rdi
callq 0x1f4f0
leaq 0x1(%rax), %rdx
movq %r12, %rdi
movq %rbp, %rsi
callq 0x1fbd0
incq %rbx
movq %rbx, %rdi
callq 0x1f710
movl %eax, 0x8b8(%r13)
movq %r14, 0x10(%rsp)
movq 0x10(%r14), %rbp
movq %rbp, %r12
pushq $0x2c
popq %rbx
leaq 0x46ea6(%rip), %r14     # 0x92877
leaq 0x4742f(%rip), %r15     # 0x92e07
testq %rbp, %rbp
je 0x4bb09
movq %r12, %rdi
movl %ebx, %esi
callq 0x1f790
movq %rax, %rbp
testq %rax, %rax
je 0x4b9f7
movb $0x0, (%rbp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x1f2e0
testl %eax, %eax
je 0x4ba9c
movq %r12, %rdi
movq %r15, %rsi
callq 0x1f2e0
testl %eax, %eax
je 0x4bac5
movq %r12, %rdi
leaq 0x47413(%rip), %rsi     # 0x92e3a
callq 0x1f2e0
testl %eax, %eax
je 0x4bacc
movq %r12, %rdi
leaq 0x46249(%rip), %rsi     # 0x91c87
callq 0x1f2e0
testl %eax, %eax
je 0x4bad3
movq %r12, %rdi
leaq 0x46238(%rip), %rsi     # 0x91c8d
callq 0x1f2e0
testl %eax, %eax
je 0x4bada
movq %r12, %rdi
leaq 0x4622a(%rip), %rsi     # 0x91c92
callq 0x1f2e0
testl %eax, %eax
je 0x4baed
movq %r12, %rdi
leaq 0x46221(%rip), %rsi     # 0x91c9c
callq 0x1f2e0
testl %eax, %eax
je 0x4baf4
movq %r12, %rdi
leaq 0x46215(%rip), %rsi     # 0x91ca3
callq 0x1f2e0
testl %eax, %eax
je 0x4baf9
jmp 0x4be09
leaq 0x7b505(%rip), %rax     # 0xc6fa8
movq 0x7d0(%rax), %rax
cmpq $0x0, (%rax)
jne 0x4bdc6
movq %r13, (%rax)
movq %r13, 0x8fb6a(%rip)     # 0xdb628
orb $0x10, 0x30(%r13)
jmp 0x4baf9
orb $0x1, 0x30(%r13)
jmp 0x4baf9
orb $0x2, 0x30(%r13)
jmp 0x4baf9
orb $0x4, 0x30(%r13)
jmp 0x4baf9
orb $0x8, 0x30(%r13)
callq 0x22843
movq %rax, 0x868(%r13)
jmp 0x4baf9
orb $0x20, 0x30(%r13)
jmp 0x4baf9
orb $0x40, 0x30(%r13)
leaq 0x1(%rbp), %rax
testq %rbp, %rbp
cmovneq %rax, %r12
jmp 0x4b9d8
movq 0x10(%rsp), %r14
movq 0x18(%r14), %rdi
cmpb $0x2d, (%rdi)
je 0x4bb4c
callq 0x4be56
movq %rax, %rbx
testq %rax, %rax
jne 0x4bb3a
movq 0x18(%r14), %rdi
xorl %esi, %esi
callq 0x4be9f
movq %rax, %rbx
movq %rax, %rdi
callq 0x4bf5b
movq %rbx, 0x850(%r13)
movq %rbx, %rdi
movq %r13, %rsi
callq 0x4bf9e
movq 0x20(%r14), %rdi
callq 0x1f710
testl %eax, %eax
je 0x4bb65
callq 0x22843
movq %rax, 0x858(%r13)
movq 0x28(%r14), %rdi
callq 0x1f710
testl %eax, %eax
je 0x4bb7e
callq 0x22843
movq %rax, 0x860(%r13)
movq 0x30(%r14), %rdi
xorl %esi, %esi
pushq $0xa
popq %rdx
callq 0x1fa00
movq %rax, 0x38(%r13)
pushq $0x8
popq %r15
movslq 0xc(%rsp), %rsi
cmpq %rsi, %r15
jge 0x4bc85
movq (%r14,%r15,8), %rbx
movb (%rbx), %bpl
movq %rbx, %rdi
pushq $0x2d
popq %rsi
callq 0x1f790
movq %rax, %r12
cmpb $0x5b, %bpl
jne 0x4bc3b
testq %r12, %r12
je 0x4bdb1
movb $0x0, (%r12)
movb 0x1(%r12), %r14b
movq 0x10(%rsp), %rax
movq (%rax,%r15,8), %rdi
incq %rdi
callq 0x1f710
movl %eax, %ebp
addq $0x3, %r12
movq %r12, %rdi
callq 0x4be56
movq %rax, %rbx
testq %rax, %rax
jne 0x4bc0c
movq %r12, %rdi
xorl %esi, %esi
callq 0x4be9f
movq %rax, %rbx
movq %rax, %rdi
callq 0x4bf5b
xorl %eax, %eax
cmpb $0x3e, %r14b
setne %al
movslq %ebp, %rcx
shll $0x11, %eax
leaq 0x7b386(%rip), %rdx     # 0xc6fa8
addq 0x7d0(%rdx), %rax
movq %rbx, 0x28(%rax,%rcx,8)
incq %r15
movq 0x10(%rsp), %r14
jmp 0x4bb94
testq %r12, %r12
je 0x4bc62
movb $0x0, (%r12)
movq 0x10(%rsp), %rax
movq (%rax,%r15,8), %rdi
callq 0x1f710
movl %eax, %ebp
incq %r12
movq %r12, %rdi
callq 0x1f710
jmp 0x4bc6c
movq %rbx, %rdi
callq 0x1f710
movl %eax, %ebp
movl %eax, %ebx
cmpl %ebx, %ebp
jg 0x4bc2e
leal 0x1(%rbp), %r14d
movq %r13, %rdi
movl %ebp, %esi
callq 0x4c00b
movl %r14d, %ebp
jmp 0x4bc6e
movq %r14, %rdi
callq 0x27d1e
movq 0x18(%rsp), %r14
leaq 0x7b30f(%rip), %r12     # 0xc6fa8
movq 0x20(%rsp), %r13
jmp 0x4b8f0
pushq $0x1
popq %r15
movq 0x18(%rsp), %r14
movq 0x20(%rsp), %r13
movslq 0xc(%rsp), %rax
cmpq %rax, %r15
jge 0x4b8f0
movq (%rbp,%r15,8), %rbx
movq %rbx, %rdi
leaq 0x45f47(%rip), %rsi     # 0x91c15
callq 0x1f2e0
testl %eax, %eax
je 0x4bd00
movq %rbx, %rdi
leaq 0x45f41(%rip), %rsi     # 0x91c22
callq 0x1f2e0
testl %eax, %eax
je 0x4bd1d
pushq $0x3
popq %rdi
leaq 0x45f3c(%rip), %rsi     # 0x91c30
movq %rbx, %rdx
xorl %eax, %eax
callq 0x22613
jmp 0x4bd3b
movq 0x8(%rbp,%r15,8), %rdi
xorl %esi, %esi
pushq $0xa
popq %rdx
callq 0x1fa00
movq 0x7d0(%r12), %rcx
movq %rax, 0x8(%rcx)
jmp 0x4bd3b
movq 0x8(%rbp,%r15,8), %rdi
xorl %esi, %esi
pushq $0xa
popq %rdx
callq 0x1fa00
movq 0x7d0(%r12), %rcx
movq %rax, 0x60070(%rcx)
addq $0x2, %r15
jmp 0x4bcb1
movq %r13, %rdi
callq 0x283cd
movq %r14, %rdi
callq 0x1f9a0
movq 0x7d0(%r12), %rax
cmpq $0x0, (%rax)
je 0x4be41
movq 0x8f8bb(%rip), %rdx     # 0xdb628
addq $0x8, %rdx
leaq 0x45f7e(%rip), %rsi     # 0x91cf6
xorl %ebx, %ebx
pushq $0x2
popq %rdi
xorl %eax, %eax
callq 0x22613
callq 0x4b7f8
movq 0x7d0(%r12), %rcx
cmpq 0x8(%rcx), %rax
jbe 0x4b8be
callq 0x4b7f8
movq 0x7d0(%r12), %rcx
movq %rax, 0x8(%rcx)
jmp 0x4b8be
leaq 0x434a1(%rip), %rdi     # 0x8f259
leaq 0x45ebe(%rip), %rsi     # 0x91c7d
movl $0x111, %edx            # imm = 0x111
jmp 0x4bdd9
leaq 0x45e91(%rip), %rdi     # 0x91c5e
leaq 0x45ea9(%rip), %rsi     # 0x91c7d
movl $0xcc, %edx
callq 0x4906b
pushq $0x1
popq %rdi
callq 0x1f3b0
leaq 0x45f2e(%rip), %rsi     # 0x91d1b
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x22613
movq 0x18(%rsp), %rdi
callq 0x1f9a0
pushq $0x1
popq %rdi
callq 0x1f2b0
leaq 0x45e9b(%rip), %rdi     # 0x91cab
leaq 0x45e66(%rip), %rsi     # 0x91c7d
movl $0xe6, %edx
callq 0x490e8
jmp 0x4bdde
callq 0x1f630
leaq 0x45db5(%rip), %rsi     # 0x91be4
pushq $0x3
popq %rdi
movq %rbx, %rdx
movq %rax, %rcx
xorl %eax, %eax
callq 0x22613
jmp 0x4be01
leaq 0x45e8f(%rip), %rdi     # 0x91cd7
leaq 0x45e2e(%rip), %rsi     # 0x91c7d
movl $0x13e, %edx            # imm = 0x13E
jmp 0x4bdd9