Revert to having the receiver handle timeouts on the receiving side.
authorWayne Davison <wayned@samba.org>
Wed, 23 Dec 2009 19:31:28 +0000 (11:31 -0800)
committerWayne Davison <wayned@samba.org>
Wed, 23 Dec 2009 19:36:27 +0000 (11:36 -0800)
This will give 3.0.7 the standard timeout handling with just a few
improvements: a fix for the detection of recent sender I/O, the use
of MSG_DATA for really old rsync versions, and better setting of
select_timeout for shorter timeout settings.

NEWS
generator.c
io.c
rsync.h

diff --git a/NEWS b/NEWS
index 7f9bf1884f630997dad47d860d0f6e17a4ba2c54..b0040bb2dcc48c10f90d7c0b20cec9685d237159 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,10 +28,9 @@ Changes since 3.0.6:
 
     - Improved the "--delete does not work without -r or -d" message.
 
-    - Improved rsync's handling of --timeout to avoid weird timeout cases and
-      to make keep-alive messages work even with older (pre-2.6.4) rsyncs (by
-      discovering a workable keep-alive signal that can be used with rsyncs
-      that don't support explicit keep-alive messages).
+    - Improved rsync's handling of --timeout to avoid a weird timeout case
+      where the sender could timeout even though it has recently written data
+      to the socket (but hasn't read data recently, due to the writing).
 
     - Some misc manpage improvements.
 
index 7e32fe1fe5ea96fa686ccb4387594df6e45eeb45..9f3586fffd7b32b567c0b54788684a1cdb211bcb 100644 (file)
@@ -69,6 +69,7 @@ extern int io_error;
 extern int flist_eof;
 extern int allowed_lull;
 extern int sock_f_out;
+extern int ignore_timeout;
 extern int protocol_version;
 extern int file_total;
 extern int fuzzy_basis;
@@ -2211,6 +2212,12 @@ void generate_files(int f_out, const char *local_name)
                        : "enabled");
        }
 
+       /* Since we often fill up the outgoing socket and then just sit around
+        * waiting for the other 2 processes to do their thing, we don't want
+        * to exit on a timeout.  If the data stops flowing, the receiver will
+        * notice that and let us know via the message pipe (or its closing). */
+       ignore_timeout = 1;
+
        dflt_perms = (ACCESSPERMS & ~orig_umask);
 
        do {
diff --git a/io.c b/io.c
index 578d2562fd832b55d33475b0334752fcad03ed13..f9fa7c793114fbc4d1084ee4bb7da46b8213817c 100644 (file)
--- a/io.c
+++ b/io.c
@@ -40,7 +40,6 @@ extern int allowed_lull;
 extern int am_server;
 extern int am_daemon;
 extern int am_sender;
-extern int am_receiver;
 extern int am_generator;
 extern int inc_recurse;
 extern int io_error;
@@ -62,6 +61,7 @@ extern iconv_t ic_send, ic_recv;
 #endif
 
 const char phase_unknown[] = "unknown";
+int ignore_timeout = 0;
 int batch_fd = -1;
 int msgdone_cnt = 0;
 
@@ -123,11 +123,7 @@ static void check_timeout(void)
 {
        time_t t, chk;
 
-       /* On the receiving side, the generator is now handling timeouts, so
-        * the receiver ignores them.  Note that the am_receiver flag is not
-        * set until the receiver forks from the generator, so timeouts will be
-        * based on receiving data on the receiving side until that event. */
-       if (!io_timeout || am_receiver)
+       if (!io_timeout || ignore_timeout)
                return;
 
        t = time(NULL);
@@ -215,13 +211,15 @@ void io_set_sock_fds(int f_in, int f_out)
 void set_io_timeout(int secs)
 {
        io_timeout = secs;
+       allowed_lull = (io_timeout + 1) / 2;
 
-       if (!io_timeout || io_timeout > SELECT_TIMEOUT)
+       if (!io_timeout || allowed_lull > SELECT_TIMEOUT)
                select_timeout = SELECT_TIMEOUT;
        else
-               select_timeout = io_timeout;
+               select_timeout = allowed_lull;
 
-       allowed_lull = read_batch ? 0 : (io_timeout + 1) / 2;
+       if (read_batch)
+               allowed_lull = 0;
 }
 
 /* Setup the fd used to receive MSG_* messages.  Only needed during the
@@ -948,18 +946,19 @@ void maybe_flush_socket(int important)
                io_flush(NORMAL_FLUSH);
 }
 
-/* Older rsync versions used to send either a MSG_NOOP (protocol 30) or a
- * raw-data-based keep-alive (protocol 29), both of which implied forwarding of
- * the message through the sender.  Since the new timeout method does not need
- * any forwarding, we just send an empty MSG_DATA message, which works with all
- * rsync versions.  This avoids any message forwarding, and leaves the raw-data
- * stream alone (since we can never be quite sure if that stream is in the
- * right state for a keep-alive message). */
 void maybe_send_keepalive(void)
 {
        if (time(NULL) - last_io_out >= allowed_lull) {
-               if (!iobuf_out || !iobuf_out_cnt)
-                       send_msg(MSG_DATA, "", 0, 0);
+               if (!iobuf_out || !iobuf_out_cnt) {
+                       if (protocol_version < 29)
+                               send_msg(MSG_DATA, "", 0, 0);
+                       else if (protocol_version >= 30)
+                               send_msg(MSG_NOOP, "", 0, 0);
+                       else {
+                               write_int(sock_f_out, cur_flist->used);
+                               write_shortint(sock_f_out, ITEM_IS_NEW);
+                       }
+               }
                if (iobuf_out)
                        io_flush(NORMAL_FLUSH);
        }
@@ -1043,7 +1042,6 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                        iobuf_in_ndx = 0;
                        break;
                case MSG_NOOP:
-                       /* Support protocol-30 keep-alive method. */
                        if (msg_bytes != 0)
                                goto invalid_msg;
                        if (am_sender)
@@ -1526,6 +1524,7 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
                        while (!am_server && fd == sock_f_out && io_multiplexing_in) {
                                char buf[1024];
                                set_io_timeout(30);
+                               ignore_timeout = 0;
                                readfd_unbuffered(sock_f_in, buf, sizeof buf);
                        }
                        exit_cleanup(RERR_STREAMIO);
diff --git a/rsync.h b/rsync.h
index 5b20c5f323ed282a71be93d9270a81eb10cd3611..d804d495dce22de2685a16fed8390034c04e755c 100644 (file)
--- a/rsync.h
+++ b/rsync.h
@@ -229,7 +229,7 @@ enum msgcode {
        MSG_FLIST=20,   /* extra file list over sibling socket */
        MSG_FLIST_EOF=21,/* we've transmitted all the file lists */
        MSG_IO_ERROR=22,/* the sending side had an I/O error */
-       MSG_NOOP=42,    /* a do-nothing message (legacy protocol-30 only) */
+       MSG_NOOP=42,    /* a do-nothing message */
        MSG_SUCCESS=100,/* successfully updated indicated flist index */
        MSG_DELETED=101,/* successfully deleted a file on receiving side */
        MSG_NO_SEND=102,/* sender failed to open a file we wanted */