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:
parent
cb393a062d
commit
94ca33d2fb
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
74
src/retr.c
74
src/retr.c
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user