1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Update the progress gauge even when the data does not arrive.

This commit is contained in:
hniksic 2003-11-08 08:56:52 -08:00
parent cb393a062d
commit 94ca33d2fb
4 changed files with 125 additions and 20 deletions

View File

@ -1,3 +1,12 @@
2003-11-08 Hrvoje Niksic <hniksic@xemacs.org>
* progress.c (update_speed_ring): Clear the speed ring when the
download stalls.
* retr.c (get_contents): Specify 0.95s read timeout, so that the
progress gauge can be updated even when data arrives very slowly
or stalls.
2003-11-08 Hrvoje Niksic <hniksic@xemacs.org> 2003-11-08 Hrvoje Niksic <hniksic@xemacs.org>
* utils.c (wtimer_allocate): Bless the use of wtimer_read on a * utils.c (wtimer_allocate): Bless the use of wtimer_read on a

View File

@ -51,6 +51,7 @@ so, delete this exception statement from your version. */
struct progress_implementation { struct progress_implementation {
char *name; char *name;
int interactive;
void *(*create) PARAMS ((long, long)); void *(*create) PARAMS ((long, long));
void (*update) PARAMS ((void *, long, double)); void (*update) PARAMS ((void *, long, double));
void (*finish) PARAMS ((void *, double)); void (*finish) PARAMS ((void *, double));
@ -70,8 +71,8 @@ static void bar_finish PARAMS ((void *, double));
static void bar_set_params PARAMS ((const char *)); static void bar_set_params PARAMS ((const char *));
static struct progress_implementation implementations[] = { static struct progress_implementation implementations[] = {
{ "dot", dot_create, dot_update, dot_finish, dot_set_params }, { "dot", 0, dot_create, dot_update, dot_finish, dot_set_params },
{ "bar", bar_create, bar_update, bar_finish, bar_set_params } { "bar", 1, bar_create, bar_update, bar_finish, bar_set_params }
}; };
static struct progress_implementation *current_impl; static struct progress_implementation *current_impl;
static int current_impl_locked; static int current_impl_locked;
@ -168,6 +169,17 @@ progress_create (long initial, long total)
return current_impl->create (initial, total); return current_impl->create (initial, total);
} }
/* Return non-zero if the progress gauge is "interactive", i.e. if it
can profit from being called regularly even in absence of data.
The progress bar is interactive because it regularly updates the
ETA and current update. */
int
progress_interactive_p (void *progress)
{
return current_impl->interactive;
}
/* Inform the progress gauge of newly received bytes. DLTIME is the /* Inform the progress gauge of newly received bytes. DLTIME is the
time in milliseconds since the beginning of the download. */ time in milliseconds since the beginning of the download. */
@ -425,6 +437,11 @@ static volatile sig_atomic_t received_sigwinch;
past. */ past. */
#define DLSPEED_SAMPLE_MIN 150 #define DLSPEED_SAMPLE_MIN 150
/* The time after which the download starts to be considered
"stalled", i.e. the current bandwidth is not printed and the recent
download speeds are scratched. */
#define STALL_START_TIME 5000
struct bar_progress { struct bar_progress {
long initial_length; /* how many bytes have been downloaded long initial_length; /* how many bytes have been downloaded
previously. */ previously. */
@ -466,8 +483,12 @@ struct bar_progress {
position. */ position. */
long recent_bytes; /* bytes downloaded so far. */ long recent_bytes; /* bytes downloaded so far. */
int stalled; /* set when no data arrives for longer
than STALL_START_TIME, then reset
when new data arrives. */
/* create_image() uses these to make sure that ETA information /* create_image() uses these to make sure that ETA information
doesn't flash. */ doesn't flicker. */
double last_eta_time; /* time of the last update to download double last_eta_time; /* time of the last update to download
speed and ETA, measured since the speed and ETA, measured since the
beginning of download. */ beginning of download. */
@ -615,6 +636,38 @@ update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
if (recent_age < DLSPEED_SAMPLE_MIN) if (recent_age < DLSPEED_SAMPLE_MIN)
return; return;
if (howmuch == 0)
{
/* If we're not downloading anything, we might be stalling,
i.e. not downloading anything for an extended period of time.
Since 0-reads do not enter the history ring, recent_age
effectively measures the time since last read. */
if (recent_age >= STALL_START_TIME)
{
/* If we're stalling, reset the ring contents because it's
stale and because it will make bar_update stop printing
the (bogus) current bandwidth. */
bp->stalled = 1;
xzero (*hist);
bp->recent_bytes = 0;
}
return;
}
/* We now have a non-zero amount of to store to the speed ring. */
/* If the stall status was acquired, reset it. */
if (bp->stalled)
{
bp->stalled = 0;
/* "recent_age" includes the the entired stalled period, which
could be very long. Don't update the speed ring with that
value because the current bandwidth would start too small.
Start with an arbitrary (but more reasonable) time value and
let it level out. */
recent_age = 1000;
}
/* Store "recent" bytes and download time to history ring at the /* Store "recent" bytes and download time to history ring at the
position POS. */ position POS. */
@ -637,7 +690,7 @@ update_speed_ring (struct bar_progress *bp, long howmuch, double dltime)
if (++hist->pos == DLSPEED_HISTORY_SIZE) if (++hist->pos == DLSPEED_HISTORY_SIZE)
hist->pos = 0; hist->pos = 0;
#if 0 #if 1
/* Sledgehammer check to verify that the totals are accurate. */ /* Sledgehammer check to verify that the totals are accurate. */
{ {
int i; int i;

View File

@ -35,6 +35,7 @@ void set_progress_implementation PARAMS ((const char *));
void progress_schedule_redirect PARAMS ((void)); void progress_schedule_redirect PARAMS ((void));
void *progress_create PARAMS ((long, long)); void *progress_create PARAMS ((long, long));
int progress_interactive_p PARAMS ((void *));
void progress_update PARAMS ((void *, long, double)); void progress_update PARAMS ((void *, long, double));
void progress_finish PARAMS ((void *, double)); void progress_finish PARAMS ((void *, double));

View File

@ -161,13 +161,25 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
static char dlbuf[16384]; static char dlbuf[16384];
int dlbufsize = sizeof (dlbuf); int dlbufsize = sizeof (dlbuf);
void *progress = NULL;
struct wget_timer *timer = wtimer_allocate (); struct wget_timer *timer = wtimer_allocate ();
double last_successful_read_tm;
/* The progress gauge, set according to the user preferences. */
void *progress = NULL;
/* Non-zero if the progress gauge is interactive, i.e. if it can
continually update the display. When true, smaller timeout
values are used so that the gauge can update the display when
data arrives slowly. */
int progress_interactive = 0;
*len = restval; *len = restval;
if (opt.verbose) if (opt.verbose)
progress = progress_create (restval, expected); {
progress = progress_create (restval, expected);
progress_interactive = progress_interactive_p (progress);
}
if (rbuf && RBUF_FD (rbuf) == fd) if (rbuf && RBUF_FD (rbuf) == fd)
{ {
@ -192,6 +204,7 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
if (opt.limit_rate) if (opt.limit_rate)
limit_bandwidth_reset (); limit_bandwidth_reset ();
wtimer_reset (timer); wtimer_reset (timer);
last_successful_read_tm = 0;
/* Use a smaller buffer for low requested bandwidths. For example, /* Use a smaller buffer for low requested bandwidths. For example,
with --limit-rate=2k, it doesn't make sense to slurp in 16K of with --limit-rate=2k, it doesn't make sense to slurp in 16K of
@ -209,24 +222,53 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
{ {
int amount_to_read = (use_expected int amount_to_read = (use_expected
? MIN (expected - *len, dlbufsize) : dlbufsize); ? MIN (expected - *len, dlbufsize) : dlbufsize);
res = xread (fd, dlbuf, amount_to_read, -1); double tmout = opt.read_timeout;
if (progress_interactive)
if (res <= 0)
break;
fwrite (dlbuf, 1, res, fp);
/* Always flush the contents of the network packet. This should
not hinder performance: fast downloads will be received in
16K chunks (which stdio would write out anyway), and slow
downloads won't be limited by disk performance. */
fflush (fp);
if (ferror (fp))
{ {
res = -2; double waittm;
goto out; /* For interactive progress gauges, always specify a ~1s
timeout, so that the gauge can be updated regularly even
when the data arrives very slowly or stalls. */
tmout = 0.95;
waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
if (waittm + tmout > opt.read_timeout)
{
/* Don't allow waiting for data to exceed read timeout. */
tmout = opt.read_timeout - waittm;
if (tmout < 0)
{
/* We've already exceeded the timeout. */
res = -1;
errno = ETIMEDOUT;
break;
}
}
} }
res = xread (fd, dlbuf, amount_to_read, tmout);
if (res == 0 || (res < 0 && errno != ETIMEDOUT))
break;
else if (res < 0)
res = 0; /* timeout */
wtimer_update (timer); wtimer_update (timer);
if (res > 0)
{
fwrite (dlbuf, 1, res, fp);
/* Always flush the contents of the network packet. This
should not hinder performance: fast downloads will be
received in 16K chunks (which stdio would write out
anyway), and slow downloads won't be limited by disk
performance. */
fflush (fp);
if (ferror (fp))
{
res = -2;
goto out;
}
last_successful_read_tm = wtimer_read (timer);
}
if (opt.limit_rate) if (opt.limit_rate)
limit_bandwidth (res, timer); limit_bandwidth (res, timer);