Have the sender use dead time to pad out the file list.
[rsync/rsync.git] / io.c
diff --git a/io.c b/io.c
index 6e5c232..c9d990a 100644 (file)
--- a/io.c
+++ b/io.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2001 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2008 Wayne Davison
+ * Copyright (C) 2003-2009 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
 
 #include "rsync.h"
 #include "ifuncs.h"
+#include "inums.h"
 
 /** If no timeout is specified then use a 60 second select timeout */
 #define SELECT_TIMEOUT 60
@@ -36,7 +37,6 @@
 extern int bwlimit;
 extern size_t bwlimit_writemax;
 extern int io_timeout;
-extern int allowed_lull;
 extern int am_server;
 extern int am_daemon;
 extern int am_sender;
@@ -45,9 +45,10 @@ extern int inc_recurse;
 extern int io_error;
 extern int eol_nulls;
 extern int flist_eof;
+extern int file_total;
+extern int file_old_total;
 extern int list_only;
 extern int read_batch;
-extern int csum_length;
 extern int protect_args;
 extern int checksum_seed;
 extern int protocol_version;
@@ -60,7 +61,8 @@ extern int filesfrom_convert;
 extern iconv_t ic_send, ic_recv;
 #endif
 
-const char phase_unknown[] = "unknown";
+int csum_length = SHORT_SUM_LENGTH; /* initial value */
+int allowed_lull = 0;
 int ignore_timeout = 0;
 int batch_fd = -1;
 int msgdone_cnt = 0;
@@ -101,7 +103,7 @@ static char ff_lastchar;
 #ifdef ICONV_OPTION
 static xbuf iconv_buf = EMPTY_XBUF;
 #endif
-static int defer_forwarding_messages = 0, defer_forwarding_keep = 0;
+static int defer_forwarding_messages = 0, keep_defer_forwarding = 0;
 static int select_timeout = SELECT_TIMEOUT;
 static int active_filecnt = 0;
 static OFF_T active_bytecnt = 0;
@@ -124,16 +126,7 @@ static void writefd(int fd, const char *buf, size_t len);
 static void writefd_unbuffered(int fd, const char *buf, size_t len);
 static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, int convert);
 
