]> git.saurik.com Git - redis.git/blobdiff - src/replication.c
Merge remote-tracking branch 'origin/unstable' into unstable
[redis.git] / src / replication.c
index c8ebb6e7fb7cf6f19bb8bb63150f2d4372706c86..30df9bc82cc128e141c1999eac97210e9b2364be 100644 (file)
@@ -358,6 +358,8 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
         server.master->authenticated = 1;
         server.replstate = REDIS_REPL_CONNECTED;
         redisLog(REDIS_NOTICE, "MASTER <-> SLAVE sync: Finished with success");
+        /* Rewrite the AOF file now that the dataset changed. */
+        if (server.appendonly) rewriteAppendOnlyFileBackground();
     }
 
     return;
@@ -374,10 +376,18 @@ void syncWithMaster(aeEventLoop *el, int fd, void *privdata, int mask) {
     REDIS_NOTUSED(privdata);
     REDIS_NOTUSED(mask);
 
+    /* If this event fired after the user turned the instance into a master
+     * with SLAVEOF NO ONE we must just return ASAP. */
+    if (server.replstate == REDIS_REPL_NONE) {
+        close(fd);
+        return;
+    }
+
+    redisLog(REDIS_NOTICE,"Non blocking connect for SYNC fired the event.");
     /* This event should only be triggered once since it is used to have a
      * non-blocking connect(2) to the master. It has been triggered when this
      * function is called, so we can delete it. */
-    aeDeleteFileEvent(server.el,fd,AE_WRITABLE);
+    aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
 
     /* AUTH with the master if required. */
     if(server.masterauth) {
@@ -453,7 +463,7 @@ int connectWithMaster(void) {
         return REDIS_ERR;
     }
 
-    if (aeCreateFileEvent(server.el,fd,AE_WRITABLE,syncWithMaster,NULL) ==
+    if (aeCreateFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE,syncWithMaster,NULL) ==
             AE_ERR)
     {
         close(fd);
@@ -461,11 +471,24 @@ int connectWithMaster(void) {
         return REDIS_ERR;
     }
 
+    server.repl_transfer_lastio = time(NULL);
     server.repl_transfer_s = fd;
     server.replstate = REDIS_REPL_CONNECTING;
     return REDIS_OK;
 }
 
+/* This function can be called when a non blocking connection is currently
+ * in progress to undo it. */
+void undoConnectWithMaster(void) {
+    int fd = server.repl_transfer_s;
+
+    redisAssert(server.replstate == REDIS_REPL_CONNECTING);
+    aeDeleteFileEvent(server.el,fd,AE_READABLE|AE_WRITABLE);
+    close(fd);
+    server.repl_transfer_s = -1;
+    server.replstate = REDIS_REPL_CONNECT;
+}
+
 void slaveofCommand(redisClient *c) {
     if (!strcasecmp(c->argv[1]->ptr,"no") &&
         !strcasecmp(c->argv[2]->ptr,"one")) {
@@ -475,6 +498,8 @@ void slaveofCommand(redisClient *c) {
             if (server.master) freeClient(server.master);
             if (server.replstate == REDIS_REPL_TRANSFER)
                 replicationAbortSyncTransfer();
+            else if (server.replstate == REDIS_REPL_CONNECTING)
+                undoConnectWithMaster();
             server.replstate = REDIS_REPL_NONE;
             redisLog(REDIS_NOTICE,"MASTER MODE enabled (user request)");
         }
@@ -494,13 +519,18 @@ void slaveofCommand(redisClient *c) {
 
 /* --------------------------- REPLICATION CRON  ---------------------------- */
 
-#define REDIS_REPL_TIMEOUT 60
-#define REDIS_REPL_PING_SLAVE_PERIOD 10
-
 void replicationCron(void) {
+    /* Non blocking connection timeout? */
+    if (server.masterhost && server.replstate == REDIS_REPL_CONNECTING &&
+        (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout)
+    {
+        redisLog(REDIS_WARNING,"Timeout connecting to the MASTER...");
+        undoConnectWithMaster();
+    }
+
     /* Bulk transfer I/O timeout? */
     if (server.masterhost && server.replstate == REDIS_REPL_TRANSFER &&
-        (time(NULL)-server.repl_transfer_lastio) > REDIS_REPL_TIMEOUT)
+        (time(NULL)-server.repl_transfer_lastio) > server.repl_timeout)
     {
         redisLog(REDIS_WARNING,"Timeout receiving bulk data from MASTER...");
         replicationAbortSyncTransfer();
@@ -508,7 +538,7 @@ void replicationCron(void) {
 
     /* Timed out master when we are an already connected slave? */
     if (server.masterhost && server.replstate == REDIS_REPL_CONNECTED &&
-        (time(NULL)-server.master->lastinteraction) > REDIS_REPL_TIMEOUT)
+        (time(NULL)-server.master->lastinteraction) > server.repl_timeout)
     {
         redisLog(REDIS_WARNING,"MASTER time out: no data nor PING received...");
         freeClient(server.master);
@@ -519,7 +549,6 @@ void replicationCron(void) {
         redisLog(REDIS_NOTICE,"Connecting to MASTER...");
         if (connectWithMaster() == REDIS_OK) {
             redisLog(REDIS_NOTICE,"MASTER <-> SLAVE sync started");
-            if (server.appendonly) rewriteAppendOnlyFileBackground();
         }
     }
     
@@ -527,7 +556,7 @@ void replicationCron(void) {
      * So slaves can implement an explicit timeout to masters, and will
      * be able to detect a link disconnection even if the TCP connection
      * will not actually go down. */
-    if (!(server.cronloops % (REDIS_REPL_PING_SLAVE_PERIOD*10))) {
+    if (!(server.cronloops % (server.repl_ping_slave_period*10))) {
         listIter li;
         listNode *ln;