diff --git a/src/networking.c b/src/networking.c index d08add5ba..180564ac9 100644 --- a/src/networking.c +++ b/src/networking.c @@ -2515,6 +2515,12 @@ int processMultibulkBuffer(client *c) { * 1. The client is reset unless there are reasons to avoid doing it. * 2. In the case of master clients, the replication offset is updated. * 3. Propagate commands we got from our master to replicas down the line. */ +/* 执行命令后执行必要的任务: + * + * 1. 重置客户端,除非有理由避免重置客户端。 + * 2. 对于主客户端,复制偏移量被更新。 + * 3. 将从节点收到的命令传播到下游的副本 + * */ void commandProcessed(client *c) { /* If client is blocked(including paused), just return avoid reset and replicate. * @@ -2539,6 +2545,8 @@ void commandProcessed(client *c) { * applied to the master state: this quantity, and its corresponding * part of the replication stream, will be propagated to the * sub-replicas and to the replication backlog. */ + /* 如果客户机是主机,我们需要计算处理缓冲区之前和之后应用的偏移量之间的差异, + * 以了解有多少复制流实际应用于主机状态:此数量及其复制流的相应部分将传播到子副本和复制积压*/ if (c->flags & CLIENT_MASTER) { long long applied = c->reploff - prev_offset; if (applied) { diff --git a/src/rdb.c b/src/rdb.c index 224e883f3..74a72ca9f 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -3610,6 +3610,11 @@ void bgsaveCommand(client *c) { * pointer if the instance has a valid master client, otherwise NULL * is returned, and the RDB saving will not persist any replication related * information. */ +/* 填充 rdbSaveInfo 结构,该结构用于将复制信息保存在 RDB 文件中。 + * 当前,该结构仅显式地包含来自主流的当前选定DB,但是,如果 rdbSave*() 系列函数接收到 NULL 的 rsi 结构,则不会保存复制 ID/偏移量。 + * 该函数填充通常在调用程序中堆栈分配的 “rsi” , + * 如果实例具有有效的主客户端,则返回填充的指针,否则返回 NULL ,并且 RDB 保存不会保留任何与复制相关的信息*/ +/* 当前方法主要会写入当前的 dbid ,分别来自于 slaveseld、master->db、cache_master->db */ rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi) { rdbSaveInfo rsi_init = RDB_SAVE_INFO_INIT; *rsi = rsi_init; diff --git a/src/replication.c b/src/replication.c index 02f766148..34504bc78 100644 --- a/src/replication.c +++ b/src/replication.c @@ -51,6 +51,7 @@ int cancelReplicationHandshake(int reconnect); /* We take a global flag to remember if this instance generated an RDB * because of replication, so that we can remove the RDB file in case * the instance is configured to have no persistence. */ +/* 使用全局标志来记住此实例是否因为复制而生成 RDB ,以便在实例被配置为没有持久性的情况下删除 RDB 文件 */ int RDBGeneratedByReplication = 0; /* 从节点建立主从复制的调用链: @@ -76,6 +77,11 @@ int RDBGeneratedByReplication = 0; * pair. Mostly useful for logging, since we want to log a slave using its * IP address and its listening port which is more clear for the user, for * example: "Closing connection with replica 10.1.2.3:6380". */ + +/* 返回一个从节点的 ip:port 信息,主要功能用于打印日志 + * 其中记录的是从节点的 ip 以及从节点监听的端口,该端口是通过 REPLCONF 命令获取 + * 例如 "Closing connection with replica 10.1.2.3:6380" + */ char *replicationGetSlaveName(client *c) { static char buf[NET_HOST_PORT_STR_LEN]; char ip[NET_IP_STR_LEN]; @@ -782,6 +788,8 @@ long long addReplyReplicationBacklog(client *c, long long offset) { * from the slave. The returned value is only valid immediately after * the BGSAVE process started and before executing any other command * from clients. */ +/* 返回偏移量,作为对从从节点接收到的 PSYNC 命令的回复。 + * 返回的值仅在 BGSAVE 进程启动后以及从节点执行任何其他命令之前才有效 */ long long getPsyncInitialOffset(void) { return server.master_repl_offset; } @@ -983,6 +991,12 @@ int masterTryPartialResynchronization(client *c, long long psync_offset) { * started. * * Returns C_OK on success or C_ERR otherwise. */ + +/* 为复制目标启动 BGSAVE,即根据配置选择磁盘或套接字目标,并确保在启动之前刷新脚本缓存。 + * mincapa 参数是等待此 BGSAVE 的从机的所有从机功能中的逐位 AND,因此表示所有从机支持的从机功能。可以通过 SLAVE_CAPA_* 宏进行测试。 + * 除启动 BGSAVE 外的副作用: + * 1. 处理处于 WAIT_START状态的从机,如果 BGSAVE 成功启动,则为它们准备完全同步,或者向它们发送错误并将它们从从机列表中删除。 + * 2. 如果 BGSAVE 实际启动,则刷新 Lua 脚本脚本缓存。*/ int startBgsaveForReplication(int mincapa, int req) { int retval; int socket_target = 0; @@ -1006,6 +1020,7 @@ int startBgsaveForReplication(int mincapa, int req) { rsiptr = rdbPopulateSaveInfo(&rsi); /* Only do rdbSave* when rsiptr is not NULL, * otherwise slave will miss repl-stream-db. */ + /* 只有 无复制链的 master、未连接 master 的 slave、不存在 cachemaster 的 slave 无法进行 rdb 生成 */ if (rsiptr) { if (socket_target) /* 直接通过 socket 发送 RDB */ @@ -1022,18 +1037,23 @@ int startBgsaveForReplication(int mincapa, int req) { * that we don't set the flag to 1 if the feature is disabled, otherwise * it would never be cleared: the file is not deleted. This way if * the user enables it later with CONFIG SET, we are fine. */ + /* 如果我们成功地启动了一个带有磁盘目标的 BGSAVE ,让我们记住这个事实,以便稍后在需要时删除该文件。 + * 请注意,如果功能被禁用,我们不会将标志设置为1,否则它将永远不会被清除:文件不会被删除。 + * 这样,如果用户稍后使用 CONFIG SET 启用它,我们就可以了*/ if (retval == C_OK && !socket_target && server.rdb_del_sync_files) RDBGeneratedByReplication = 1; /* If we failed to BGSAVE, remove the slaves waiting for a full * resynchronization from the list of slaves, inform them with * an error about what happened, close the connection ASAP. */ + /* 如果我们无法 BGSAVE,请从从机列表中删除等待完全重新同步的从机,并通知他们发生的错误,尽快关闭连接 */ if (retval == C_ERR) { serverLog(LL_WARNING,"BGSAVE for replication failed"); listRewind(server.slaves,&li); while((ln = listNext(&li))) { client *slave = ln->value; + /* 发送给所有等待 bgsave 开始的 slave 发送错误 BGSAVE failed */ if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) { slave->replstate = REPL_STATE_NONE; slave->flags &= ~CLIENT_SLAVE; @@ -1048,6 +1068,7 @@ int startBgsaveForReplication(int mincapa, int req) { /* If the target is socket, rdbSaveToSlavesSockets() already setup * the slaves for a full resync. Otherwise for disk target do it now.*/ + /* 如果目标是套接字,则 rdbSaveToSlavesSockets() 已设置从机以进行完全重新同步。否则,对于磁盘目标,请立即执行 */ if (!socket_target) { listRewind(server.slaves,&li); while((ln = listNext(&li))) { @@ -1432,7 +1453,15 @@ void replconfCommand(client *c) { * 1) Put the slave in ONLINE state. * 2) Update the count of "good replicas". * 3) Trigger the module event. */ +/** + * 此函数将副本置于联机状态,并应在副本收到用于初始同步的RDB文件后立即调用。 + * 其中包括以下影响: + * 1. 将从节点设置为 online 状态 + * 2. 更新 repl_good_slaves_count 计数 + * 3. 触发 module 的事件 +*/ void replicaPutOnline(client *slave) { + /* 如果从节点只需要 RDB 文件,则不需要继续设置为 online 状态,参考:redis-cli --rdb */ if (slave->flags & CLIENT_REPL_RDBONLY) { return; } @@ -1460,7 +1489,14 @@ void replicaPutOnline(client *slave) { * command we had no replies and it was disabled, and then we could * accumulate output buffer data without sending it to the replica so it * won't get mixed with the RDB stream. */ + +/* 在同步的 RDB 文件之后立即调用此函数,并且开始发送增量命令流 + * + * 它做了一些事情: + * 1. 如果不需要复制命令缓冲流,则异步关闭副本的连接,因为它实际上不是有效的副本。 + * 2. 将当前的 slave 写入 pendingWriteQueue 待写队列中 */ void replicaStartCommandStream(client *slave) { + /* 设置当前的 slave 已经设置了可写事件,不需要重入 */ slave->repl_start_cmd_stream_on_ack = 0; if (slave->flags & CLIENT_REPL_RDBONLY) { serverLog(LL_NOTICE, @@ -1478,6 +1514,8 @@ void replicaStartCommandStream(client *slave) { * without any persistence. We don't want instances without persistence * to take RDB files around, this violates certain policies in certain * environments. */ +/* 定期调用此函数以删除由于复制而生成的 RDB 文件,而该文件在其他情况下没有任何持久性。 + * 不希望没有持久性的实例到处携带 RDB 文件,这违反了某些环境中的某些策略 */ void removeRDBUsedToSyncReplicas(void) { /* If the feature is disabled, return ASAP but also clear the * RDBGeneratedByReplication flag in case it was set. Otherwise if the @@ -1485,6 +1523,9 @@ void removeRDBUsedToSyncReplicas(void) { * flag may remain set to one: then next time the feature is re-enabled * via CONFIG SET we have it set even if no RDB was generated * because of replication recently. */ + /* 如果该功能被禁用,请尽快返回,但如果设置了 RDBGeneratedByReplication 标志,请清除该标志。否则,如果该功能已启用, + * 但稍后使用 CONFIG SET 被禁用,则该标志可能会保持为1 + * 那么下次通过 CONFIG NET 重新启用该功能时,即使最近由于复制而没有生成 RDB,我们也会将其设置为1 */ if (!server.rdb_del_sync_files) { RDBGeneratedByReplication = 0; return; @@ -1507,6 +1548,7 @@ void removeRDBUsedToSyncReplicas(void) { break; /* No need to check the other replicas. */ } } + /* 如果不存在等待 bgsave 的从节点,则开始删除 rdb 文件 */ if (delrdb) { struct stat sb; if (lstat(server.rdb_filename,&sb) != -1) { @@ -1520,6 +1562,9 @@ void removeRDBUsedToSyncReplicas(void) { } } +/** + * 主节点进行主从同步时绑定的写回调事件 +*/ void sendBulkToSlave(connection *conn) { client *slave = connGetPrivateData(conn); char buf[PROTO_IOBUF_LEN]; @@ -1528,6 +1573,9 @@ void sendBulkToSlave(connection *conn) { /* Before sending the RDB file, we send the preamble as configured by the * replication process. Currently the preamble is just the bulk count of * the file in the form "$\r\n". */ + /* 在发送 RDB 文件之前,需要提前发送复制内容的属性 + * 目前,属性只是包含文件的大小,格式为 “$\r\n” + * 这个字段在设置写事件时设置,并在发送后设置为 NULL */ if (slave->replpreamble) { nwritten = connWrite(conn,slave->replpreamble,sdslen(slave->replpreamble)); if (nwritten == -1) { @@ -1538,7 +1586,9 @@ void sendBulkToSlave(connection *conn) { return; } atomicIncr(server.stat_net_repl_output_bytes, nwritten); + /* 移除 replpreamble 已发送的数据 */ sdsrange(slave->replpreamble,nwritten,-1); + /* 若 replpreamble 已经发送完成,则直接清空 */ if (sdslen(slave->replpreamble) == 0) { sdsfree(slave->replpreamble); slave->replpreamble = NULL; @@ -1549,6 +1599,7 @@ void sendBulkToSlave(connection *conn) { } /* If the preamble was already transferred, send the RDB bulk data. */ + /* 发送 replpreamble 后,开始发送 RDB 文件数据,同时设置当前的偏移量,以及每次传输 16K 数据 */ lseek(slave->repldbfd,slave->repldboff,SEEK_SET); buflen = read(slave->repldbfd,buf,PROTO_IOBUF_LEN); if (buflen <= 0) { @@ -1567,6 +1618,7 @@ void sendBulkToSlave(connection *conn) { } slave->repldboff += nwritten; atomicIncr(server.stat_net_repl_output_bytes, nwritten); + /* 当写入的数据量和RDB数据大小相同,则认为传输完成,开始关闭RDB的fd,并重置写事件 */ if (slave->repldboff == slave->repldbsize) { close(slave->repldbfd); slave->repldbfd = -1; @@ -1915,6 +1967,7 @@ void replicationEmptyDbCallback(dict *d) { /* Once we have a link with the master and the synchronization was * performed, this function materializes the master client we store * at server.master, starting from the specified file descriptor. */ +/* 一旦我们与 master 建立了链接并执行了同步,此函数将从指定的文件描述符开始具体化我们存储在 server.master 中的 master 客户端 */ void replicationCreateMasterClient(connection *conn, int dbid) { server.master = createClient(conn); if (conn) @@ -3650,6 +3703,7 @@ void roleCommand(client *c) { /* Send a REPLCONF ACK command to the master to inform it about the current * processed offset. If we are not connected with a master, the command has * no effects. */ +/* 向主节点发送 REPLCONF ACK 命令,通知其当前处理的偏移量。如果我们没有与主机连接,则该命令无效 */ void replicationSendAck(void) { client *c = server.master; @@ -3819,6 +3873,11 @@ void replicationResurrectCachedMaster(connection *conn) { /* This function counts the number of slaves with lag <= min-slaves-max-lag. * If the option is active, the server will prevent writes if there are not * enough connected slaves with the specified lag (or less). */ +/** + * 只有 lag <= min-slaves-max-lag 才被认为是好的从节点。 + * 其中 repl_good_slaves_count 计数主要用于与 repl_min_slaves_to_write 对比,确定当前主节点是否可写 + * 若 repl_min_slaves_to_write 未设置,则不需要进行 repl_good_slaves_count 的计数操作 +*/ void refreshGoodSlavesCount(void) { listIter li; listNode *ln; @@ -3839,6 +3898,14 @@ void refreshGoodSlavesCount(void) { } /* return true if status of good replicas is OK. otherwise false */ +/** + * 判断当前主节点是否可用: + * 1. 从节点可用 + * 2. 未设置了偏移容忍度 repl_min_slaves_max_lag + * 3. 未设置了最小可用 slave:repl_min_slaves_to_write + * 4. 存在足够多的好节点 + * 若完全不满足,则会导致主节点禁止写入 + */ int checkGoodReplicasStatus(void) { return server.masterhost || /* not a primary status should be OK */ !server.repl_min_slaves_max_lag || /* Min slave max lag not configured */ @@ -3882,6 +3949,7 @@ void replicationRequestAckFromSlaves(void) { /* Return the number of slaves that already acknowledged the specified * replication offset. */ +/* 返回已确认指定复制偏移量的从机数量 */ int replicationCountAcksByOffset(long long offset) { listIter li; listNode *ln; @@ -3899,6 +3967,7 @@ int replicationCountAcksByOffset(long long offset) { /* WAIT for N replicas to acknowledge the processing of our latest * write command (and all the previous commands). */ +/* 等待 N 个副本,以确认我们最新的写入命令(以及所有以前的命令)的处理 */ void waitCommand(client *c) { mstime_t timeout; long numreplicas, ackreplicas; @@ -3932,6 +4001,7 @@ void waitCommand(client *c) { /* Make sure that the server will send an ACK request to all the slaves * before returning to the event loop. */ + /* 在返回事件循环之前,确保服务器将向所有从节点发送ACK请求 */ replicationRequestAckFromSlaves(); } @@ -3947,6 +4017,7 @@ void unblockClientWaitingReplicas(client *c) { /* Check if there are clients blocked in WAIT that can be unblocked since * we received enough ACKs from slaves. */ +/* 检查是否有在等待中被阻止的客户端可以被解除阻止,因为我们从从属服务器收到了足够的 ACK */ void processClientsWaitingReplicas(void) { long long last_offset = 0; int last_numreplicas = 0; @@ -4358,6 +4429,7 @@ const char *getFailoverStateString() { /* Resets the internal failover configuration, this needs * to be called after a failover either succeeds or fails * as it includes the client unpause. */ +/* 重置内部故障切换配置,这需要在故障切换成功或失败后调用,因为它包括客户端取消连接 */ void clearFailoverState() { server.failover_end_time = 0; server.force_failover = 0; @@ -4369,6 +4441,7 @@ void clearFailoverState() { } /* Abort an ongoing failover if one is going on. */ +/* 如果正在进行故障转移,则中止正在进行的故障转移 */ void abortFailover(const char *err) { if (server.failover_state == NO_FAILOVER) return; @@ -4411,6 +4484,16 @@ void abortFailover(const char *err) { * a replica to sync up before aborting. If not specified, the failover * will attempt forever and must be manually aborted. */ +/* + * 此命令将协调主节点和从节点之间的故障转移 + * 包含以下步骤: + * 1. 主节点将启动客户端暂停写入,以停止复制。 + * 2. 主节点将定期检查其任何副本是否具有通过ack消耗了整个复制流。 + * 3. 一旦任何副本赶上,主节点本身将成为副本。 + * 4. 主节点将向目标副本发送 PSYNC FAILOVER 请求如果接受,将使副本成为新的主副本并开始同步。 + * + * 其中包括 FORCE、ABORT、TIMEOUT 的选项,分别代表强制切换、中断切换、切换超时 +*/ void failoverCommand(client *c) { if (server.cluster_enabled) { addReplyError(c,"FAILOVER not allowed in cluster mode. " @@ -4525,11 +4608,17 @@ void failoverCommand(client *c) { * failover doesn't work like blocked clients will be unblocked and replicas will * be disconnected. This could be optimized further. */ +/* 故障转移 cron 功能,检查协调的故障转移状态。 + * + * 实施说明:当前的实现调用 replicationSetMaster() 来启动故障转移请求,如果故障转移无法正常工作,则会产生一些意外的副作用, + * 比如被阻止的客户端将被解锁,副本将被断开连接。这可以进一步优化。 + */ void updateFailoverStatus(void) { if (server.failover_state != FAILOVER_WAIT_FOR_SYNC) return; mstime_t now = server.mstime; /* Check if failover operation has timed out */ + /* 如果 failover 的时间已过,则判断是否强制 failover */ if (server.failover_end_time && server.failover_end_time <= now) { if (server.force_failover) { serverLog(LL_NOTICE, @@ -4537,17 +4626,20 @@ void updateFailoverStatus(void) { server.target_replica_host, server.target_replica_port); server.failover_state = FAILOVER_IN_PROGRESS; /* If timeout has expired force a failover if requested. */ + /* 如果强行 failover,则直接设置 master */ replicationSetMaster(server.target_replica_host, server.target_replica_port); return; } else { /* Force was not requested, so timeout. */ + /* 超时则直接暂停 failover 操作 */ abortFailover("Replica never caught up before timeout"); return; } } /* Check to see if the replica has caught up so failover can start */ + /* 选取一个 replica 作为新的 master */ client *replica = NULL; if (server.target_replica_host) { replica = findReplica(server.target_replica_host, @@ -4560,6 +4652,7 @@ void updateFailoverStatus(void) { /* Find any replica that has matched our repl_offset */ while((ln = listNext(&li))) { replica = ln->value; + /* 如果存在一个 replica 偏移量和当前 master 的偏移量相同,则采用当前的 replica */ if (replica->repl_ack_off == server.master_repl_offset) { char ip[NET_IP_STR_LEN], *replicaaddr = replica->slave_addr; @@ -4578,6 +4671,7 @@ void updateFailoverStatus(void) { } /* We've found a replica that is caught up */ + /* 找到了一个 replica,且偏移量满足需求,则直接设置 master 信息 */ if (replica && (replica->repl_ack_off == server.master_repl_offset)) { server.failover_state = FAILOVER_IN_PROGRESS; serverLog(LL_NOTICE, diff --git a/src/server.c b/src/server.c index b0cef8870..93d1305d3 100644 --- a/src/server.c +++ b/src/server.c @@ -647,6 +647,7 @@ int isInsideYieldingLongCommand() { /* Return true if this instance has persistence completely turned off: * both RDB and AOF are disabled. */ +/* 如果此实例已完全关闭持久性,则返回 true,表示 RDB 和 AOF 都已禁用 */ int allPersistenceDisabled(void) { return server.saveparamslen == 0 && server.aof_state == AOF_OFF; } @@ -1594,6 +1595,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) { * We also don't send the ACKs while clients are paused, since it can * increment the replication backlog, they'll be sent after the pause * if we are still the master. */ + /* 如果在上一次事件循环迭代期间至少有一个客户端被阻塞,则向所有从机发送ACK请求。 + * 请注意,我们在 processUnblockedClients() 之后执行此操作,因此如果有多个流水线 WAIT ,并且刚刚解锁的 WAIT 再次被阻塞, + * 我们不必在没有其他事件循环事件的情况下等待服务器 cron 循环。参见#6623。 + * + * 我们也不会在客户端暂停时发送 ACK ,因为它会增加复制积压,如果我们仍然是主机,它们将在暂停后发送 */ if (server.get_ack_from_slaves && !checkClientPauseTimeoutAndReturnIfPaused()) { sendGetackToReplicas(); server.get_ack_from_slaves = 0; @@ -1602,6 +1608,8 @@ void beforeSleep(struct aeEventLoop *eventLoop) { /* We may have received updates from clients about their current offset. NOTE: * this can't be done where the ACK is received since failover will disconnect * our clients. */ + /* 我们可能已经收到客户关于当前偏移量的更新。 + * 注意:在收到 ACK 的情况下无法执行此操作,因为故障切换将断开我们的客户端 */ updateFailoverStatus(); /* Since we rely on current_client to send scheduled invalidation messages diff --git a/src/server.h b/src/server.h index 345e00a19..088f8c4a8 100644 --- a/src/server.h +++ b/src/server.h @@ -413,9 +413,13 @@ typedef enum { } repl_state; /* The state of an in progress coordinated failover */ +/* 正在进行的协调故障转移的状态 */ typedef enum { + /* 未进行故障切换 */ NO_FAILOVER = 0, /* No failover in progress */ + /* 等待目标复制副本赶上 */ FAILOVER_WAIT_FOR_SYNC, /* Waiting for target replica to catch up */ + /* 正在等待目标副本接受PSYNC FAILOVER请求 */ FAILOVER_IN_PROGRESS /* Waiting for target replica to accept * PSYNC FAILOVER request. */ } failover_state; @@ -436,7 +440,9 @@ typedef enum { /* Slave requirements */ #define SLAVE_REQ_NONE 0 +/* 不包括 rdb 的数据 */ #define SLAVE_REQ_RDB_EXCLUDE_DATA (1 << 0) /* Exclude data from RDB */ +/* 不包括 rdb 的方法 */ #define SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS (1 << 1) /* Exclude functions from RDB */ /* Mask of all bits in the slave requirements bitfield that represent non-standard (filtered) RDB requirements */ #define SLAVE_REQ_RDB_MASK (SLAVE_REQ_RDB_EXCLUDE_DATA | SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS) @@ -571,9 +577,13 @@ typedef enum { } pause_type; /* Client pause purposes. Each purpose has its own end time and pause type. */ +/* 客户端暂停目的。每个目的都有自己的结束时间和暂停类型 */ typedef enum { + /* 命令方式暂停 */ PAUSE_BY_CLIENT_COMMAND = 0, + /* 停止服务中间的暂停 */ PAUSE_DURING_SHUTDOWN, + /* Failover的暂停 */ PAUSE_DURING_FAILOVER, NUM_PAUSE_PURPOSES /* This value is the number of purposes above. */ } pause_purpose; @@ -1128,11 +1138,17 @@ typedef struct client { off_t repldboff; /* Replication DB file offset. */ off_t repldbsize; /* Replication DB file size. */ sds replpreamble; /* Replication DB preamble. */ + /* master-client 的读取的偏移量 */ long long read_reploff; /* Read replication offset if this is a master. */ + /* 已经执行的数据偏移量 */ long long reploff; /* Applied replication offset if this is a master. */ + /* 已经发送出去的数据偏移量 */ long long repl_applied; /* Applied replication data count in querybuf, if this is a replica. */ + /* client 接受到的偏移量 */ long long repl_ack_off; /* Replication ack offset, if this is a slave. */ + /* client 接受到的时间 */ long long repl_ack_time;/* Replication ack time, if this is a slave. */ + /* 服务器上次从 RDB 子管道向此副本执行部分写入的时间 */ long long repl_last_partial_write; /* The last time the server did a partial write from the RDB child pipe to this replica */ long long psync_initial_offset; /* FULLRESYNC reply offset other slaves copying this slave output buffer @@ -1145,6 +1161,7 @@ typedef struct client { multiState mstate; /* MULTI/EXEC state */ int btype; /* Type of blocking op if CLIENT_BLOCKED. */ blockingState bpop; /* blocking state */ + /* 上次写入全局复制偏移量 */ long long woff; /* Last write global replication offset. */ list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */ dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */ @@ -1352,6 +1369,8 @@ typedef enum { * replication in order to make sure that chained slaves (slaves of slaves) * select the correct DB and are able to accept the stream coming from the * top-level master. */ +/* 此结构可以可选地传递给 RDB 保存/加载函数,以便通过将元数据存储和加载到 RDB 文件来实现其他功能 + * 例如,在加载时使用 select 一个 DB,这在复制中非常有用,以确保链接的从机(从机的从机)选择正确的 DB,并且能够接受来自顶部的 master 的数据 */ typedef struct rdbSaveInfo { /* Used saving and loading. */ int repl_stream_db; /* DB to select in server.master client. */ @@ -1754,6 +1773,7 @@ struct redisServer { * 若新 master 收到的 psync 命令中的 replid 与自己的 replid2 相同且同时复制偏移仍然在复制积压缓冲区内,那么仍然可以进行部分同步 */ char replid2[CONFIG_RUN_ID_SIZE+1]; /* replid inherited from master*/ + /* 当前的复制偏移量 */ long long master_repl_offset; /* My current replication offset */ long long second_replid_offset; /* Accept offsets up to this for replid2. */ int slaveseldb; /* Last SELECTed DB in replication output */ @@ -1813,6 +1833,7 @@ struct redisServer { * while the PSYNC is in progress. At the end we'll copy the fields into * the server->master client structure. */ char master_replid[CONFIG_RUN_ID_SIZE+1]; /* Master PSYNC runid. */ + /* 初始化的偏移量 */ long long master_initial_offset; /* Master PSYNC offset. */ int repl_slave_lazy_flush; /* Lazy FLUSHALL before loading DB? */ /* Synchronous replication. */ @@ -1942,9 +1963,12 @@ struct redisServer { mstime_t failover_end_time; /* Deadline for failover command. */ int force_failover; /* If true then failover will be forced at the * deadline, otherwise failover is aborted. */ + /* failover 的目标 host */ char *target_replica_host; /* Failover target host. If null during a * failover then any replica can be used. */ + /* failover 的目标 port */ int target_replica_port; /* Failover target port */ + /* failover 的状态信息: 无 failover,待切换、待确认 */ int failover_state; /* Failover state */ int cluster_allow_pubsubshard_when_down; /* Is pubsubshard allowed when the cluster is down, doesn't affect pubsub global. */