-struct flist_ndx_item {
-       struct flist_ndx_item *next;
-       int ndx;
-};
-
-struct flist_ndx_list {
-       struct flist_ndx_item *head, *tail;
-};
-
-static struct flist_ndx_list redo_list, hlink_list;
+static flist_ndx_list redo_list, hlink_list;
 
 struct msg_list_item {
        struct msg_list_item *next;
@@ -147,45 +140,10 @@ struct msg_list {
 
 static struct msg_list msg_queue;
 
-static void flist_ndx_push(struct flist_ndx_list *lp, int ndx)
-{
-       struct flist_ndx_item *item;
-
-       if (!(item = new(struct flist_ndx_item)))
-               out_of_memory("flist_ndx_push");
-       item->next = NULL;
-       item->ndx = ndx;
-       if (lp->tail)
-               lp->tail->next = item;
-       else
-               lp->head = item;
-       lp->tail = item;
-}
-
-static int flist_ndx_pop(struct flist_ndx_list *lp)
-{
-       struct flist_ndx_item *next;
-       int ndx;
-
-       if (!lp->head)
-               return -1;
-
-       ndx = lp->head->ndx;
-       next = lp->head->next;
-       free(lp->head);
-       lp->head = next;
-       if (!next)
-               lp->tail = NULL;
-
-       return ndx;
-}
-
 static void got_flist_entry_status(enum festatus status, const char *buf)
 {
        int ndx = IVAL(buf, 0);
-       struct file_list *flist = flist_for_ndx(ndx);
-
-       assert(flist != NULL);
+       struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status");
 
        if (remove_source_files) {
                active_filecnt--;
@@ -208,6 +166,11 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
                }
                break;
        case FES_REDO:
+               if (read_batch) {
+                       if (inc_recurse)
+                               flist->in_progress++;
+                       break;
+               }
                if (inc_recurse)
                        flist->to_redo++;
                flist_ndx_push(&redo_list, ndx);
@@ -296,33 +259,32 @@ static void msg_list_add(struct msg_list *lst, int code, const char *buf, int le
        lst->tail = m;
 }
 
+static inline int flush_a_msg(int fd)
+{
+       struct msg_list_item *m = msg_queue.head;
+       int len = IVAL(m->buf, 0) & 0xFFFFFF;
+       int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
+
+       if (!(msg_queue.head = m->next))
+               msg_queue.tail = NULL;
+
+       defer_forwarding_messages++;
+       mplex_write(fd, tag, m->buf + 4, len, m->convert);
+       defer_forwarding_messages--;
+
+       free(m);
+
+       return len;
+}
+
 static void msg_flush(void)
 {
        if (am_generator) {
-               while (msg_queue.head && io_multiplexing_out) {
-                       struct msg_list_item *m = msg_queue.head;
-                       int len = IVAL(m->buf, 0) & 0xFFFFFF;
-                       int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
-                       if (!(msg_queue.head = m->next))
-                               msg_queue.tail = NULL;
-                       stats.total_written += len + 4;
-                       defer_forwarding_messages++;
-                       mplex_write(sock_f_out, tag, m->buf + 4, len, m->convert);
-                       defer_forwarding_messages--;
-                       free(m);
-               }
+               while (msg_queue.head && io_multiplexing_out)
+                       stats.total_written += flush_a_msg(sock_f_out) + 4;
        } else {
-               while (msg_queue.head) {
-                       struct msg_list_item *m = msg_queue.head;
-                       int len = IVAL(m->buf, 0) & 0xFFFFFF;
-                       int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
-                       if (!(msg_queue.head = m->next))
-                               msg_queue.tail = NULL;
-                       defer_forwarding_messages++;
-                       mplex_write(msg_fd_out, tag, m->buf + 4, len, m->convert);
-                       defer_forwarding_messages--;
-                       free(m);
-               }
+               while (msg_queue.head)
+                       (void)flush_a_msg(msg_fd_out);
        }
 }
 
@@ -449,6 +411,7 @@ static void read_msg_fd(void)
                got_flist_entry_status(FES_NO_SEND, buf);
                break;
        case MSG_ERROR_SOCKET:
+       case MSG_ERROR_UTF8:
        case MSG_CLIENT:
                if (!am_generator)
                        goto invalid_msg;
@@ -486,9 +449,14 @@ static void read_msg_fd(void)
  * this, sender-side deletions were mostly happening at the end. */
 void increment_active_files(int ndx, int itemizing, enum logcode code)
 {
-       /* TODO: tune these limits? */
-       while (active_filecnt >= (active_bytecnt >= 128*1024 ? 10 : 50)) {
+       while (1) {
+               /* TODO: tune these limits? */
+               int limit = active_bytecnt >= 128*1024 ? 10 : 50;
+               if (active_filecnt < limit)
+                       break;
                check_for_finished_files(itemizing, code, 0);
+               if (active_filecnt < limit)
+                       break;
                if (iobuf_out_cnt)
                        io_flush(NORMAL_FLUSH);
                else
@@ -512,7 +480,7 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len,
                xbuf outbuf, inbuf;
 
                INIT_XBUF(outbuf, buffer + 4, 0, sizeof buffer - 4);
-               INIT_XBUF(inbuf, (char*)buf, len, -1);
+               INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1);
 
                iconvbufs(ic_send, &inbuf, &outbuf,
                          ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
@@ -531,9 +499,9 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len,
 
        SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
 
-       defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
+       keep_defer_forwarding++; /* defer_forwarding_messages++ on return */
        writefd_unbuffered(fd, buffer, n+4);
-       defer_forwarding_keep = 0;
+       keep_defer_forwarding--;
 
        if (len > n)
                writefd_unbuffered(fd, buf+n, len-n);
@@ -568,10 +536,9 @@ void send_msg_int(enum msgcode code, int num)
 
 void wait_for_receiver(void)
 {
-       if (iobuf_out_cnt)
-               io_flush(NORMAL_FLUSH);
-       else
-               read_msg_fd();
+       if (io_flush(FULL_FLUSH))
+               return;
+       read_msg_fd();
 }
 
 int get_redo_num(void)
@@ -630,7 +597,7 @@ static void whine_about_eof(int fd)
 
        rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed "
                "(%s bytes received so far) [%s]\n",
-               big_num(stats.total_read, 0), who_am_i());
+               big_num(stats.total_read), who_am_i());
 
        exit_cleanup(RERR_STREAMIO);
 }
@@ -680,7 +647,12 @@ static int read_timeout(int fd, char *buf, size_t len)
                                maxfd = new_fd;
                }
 
-               tv.tv_sec = select_timeout;
+               if (am_sender && inc_recurse && !flist_eof && !defer_forwarding_messages && !cnt
+                && file_total - file_old_total < MAX_FILECNT_LOOKAHEAD
+                && file_total - file_old_total >= MIN_FILECNT_LOOKAHEAD)
+                       tv.tv_sec = 0;
+               else
+                       tv.tv_sec = select_timeout;
                tv.tv_usec = 0;
 
                errno = 0;
@@ -692,7 +664,10 @@ static int read_timeout(int fd, char *buf, size_t len)
                                defer_forwarding_messages = 0;
                                exit_cleanup(RERR_SOCKETIO);
                        }
-                       check_timeout();
+                       if (am_sender && tv.tv_sec == 0)
+                               send_extra_file_list(sock_f_out, -1);
+                       else
+                               check_timeout();
                        continue;
                }
 
