X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/880da0072e01453a6a7329ce402d35093bce2618..931a979904a17a28af6265b60a088824edb78fa7:/io.c diff --git a/io.c b/io.c index 3349b83b..f651116e 100644 --- a/io.c +++ b/io.c @@ -52,6 +52,24 @@ extern int io_timeout; extern struct stats stats; +const char phase_unknown[] = "unknown"; + +/** + * The connection might be dropped at some point; perhaps because the + * remote instance crashed. Just giving the offset on the stream is + * not very helpful. So instead we try to make io_phase_name point to + * something useful. + * + * For buffered/multiplexed IO these names will be somewhat + * approximate; perhaps for ease of support we would rather make the + * buffer always flush when a single application-level IO finishes. + * + * @todo Perhaps we want some simple stack functionality, but there's + * no need to overdo it. + **/ +const char *io_write_phase = phase_unknown; +const char *io_read_phase = phase_unknown; + /** Ignore EOF errors while reading a module listing if the remote version is 24 or less. */ int kludge_around_eof = False; @@ -86,7 +104,7 @@ static void check_timeout(void) } } -/** Setup the fd used to propogate errors */ +/** Setup the fd used to propagate errors */ void io_set_error_fd(int fd) { io_error_fd = fd; @@ -390,6 +408,33 @@ unsigned char read_byte(int f) } +/** + * Sleep after writing to limit I/O bandwidth usage. + * + * @todo Rather than sleeping after each write, it might be better to + * use some kind of averaging. The current algorithm seems to always + * use a bit less bandwidth than specified, because it doesn't make up + * for slow periods. But arguably this is a feature. In addition, we + * ought to take the time used to write the data into account. + **/ +static void sleep_for_bwlimit(int bytes_written) +{ + struct timeval tv; + + if (!bwlimit) + return; + + assert(bytes_written > 0); + assert(bwlimit > 0); + + tv.tv_usec = bytes_written * 1000 / bwlimit; + tv.tv_sec = tv.tv_usec / 1000000; + tv.tv_usec = tv.tv_usec % 1000000; + + select(0, NULL, NULL, NULL, &tv); +} + + /** * Write len bytes to the file descriptor @p fd. * @@ -464,24 +509,13 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) * across the stream */ io_multiplexing_close(); rprintf(FERROR, RSYNC_NAME - ": error writing %d unbuffered bytes" - " - exiting: %s\n", len, + ": writefd_unbuffered failed to write %ld bytes: phase \"%s\": %s\n", + (long) len, io_write_phase, strerror(errno)); exit_cleanup(RERR_STREAMIO); } - /* Sleep after writing to limit I/O bandwidth */ - if (bwlimit) - { - tv.tv_sec = 0; - tv.tv_usec = ret * 1000 / bwlimit; - while (tv.tv_usec > 1000000) - { - tv.tv_sec++; - tv.tv_usec -= 1000000; - } - select(0, NULL, NULL, NULL, &tv); - } + sleep_for_bwlimit(ret); total += ret; @@ -592,6 +626,14 @@ void write_int(int f,int32 x) } +void write_int_named(int f, int32 x, const char *phase) +{ + io_write_phase = phase; + write_int(f, x); + io_write_phase = phase_unknown; +} + + /* * Note: int64 may actually be a 32-bit type if ./configure couldn't find any * 64-bit types on this platform.