]> git.saurik.com Git - redis.git/blame - src/replication.c
Non-blocking connect with master
[redis.git] / src / replication.c
CommitLineData
e2641e09 1#include "redis.h"
2
3#include <sys/time.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <sys/stat.h>
7
f4aa600b 8/* ---------------------------------- MASTER -------------------------------- */
9
e2641e09 10void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
11 listNode *ln;
12 listIter li;
13 int outc = 0, j;
14 robj **outv;
15 /* We need 1+(ARGS*3) objects since commands are using the new protocol
16 * and we one 1 object for the first "*<count>\r\n" multibulk count, then
17 * for every additional object we have "$<count>\r\n" + object + "\r\n". */
18 robj *static_outv[REDIS_STATIC_ARGS*3+1];
19 robj *lenobj;
20
21 if (argc <= REDIS_STATIC_ARGS) {
22 outv = static_outv;
23 } else {
24 outv = zmalloc(sizeof(robj*)*(argc*3+1));
25 }
26
27 lenobj = createObject(REDIS_STRING,
28 sdscatprintf(sdsempty(), "*%d\r\n", argc));
29 lenobj->refcount = 0;
30 outv[outc++] = lenobj;
31 for (j = 0; j < argc; j++) {
32 lenobj = createObject(REDIS_STRING,
33 sdscatprintf(sdsempty(),"$%lu\r\n",
34 (unsigned long) stringObjectLen(argv[j])));
35 lenobj->refcount = 0;
36 outv[outc++] = lenobj;
37 outv[outc++] = argv[j];
38 outv[outc++] = shared.crlf;
39 }
40
41 /* Increment all the refcounts at start and decrement at end in order to
42 * be sure to free objects if there is no slave in a replication state
43 * able to be feed with commands */
44 for (j = 0; j < outc; j++) incrRefCount(outv[j]);
45 listRewind(slaves,&li);
46 while((ln = listNext(&li))) {
47 redisClient *slave = ln->value;
48
49 /* Don't feed slaves that are still waiting for BGSAVE to start */
50 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) continue;
51
52 /* Feed all the other slaves, MONITORs and so on */
53 if (slave->slaveseldb != dictid) {
54 robj *selectcmd;
55
56 switch(dictid) {
57 case 0: selectcmd = shared.select0; break;
58 case 1: selectcmd = shared.select1; break;
59 case 2: selectcmd = shared.select2; break;
60 case 3: selectcmd = shared.select3; break;
61 case 4: selectcmd = shared.select4; break;
62 case 5: selectcmd = shared.select5; break;
63 case 6: selectcmd = shared.select6; break;
64 case 7: selectcmd = shared.select7; break;
65 case 8: selectcmd = shared.select8; break;
66 case 9: selectcmd = shared.select9; break;
67 default:
68 selectcmd = createObject(REDIS_STRING,
69 sdscatprintf(sdsempty(),"select %d\r\n",dictid));
70 selectcmd->refcount = 0;
71 break;
72 }
73 addReply(slave,selectcmd);
74 slave->slaveseldb = dictid;
75 }
76 for (j = 0; j < outc; j++) addReply(slave,outv[j]);
77 }
78 for (j = 0; j < outc; j++) decrRefCount(outv[j]);
79 if (outv != static_outv) zfree(outv);
80}
81
82void replicationFeedMonitors(list *monitors, int dictid, robj **argv, int argc) {
83 listNode *ln;
84 listIter li;
85 int j;
86 sds cmdrepr = sdsnew("+");
87 robj *cmdobj;
88 struct timeval tv;
89
90 gettimeofday(&tv,NULL);
2b2eca1f 91 cmdrepr = sdscatprintf(cmdrepr,"%ld.%06ld ",(long)tv.tv_sec,(long)tv.tv_usec);
e2641e09 92 if (dictid != 0) cmdrepr = sdscatprintf(cmdrepr,"(db %d) ", dictid);
93
94 for (j = 0; j < argc; j++) {
95 if (argv[j]->encoding == REDIS_ENCODING_INT) {
d3b958c3 96 cmdrepr = sdscatprintf(cmdrepr, "\"%ld\"", (long)argv[j]->ptr);
e2641e09 97 } else {
98 cmdrepr = sdscatrepr(cmdrepr,(char*)argv[j]->ptr,
99 sdslen(argv[j]->ptr));
100 }
101 if (j != argc-1)
102 cmdrepr = sdscatlen(cmdrepr," ",1);
103 }
104 cmdrepr = sdscatlen(cmdrepr,"\r\n",2);
105 cmdobj = createObject(REDIS_STRING,cmdrepr);
106
107 listRewind(monitors,&li);
108 while((ln = listNext(&li))) {
109 redisClient *monitor = ln->value;
110 addReply(monitor,cmdobj);
111 }
112 decrRefCount(cmdobj);
113}
114
e2641e09 115void syncCommand(redisClient *c) {
116 /* ignore SYNC if aleady slave or in monitor mode */
117 if (c->flags & REDIS_SLAVE) return;
118
778b2210 119 /* Refuse SYNC requests if we are a slave but the link with our master
120 * is not ok... */
121 if (server.masterhost && server.replstate != REDIS_REPL_CONNECTED) {
3ab20376 122 addReplyError(c,"Can't SYNC while not connected with my master");
778b2210 123 return;
124 }
125
e2641e09 126 /* SYNC can't be issued when the server has pending data to send to
127 * the client about already issued commands. We need a fresh reply
128 * buffer registering the differences between the BGSAVE and the current
129 * dataset, so that we can copy to other slaves if needed. */
130 if (listLength(c->reply) != 0) {
3ab20376 131 addReplyError(c,"SYNC is invalid with pending input");
e2641e09 132 return;
133 }
134
135 redisLog(REDIS_NOTICE,"Slave ask for synchronization");
136 /* Here we need to check if there is a background saving operation
137 * in progress, or if it is required to start one */
138 if (server.bgsavechildpid != -1) {
139 /* Ok a background save is in progress. Let's check if it is a good
140 * one for replication, i.e. if there is another slave that is
141 * registering differences since the server forked to save */
142 redisClient *slave;
143 listNode *ln;
144 listIter li;
145
146 listRewind(server.slaves,&li);
147 while((ln = listNext(&li))) {
148 slave = ln->value;
149 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
150 }
151 if (ln) {
152 /* Perfect, the server is already registering differences for
153 * another slave. Set the right state, and copy the buffer. */
154 listRelease(c->reply);
155 c->reply = listDup(slave->reply);
156 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
157 redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
158 } else {
159 /* No way, we need to wait for the next BGSAVE in order to
160 * register differences */
161 c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
162 redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
163 }
164 } else {
165 /* Ok we don't have a BGSAVE in progress, let's start one */
166 redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
167 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
168 redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
3ab20376 169 addReplyError(c,"Unable to perform background save");
e2641e09 170 return;
171 }
172 c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
173 }
174 c->repldbfd = -1;
175 c->flags |= REDIS_SLAVE;
176 c->slaveseldb = 0;
177 listAddNodeTail(server.slaves,c);
178 return;
179}
180
181void sendBulkToSlave(aeEventLoop *el, int fd, void *privdata, int mask) {
182 redisClient *slave = privdata;
183 REDIS_NOTUSED(el);
184 REDIS_NOTUSED(mask);
185 char buf[REDIS_IOBUF_LEN];
186 ssize_t nwritten, buflen;
187
188 if (slave->repldboff == 0) {
189 /* Write the bulk write count before to transfer the DB. In theory here
190 * we don't know how much room there is in the output buffer of the
191 * socket, but in pratice SO_SNDLOWAT (the minimum count for output
192 * operations) will never be smaller than the few bytes we need. */
193 sds bulkcount;
194
195 bulkcount = sdscatprintf(sdsempty(),"$%lld\r\n",(unsigned long long)
196 slave->repldbsize);
197 if (write(fd,bulkcount,sdslen(bulkcount)) != (signed)sdslen(bulkcount))
198 {
199 sdsfree(bulkcount);
200 freeClient(slave);
201 return;
202 }
203 sdsfree(bulkcount);
204 }
205 lseek(slave->repldbfd,slave->repldboff,SEEK_SET);
206 buflen = read(slave->repldbfd,buf,REDIS_IOBUF_LEN);
207 if (buflen <= 0) {
208 redisLog(REDIS_WARNING,"Read error sending DB to slave: %s",
209 (buflen == 0) ? "premature EOF" : strerror(errno));
210 freeClient(slave);
211 return;
212 }
213 if ((nwritten = write(fd,buf,buflen)) == -1) {
214 redisLog(REDIS_VERBOSE,"Write error sending DB to slave: %s",
215 strerror(errno));
216 freeClient(slave);
217 return;
218 }
219 slave->repldboff += nwritten;
220 if (slave->repldboff == slave->repldbsize) {
221 close(slave->repldbfd);
222 slave->repldbfd = -1;
223 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
224 slave->replstate = REDIS_REPL_ONLINE;
225 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE,
226 sendReplyToClient, slave) == AE_ERR) {
227 freeClient(slave);
228 return;
229 }
230 addReplySds(slave,sdsempty());
231 redisLog(REDIS_NOTICE,"Synchronization with slave succeeded");
232 }
233}
234
235/* This function is called at the end of every backgrond saving.
236 * The argument bgsaveerr is REDIS_OK if the background saving succeeded
237 * otherwise REDIS_ERR is passed to the function.
238 *
239 * The goal of this function is to handle slaves waiting for a successful
240 * background saving in order to perform non-blocking synchronization. */
241void updateSlavesWaitingBgsave(int bgsaveerr) {
242 listNode *ln;
243 int startbgsave = 0;
244 listIter li;
245
246 listRewind(server.slaves,&li);
247 while((ln = listNext(&li))) {
248 redisClient *slave = ln->value;
249
250 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START) {
251 startbgsave = 1;
252 slave->replstate = REDIS_REPL_WAIT_BGSAVE_END;
253 } else if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) {
254 struct redis_stat buf;
255
256 if (bgsaveerr != REDIS_OK) {
257 freeClient(slave);
258 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE child returned an error");
259 continue;
260 }
261 if ((slave->repldbfd = open(server.dbfilename,O_RDONLY)) == -1 ||
262 redis_fstat(slave->repldbfd,&buf) == -1) {
263 freeClient(slave);
264 redisLog(REDIS_WARNING,"SYNC failed. Can't open/stat DB after BGSAVE: %s", strerror(errno));
265 continue;
266 }
267 slave->repldboff = 0;
268 slave->repldbsize = buf.st_size;
269 slave->replstate = REDIS_REPL_SEND_BULK;
270 aeDeleteFileEvent(server.el,slave->fd,AE_WRITABLE);
271 if (aeCreateFileEvent(server.el, slave->fd, AE_WRITABLE, sendBulkToSlave, slave) == AE_ERR) {
272 freeClient(slave);
273 continue;
274 }
275 }
276 }
277 if (startbgsave) {
278 if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
279 listIter li;
280
281 listRewind(server.slaves,&li);
282 redisLog(REDIS_WARNING,"SYNC failed. BGSAVE failed");
283 while((ln = listNext(&li))) {
284 redisClient *slave = ln->value;
285
286 if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_START)
287 freeClient(slave);
288 }
289 }
290 }
291}
292
f4aa600b 293/* ----------------------------------- SLAVE -------------------------------- */
294
295/* Abort the async download of the bulk dataset while SYNC-ing with master */
296void replicationAbortSyncTransfer(void) {
297 redisAssert(server.replstate == REDIS_REPL_TRANSFER);
298
299 aeDeleteFileEvent(server.el,server.repl_transfer_s,AE_READABLE);
300 close(server.repl_transfer_s);
301 close(server.repl_transfer_fd);
302 unlink(server.repl_transfer_tmpfile);
303 zfree(server.repl_transfer_tmpfile);
304 server.replstate = REDIS_REPL_CONNECT;
305}
306
307/* Asynchronously read the SYNC payload we receive from a master */
308void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
26b33669 309 char buf[4096];
62ec599c 310 ssize_t nread, readlen;
311 REDIS_NOTUSED(el);
312 REDIS_NOTUSED(privdata);
313 REDIS_NOTUSED(mask);
f4aa600b 314
26b33669 315 /* If repl_transfer_left == -1 we still have to read the bulk length
316 * from the master reply. */
317 if (server.repl_transfer_left == -1) {
318 if (syncReadLine(fd,buf,1024,3600) == -1) {
319 redisLog(REDIS_WARNING,
320 "I/O error reading bulk count from MASTER: %s",
321 strerror(errno));
322 replicationAbortSyncTransfer();
323 return;
324 }
325 if (buf[0] == '-') {
326 redisLog(REDIS_WARNING,
327 "MASTER aborted replication with an error: %s",
328 buf+1);
329 replicationAbortSyncTransfer();
330 return;
89a1433e 331 } else if (buf[0] == '\0') {
332 /* At this stage just a newline works as a PING in order to take
333 * the connection live. So we refresh our last interaction
334 * timestamp. */
335 server.repl_transfer_lastio = time(NULL);
336 return;
26b33669 337 } else if (buf[0] != '$') {
338 redisLog(REDIS_WARNING,"Bad protocol from MASTER, the first byte is not '$', are you sure the host and port are right?");
339 replicationAbortSyncTransfer();
340 return;
341 }
342 server.repl_transfer_left = strtol(buf+1,NULL,10);
343 redisLog(REDIS_NOTICE,
344 "MASTER <-> SLAVE sync: receiving %ld bytes from master",
345 server.repl_transfer_left);
346 return;
347 }
348
349 /* Read bulk data */
62ec599c 350 readlen = (server.repl_transfer_left < (signed)sizeof(buf)) ?
351 server.repl_transfer_left : (signed)sizeof(buf);
f4aa600b 352 nread = read(fd,buf,readlen);
353 if (nread <= 0) {
354 redisLog(REDIS_WARNING,"I/O error trying to sync with MASTER: %s",
355 (nread == -1) ? strerror(errno) : "connection lost");
356 replicationAbortSyncTransfer();
357 return;
358 }
359 server.repl_transfer_lastio = time(NULL);
360 if (write(server.repl_transfer_fd,buf,nread) != nread) {
361 redisLog(REDIS_WARNING,"Write error or short write writing to the DB dump file needed for MASTER <-> SLAVE synchrnonization: %s", strerror(errno));
362 replicationAbortSyncTransfer();
363 return;
364 }
365 server.repl_transfer_left -= nread;
366 /* Check if the transfer is now complete */
367 if (server.repl_transfer_left == 0) {
368 if (rename(server.repl_transfer_tmpfile,server.dbfilename) == -1) {
369 redisLog(REDIS_WARNING,"Failed trying to rename the temp DB into dump.rdb in MASTER <-> SLAVE synchronization: %s", strerror(errno));
370 replicationAbortSyncTransfer();
371 return;
372 }
f6433915 373 redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Loading DB in memory");
f4aa600b 374 emptyDb();
9fd01051 375 /* Before loading the DB into memory we need to delete the readable
376 * handler, otherwise it will get called recursively since
377 * rdbLoad() will call the event loop to process events from time to
378 * time for non blocking loading. */
379 aeDeleteFileEvent(server.el,server.repl_transfer_s,AE_READABLE);
f4aa600b 380 if (rdbLoad(server.dbfilename) != REDIS_OK) {
381 redisLog(REDIS_WARNING,"Failed trying to load the MASTER synchronization DB from disk");
382 replicationAbortSyncTransfer();
383 return;
384 }
385 /* Final setup of the connected slave <- master link */
f4aa600b 386 zfree(server.repl_transfer_tmpfile);
387 close(server.repl_transfer_fd);
388 server.master = createClient(server.repl_transfer_s);
389 server.master->flags |= REDIS_MASTER;
390 server.master->authenticated = 1;
391 server.replstate = REDIS_REPL_CONNECTED;
26b33669 392 redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Finished with success");
f4aa600b 393 }
394}
395
a3309139
PN
396void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
397 char buf[1024], tmpfile[256];
e2641e09 398 int dfd, maxtries = 5;
a3309139
PN
399 REDIS_NOTUSED(el);
400 REDIS_NOTUSED(privdata);
401 REDIS_NOTUSED(mask);
e2641e09 402
a3309139
PN
403 /* Remove this event before anything else. */
404 aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
e2641e09 405
406 /* AUTH with the master if required. */
407 if(server.masterauth) {
a3309139
PN
408 char authcmd[1024];
409 size_t authlen;
410
411 authlen = snprintf(authcmd,sizeof(authcmd),"AUTH %s\r\n",server.masterauth);
412 if (syncWrite(fd,authcmd,authlen,5) == -1) {
e2641e09 413 redisLog(REDIS_WARNING,"Unable to AUTH to MASTER: %s",
414 strerror(errno));
a3309139
PN
415 goto error;
416 }
e2641e09 417 /* Read the AUTH result. */
418 if (syncReadLine(fd,buf,1024,3600) == -1) {
e2641e09 419 redisLog(REDIS_WARNING,"I/O error reading auth result from MASTER: %s",
420 strerror(errno));
a3309139 421 goto error;
e2641e09 422 }
423 if (buf[0] != '+') {
e2641e09 424 redisLog(REDIS_WARNING,"Cannot AUTH to MASTER, is the masterauth password correct?");
a3309139 425 goto error;
e2641e09 426 }
427 }
428
429 /* Issue the SYNC command */
430 if (syncWrite(fd,"SYNC \r\n",7,5) == -1) {
e2641e09 431 redisLog(REDIS_WARNING,"I/O error writing to MASTER: %s",
432 strerror(errno));
a3309139 433 goto error;
e2641e09 434 }
26b33669 435
436 /* Prepare a suitable temp file for bulk transfer */
e2641e09 437 while(maxtries--) {
438 snprintf(tmpfile,256,
439 "temp-%d.%ld.rdb",(int)time(NULL),(long int)getpid());
440 dfd = open(tmpfile,O_CREAT|O_WRONLY|O_EXCL,0644);
441 if (dfd != -1) break;
442 sleep(1);
443 }
444 if (dfd == -1) {
e2641e09 445 redisLog(REDIS_WARNING,"Opening the temp file needed for MASTER <-> SLAVE synchronization: %s",strerror(errno));
a3309139 446 goto error;
e2641e09 447 }
e2641e09 448
f4aa600b 449 /* Setup the non blocking download of the bulk file. */
a3309139 450 if (aeCreateFileEvent(server.el,fd, AE_READABLE,readSyncBulkPayload,NULL)
62ec599c 451 == AE_ERR)
f4aa600b 452 {
f4aa600b 453 redisLog(REDIS_WARNING,"Can't create readable event for SYNC");
a3309139 454 goto error;
e2641e09 455 }
a3309139 456
f4aa600b 457 server.replstate = REDIS_REPL_TRANSFER;
26b33669 458 server.repl_transfer_left = -1;
f4aa600b 459 server.repl_transfer_fd = dfd;
460 server.repl_transfer_lastio = time(NULL);
461 server.repl_transfer_tmpfile = zstrdup(tmpfile);
a3309139
PN
462 return;
463
464error:
465 server.replstate = REDIS_REPL_CONNECT;
466 close(fd);
467 return;
468}
469
470int connectWithMaster(void) {
471 int fd;
472
473 fd = anetTcpNonBlockConnect(NULL,server.masterhost,server.masterport);
474 if (fd == -1) {
475 redisLog(REDIS_WARNING,"Unable to connect to MASTER: %s",
476 strerror(errno));
477 return REDIS_ERR;
478 }
479
480 if (aeCreateFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE,
481 syncWithMaster,NULL) == AE_ERR)
482 {
483 close(fd);
484 redisLog(REDIS_WARNING,"Can't create readable event for SYNC");
485 return REDIS_ERR;
486 }
487
488 server.repl_transfer_s = fd;
489 server.replstate = REDIS_REPL_CONNECTING;
e2641e09 490 return REDIS_OK;
491}
492
493void slaveofCommand(redisClient *c) {
494 if (!strcasecmp(c->argv[1]->ptr,"no") &&
495 !strcasecmp(c->argv[2]->ptr,"one")) {
496 if (server.masterhost) {
497 sdsfree(server.masterhost);
498 server.masterhost = NULL;
499 if (server.master) freeClient(server.master);
f4aa600b 500 if (server.replstate == REDIS_REPL_TRANSFER)
501 replicationAbortSyncTransfer();
e2641e09 502 server.replstate = REDIS_REPL_NONE;
503 redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
504 }
505 } else {
506 sdsfree(server.masterhost);
507 server.masterhost = sdsdup(c->argv[1]->ptr);
508 server.masterport = atoi(c->argv[2]->ptr);
509 if (server.master) freeClient(server.master);
f4aa600b 510 if (server.replstate == REDIS_REPL_TRANSFER)
511 replicationAbortSyncTransfer();
e2641e09 512 server.replstate = REDIS_REPL_CONNECT;
513 redisLog(REDIS_NOTICE,"SLAVE OF %s:%d enabled (user request)",
514 server.masterhost, server.masterport);
515 }
516 addReply(c,shared.ok);
517}
f4aa600b 518
519/* --------------------------- REPLICATION CRON ---------------------------- */
520
89a1433e 521#define REDIS_REPL_TIMEOUT 60
522#define REDIS_REPL_PING_SLAVE_PERIOD 10
f4aa600b 523
524void replicationCron(void) {
525 /* Bulk transfer I/O timeout? */
526 if (server.masterhost && server.replstate == REDIS_REPL_TRANSFER &&
89a1433e 527 (time(NULL)-server.repl_transfer_lastio) > REDIS_REPL_TIMEOUT)
f4aa600b 528 {
529 redisLog(REDIS_WARNING,"Timeout receiving bulk data from MASTER...");
530 replicationAbortSyncTransfer();
531 }
532
89a1433e 533 /* Timed out master when we are an already connected slave? */
534 if (server.masterhost && server.replstate == REDIS_REPL_CONNECTED &&
535 (time(NULL)-server.master->lastinteraction) > REDIS_REPL_TIMEOUT)
536 {
537 redisLog(REDIS_WARNING,"MASTER time out: no data nor PING received...");
538 freeClient(server.master);
539 }
540
f4aa600b 541 /* Check if we should connect to a MASTER */
62ec599c 542 if (server.replstate == REDIS_REPL_CONNECT) {
f4aa600b 543 redisLog(REDIS_NOTICE,"Connecting to MASTER...");
a3309139
PN
544 if (connectWithMaster() == REDIS_OK) {
545 redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync started");
f4aa600b 546 if (server.appendonly) rewriteAppendOnlyFileBackground();
547 }
548 }
89a1433e 549
550 /* If we have attached slaves, PING them from time to time.
551 * So slaves can implement an explicit timeout to masters, and will
552 * be able to detect a link disconnection even if the TCP connection
553 * will not actually go down. */
554 if (!(server.cronloops % (REDIS_REPL_PING_SLAVE_PERIOD*10))) {
555 listIter li;
556 listNode *ln;
557
558 listRewind(server.slaves,&li);
559 while((ln = listNext(&li))) {
560 redisClient *slave = ln->value;
561
562 /* Don't ping slaves that are in the middle of a bulk transfer
563 * with the master for first synchronization. */
564 if (slave->replstate == REDIS_REPL_SEND_BULK) continue;
565 if (slave->replstate == REDIS_REPL_ONLINE) {
566 /* If the slave is online send a normal ping */
567 addReplySds(slave,sdsnew("PING\r\n"));
568 } else {
569 /* Otherwise we are in the pre-synchronization stage.
570 * Just a newline will do the work of refreshing the
571 * connection last interaction time, and at the same time
572 * we'll be sure that being a single char there are no
573 * short-write problems. */
f96a9f82 574 if (write(slave->fd, "\n", 1) == -1) {
575 /* Don't worry, it's just a ping. */
576 }
89a1433e 577 }
578 }
579 }
f4aa600b 580}