@@ -1084,6 +1059,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                        send_msg_int(MSG_IO_ERROR, IVAL(line, 0));
                        io_error |= IVAL(line, 0);
                        break;
+               case MSG_DEL_STATS:
+                       if (msg_bytes)
+                               goto invalid_msg;
+                       read_del_stats(fd);
+                       if (am_sender && am_server)
+                               write_del_stats(sock_f_out);
+                       break;
                case MSG_DELETED:
                        if (msg_bytes >= sizeof line)
                                goto overflow;
@@ -1092,10 +1074,9 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                                xbuf outbuf, inbuf;
                                char ibuf[512];
                                int add_null = 0;
-                               int pos = 0;
 
                                INIT_CONST_XBUF(outbuf, line);
-                               INIT_XBUF(inbuf, ibuf, 0, -1);
+                               INIT_XBUF(inbuf, ibuf, 0, (size_t)-1);
 
                                while (msg_bytes) {
                                        inbuf.len = msg_bytes > sizeof ibuf
@@ -1107,7 +1088,6 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                                        if (iconvbufs(ic_send, &inbuf, &outbuf,
                                            ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE) < 0)
                                                goto overflow;
-                                       pos = -1;
                                }
                                if (add_null) {
                                        if (outbuf.len == outbuf.size)
@@ -1453,6 +1433,22 @@ static void sleep_for_bwlimit(int bytes_written)
        total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
 }
 
+static const char *what_fd_is(int fd)
+{
+       static char buf[20];
+
+       if (fd == sock_f_out)
+               return "socket";
+       else if (fd == msg_fd_out)
+               return "message fd";
+       else if (fd == batch_fd)
+               return "batch file";
+       else {
+               snprintf(buf, sizeof buf, "fd %d", fd);
+               return buf;
+       }
+}
+
 /* Write len bytes to the file descriptor fd, looping as necessary to get
  * the job done and also (in certain circumstances) reading any data on
  * msg_fd_in to avoid deadlock.
@@ -1531,8 +1527,8 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
                        if (am_server && fd == msg_fd_out)
                                exit_cleanup(RERR_STREAMIO);
                        rsyserr(FERROR, errno,
-                               "writefd_unbuffered failed to write %ld bytes [%s]",
-                               (long)len, who_am_i());
+                               "writefd_unbuffered failed to write %ld bytes to %s [%s]",
+                               (long)len, what_fd_is(fd), who_am_i());
                        /* If the other side is sending us error messages, try
                         * to grab any messages they sent before they died. */
                        while (!am_server && fd == sock_f_out && io_multiplexing_in) {
@@ -1555,24 +1551,34 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
        }
 
        no_flush--;
-       defer_inc -= defer_forwarding_keep;
+       if (keep_defer_forwarding)
+               defer_inc--;
        if (!(defer_forwarding_messages -= defer_inc) && !no_flush)
                msg_flush();
 }
 
-void io_flush(int flush_it_all)
+int io_flush(int flush_it_all)
 {
-       if (!iobuf_out_cnt || no_flush)
-               return;
+       int flushed_something = 0;
 
-       if (io_multiplexing_out)
-               mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0);
-       else
-               writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt);
-       iobuf_out_cnt = 0;
+       if (no_flush)
+               return 0;
 
-       if (flush_it_all && !defer_forwarding_messages)
+       if (iobuf_out_cnt) {
+               if (io_multiplexing_out)
+                       mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0);
+               else
+                       writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt);
+               iobuf_out_cnt = 0;
+               flushed_something = 1;
+       }
+
+       if (flush_it_all && !defer_forwarding_messages && msg_queue.head) {
                msg_flush();
+               flushed_something = 1;
+       }
+
+       return flushed_something;
 }
 
 static void writefd(int fd, const char *buf, size_t len)
@@ -1580,10 +1586,8 @@ static void writefd(int fd, const char *buf, size_t len)
        if (fd == sock_f_out)
                stats.total_written += len;
 
-       if (fd == write_batch_monitor_out) {
-               if ((size_t)write(batch_fd, buf, len) != len)
-                       exit_cleanup(RERR_FILEIO);
-       }
+       if (fd == write_batch_monitor_out)
+               writefd_unbuffered(batch_fd, buf, len);
 
        if (!iobuf_out || fd != iobuf_f_out) {
                writefd_unbuffered(fd, buf, len);