1/* Asynchronous replication implementation.2 *3 * Copyright (c) 2009-Present, Redis Ltd.4 * All rights reserved.5 *6 * Copyright (c) 2024-present, Valkey contributors.7 * All rights reserved.8 *9 * Licensed under your choice of (a) the Redis Source Available License 2.010 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the11 * GNU Affero General Public License v3 (AGPLv3).12 *13 * Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.14 */1516/*17 * replication.c - Replication Management18 *19 * This file contains the implementation of Redis's replication logic, which20 * enables data synchronization between master and replica instances.21 * It handles:22 * - Master-to-replica synchronization23 * - Full and partial resynchronizations24 * - Replication backlog management25 * - State machines for replica operations26 * - RDB Channel for Full Sync (lookup "rdb channel for full sync")27 */2829#include "server.h"30#include "cluster.h"31#include "cluster_slot_stats.h"32#include "bio.h"33#include "functions.h"34#include "connection.h"35#include "cluster_asm.h"3637#include <memory.h>38#include <sys/time.h>39#include <unistd.h>40#include <fcntl.h>41#include <sys/socket.h>42#include <sys/stat.h>4344void replicationDiscardCachedMaster(void);45void replicationResurrectCachedMaster(connection *conn);46void replicationSendAck(void);47int replicaPutOnline(client *slave);48void replicaStartCommandStream(client *slave);49int cancelReplicationHandshake(int reconnect);50static void rdbChannelFullSyncWithMaster(connection *conn);51static int rdbChannelAbort(void);52static void rdbChannelBufferReplData(connection *conn);53static void rdbChannelReplDataBufInit(void);54static void rdbChannelStreamReplDataToDb(void);55static void rdbChannelCleanup(void);5657/* We take a global flag to remember if this instance generated an RDB58 * because of replication, so that we can remove the RDB file in case59 * the instance is configured to have no persistence. */60int RDBGeneratedByReplication = 0;616263/* A reference to diskless loading rio to abort it asynchronously. It's needed64 * for rdbchannel replication. While loading from rdbchannel connection, we may65 * yield back to eventloop. If main channel connection detects a network problem66 * we want to abort loading. It calls rioAbort() in this case, so next rioRead()67 * from rdbchannel connection will return error to cancel loading safely. */68static rio *disklessLoadingRio = NULL;6970/* --------------------------- Utility functions ---------------------------- */7172/* Returns 1 if the replica is rdbchannel and there is an associated main73 * channel slave with that. */74int replicationCheckHasMainChannel(client *replica) {75 if (!(replica->flags & CLIENT_REPL_RDB_CHANNEL) ||76 !replica->main_ch_client_id ||77 lookupClientByID(replica->main_ch_client_id) == NULL)78 {79 return 0;80 }81 return 1;82}8384/* During rdb channel replication, replica opens two connections. From master85 * POV, these connections are distinct replicas in server.slaves. This function86 * counts associated replicas as one and returns logical replica count. */87unsigned long replicationLogicalReplicaCount(void) {88 unsigned long count = 0;89 listNode *ln;90 listIter li;9192 listRewind(server.slaves,&li);93 while ((ln = listNext(&li))) {94 client *replica = listNodeValue(ln);95 if (!replicationCheckHasMainChannel(replica))96 count++;97 }98 return count;99}100101int replicaFromIOThreadHasPendingRead(client *c) {102 serverAssert(c->tid != IOTHREAD_MAIN_THREAD_ID);103104 int pending_read;105 atomicGetWithSync(c->pending_read, pending_read);106 return pending_read;107}108109/* Send replicas to their respective IO threads if it has pending reads or110 * writes. Otherwise it remains in main thread so it can check for new data in111 * the replication buffer ASAP. */112void putReplicasInPendingClientsToIOThreads(void) {113 if (server.io_threads_num <= 1) return;114115 serverAssert(pthread_equal(pthread_self(), server.main_thread_id));116117 listIter li;118 listNode *ln;119 listRewind(server.slaves,&li);120 while((ln = listNext(&li))) {121 client *replica = listNodeValue(ln);122123 /* We only care about replicas that need to run on IO thread but are124 * currently in main */125 if (replica->tid == IOTHREAD_MAIN_THREAD_ID ||126 replica->running_tid != IOTHREAD_MAIN_THREAD_ID)127 {128 continue;129 }130131 /* Skip the replica if it's scheduled for close */132 if (replica->flags & CLIENT_CLOSE_ASAP) continue;133134 /* The call to clientHasPendingReplies may seem redundant but in the135 * case of replica being in IO thread we can have the following case:136 * replica gets back to main thread after sending the repl buffer it137 * knows about. In the mean time main thread has accumulated new repl138 * data. In that case the replica's client wouldn't have been put in139 * the pending write queue but will still have new repl data it needs to140 * send, so we make sure to check for that and send it back to IO thread141 * if so. On the other hand if replica gets back to main thread before142 * any new repl data has accumulated then after a new cmd is propagated143 * the replica will be put in the pending write queue as usual so we144 * need to check for that also.145 * In addition, if the replica client has pending read events, we should146 * also send them to the IO thread. */147 if (replica->flags & CLIENT_PENDING_WRITE ||148 clientHasPendingReplies(replica) ||149 replicaFromIOThreadHasPendingRead(replica))150 {151 enqueuePendingClienstToIOThreads(replica);152 }153 }154}155156/* Run some cron tasks for a connected master client. Return 1 when the client157 * is freed, 0 otherwise. */158int replicationCronRunMasterClient(void) {159 if (!server.masterhost || !server.master) return 0;160161 if (server.master->running_tid != IOTHREAD_MAIN_THREAD_ID) return 0;162163 /* Timed out master when we are an already connected slave? */164 if (server.repl_state == REPL_STATE_CONNECTED &&165 (time(NULL)-server.master->lastinteraction) > server.repl_timeout)166 {167 serverLog(LL_WARNING,"MASTER timeout: no data nor PING received...");168 freeClient(server.master);169 return 1;170 }171172 /* Send ACK to master from time to time.173 * Note that we do not send periodic acks to masters that don't174 * support PSYNC and replication offsets. */175 if (!(server.master->flags & CLIENT_PRE_PSYNC))176 replicationSendAck();177178 return 0;179}180181ConnectionType *connTypeOfReplication(void) {182 if (server.tls_replication) {183 return connectionTypeTls();184 }185186 return connectionTypeTcp();187}188189/* Return the pointer to a string representing the slave ip:listening_port190 * pair. Mostly useful for logging, since we want to log a slave using its191 * IP address and its listening port which is more clear for the user, for192 * example: "Closing connection with replica 10.1.2.3:6380". */193char *replicationGetSlaveName(client *c) {194 static char buf[NET_HOST_PORT_STR_LEN];195 char ip[NET_IP_STR_LEN];196197 ip[0] = '\0';198 buf[0] = '\0';199 if (c->slave_addr ||200 connAddrPeerName(c->conn,ip,sizeof(ip),NULL) != -1)201 {202 char *addr = c->slave_addr ? c->slave_addr : ip;203 if (c->slave_listening_port)204 formatAddr(buf,sizeof(buf),addr,c->slave_listening_port);205 else206 snprintf(buf,sizeof(buf),"%s:<unknown-replica-port>",addr);207 } else {208 snprintf(buf,sizeof(buf),"client id #%llu",209 (unsigned long long) c->id);210 }211 return buf;212}213214/* Plain unlink() can block for quite some time in order to actually apply215 * the file deletion to the filesystem. This call removes the file in a216 * background thread instead. We actually just do close() in the thread,217 * by using the fact that if there is another instance of the same file open,218 * the foreground unlink() will only remove the fs name, and deleting the219 * file's storage space will only happen once the last reference is lost. */220int bg_unlink(const char *filename) {221 int fd = open(filename,O_RDONLY|O_NONBLOCK);222 if (fd == -1) {223 /* Can't open the file? Fall back to unlinking in the main thread. */224 return unlink(filename);225 } else {226 /* The following unlink() removes the name but doesn't free the227 * file contents because a process still has it open. */228 int retval = unlink(filename);229 if (retval == -1) {230 /* If we got an unlink error, we just return it, closing the231 * new reference we have to the file. */232 int old_errno = errno;233 close(fd); /* This would overwrite our errno. So we saved it. */234 errno = old_errno;235 return -1;236 }237 bioCreateCloseJob(fd, 0, 0);238 return 0; /* Success. */239 }240}241242/* ---------------------------------- MASTER -------------------------------- */243244void createReplicationBacklog(void) {245 serverAssert(server.repl_backlog == NULL);246 server.repl_backlog = zmalloc(sizeof(replBacklog));247 server.repl_backlog->ref_repl_buf_node = NULL;248 server.repl_backlog->unindexed_count = 0;249 server.repl_backlog->blocks_index = raxNewEx(0, NULL, sizeof(uint64_t));250 server.repl_backlog->histlen = 0;251 /* We don't have any data inside our buffer, but virtually the first252 * byte we have is the next byte that will be generated for the253 * replication stream. */254 server.repl_backlog->offset = server.master_repl_offset+1;255}256257/* This function is called when the user modifies the replication backlog258 * size at runtime. It is up to the function to resize the buffer and setup it259 * so that it contains the same data as the previous one (possibly less data,260 * but the most recent bytes, or the same data and more free space in case the261 * buffer is enlarged). */262void resizeReplicationBacklog(void) {263 if (server.repl_backlog_size < CONFIG_REPL_BACKLOG_MIN_SIZE)264 server.repl_backlog_size = CONFIG_REPL_BACKLOG_MIN_SIZE;265 if (server.repl_backlog)266 incrementalTrimReplicationBacklog(REPL_BACKLOG_TRIM_BLOCKS_PER_CALL);267}268269void freeReplicationBacklog(void) {270 serverAssert(listLength(server.slaves) == 0);271 if (server.repl_backlog == NULL) return;272273 /* Decrease the start buffer node reference count. */274 if (server.repl_backlog->ref_repl_buf_node) {275 replBufBlock *o = listNodeValue(276 server.repl_backlog->ref_repl_buf_node);277 serverAssert(o->refcount == 1); /* Last reference. */278 o->refcount--;279 }280281 /* Replication buffer blocks are completely released when we free the282 * backlog, since the backlog is released only when there are no replicas283 * and the backlog keeps the last reference of all blocks. */284 freeReplicationBacklogRefMemAsync(server.repl_buffer_blocks,285 server.repl_backlog->blocks_index);286 resetReplicationBuffer();287 zfree(server.repl_backlog);288 server.repl_backlog = NULL;289}290291/* To make search offset from replication buffer blocks quickly292 * when replicas ask partial resynchronization, we create one index293 * block every REPL_BACKLOG_INDEX_PER_BLOCKS blocks. */294void createReplicationBacklogIndex(listNode *ln) {295 server.repl_backlog->unindexed_count++;296 if (server.repl_backlog->unindexed_count >= REPL_BACKLOG_INDEX_PER_BLOCKS) {297 replBufBlock *o = listNodeValue(ln);298 uint64_t encoded_offset = htonu64(o->repl_offset);299 raxInsert(server.repl_backlog->blocks_index,300 (unsigned char*)&encoded_offset, sizeof(uint64_t),301 ln, NULL);302 server.repl_backlog->unindexed_count = 0;303 }304}305306/* Rebase replication buffer blocks' offset since the initial307 * setting offset starts from 0 when master restart. */308void rebaseReplicationBuffer(long long base_repl_offset) {309 raxFree(server.repl_backlog->blocks_index);310 server.repl_backlog->blocks_index = raxNewEx(0, NULL, sizeof(uint64_t));311 server.repl_backlog->unindexed_count = 0;312313 listIter li;314 listNode *ln;315 listRewind(server.repl_buffer_blocks, &li);316 while ((ln = listNext(&li))) {317 replBufBlock *o = listNodeValue(ln);318 o->repl_offset += base_repl_offset;319 createReplicationBacklogIndex(ln);320 }321}322323void resetReplicationBuffer(void) {324 server.repl_buffer_mem = 0;325 server.repl_buffer_blocks = listCreate();326 listSetFreeMethod(server.repl_buffer_blocks, zfree);327}328329int canFeedReplicaReplBuffer(client *replica) {330 /* Don't feed replicas that only want the RDB or main channels of migration331 * destinations which need filtered stream for migrating slot ranges. */332 if (replica->flags & CLIENT_REPL_RDBONLY ||333 replica->flags & CLIENT_ASM_MIGRATING) return 0;334335 /* Don't feed replicas that are still waiting for BGSAVE to start. */336 if (replica->replstate == SLAVE_STATE_WAIT_BGSAVE_START ||337 replica->replstate == SLAVE_STATE_WAIT_RDB_CHANNEL) return 0;338339 /* Don't feed replicas that are going to be closed ASAP. */340 if (replica->flags & CLIENT_CLOSE_ASAP) return 0;341342 return 1;343}344345/* Create the replication backlog if needed. */346void createReplicationBacklogIfNeeded(void) {347 if (listLength(server.slaves) == 1 && server.repl_backlog == NULL) {348 /* When we create the backlog from scratch, we always use a new349 * replication ID and clear the ID2, since there is no valid350 * past history. */351 changeReplicationId();352 clearReplicationId2();353 createReplicationBacklog();354 serverLog(LL_NOTICE,"Replication backlog created, my new "355 "replication IDs are '%s' and '%s'",356 server.replid, server.replid2);357 }358}359/* Similar with 'prepareClientToWrite', note that we must call this function360 * before feeding replication stream into global replication buffer, since361 * clientHasPendingReplies in prepareClientToWrite will access the global362 * replication buffer to make judgements. */363int prepareReplicasToWrite(void) {364 listIter li;365 listNode *ln;366 int prepared = 0;367368 listRewind(server.slaves,&li);369 while((ln = listNext(&li))) {370 client *slave = ln->value;371 if (!canFeedReplicaReplBuffer(slave)) continue;372 if (prepareClientToWrite(slave) == C_ERR) continue;373 prepared++;374 }375376 return prepared;377}378379/* Generally, we only have one replication buffer block to trim when replication380 * backlog size exceeds our setting and no replica reference it. But if replica381 * clients disconnect, we need to free many replication buffer blocks that are382 * referenced. It would cost much time if there are a lots blocks to free, that383 * will freeze server, so we trim replication backlog incrementally. */384void incrementalTrimReplicationBacklog(size_t max_blocks) {385 serverAssert(server.repl_backlog != NULL);386387 size_t trimmed_blocks = 0;388 while (server.repl_backlog->histlen > server.repl_backlog_size &&389 trimmed_blocks < max_blocks)390 {391 /* We never trim backlog to less than one block. */392 if (listLength(server.repl_buffer_blocks) <= 1) break;393394 /* Replicas increment the refcount of the first replication buffer block395 * they refer to, in that case, we don't trim the backlog even if396 * backlog_histlen exceeds backlog_size. This implicitly makes backlog397 * bigger than our setting, but makes the master accept partial resync as398 * much as possible. So that backlog must be the last reference of399 * replication buffer blocks. */400 listNode *first = listFirst(server.repl_buffer_blocks);401 serverAssert(first == server.repl_backlog->ref_repl_buf_node);402 replBufBlock *fo = listNodeValue(first);403 if (fo->refcount != 1) break;404405 /* We don't try trim backlog if backlog valid size will be lessen than406 * setting backlog size once we release the first repl buffer block. */407 if (server.repl_backlog->histlen - (long long)fo->size <=408 server.repl_backlog_size) break;409410 /* Decr refcount and release the first block later. */411 fo->refcount--;412 trimmed_blocks++;413 server.repl_backlog->histlen -= fo->size;414415 /* Go to use next replication buffer block node. */416 listNode *next = listNextNode(first);417 server.repl_backlog->ref_repl_buf_node = next;418 serverAssert(server.repl_backlog->ref_repl_buf_node != NULL);419 /* Incr reference count to keep the new head node. */420 ((replBufBlock *)listNodeValue(next))->refcount++;421422 /* Remove the node in recorded blocks. */423 uint64_t encoded_offset = htonu64(fo->repl_offset);424 raxRemove(server.repl_backlog->blocks_index,425 (unsigned char*)&encoded_offset, sizeof(uint64_t), NULL);426427 /* Delete the first node from global replication buffer. */428 serverAssert(fo->refcount == 0 && fo->used == fo->size);429 server.repl_buffer_mem -= (fo->size +430 sizeof(listNode) + sizeof(replBufBlock));431 listDelNode(server.repl_buffer_blocks, first);432 }433434 /* Set the offset of the first byte we have in the backlog. */435 server.repl_backlog->offset = server.master_repl_offset -436 server.repl_backlog->histlen + 1;437}438439/* Free replication buffer blocks that are referenced by this client. */440void freeReplicaReferencedReplBuffer(client *replica) {441 serverAssert(replica->running_tid == IOTHREAD_MAIN_THREAD_ID);442443 if (replica->ref_repl_buf_node != NULL) {444 /* Decrease the start buffer node reference count. */445 replBufBlock *o = listNodeValue(replica->ref_repl_buf_node);446 serverAssert(o->refcount > 0);447 o->refcount--;448 incrementalTrimReplicationBacklog(REPL_BACKLOG_TRIM_BLOCKS_PER_CALL);449 }450 replica->ref_repl_buf_node = NULL;451 replica->ref_block_pos = 0;452}453454/* Batched write API for the global replication backlog, optimized for minimal455 * overhead per append: data writes are just memcpys into the tail block.456 * All bookkeeping is deferred to replBufWriterEnd(). */457typedef struct replBufWriter {458 listNode *start_node; /* First repl buffer block written to. */459 size_t start_pos; /* Byte offset within start_node where writing began. */460 size_t total_len; /* Total bytes written across all writes. */461 int new_blocks; /* Number of new blocks allocated during this stream. */462 replBufBlock *tail; /* Current tail block. */463} replBufWriter;464465/* Initialize the writer, cache the current tail position. */466static void replBufWriterBegin(replBufWriter *wr) {467 listNode *ln = listLast(server.repl_buffer_blocks);468 replBufBlock *tail = ln ? listNodeValue(ln) : NULL;469470 if (tail && tail->used < tail->size) {471 wr->start_node = ln;472 wr->start_pos = tail->used;473 } else {474 wr->start_node = NULL;475 wr->start_pos = 0;476 }477478 wr->total_len = 0;479 wr->new_blocks = 0;480 wr->tail = tail;481}482483/* Allocate a new replication backlog block. Called when current block is full. */484static void replBufWriterAllocBlock(replBufWriter *wr, size_t hint) {485 static long long repl_block_id = 0;486 size_t usable_size;487 /* Avoid creating nodes smaller than PROTO_REPLY_CHUNK_BYTES, so that we can append more data into them,488 * and also avoid creating nodes bigger than repl_backlog_size / 16, so that we won't have huge nodes that can't489 * trim when we only still need to hold a small portion from them. */490 size_t limit = max((size_t)server.repl_backlog_size / 16, (size_t)PROTO_REPLY_CHUNK_BYTES);491 size_t bsize = min(max(hint, (size_t)PROTO_REPLY_CHUNK_BYTES), limit);492 replBufBlock *tail = zmalloc_usable(bsize + sizeof(replBufBlock), &usable_size);493 /* Take over the allocation's internal fragmentation */494 tail->size = usable_size - sizeof(replBufBlock);495 tail->used = 0;496 tail->refcount = 0;497 tail->repl_offset = server.master_repl_offset + wr->total_len + 1;498 tail->id = repl_block_id++;499 listAddNodeTail(server.repl_buffer_blocks, tail);500 server.repl_buffer_mem += (usable_size + sizeof(listNode));501 createReplicationBacklogIndex(listLast(server.repl_buffer_blocks));502503 /* Update stream state. */504 wr->tail = tail;505 wr->new_blocks++;506 if (wr->start_node == NULL) {507 wr->start_node = listLast(server.repl_buffer_blocks);508 wr->start_pos = 0;509 }510}511512/* Slow path: fill remainder of current block + allocate as needed. */513static void replBufWriterAppendSlow(replBufWriter *wr, const char *buf, size_t len) {514 while (len > 0) {515 size_t avail = wr->tail ? wr->tail->size - wr->tail->used : 0;516 if (avail > 0) {517 size_t copy = (avail >= len) ? len : avail;518 memcpy(wr->tail->buf + wr->tail->used, buf, copy);519 wr->tail->used += copy;520 wr->total_len += copy;521 buf += copy;522 len -= copy;523 }524525 if (len > 0)526 replBufWriterAllocBlock(wr, len);527 }528}529530/* Write data into the replication buffer. The slow path is split out to give 531 * the compiler a chance to inline the common case where the write fits entirely532 * in the current block. */533static inline void replBufWriterAppend(replBufWriter *wr, const char *buf, size_t len) {534 size_t avail = wr->tail ? wr->tail->size - wr->tail->used : 0;535 if (len > 0 && avail >= len) {536 memcpy(wr->tail->buf + wr->tail->used, buf, len);537 wr->tail->used += len;538 wr->total_len += len;539 return;540 }541 replBufWriterAppendSlow(wr, buf, len);542}543544/* Write a RESP header prefix<value>\r\n (e.g. "$12\r\n" or "*3\r\n").545 * Uses pre-built shared objects for small values, formats manually otherwise. */546static inline void replBufWriterAppendBulkLen(replBufWriter *wr, char prefix, long long value) {547 serverAssert(prefix == '$' || prefix == '*');548 if (value >= 0 && value < OBJ_SHARED_BULKHDR_LEN) {549 robj **tbl = (prefix == '$') ? shared.bulkhdr : shared.mbulkhdr;550 replBufWriterAppend(wr, tbl[value]->ptr, OBJ_SHARED_HDR_STRLEN(value));551 return;552 }553 char buf[LONG_STR_SIZE+3];554 buf[0] = prefix;555 int len = ll2string(buf+1, sizeof(buf)-1, value);556 buf[len+1] = '\r';557 buf[len+2] = '\n';558 replBufWriterAppend(wr, buf, len+3);559}560561562/* Finalize the replication buffer write: update global offsets, set up replica563 * references for new data, check output buffer limits, and trim the564 * backlog if new blocks were allocated. */565static void replBufWriterEnd(replBufWriter *wr) {566 if (wr->total_len == 0) return;567568 serverAssert(wr->start_node != NULL);569 clusterSlotStatsIncrNetworkBytesOutForReplication(wr->total_len);570571 /* Update the current cmd's keys with the commands replication bytes*/572 hotkeyMetrics metrics = {0, wr->total_len};573 hotkeyStatsUpdateCurrentCmd(server.hotkeys, metrics);574575 server.master_repl_offset += wr->total_len;576 server.repl_backlog->histlen += wr->total_len;577578 /* For output buffer of replicas. */579 listIter li;580 listNode *ln;581 listRewind(server.slaves,&li);582 while((ln = listNext(&li))) {583 client *slave = ln->value;584 if (!canFeedReplicaReplBuffer(slave)) continue;585586 /* Update shared replication buffer start position. */587 if (slave->ref_repl_buf_node == NULL) {588 slave->ref_repl_buf_node = wr->start_node;589 slave->ref_block_pos = wr->start_pos;590 /* Only increase the start block reference count. */591 ((replBufBlock *)listNodeValue(wr->start_node))->refcount++;592 }593594 /* Check output buffer limit only when new blocks were added. */595 if (wr->new_blocks) closeClientOnOutputBufferLimitReached(slave, 1);596 }597598 /* For replication backlog */599 if (server.repl_backlog->ref_repl_buf_node == NULL) {600 server.repl_backlog->ref_repl_buf_node = wr->start_node;601 /* Only increase the start block reference count. */602 ((replBufBlock *)listNodeValue(wr->start_node))->refcount++;603604 /* Replication buffer must be empty before adding replication stream605 * into replication backlog. */606 serverAssert(wr->new_blocks > 0 && wr->start_pos == 0);607 }608 if (wr->new_blocks) {609 /* It is important to trim after adding replication data to keep the backlog size close to610 * repl_backlog_size in the common case. We wait until we add a new block to avoid repeated611 * unnecessary trimming attempts when small amounts of data are added. See comments in612 * freeMemoryGetNotCountedMemory() for details on replication backlog memory tracking. */613 incrementalTrimReplicationBacklog(REPL_BACKLOG_TRIM_BLOCKS_PER_CALL);614 }615}616617/* Append bytes into the global replication buffer. */618static void feedReplicationBuffer(const char *buf, size_t len) {619 replBufWriter wr;620 replBufWriterBegin(&wr);621 replBufWriterAppend(&wr, buf, len);622 replBufWriterEnd(&wr);623}624625/* Propagate write commands to replication stream.626 *627 * This function is used if the instance is a master: we use the commands628 * received by our clients in order to create the replication stream.629 * Instead if the instance is a replica and has sub-replicas attached, we use630 * replicationFeedStreamFromMasterStream() */631void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {632 int j, len;633 char llstr[LONG_STR_SIZE];634635 /* In case we propagate a command that doesn't touch keys (PING, REPLCONF) we636 * pass dbid=-1 that indicate there is no need to replicate `select` command. */637 serverAssert(dictid == -1 || (dictid >= 0 && dictid < server.dbnum));638639 /* If the instance is not a top level master, return ASAP: we'll just proxy640 * the stream of data we receive from our master instead, in order to641 * propagate *identical* replication stream. In this way this slave can642 * advertise the same replication ID as the master (since it shares the643 * master replication history and has the same backlog and offsets). */644 if (server.masterhost != NULL) return;645646 /* If current client is marked as master, we will proxy the command stream647 * to our slaves instead of replicating them, that also happens when being648 * in atomic slot migration. */649 if (server.current_client && server.current_client->flags & CLIENT_MASTER) return;650651 /* If there aren't slaves, and there is no backlog buffer to populate,652 * we can return ASAP. */653 if (server.repl_backlog == NULL && listLength(slaves) == 0) {654 /* We increment the repl_offset anyway, since we use that for tracking AOF fsyncs655 * even when there's no replication active. This code will not be reached if AOF656 * is also disabled. */657 server.master_repl_offset += 1;658 return;659 }660661 /* We can't have slaves attached and no backlog. */662 serverAssert(!(listLength(slaves) != 0 && server.repl_backlog == NULL));663664 /* Update the time of sending replication stream to replicas. */665 server.repl_stream_lastio = server.unixtime;666667 /* Must install write handler for all replicas first before feeding668 * replication stream. */669 prepareReplicasToWrite();670671 /* Send SELECT command to every slave if needed. */672 if (dictid != -1 && server.slaveseldb != dictid) {673 robj *selectcmd;674675 /* For a few DBs we have pre-computed SELECT command. */676 if (dictid >= 0 && dictid < PROTO_SHARED_SELECT_CMDS) {677 selectcmd = shared.select[dictid];678 } else {679 int dictid_len;680681 dictid_len = ll2string(llstr,sizeof(llstr),dictid);682 selectcmd = createObject(OBJ_STRING,683 sdscatprintf(sdsempty(),684 "*2\r\n$6\r\nSELECT\r\n$%d\r\n%s\r\n",685 dictid_len, llstr));686 }687688 feedReplicationBuffer(selectcmd->ptr, sdslen(selectcmd->ptr));689690 /* Although the SELECT command is not associated with any slot,691 * its per-slot network-bytes-out accumulation is made by the above function call.692 * To cancel-out this accumulation, below adjustment is made. */693 clusterSlotStatsDecrNetworkBytesOutForReplication(sdslen(selectcmd->ptr));694695 if (dictid < 0 || dictid >= PROTO_SHARED_SELECT_CMDS)696 decrRefCount(selectcmd);697698 server.slaveseldb = dictid;699 }700701 /* Write the command to the replication buffer if any. */702 char aux[LONG_STR_SIZE+3];703 replBufWriter wr;704 replBufWriterBegin(&wr);705706 /* Write the multi bulk count */707 replBufWriterAppendBulkLen(&wr, '*', argc);708709 for (j = 0; j < argc; j++) {710 /* Write the bulk count */711 long objlen = stringObjectLen(argv[j]);712 replBufWriterAppendBulkLen(&wr, '$', objlen);713714 /* Write the bulk data */715 if (argv[j]->encoding == OBJ_ENCODING_INT) {716 len = ll2string(aux, sizeof(aux), (long)argv[j]->ptr);717 replBufWriterAppend(&wr, aux, len);718 } else {719 replBufWriterAppend(&wr, argv[j]->ptr, objlen);720 }721 replBufWriterAppend(&wr, "\r\n", 2);722 }723724 replBufWriterEnd(&wr);725}726727/* This is a debugging function that gets called when we detect something728 * wrong with the replication protocol: the goal is to peek into the729 * replication backlog and show a few final bytes to make simpler to730 * guess what kind of bug it could be. */731void showLatestBacklog(void) {732 if (server.repl_backlog == NULL) return;733 if (listLength(server.repl_buffer_blocks) == 0) return;734 if (server.hide_user_data_from_log) {735 serverLog(LL_NOTICE,"hide-user-data-from-log is on, skip logging backlog content to avoid spilling PII.");736 return;737 }738739 size_t dumplen = 256;740 if (server.repl_backlog->histlen < (long long)dumplen)741 dumplen = server.repl_backlog->histlen;742743 sds dump = sdsempty();744 listNode *node = listLast(server.repl_buffer_blocks);745 while(dumplen) {746 if (node == NULL) break;747 replBufBlock *o = listNodeValue(node);748 size_t thislen = o->used >= dumplen ? dumplen : o->used;749 sds head = sdscatrepr(sdsempty(), o->buf+o->used-thislen, thislen);750 sds tmp = sdscatsds(head, dump);751 sdsfree(dump);752 dump = tmp;753 dumplen -= thislen;754 node = listPrevNode(node);755 }756757 /* Finally log such bytes: this is vital debugging info to758 * understand what happened. */759 serverLog(LL_NOTICE,"Latest backlog is: '%s'", dump);760 sdsfree(dump);761}762763/* This function is used in order to proxy what we receive from our master764 * to our sub-slaves. Besides, we also proxy the replication stream from765 * the source node when being in atomic slot migration. */766void replicationFeedStreamFromMasterStream(char *buf, size_t buflen) {767 /* There must be replication backlog if having attached slaves. */768 if (listLength(server.slaves)) serverAssert(server.repl_backlog != NULL);769 if (server.repl_backlog) {770 /* Must install write handler for all replicas first before feeding771 * replication stream. */772 prepareReplicasToWrite();773 feedReplicationBuffer(buf,buflen);774 } else if (server.masterhost == NULL && server.aof_enabled) {775 /* We increment the repl_offset anyway, since we use that for tracking776 * AOF fsyncs even when there's no replication active. This code will777 * not be reached if AOF is also disabled.778 *779 * As we skip feeding the replication buffer in atomic slot migration,780 * so here we need to update the replication offset manually. */781 server.master_repl_offset += 1;782 }783}784785void replicationFeedMonitors(client *c, list *monitors, int dictid, robj **argv, int argc) {786 /* Fast path to return if the monitors list is empty or the server is in loading. */787 if (monitors == NULL || listLength(monitors) == 0 || server.loading) return;788 listNode *ln;789 listIter li;790 int j;791 sds cmdrepr = sdsnew("+");792 robj *cmdobj;793 struct timeval tv;794795 gettimeofday(&tv,NULL);796 cmdrepr = sdscatprintf(cmdrepr,"%ld.%06ld ",(long)tv.tv_sec,(long)tv.tv_usec);797 if (c->flags & CLIENT_SCRIPT) {798 cmdrepr = sdscatprintf(cmdrepr,"[%d lua] ",dictid);799 } else if (c->flags & CLIENT_UNIX_SOCKET) {800 cmdrepr = sdscatprintf(cmdrepr,"[%d unix:%s] ",dictid,server.unixsocket);801 } else {802 cmdrepr = sdscatprintf(cmdrepr,"[%d %s] ",dictid,getClientPeerId(c));803 }804805 for (j = 0; j < argc; j++) {806 if (argv[j]->encoding == OBJ_ENCODING_INT) {807 cmdrepr = sdscatprintf(cmdrepr, "\"%ld\"", (long)argv[j]->ptr);808 } else {809 cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr,810 sdslen(argv[j]->ptr));811 }812 if (j != argc-1)813 cmdrepr = sdscatlen(cmdrepr," ",1);814 }815 cmdrepr = sdscatlen(cmdrepr,"\r\n",2);816 cmdobj = createObject(OBJ_STRING,cmdrepr);817818 listRewind(monitors,&li);819 while((ln = listNext(&li))) {820 client *monitor = ln->value;821 /* Do not show internal commands to non-internal clients. */822 if (c->realcmd && (c->realcmd->flags & CMD_INTERNAL) && !(monitor->flags & CLIENT_INTERNAL)) {823 continue;824 }825 addReply(monitor,cmdobj);826 updateClientMemUsageAndBucket(monitor);827 }828 decrRefCount(cmdobj);829}830831/* Feed the slave 'c' with the replication backlog starting from the832 * specified 'offset' up to the end of the backlog. */833long long addReplyReplicationBacklog(client *c, long long offset) {834 serverAssert(c->running_tid == IOTHREAD_MAIN_THREAD_ID);835836 long long skip;837838 serverLog(LL_DEBUG, "[PSYNC] Replica request offset: %lld", offset);839840 if (server.repl_backlog->histlen == 0) {841 serverLog(LL_DEBUG, "[PSYNC] Backlog history len is zero");842 return 0;843 }844845 serverLog(LL_DEBUG, "[PSYNC] Backlog size: %lld",846 server.repl_backlog_size);847 serverLog(LL_DEBUG, "[PSYNC] First byte: %lld",848 server.repl_backlog->offset);849 serverLog(LL_DEBUG, "[PSYNC] History len: %lld",850 server.repl_backlog->histlen);851852 /* Compute the amount of bytes we need to discard. */853 skip = offset - server.repl_backlog->offset;854 serverLog(LL_DEBUG, "[PSYNC] Skipping: %lld", skip);855856 /* Iterate recorded blocks, quickly search the approximate node. */857 listNode *node = NULL;858 if (raxSize(server.repl_backlog->blocks_index) > 0) {859 uint64_t encoded_offset = htonu64(offset);860 raxIterator ri;861 raxStart(&ri, server.repl_backlog->blocks_index);862 raxSeek(&ri, ">", (unsigned char*)&encoded_offset, sizeof(uint64_t));863 if (raxEOF(&ri)) {864 /* No found, so search from the last recorded node. */865 raxSeek(&ri, "$", NULL, 0);866 raxPrev(&ri);867 node = (listNode *)ri.data;868 } else {869 raxPrev(&ri); /* Skip the sought node. */870 /* We should search from the prev node since the offset of current871 * sought node exceeds searching offset. */872 if (raxPrev(&ri))873 node = (listNode *)ri.data;874 else875 node = server.repl_backlog->ref_repl_buf_node;876 }877 raxStop(&ri);878 } else {879 /* No recorded blocks, just from the start node to search. */880 node = server.repl_backlog->ref_repl_buf_node;881 }882883 /* Search the exact node. */884 while (node != NULL) {885 replBufBlock *o = listNodeValue(node);886 if (o->repl_offset + (long long)o->used >= offset) break;887 node = listNextNode(node);888 }889 serverAssert(node != NULL);890891 /* Install a writer handler first.*/892 prepareClientToWrite(c);893 /* Setting output buffer of the replica. */894 replBufBlock *o = listNodeValue(node);895 o->refcount++;896 c->ref_repl_buf_node = node;897 c->ref_block_pos = offset - o->repl_offset;898899 return server.repl_backlog->histlen - skip;900}901902/* Return the offset to provide as reply to the PSYNC command received903 * from the slave. The returned value is only valid immediately after904 * the BGSAVE process started and before executing any other command905 * from clients. */906long long getPsyncInitialOffset(void) {907 return server.master_repl_offset;908}909910/* Send a FULLRESYNC reply in the specific case of a full resynchronization,911 * as a side effect setup the slave for a full sync in different ways:912 *913 * 1) Remember, into the slave client structure, the replication offset914 * we sent here, so that if new slaves will later attach to the same915 * background RDB saving process (by duplicating this client output916 * buffer), we can get the right offset from this slave.917 * 2) Set the replication state of the slave to WAIT_BGSAVE_END so that918 * we start accumulating differences from this point.919 * 3) Force the replication stream to re-emit a SELECT statement so920 * the new slave incremental differences will start selecting the921 * right database number.922 *923 * Normally this function should be called immediately after a successful924 * BGSAVE for replication was started, or when there is one already in925 * progress that we attached our slave to. */926int replicationSetupSlaveForFullResync(client *slave, long long offset) {927 char buf[128];928 int buflen;929930 slave->psync_initial_offset = offset;931 slave->replstate = SLAVE_STATE_WAIT_BGSAVE_END;932 /* We are going to accumulate the incremental changes for this933 * slave as well. Set slaveseldb to -1 in order to force to re-emit934 * a SELECT statement in the replication stream. */935 server.slaveseldb = -1;936937 /* Slots snapshot. */938 if (slave->flags & CLIENT_REPL_RDB_CHANNEL &&939 slave->slave_req & SLAVE_REQ_SLOTS_SNAPSHOT)940 {941 /* Start to deliver the commands stream on migrating slots. */942 asmSlotSnapshotAndStreamStart(slave->task);943944 buflen = snprintf(buf, sizeof(buf), "+SLOTSSNAPSHOT\r\n");945 if (connWrite(slave->conn, buf, buflen) != buflen) {946 freeClientAsync(slave);947 return C_ERR;948 }949 return C_OK;950 }951952 /* Don't send this reply to slaves that approached us with953 * the old SYNC command. */954 if (!(slave->flags & CLIENT_PRE_PSYNC)) {955 if (slave->flags & CLIENT_REPL_RDB_CHANNEL) {956 /* This slave is rdbchannel. Find its associated main channel and957 * change its state so we can deliver replication stream from now958 * on, in parallel to rdb. */959 uint64_t id = slave->main_ch_client_id;960 client *c = lookupClientByID(id);961 if (c && c->replstate == SLAVE_STATE_WAIT_RDB_CHANNEL) {962 c->replstate = SLAVE_STATE_SEND_BULK_AND_STREAM;963 serverLog(LL_NOTICE, "Starting to deliver RDB and replication stream to replica: %s",964 replicationGetSlaveName(c));965 } else {966 serverLog(LL_WARNING, "Starting to deliver RDB to replica %s"967 " but it has no associated main channel",968 replicationGetSlaveName(slave));969 }970 }971 buflen = snprintf(buf,sizeof(buf),"+FULLRESYNC %s %lld\r\n",972 server.replid,offset);973 if (connWrite(slave->conn,buf,buflen) != buflen) {974 freeClientAsync(slave);975 return C_ERR;976 }977 }978 return C_OK;979}980981/* This function handles the PSYNC command from the point of view of a982 * master receiving a request for partial resynchronization.983 *984 * On success return C_OK, otherwise C_ERR is returned and we proceed985 * with the usual full resync. */986int masterTryPartialResynchronization(client *c, long long psync_offset) {987 long long psync_len;988 char *master_replid = c->argv[1]->ptr;989 char buf[128];990 int buflen;991992 /* Is the replication ID of this master the same advertised by the wannabe993 * slave via PSYNC? If the replication ID changed this master has a994 * different replication history, and there is no way to continue.995 *996 * Note that there are two potentially valid replication IDs: the ID1997 * and the ID2. The ID2 however is only valid up to a specific offset. */998 if (strcasecmp(master_replid, server.replid) &&999 (strcasecmp(master_replid, server.replid2) ||1000 psync_offset > server.second_replid_offset))1001 {1002 /* Replid "?" is used by slaves that want to force a full resync. */1003 if (master_replid[0] != '?') {1004 if (strcasecmp(master_replid, server.replid) &&1005 strcasecmp(master_replid, server.replid2))1006 {1007 serverLog(LL_NOTICE,"Partial resynchronization not accepted: "1008 "Replication ID mismatch (Replica asked for '%s', my "1009 "replication IDs are '%s' and '%s')",1010 master_replid, server.replid, server.replid2);1011 } else {1012 serverLog(LL_NOTICE,"Partial resynchronization not accepted: "1013 "Requested offset for second ID was %lld, but I can reply "1014 "up to %lld", psync_offset, server.second_replid_offset);1015 }1016 } else {1017 serverLog(LL_NOTICE,"Full resync requested by replica %s %s",1018 replicationGetSlaveName(c),1019 c->flags & CLIENT_REPL_RDB_CHANNEL ? "(rdb-channel)" : "");1020 }1021 goto need_full_resync;1022 }10231024 /* We still have the data our slave is asking for? */1025 if (!server.repl_backlog ||1026 psync_offset < server.repl_backlog->offset ||1027 psync_offset > (server.repl_backlog->offset + server.repl_backlog->histlen))1028 {1029 serverLog(LL_NOTICE,1030 "Unable to partial resync with replica %s for lack of backlog (Replica request was: %lld).", replicationGetSlaveName(c), psync_offset);1031 if (psync_offset > server.master_repl_offset) {1032 serverLog(LL_WARNING,1033 "Warning: replica %s tried to PSYNC with an offset that is greater than the master replication offset.", replicationGetSlaveName(c));1034 }1035 goto need_full_resync;1036 }10371038 /* If we reached this point, we are able to perform a partial resync:1039 * 1) Set client state to make it a slave.1040 * 2) Inform the client we can continue with +CONTINUE1041 * 3) Send the backlog data (from the offset to the end) to the slave. */1042 c->flags |= CLIENT_SLAVE;1043 c->replstate = SLAVE_STATE_ONLINE;1044 c->repl_ack_time = server.unixtime;1045 c->repl_start_cmd_stream_on_ack = 0;1046 listAddNodeTail(server.slaves,c);1047 /* We can't use the connection buffers since they are used to accumulate1048 * new commands at this stage. But we are sure the socket send buffer is1049 * empty so this write will never fail actually. */1050 if (c->slave_capa & SLAVE_CAPA_PSYNC2) {1051 buflen = snprintf(buf,sizeof(buf),"+CONTINUE %s\r\n", server.replid);1052 } else {1053 buflen = snprintf(buf,sizeof(buf),"+CONTINUE\r\n");1054 }1055 if (connWrite(c->conn,buf,buflen) != buflen) {1056 freeClientAsync(c);1057 return C_OK;1058 }1059 psync_len = addReplyReplicationBacklog(c,psync_offset);1060 serverLog(LL_NOTICE,1061 "Partial resynchronization request from %s accepted. Sending %lld bytes of backlog starting from offset %lld.",1062 replicationGetSlaveName(c),1063 psync_len, psync_offset);1064 /* Note that we don't need to set the selected DB at server.slaveseldb1065 * to -1 to force the master to emit SELECT, since the slave already1066 * has this state from the previous connection with the master. */10671068 refreshGoodSlavesCount();10691070 /* Fire the replica change modules event. */1071 moduleFireServerEvent(REDISMODULE_EVENT_REPLICA_CHANGE,1072 REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,1073 NULL);10741075 return C_OK; /* The caller can return, no full resync needed. */10761077need_full_resync:1078 /* We need a full resync for some reason... Note that we can't1079 * reply to PSYNC right now if a full SYNC is needed. The reply1080 * must include the master offset at the time the RDB file we transfer1081 * is generated, so we need to delay the reply to that moment. */1082 return C_ERR;1083}10841085/* Start a BGSAVE for replication goals, which is, selecting the disk or1086 * socket target depending on the configuration, and making sure that1087 * the script cache is flushed before to start.1088 *1089 * The mincapa argument is the bitwise AND among all the slaves capabilities1090 * of the slaves waiting for this BGSAVE, so represents the slave capabilities1091 * all the slaves support. Can be tested via SLAVE_CAPA_* macros.1092 *1093 * Side effects, other than starting a BGSAVE:1094 *1095 * 1) Handle the slaves in WAIT_START state, by preparing them for a full1096 * sync if the BGSAVE was successfully started, or sending them an error1097 * and dropping them from the list of slaves.1098 *1099 * 2) Flush the Lua scripting script cache if the BGSAVE was actually1100 * started.1101 *1102 * Returns C_OK on success or C_ERR otherwise. */1103int startBgsaveForReplication(int mincapa, int req) {1104 int retval;1105 int socket_target = 0;1106 listIter li;1107 listNode *ln;11081109 /* We use a socket target if slave can handle the EOF marker and we're configured to do diskless syncs.1110 * Note that in case we're creating a "filtered" RDB (functions-only, for example) we also force socket replication1111 * to avoid overwriting the snapshot RDB file with filtered data. */1112 socket_target = (server.repl_diskless_sync || req & SLAVE_REQ_RDB_MASK) && (mincapa & SLAVE_CAPA_EOF);1113 /* `SYNC` should have failed with error if we don't support socket and require a filter, assert this here */1114 serverAssert(socket_target || !(req & SLAVE_REQ_RDB_MASK));11151116 int slots_req = req & SLAVE_REQ_SLOTS_SNAPSHOT;1117 serverLog(LL_NOTICE,"Starting BGSAVE for SYNC with target: %s%s",1118 socket_target ? (slots_req ? "slot migration destination socket" : "replicas sockets") : "disk",1119 (req & SLAVE_REQ_RDB_CHANNEL) ? " (rdb-channel)" : "");11201121 rdbSaveInfo rsi, *rsiptr;1122 rsiptr = rdbPopulateSaveInfo(&rsi);1123 /* Only do rdbSave* when rsiptr is not NULL,1124 * otherwise slave will miss repl-stream-db. */1125 if (rsiptr) {1126 if (socket_target)1127 retval = rdbSaveToSlavesSockets(req,rsiptr);1128 else {1129 /* Keep the page cache since it'll get used soon */1130 retval = rdbSaveBackground(req, server.rdb_filename, rsiptr, RDBFLAGS_REPLICATION | RDBFLAGS_KEEP_CACHE);1131 }1132 if (server.repl_debug_pause & REPL_DEBUG_AFTER_FORK)1133 debugPauseProcess();1134 } else {1135 serverLog(LL_WARNING,"BGSAVE for replication: replication information not available, can't generate the RDB file right now. Try later.");1136 retval = C_ERR;1137 }11381139 /* If we succeeded to start a BGSAVE with disk target, let's remember1140 * this fact, so that we can later delete the file if needed. Note1141 * that we don't set the flag to 1 if the feature is disabled, otherwise1142 * it would never be cleared: the file is not deleted. This way if1143 * the user enables it later with CONFIG SET, we are fine. */1144 if (retval == C_OK && !socket_target && server.rdb_del_sync_files)1145 RDBGeneratedByReplication = 1;11461147 /* If we failed to BGSAVE, remove the slaves waiting for a full1148 * resynchronization from the list of slaves, inform them with1149 * an error about what happened, close the connection ASAP. */1150 if (retval == C_ERR) {1151 serverLog(LL_WARNING,"BGSAVE for replication failed");1152 listRewind(server.slaves,&li);1153 while((ln = listNext(&li))) {1154 client *slave = ln->value;11551156 if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) {1157 slave->replstate = REPL_STATE_NONE;1158 slave->flags &= ~CLIENT_SLAVE;1159 listDelNode(server.slaves,ln);1160 addReplyError(slave,1161 "BGSAVE failed, replication can't continue");1162 slave->flags |= CLIENT_CLOSE_AFTER_REPLY;1163 }1164 }1165 return retval;1166 }11671168 /* If the target is socket, rdbSaveToSlavesSockets() already setup1169 * the slaves for a full resync. Otherwise for disk target do it now.*/1170 if (!socket_target) {1171 listRewind(server.slaves,&li);1172 while((ln = listNext(&li))) {1173 client *slave = ln->value;11741175 if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) {1176 /* Check slave has the exact requirements */1177 if (slave->slave_req != req)1178 continue;1179 replicationSetupSlaveForFullResync(slave, getPsyncInitialOffset());1180 }1181 }1182 }11831184 return retval;1185}11861187/* SYNC and PSYNC command implementation. */1188void syncCommand(client *c) {1189 /* ignore SYNC if already slave or in monitor mode */1190 if (c->flags & CLIENT_SLAVE) return;11911192 /* Check if this is a failover request to a replica with the same replid and1193 * become a master if so. */1194 if (c->argc > 3 && !strcasecmp(c->argv[0]->ptr,"psync") && 1195 !strcasecmp(c->argv[3]->ptr,"failover"))1196 {1197 serverLog(LL_NOTICE, "Failover request received for replid %s.",1198 (unsigned char *)c->argv[1]->ptr);1199 if (!server.masterhost) {1200 addReplyError(c, "PSYNC FAILOVER can't be sent to a master.");1201 return;1202 }12031204 if (!strcasecmp(c->argv[1]->ptr,server.replid)) {1205 if (server.cluster_enabled) {1206 clusterPromoteSelfToMaster();1207 } else {1208 replicationUnsetMaster();1209 }1210 sds client = catClientInfoString(sdsempty(),c);1211 serverLog(LL_NOTICE,1212 "MASTER MODE enabled (failover request from '%s')",client);1213 sdsfree(client);1214 } else {1215 addReplyError(c, "PSYNC FAILOVER replid must match my replid.");1216 return; 1217 }1218 }12191220 /* Don't let replicas sync with us while we're failing over */1221 if (server.failover_state != NO_FAILOVER) {1222 addReplyError(c,"-NOMASTERLINK Can't SYNC while failing over");1223 return;1224 }12251226 /* Refuse SYNC requests if we are a slave but the link with our master1227 * is not ok... */1228 if (server.masterhost && server.repl_state != REPL_STATE_CONNECTED) {1229 addReplyError(c,"-NOMASTERLINK Can't SYNC while not connected with my master");1230 return;1231 }12321233 /* SYNC can't be issued when the server has pending data to send to1234 * the client about already issued commands. We need a fresh reply1235 * buffer registering the differences between the BGSAVE and the current1236 * dataset, so that we can copy to other slaves if needed. */1237 if (clientHasPendingReplies(c)) {1238 addReplyError(c,"SYNC and PSYNC are invalid with pending output");1239 return;1240 }12411242 /* Fail sync if slave doesn't support EOF capability but wants a filtered RDB. This is because we force filtered1243 * RDB's to be generated over a socket and not through a file to avoid conflicts with the snapshot files. Forcing1244 * use of a socket is handled, if needed, in `startBgsaveForReplication`. */1245 if (c->slave_req & SLAVE_REQ_RDB_MASK && !(c->slave_capa & SLAVE_CAPA_EOF)) {1246 addReplyError(c,"Filtered replica requires EOF capability");1247 return;1248 }12491250 serverLog(LL_NOTICE,"Replica %s asks for synchronization",1251 replicationGetSlaveName(c));12521253 /* Try a partial resynchronization if this is a PSYNC command.1254 * If it fails, we continue with usual full resynchronization, however1255 * when this happens replicationSetupSlaveForFullResync will replied1256 * with:1257 *1258 * +FULLRESYNC <replid> <offset>1259 *1260 * So the slave knows the new replid and offset to try a PSYNC later1261 * if the connection with the master is lost. */1262 if (!strcasecmp(c->argv[0]->ptr,"psync")) {1263 long long psync_offset;1264 if (getLongLongFromObjectOrReply(c, c->argv[2], &psync_offset, NULL) != C_OK) {1265 serverLog(LL_WARNING, "Replica %s asks for synchronization but with a wrong offset",1266 replicationGetSlaveName(c));1267 return;1268 }12691270 if (masterTryPartialResynchronization(c, psync_offset) == C_OK) {1271 server.stat_sync_partial_ok++;1272 return; /* No full resync needed, return. */1273 } else {1274 char *master_replid = c->argv[1]->ptr;12751276 /* Increment stats for failed PSYNCs, but only if the1277 * replid is not "?", as this is used by slaves to force a full1278 * resync on purpose when they are not able to partially1279 * resync. */1280 if (master_replid[0] != '?') server.stat_sync_partial_err++;1281 if (c->slave_capa & SLAVE_CAPA_RDB_CHANNEL_REPL) {1282 int len;1283 char buf[128];1284 /* Replica is capable of rdbchannel replication. This is1285 * replica's main channel. Let replica know full sync is needed.1286 * Replica will open another connection (rdbchannel). Once rdb1287 * delivery starts, we'll stream repl data to the main channel.*/1288 c->flags |= CLIENT_SLAVE;1289 c->replstate = SLAVE_STATE_WAIT_RDB_CHANNEL;1290 c->repl_ack_time = server.unixtime;1291 listAddNodeTail(server.slaves, c);1292 createReplicationBacklogIfNeeded();12931294 serverLog(LL_NOTICE,1295 "Replica %s is capable of rdb channel synchronization, and partial sync isn't possible. "1296 "Full sync will continue with dedicated rdb channel.",1297 replicationGetSlaveName(c));12981299 /* Send +RDBCHANNELSYNC with client id so we can associate replica connections on master.*/1300 len = snprintf(buf, sizeof(buf), "+RDBCHANNELSYNC %llu\r\n",1301 (unsigned long long) c->id);1302 if (connWrite(c->conn, buf, strlen(buf)) != len)1303 freeClientAsync(c);13041305 return;1306 }1307 }1308 } else {1309 /* If a slave uses SYNC, we are dealing with an old implementation1310 * of the replication protocol (like redis-cli --slave). Flag the client1311 * so that we don't expect to receive REPLCONF ACK feedbacks. */1312 c->flags |= CLIENT_PRE_PSYNC;1313 }13141315 /* Full resynchronization. */1316 server.stat_sync_full++;13171318 /* Setup the slave as one waiting for BGSAVE to start. The following code1319 * paths will change the state if we handle the slave differently. */1320 c->replstate = SLAVE_STATE_WAIT_BGSAVE_START;1321 if (server.repl_disable_tcp_nodelay)1322 connDisableTcpNoDelay(c->conn); /* Non critical if it fails. */1323 c->repldbfd = -1;1324 c->flags |= CLIENT_SLAVE;1325 listAddNodeTail(server.slaves,c);13261327 /* Create the replication backlog if needed. */1328 createReplicationBacklogIfNeeded();13291330 /* Keep the client in the main thread to avoid data races between the1331 * connWrite call in startBgsaveForReplication and the client's event1332 * handler in IO threads. */1333 if (c->tid != IOTHREAD_MAIN_THREAD_ID) keepClientInMainThread(c);13341335 /* CASE 1: BGSAVE is in progress, with disk target. */1336 if (server.child_type == CHILD_TYPE_RDB &&1337 server.rdb_child_type == RDB_CHILD_TYPE_DISK)1338 {1339 /* Ok a background save is in progress. Let's check if it is a good1340 * one for replication, i.e. if there is another slave that is1341 * registering differences since the server forked to save. */1342 client *slave;1343 listNode *ln;1344 listIter li;13451346 listRewind(server.slaves,&li);1347 while((ln = listNext(&li))) {1348 slave = ln->value;1349 /* If the client needs a buffer of commands, we can't use1350 * a replica without replication buffer. */1351 if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END &&1352 (!(slave->flags & CLIENT_REPL_RDBONLY) ||1353 (c->flags & CLIENT_REPL_RDBONLY)))1354 break;1355 }1356 /* To attach this slave, we check that it has at least all the1357 * capabilities of the slave that triggered the current BGSAVE1358 * and its exact requirements. */1359 if (ln && ((c->slave_capa & slave->slave_capa) == slave->slave_capa) &&1360 c->slave_req == slave->slave_req) {1361 /* Perfect, the server is already registering differences for1362 * another slave. Set the right state, and copy the buffer.1363 * We don't copy buffer if clients don't want. */1364 if (!(c->flags & CLIENT_REPL_RDBONLY))1365 copyReplicaOutputBuffer(c,slave);1366 replicationSetupSlaveForFullResync(c,slave->psync_initial_offset);1367 serverLog(LL_NOTICE,"Waiting for end of BGSAVE for SYNC");1368 } else {1369 /* No way, we need to wait for the next BGSAVE in order to1370 * register differences. */1371 serverLog(LL_NOTICE,"Can't attach the replica to the current BGSAVE. Waiting for next BGSAVE for SYNC");1372 }13731374 /* CASE 2: BGSAVE is in progress, with socket target. */1375 } else if (server.child_type == CHILD_TYPE_RDB &&1376 server.rdb_child_type == RDB_CHILD_TYPE_SOCKET)1377 {1378 /* There is an RDB child process but it is writing directly to1379 * children sockets. We need to wait for the next BGSAVE1380 * in order to synchronize. */1381 serverLog(LL_NOTICE,"Current BGSAVE has socket target. Waiting for next BGSAVE for SYNC");13821383 /* CASE 3: There is no BGSAVE is in progress. */1384 } else {1385 if (server.repl_diskless_sync && (c->slave_capa & SLAVE_CAPA_EOF) &&1386 server.repl_diskless_sync_delay)1387 {1388 /* Diskless replication RDB child is created inside1389 * replicationCron() since we want to delay its start a1390 * few seconds to wait for more slaves to arrive. */1391 serverLog(LL_NOTICE,"Delay next BGSAVE for diskless SYNC");1392 } else {1393 /* We don't have a BGSAVE in progress, let's start one. Diskless1394 * or disk-based mode is determined by replica's capacity. */1395 if (!hasActiveChildProcess()) {1396 startBgsaveForReplication(c->slave_capa, c->slave_req);1397 } else {1398 serverLog(LL_NOTICE,1399 "No BGSAVE in progress, but another BG operation is active. "1400 "BGSAVE for replication delayed");1401 }1402 }1403 }1404 return;1405}14061407/* REPLCONF <option> <value> <option> <value> ...1408 * This command is used by a replica in order to configure the replication1409 * process before starting it with the SYNC command.1410 * This command is also used by a master in order to get the replication1411 * offset from a replica.1412 *1413 * Currently we support these options:1414 *1415 * - listening-port <port>1416 * - ip-address <ip>1417 * What is the listening ip and port of the Replica redis instance, so that1418 * the master can accurately lists replicas and their listening ports in the1419 * INFO output.1420 *1421 * - capa <eof|psync2|rdb-channel-repl>1422 * What is the capabilities of this instance.1423 * eof: supports EOF-style RDB transfer for diskless replication.1424 * psync2: supports PSYNC v2, so understands +CONTINUE <new repl ID>.1425 *1426 * - ack <offset> [fack <aofofs>]1427 * Replica informs the master the amount of replication stream that it1428 * processed so far, and optionally the replication offset fsynced to the AOF file.1429 * This special pattern doesn't reply to the caller.1430 *1431 * - getack <dummy>1432 * Unlike other subcommands, this is used by master to get the replication1433 * offset from a replica.1434 *1435 * - rdb-only <0|1>1436 * Only wants RDB snapshot without replication buffer.1437 *1438 * - rdb-filter-only <include-filters>1439 * Define "include" filters for the RDB snapshot. Currently we only support1440 * a single include filter: "functions". Passing an empty string "" will1441 * result in an empty RDB.1442 *1443 * - main-ch-client-id <client-id>1444 * Replica's main channel informs master that this is the main channel of the1445 * rdb channel identified by the client-id. */1446void replconfCommand(client *c) {1447 int j;14481449 if ((c->argc % 2) == 0) {1450 /* Number of arguments must be odd to make sure that every1451 * option has a corresponding value. */1452 addReplyErrorObject(c,shared.syntaxerr);1453 return;1454 }14551456 /* Process every option-value pair. */1457 for (j = 1; j < c->argc; j+=2) {1458 if (!strcasecmp(c->argv[j]->ptr,"listening-port")) {1459 long port;14601461 if ((getLongFromObjectOrReply(c,c->argv[j+1],1462 &port,NULL) != C_OK))1463 return;1464 c->slave_listening_port = port;1465 } else if (!strcasecmp(c->argv[j]->ptr,"ip-address")) {1466 sds addr = c->argv[j+1]->ptr;1467 if (sdslen(addr) < NET_HOST_STR_LEN) {1468 if (c->slave_addr) sdsfree(c->slave_addr);1469 c->slave_addr = sdsdup(addr);1470 } else {1471 addReplyErrorFormat(c,"REPLCONF ip-address provided by "1472 "replica instance is too long: %zd bytes", sdslen(addr));1473 return;1474 }1475 } else if (!strcasecmp(c->argv[j]->ptr,"capa")) {1476 /* Ignore capabilities not understood by this master. */1477 if (!strcasecmp(c->argv[j+1]->ptr,"eof"))1478 c->slave_capa |= SLAVE_CAPA_EOF;1479 else if (!strcasecmp(c->argv[j+1]->ptr,"psync2"))1480 c->slave_capa |= SLAVE_CAPA_PSYNC2;1481 else if (!strcasecmp(c->argv[j+1]->ptr,"rdb-channel-repl") && server.repl_rdb_channel &&1482 server.repl_diskless_sync) {1483 c->slave_capa |= SLAVE_CAPA_RDB_CHANNEL_REPL;1484 }1485 } else if (!strcasecmp(c->argv[j]->ptr,"ack")) {1486 /* REPLCONF ACK is used by slave to inform the master the amount1487 * of replication stream that it processed so far. It is an1488 * internal only command that normal clients should never use. */1489 long long offset;14901491 if (!(c->flags & CLIENT_SLAVE)) return;1492 if ((getLongLongFromObject(c->argv[j+1], &offset) != C_OK))1493 return;1494 if (offset > c->repl_ack_off)1495 c->repl_ack_off = offset;1496 if (c->argc > j+3 && !strcasecmp(c->argv[j+2]->ptr,"fack")) {1497 if ((getLongLongFromObject(c->argv[j+3], &offset) != C_OK))1498 return;1499 if (offset > c->repl_aof_off)1500 c->repl_aof_off = offset;1501 }1502 c->repl_ack_time = server.unixtime;1503 /* If this was a diskless replication, we need to really put1504 * the slave online when the first ACK is received (which1505 * confirms slave is online and ready to get more data). This1506 * allows for simpler and less CPU intensive EOF detection1507 * when streaming RDB files.1508 * There's a chance the ACK got to us before we detected that the1509 * bgsave is done (since that depends on cron ticks), so run a1510 * quick check first (instead of waiting for the next ACK. */1511 if (server.child_type == CHILD_TYPE_RDB && c->replstate == SLAVE_STATE_WAIT_BGSAVE_END)1512 checkChildrenDone();1513 if (c->repl_start_cmd_stream_on_ack && c->replstate == SLAVE_STATE_ONLINE)1514 replicaStartCommandStream(c);1515 /* If state is send_bulk_and_stream, it means this is the main1516 * channel of the slave in rdbchannel replication. Normally, slave1517 * will be put online after rdb fork is completed. There is chance1518 * that 'ack' might be received before we detect bgsave is done. */1519 if (c->replstate == SLAVE_STATE_SEND_BULK_AND_STREAM)1520 replicaPutOnline(c);1521 /* Note: this command does not reply anything! */1522 return;1523 } else if (!strcasecmp(c->argv[j]->ptr,"getack")) {1524 /* REPLCONF GETACK is used in order to request an ACK ASAP1525 * to the slave. */1526 if (server.masterhost && server.master) replicationSendAck();1527 return;1528 } else if (!strcasecmp(c->argv[j]->ptr,"rdb-only")) {1529 /* REPLCONF RDB-ONLY is used to identify the client only wants1530 * RDB snapshot without replication buffer. */1531 long rdb_only = 0;1532 if (getRangeLongFromObjectOrReply(c,c->argv[j+1],1533 0,1,&rdb_only,NULL) != C_OK)1534 return;1535 if (rdb_only == 1) {1536 c->flags |= CLIENT_REPL_RDBONLY;1537 /* If replicas ask for RDB only, We can apply the background1538 * RDB transfer optimization based on the configurations. */1539 if (server.repl_rdb_channel && server.repl_diskless_sync)1540 c->slave_req |= SLAVE_REQ_RDB_CHANNEL;1541 } else {1542 c->flags &= ~CLIENT_REPL_RDBONLY;1543 c->slave_req &= ~SLAVE_REQ_RDB_CHANNEL;1544 }1545 } else if (!strcasecmp(c->argv[j]->ptr,"rdb-filter-only")) {1546 /* REPLCONFG RDB-FILTER-ONLY is used to define "include" filters1547 * for the RDB snapshot. Currently we only support a single1548 * include filter: "functions". In the future we may want to add1549 * other filters like key patterns, key types, non-volatile, module1550 * aux fields, ...1551 * We might want to add the complementing "RDB-FILTER-EXCLUDE" to1552 * filter out certain data. */1553 int filter_count, i;1554 sds *filters;1555 if (!(filters = sdssplitargs(c->argv[j+1]->ptr, &filter_count))) {1556 addReplyError(c, "Missing rdb-filter-only values");1557 return;1558 }1559 /* By default filter out all parts of the rdb */1560 c->slave_req |= SLAVE_REQ_RDB_EXCLUDE_DATA;1561 c->slave_req |= SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS;1562 for (i = 0; i < filter_count; i++) {1563 if (!strcasecmp(filters[i], "functions"))1564 c->slave_req &= ~SLAVE_REQ_RDB_EXCLUDE_FUNCTIONS;1565 else {1566 addReplyErrorFormat(c, "Unsupported rdb-filter-only option: %s", (char*)filters[i]);1567 sdsfreesplitres(filters, filter_count);1568 return;1569 }1570 }1571 sdsfreesplitres(filters, filter_count);1572 } else if (!strcasecmp(c->argv[j]->ptr, "rdb-channel")) {1573 long rdb_channel = 0;1574 if (getRangeLongFromObjectOrReply(c, c->argv[j + 1], 0, 1, &rdb_channel, NULL) != C_OK)1575 return;1576 if (rdb_channel == 1) {1577 c->flags |= CLIENT_REPL_RDB_CHANNEL;1578 } else {1579 c->flags &= ~CLIENT_REPL_RDB_CHANNEL;1580 }1581 } else if (!strcasecmp(c->argv[j]->ptr, "main-ch-client-id")) {1582 /* REPLCONF main-ch-client-id <client-id> is used to identify1583 * the current replica rdb channel with existing main channel1584 * connection. */1585 long long client_id = 0;1586 client *main_ch;1587 if (getLongLongFromObjectOrReply(c, c->argv[j + 1], &client_id, NULL) != C_OK)1588 return;1589 main_ch = lookupClientByID(client_id);1590 if (!main_ch || main_ch->replstate != SLAVE_STATE_WAIT_RDB_CHANNEL) {1591 addReplyErrorFormat(c, "Unrecognized RDB client id: %lld", client_id);1592 return;1593 }1594 c->main_ch_client_id = (uint64_t)client_id;1595 /* Inherit the rdb-no-compress and rdb-no-checksum request from the main channel. */1596 if (main_ch->slave_req & SLAVE_REQ_RDB_NO_COMPRESS)1597 c->slave_req |= SLAVE_REQ_RDB_NO_COMPRESS;1598 if (main_ch->slave_req & SLAVE_REQ_RDB_NO_CHECKSUM)1599 c->slave_req |= SLAVE_REQ_RDB_NO_CHECKSUM;1600 } else if (!strcasecmp(c->argv[j]->ptr, "rdb-no-compress")) {1601 long rdb_no_compress = 0;1602 if (getRangeLongFromObjectOrReply(c, c->argv[j + 1], 0, 1, &rdb_no_compress, NULL) != C_OK)1603 return;1604 if (rdb_no_compress == 1) {1605 c->slave_req |= SLAVE_REQ_RDB_NO_COMPRESS;1606 } else {1607 c->slave_req &= ~SLAVE_REQ_RDB_NO_COMPRESS;1608 }1609 } else if (!strcasecmp(c->argv[j]->ptr, "rdb-no-checksum")) {1610 long rdb_no_checksum = 0;1611 if (getRangeLongFromObjectOrReply(c, c->argv[j + 1], 0, 1, &rdb_no_checksum, NULL) != C_OK)1612 return;1613 if (rdb_no_checksum == 1) {1614 c->slave_req |= SLAVE_REQ_RDB_NO_CHECKSUM;1615 } else {1616 c->slave_req &= ~SLAVE_REQ_RDB_NO_CHECKSUM;1617 }1618 } else {1619 addReplyErrorFormat(c,"Unrecognized REPLCONF option: %s",1620 (char*)c->argv[j]->ptr);1621 return;1622 }1623 }1624 addReply(c,shared.ok);1625}16261627/* This function puts a replica in the online state, and should be called just1628 * after a replica received the RDB file for the initial synchronization.1629 *1630 * It does a few things:1631 * 1) Put the slave in ONLINE state.1632 * 2) Update the count of "good replicas".1633 * 3) Trigger the module event.1634 *1635 * the return value indicates that the replica should be disconnected.1636 * */1637int replicaPutOnline(client *slave) {1638 if (slave->flags & CLIENT_REPL_RDBONLY) {1639 slave->replstate = SLAVE_STATE_RDB_TRANSMITTED;1640 /* The client asked for RDB only so we should close it ASAP */1641 serverLog(LL_NOTICE,1642 "RDB transfer completed, rdb only replica (%s) should be disconnected asap",1643 replicationGetSlaveName(slave));1644 return 0;1645 }16461647 /* Don't put migration destination client online. */1648 if (slave->flags & CLIENT_ASM_MIGRATING) return 0;16491650 slave->replstate = SLAVE_STATE_ONLINE;1651 slave->repl_ack_time = server.unixtime; /* Prevent false timeout. */16521653 refreshGoodSlavesCount();1654 /* Fire the replica change modules event. */1655 moduleFireServerEvent(REDISMODULE_EVENT_REPLICA_CHANGE,1656 REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE,1657 NULL);1658 serverLog(LL_NOTICE,"Synchronization with replica %s succeeded",1659 replicationGetSlaveName(slave));1660 return 1;1661}16621663/* This function should be called just after a replica received the RDB file1664 * for the initial synchronization, and we are finally ready to send the1665 * incremental stream of commands.1666 *1667 * It does a few things:1668 * 1) Close the replica's connection async if it doesn't need replication1669 * commands buffer stream, since it actually isn't a valid replica.1670 * 2) Make sure the writable event is re-installed, since when calling the SYNC1671 * command we had no replies and it was disabled, and then we could1672 * accumulate output buffer data without sending it to the replica so it1673 * won't get mixed with the RDB stream. */1674void replicaStartCommandStream(client *slave) {1675 serverAssert(!(slave->flags & CLIENT_REPL_RDBONLY));1676 slave->repl_start_cmd_stream_on_ack = 0;16771678 putClientInPendingWriteQueue(slave);1679}16801681/* We call this function periodically to remove an RDB file that was1682 * generated because of replication, in an instance that is otherwise1683 * without any persistence. We don't want instances without persistence1684 * to take RDB files around, this violates certain policies in certain1685 * environments. */1686void removeRDBUsedToSyncReplicas(void) {1687 /* If the feature is disabled, return ASAP but also clear the1688 * RDBGeneratedByReplication flag in case it was set. Otherwise if the1689 * feature was enabled, but gets disabled later with CONFIG SET, the1690 * flag may remain set to one: then next time the feature is re-enabled1691 * via CONFIG SET we have it set even if no RDB was generated1692 * because of replication recently. */1693 if (!server.rdb_del_sync_files) {1694 RDBGeneratedByReplication = 0;1695 return;1696 }16971698 if (allPersistenceDisabled() && RDBGeneratedByReplication) {1699 client *slave;1700 listNode *ln;1701 listIter li;17021703 int delrdb = 1;1704 listRewind(server.slaves,&li);1705 while((ln = listNext(&li))) {1706 slave = ln->value;1707 if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START ||1708 slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END ||1709 slave->replstate == SLAVE_STATE_SEND_BULK)1710 {1711 delrdb = 0;1712 break; /* No need to check the other replicas. */1713 }1714 }1715 if (delrdb) {1716 struct stat sb;1717 if (lstat(server.rdb_filename,&sb) != -1) {1718 RDBGeneratedByReplication = 0;1719 serverLog(LL_NOTICE,1720 "Removing the RDB file used to feed replicas "1721 "in a persistence-less instance");1722 bg_unlink(server.rdb_filename);1723 }1724 }1725 }1726}17271728/* Close the repldbfd and reclaim the page cache if the client hold1729 * the last reference to replication DB */1730void closeRepldbfd(client *myself) {1731 listNode *ln;1732 listIter li;1733 int reclaim = 1;1734 listRewind(server.slaves,&li);1735 while((ln = listNext(&li))) {1736 client *slave = ln->value;1737 if (slave != myself && slave->replstate == SLAVE_STATE_SEND_BULK) {1738 reclaim = 0;1739 break;1740 }1741 }17421743 if (reclaim) {1744 bioCreateCloseJob(myself->repldbfd, 0, 1);1745 } else {1746 close(myself->repldbfd);1747 }1748 myself->repldbfd = -1;1749}17501751void sendBulkToSlave(connection *conn) {1752 client *slave = connGetPrivateData(conn);1753 char buf[PROTO_IOBUF_LEN];1754 ssize_t nwritten, buflen;17551756 /* Before sending the RDB file, we send the preamble as configured by the1757 * replication process. Currently the preamble is just the bulk count of1758 * the file in the form "$<length>\r\n". */1759 if (slave->replpreamble) {1760 nwritten = connWrite(conn,slave->replpreamble,sdslen(slave->replpreamble));1761 if (nwritten == -1) {1762 serverLog(LL_WARNING,1763 "Write error sending RDB preamble to replica: %s",1764 connGetLastError(conn));1765 freeClient(slave);1766 return;1767 }1768 atomicIncr(server.stat_net_repl_output_bytes, nwritten);1769 sdsrange(slave->replpreamble,nwritten,-1);1770 if (sdslen(slave->replpreamble) == 0) {1771 sdsfree(slave->replpreamble);1772 slave->replpreamble = NULL;1773 /* fall through sending data. */1774 } else {1775 return;1776 }1777 }17781779 /* If the preamble was already transferred, send the RDB bulk data. */1780 if (lseek(slave->repldbfd,slave->repldboff,SEEK_SET) == -1) {1781 serverLog(LL_WARNING,"Failed to lseek the RDB file to offset %lld for replica %s: %s",1782 (long long)slave->repldboff, replicationGetSlaveName(slave), strerror(errno));1783 freeClient(slave);1784 return;1785 }1786 buflen = read(slave->repldbfd,buf,PROTO_IOBUF_LEN);1787 if (buflen <= 0) {1788 serverLog(LL_WARNING,"Read error sending DB to replica: %s",1789 (buflen == 0) ? "premature EOF" : strerror(errno));1790 freeClient(slave);1791 return;1792 }1793 if ((nwritten = connWrite(conn,buf,buflen)) == -1) {1794 if (connGetState(conn) != CONN_STATE_CONNECTED) {1795 serverLog(LL_WARNING,"Write error sending DB to replica: %s",1796 connGetLastError(conn));1797 freeClient(slave);1798 }1799 return;1800 }1801 slave->repldboff += nwritten;1802 atomicIncr(server.stat_net_repl_output_bytes, nwritten);1803 if (slave->repldboff == slave->repldbsize) {1804 closeRepldbfd(slave);1805 connSetWriteHandler(slave->conn,NULL);1806 if (!replicaPutOnline(slave)) {1807 freeClient(slave);1808 return;1809 }1810 replicaStartCommandStream(slave);1811 }1812}18131814/* Remove one write handler from the list of connections waiting to be writable1815 * during rdb pipe transfer. */1816void rdbPipeWriteHandlerConnRemoved(struct connection *conn) {1817 if (!connHasWriteHandler(conn))1818 return;1819 connSetWriteHandler(conn, NULL);1820 client *slave = connGetPrivateData(conn);1821 slave->repl_last_partial_write = 0;1822 server.rdb_pipe_numconns_writing--;1823 /* if there are no more writes for now for this conn, or write error: */1824 if (server.rdb_pipe_numconns_writing == 0) {1825 if (aeCreateFileEvent(server.el, server.rdb_pipe_read, AE_READABLE, rdbPipeReadHandler,NULL) == AE_ERR) {1826 serverPanic("Unrecoverable error creating server.rdb_pipe_read file event.");1827 }1828 }1829}18301831/* Called in diskless master during transfer of data from the rdb pipe, when1832 * the replica becomes writable again. */1833void rdbPipeWriteHandler(struct connection *conn) {1834 serverAssert(server.rdb_pipe_bufflen>0);1835 client *slave = connGetPrivateData(conn);1836 ssize_t nwritten;1837 if ((nwritten = connWrite(conn, server.rdb_pipe_buff + slave->repldboff,1838 server.rdb_pipe_bufflen - slave->repldboff)) == -1)1839 {1840 if (connGetState(conn) == CONN_STATE_CONNECTED)1841 return; /* equivalent to EAGAIN */1842 serverLog(LL_WARNING,"Write error sending DB to replica: %s",1843 connGetLastError(conn));1844 freeClient(slave);1845 return;1846 } else {1847 slave->repldboff += nwritten;1848 atomicIncr(server.stat_net_repl_output_bytes, nwritten);1849 if (slave->repldboff < server.rdb_pipe_bufflen) {1850 slave->repl_last_partial_write = server.unixtime;1851 return; /* more data to write.. */1852 }1853 }1854 rdbPipeWriteHandlerConnRemoved(conn);1855}18561857/* Called in diskless master, when there's data to read from the child's rdb pipe */1858void rdbPipeReadHandler(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask) {1859 UNUSED(mask);1860 UNUSED(clientData);1861 UNUSED(eventLoop);1862 int i;1863 if (!server.rdb_pipe_buff)1864 server.rdb_pipe_buff = zmalloc(PROTO_IOBUF_LEN);1865 serverAssert(server.rdb_pipe_numconns_writing==0);18661867 while (1) {1868 server.rdb_pipe_bufflen = read(fd, server.rdb_pipe_buff, PROTO_IOBUF_LEN);1869 if (server.rdb_pipe_bufflen < 0) {1870 if (errno == EAGAIN || errno == EWOULDBLOCK)1871 return;1872 serverLog(LL_WARNING,"Diskless rdb transfer, read error sending DB to replicas: %s", strerror(errno));1873 for (i=0; i < server.rdb_pipe_numconns; i++) {1874 connection *conn = server.rdb_pipe_conns[i];1875 if (!conn)1876 continue;1877 client *slave = connGetPrivateData(conn);1878 freeClient(slave);1879 server.rdb_pipe_conns[i] = NULL;1880 }1881 killRDBChild();1882 return;1883 }18841885 if (server.rdb_pipe_bufflen == 0) {1886 /* EOF - write end was closed. */1887 int stillUp = 0;1888 aeDeleteFileEvent(server.el, server.rdb_pipe_read, AE_READABLE);1889 for (i=0; i < server.rdb_pipe_numconns; i++)1890 {1891 connection *conn = server.rdb_pipe_conns[i];1892 if (!conn)1893 continue;1894 stillUp++;1895 }1896 serverLog(LL_NOTICE,"Diskless rdb transfer, done reading from pipe, %d replicas still up.", stillUp);1897 /* Now that the replicas have finished reading, notify the child that it's safe to exit. 1898 * When the server detects the child has exited, it can mark the replica as online, and1899 * start streaming the replication buffers. */1900 close(server.rdb_child_exit_pipe);1901 server.rdb_child_exit_pipe = -1;1902 return;1903 }19041905 int stillAlive = 0;1906 for (i=0; i < server.rdb_pipe_numconns; i++)1907 {1908 ssize_t nwritten;1909 connection *conn = server.rdb_pipe_conns[i];1910 if (!conn)1911 continue;19121913 client *slave = connGetPrivateData(conn);1914 if ((nwritten = connWrite(conn, server.rdb_pipe_buff, server.rdb_pipe_bufflen)) == -1) {1915 if (connGetState(conn) != CONN_STATE_CONNECTED) {1916 serverLog(LL_WARNING,"Diskless rdb transfer, write error sending DB to replica: %s",1917 connGetLastError(conn));1918 freeClient(slave);1919 server.rdb_pipe_conns[i] = NULL;1920 continue;1921 }1922 /* An error and still in connected state, is equivalent to EAGAIN */1923 slave->repldboff = 0;1924 } else {1925 /* Note: when use diskless replication, 'repldboff' is the offset1926 * of 'rdb_pipe_buff' sent rather than the offset of entire RDB. */1927 slave->repldboff = nwritten;1928 atomicIncr(server.stat_net_repl_output_bytes, nwritten);1929 }1930 /* If we were unable to write all the data to one of the replicas,1931 * setup write handler (and disable pipe read handler, below) */1932 if (nwritten != server.rdb_pipe_bufflen) {1933 slave->repl_last_partial_write = server.unixtime;1934 server.rdb_pipe_numconns_writing++;1935 connSetWriteHandler(conn, rdbPipeWriteHandler);1936 }1937 stillAlive++;1938 }19391940 if (stillAlive == 0) {1941 serverLog(LL_WARNING,"Diskless rdb transfer, last replica dropped, killing fork child.");1942 /* Avoid deleting events after killRDBChild as it may trigger new bgsaves for other replicas. */1943 aeDeleteFileEvent(server.el, server.rdb_pipe_read, AE_READABLE); 1944 killRDBChild();1945 break;1946 }1947 /* Remove the pipe read handler if at least one write handler was set. */1948 else if (server.rdb_pipe_numconns_writing) {1949 aeDeleteFileEvent(server.el, server.rdb_pipe_read, AE_READABLE);1950 break;1951 }1952 }1953}19541955/* This function is called at the end of every background saving.1956 *1957 * The argument bgsaveerr is C_OK if the background saving succeeded1958 * otherwise C_ERR is passed to the function.1959 * The 'type' argument is the type of the child that terminated1960 * (if it had a disk or socket target). */1961void updateSlavesWaitingBgsave(int bgsaveerr, int type) {1962 listNode *ln;1963 listIter li;19641965 /* Note: there's a chance we got here from within the REPLCONF ACK command1966 * so we must avoid using freeClient, otherwise we'll crash on our way up. */19671968 listRewind(server.slaves,&li);1969 while((ln = listNext(&li))) {1970 client *slave = ln->value;19711972 /* We can get here via freeClient()->killRDBChild()->checkChildrenDone(). skip disconnected slaves. */1973 if (!slave->conn) continue;19741975 if (slave->replstate == SLAVE_STATE_SEND_BULK_AND_STREAM) {1976 /* This is the main channel of the slave that received the RDB.1977 * Put it online if RDB delivery is successful. */1978 if (bgsaveerr == C_OK) {1979 /* Notify the task that the snapshot bulk delivery is done */1980 if (slave->flags & CLIENT_ASM_MIGRATING)1981 asmSlotSnapshotSucceed(slave->task);1982 replicaPutOnline(slave);1983 } else {1984 freeClientAsync(slave);1985 }1986 } else if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END) {1987 struct redis_stat buf;19881989 if (bgsaveerr != C_OK) {1990 /* Notify the task that the snapshot bulk delivery failed */1991 if (slave->flags & CLIENT_ASM_MIGRATING)1992 asmSlotSnapshotFailed(slave->task);1993 freeClientAsync(slave);1994 serverLog(LL_WARNING,"SYNC failed. BGSAVE child returned an error");1995 continue;1996 }19971998 /* If this was an RDB on disk save, we have to prepare to send1999 * the RDB from disk to the slave socket. Otherwise if this was2000 * already an RDB -> Slaves socket transfer, used in the case of
Findings
✓ No findings reported for this file.