mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] Adjust bandwidth limitation sleep for the error of previous sleeps.
Allow decimal numbers in bandwidth limit specification.
This commit is contained in:
parent
0bc3dc073f
commit
b8e416c6c7
3
NEWS
3
NEWS
@ -52,7 +52,8 @@ as "//img.foo.com/foo.jpg".
|
||||
values "yes" and "no" along with the traditional "on" and "off".
|
||||
|
||||
** It is now possible to specify decimal values for --timeout, --wait,
|
||||
and --waitretry. For instance, `--wait=0.5' now works as expected.
|
||||
--waitretry, and --limit-rate. For instance, `--wait=0.5' now
|
||||
works as expected, and so does --limit-rate=2.5k.
|
||||
|
||||
* Wget 1.8.2 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
@ -1,3 +1,13 @@
|
||||
2003-09-21 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* init.c (simple_atof): New function.
|
||||
(cmd_time): Use it.
|
||||
(cmd_bytes): Accept things like "1.5k" and such. Use simple_atof
|
||||
to parse decimals.
|
||||
|
||||
* retr.c (limit_bandwidth): Adjust each sleep by the error of the
|
||||
previous one.
|
||||
|
||||
2003-09-21 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* main.c (main): Use setoptval() for setting the options. Use
|
||||
|
173
src/init.c
173
src/init.c
@ -839,64 +839,115 @@ cmd_directory_vector (const char *com, const char *val, void *closure)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set the value stored in VAL to CLOSURE (which should point to a
|
||||
long int), allowing several postfixes, with the following syntax
|
||||
(regexp):
|
||||
/* Poor man's atof: handles only <digits>.<digits>. Returns 1 on
|
||||
success, 0 on failure. In case of success, stores its result to
|
||||
*DEST. */
|
||||
|
||||
[0-9]+ -> bytes
|
||||
[0-9]+[kK] -> bytes * 1024
|
||||
[0-9]+[mM] -> bytes * 1024 * 1024
|
||||
inf -> 0
|
||||
static int
|
||||
simple_atof (const char *beg, const char *end, double *dest)
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
int seen_dot = 0;
|
||||
int seen_digit = 0;
|
||||
double divider = 1;
|
||||
|
||||
const char *p = beg;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
char ch = *p++;
|
||||
if (ISDIGIT (ch))
|
||||
{
|
||||
if (!seen_dot)
|
||||
result = (10 * result) + (ch - '0');
|
||||
else
|
||||
result += (ch - '0') / (divider *= 10);
|
||||
seen_digit = 1;
|
||||
}
|
||||
else if (ch == '.')
|
||||
{
|
||||
if (!seen_dot)
|
||||
seen_dot = 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!seen_digit)
|
||||
return 0;
|
||||
|
||||
*dest = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse VAL as a number and set its value to CLOSURE (which should
|
||||
point to a long int).
|
||||
|
||||
By default, the value is assumed to be in bytes. If "K", "M", or
|
||||
"G" are appended, the value is multiplied with 1<<10, 1<<20, or
|
||||
1<<30, respectively. Floating point values are allowed and are
|
||||
cast to integer before use. The idea is to be able to use things
|
||||
like 1.5k instead of "1536".
|
||||
|
||||
The string "inf" is returned as 0.
|
||||
|
||||
In case of error, 0 is returned and memory pointed to by CLOSURE
|
||||
remains unmodified. */
|
||||
|
||||
Anything else is flagged as incorrect, and CLOSURE is unchanged. */
|
||||
static int
|
||||
cmd_bytes (const char *com, const char *val, void *closure)
|
||||
{
|
||||
long result;
|
||||
long *out = (long *)closure;
|
||||
const char *p;
|
||||
long mult;
|
||||
double number;
|
||||
const char *end = val + strlen (val);
|
||||
|
||||
result = 0;
|
||||
p = val;
|
||||
/* Check for "inf". */
|
||||
if (p[0] == 'i' && p[1] == 'n' && p[2] == 'f' && p[3] == '\0')
|
||||
if (0 == strcmp (val, "inf"))
|
||||
{
|
||||
*out = 0;
|
||||
*(long *)closure = 0;
|
||||
return 1;
|
||||
}
|
||||
/* Search for digits and construct result. */
|
||||
for (; *p && ISDIGIT (*p); p++)
|
||||
result = (10 * result) + (*p - '0');
|
||||
/* If no digits were found, or more than one character is following
|
||||
them, bail out. */
|
||||
if (p == val || (*p != '\0' && *(p + 1) != '\0'))
|
||||
|
||||
/* Strip trailing whitespace. */
|
||||
while (val < end && ISSPACE (end[-1]))
|
||||
--end;
|
||||
|
||||
if (val == end)
|
||||
{
|
||||
printf (_("%s: Invalid specification `%s'\n"), com, val);
|
||||
err:
|
||||
fprintf (stderr, _("%s: Invalid byte value `%s'\n"), com, val);
|
||||
return 0;
|
||||
}
|
||||
/* Search for a designator. */
|
||||
switch (TOLOWER (*p))
|
||||
|
||||
switch (TOLOWER (end[-1]))
|
||||
{
|
||||
case '\0':
|
||||
/* None */
|
||||
break;
|
||||
case 'k':
|
||||
/* Kilobytes */
|
||||
result *= 1024;
|
||||
--end, mult = 1L<<10;
|
||||
break;
|
||||
case 'm':
|
||||
/* Megabytes */
|
||||
result *= (long)1024 * 1024;
|
||||
--end, mult = 1L<<20;
|
||||
break;
|
||||
case 'g':
|
||||
/* Gigabytes */
|
||||
result *= (long)1024 * 1024 * 1024;
|
||||
--end, mult = 1L<<30;
|
||||
break;
|
||||
default:
|
||||
printf (_("%s: Invalid specification `%s'\n"), com, val);
|
||||
return 0;
|
||||
/* Not a recognized suffix: assume it belongs to the number.
|
||||
(If not, atof simple_atof will raise an error.) */
|
||||
mult = 1;
|
||||
}
|
||||
*out = result;
|
||||
|
||||
/* Skip leading and trailing whitespace. */
|
||||
while (val < end && ISSPACE (*val))
|
||||
++val;
|
||||
while (val < end && ISSPACE (end[-1]))
|
||||
--end;
|
||||
if (val == end)
|
||||
goto err;
|
||||
|
||||
if (!simple_atof (val, end, &number))
|
||||
goto err;
|
||||
|
||||
*(long *)closure = (long)(number * mult);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -907,14 +958,11 @@ cmd_bytes (const char *com, const char *val, void *closure)
|
||||
static int
|
||||
cmd_time (const char *com, const char *val, void *closure)
|
||||
{
|
||||
double result, mult, divider;
|
||||
int seen_dot, seen_digit;
|
||||
|
||||
const char *p;
|
||||
double number, mult;
|
||||
const char *end = val + strlen (val);
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
while (end > val && ISSPACE (end[-1]))
|
||||
/* Strip trailing whitespace. */
|
||||
while (val < end && ISSPACE (end[-1]))
|
||||
--end;
|
||||
|
||||
if (val == end)
|
||||
@ -936,54 +984,29 @@ cmd_time (const char *com, const char *val, void *closure)
|
||||
--end, mult = 3600; /* hours */
|
||||
break;
|
||||
case 'd':
|
||||
--end, mult = 86400; /* days */
|
||||
--end, mult = 86400.0; /* days */
|
||||
break;
|
||||
case 'w':
|
||||
--end, mult = 604800; /* weeks */
|
||||
--end, mult = 604800.0; /* weeks */
|
||||
break;
|
||||
default:
|
||||
/* Not a recognized suffix: treat it as part of number, and
|
||||
assume seconds. */
|
||||
/* Not a recognized suffix: assume it belongs to the number.
|
||||
(If not, atof simple_atof will raise an error.) */
|
||||
mult = 1;
|
||||
}
|
||||
|
||||
/* Skip leading and trailing whitespace. */
|
||||
while (val < end && ISSPACE (*val))
|
||||
++val;
|
||||
while (val > end && ISSPACE (end[-1]))
|
||||
while (val < end && ISSPACE (end[-1]))
|
||||
--end;
|
||||
if (val == end)
|
||||
goto err;
|
||||
|
||||
/* Poor man's strtod: */
|
||||
result = 0;
|
||||
seen_dot = seen_digit = 0;
|
||||
divider = 1;
|
||||
|
||||
p = val;
|
||||
while (p < end)
|
||||
{
|
||||
char ch = *p++;
|
||||
if (ISDIGIT (ch))
|
||||
{
|
||||
if (!seen_dot)
|
||||
result = (10 * result) + (ch - '0');
|
||||
else
|
||||
result += (ch - '0') / (divider *= 10);
|
||||
seen_digit = 1;
|
||||
}
|
||||
else if (ch == '.')
|
||||
{
|
||||
if (!seen_dot)
|
||||
seen_dot = 1;
|
||||
else
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (!seen_digit)
|
||||
if (!simple_atof (val, end, &number))
|
||||
goto err;
|
||||
result *= mult;
|
||||
*(double *)closure = result;
|
||||
|
||||
*(double *)closure = number * mult;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
57
src/retr.c
57
src/retr.c
@ -67,15 +67,16 @@ int global_download_count;
|
||||
|
||||
|
||||
static struct {
|
||||
long bytes;
|
||||
double dltime;
|
||||
long chunk_bytes;
|
||||
double chunk_start;
|
||||
double sleep_adjust;
|
||||
} limit_data;
|
||||
|
||||
static void
|
||||
limit_bandwidth_reset (void)
|
||||
{
|
||||
limit_data.bytes = 0;
|
||||
limit_data.dltime = 0;
|
||||
limit_data.chunk_bytes = 0;
|
||||
limit_data.chunk_start = 0;
|
||||
}
|
||||
|
||||
/* Limit the bandwidth by pausing the download for an amount of time.
|
||||
@ -83,30 +84,48 @@ limit_bandwidth_reset (void)
|
||||
is the number of milliseconds it took to receive them. */
|
||||
|
||||
static void
|
||||
limit_bandwidth (long bytes, double delta)
|
||||
limit_bandwidth (long bytes, double *dltime, struct wget_timer *timer)
|
||||
{
|
||||
double delta_t = *dltime - limit_data.chunk_start;
|
||||
double expected;
|
||||
|
||||
limit_data.bytes += bytes;
|
||||
limit_data.dltime += delta;
|
||||
limit_data.chunk_bytes += bytes;
|
||||
|
||||
expected = 1000.0 * limit_data.bytes / opt.limit_rate;
|
||||
/* Calculate the amount of time we expect downloading the chunk
|
||||
should take. If in reality it took less time, sleep to
|
||||
compensate for the difference. */
|
||||
expected = 1000.0 * limit_data.chunk_bytes / opt.limit_rate;
|
||||
|
||||
if (expected > limit_data.dltime)
|
||||
if (expected > delta_t)
|
||||
{
|
||||
double slp = expected - limit_data.dltime;
|
||||
double slp = expected - delta_t + limit_data.sleep_adjust;
|
||||
double t0, t1;
|
||||
if (slp < 200)
|
||||
{
|
||||
DEBUGP (("deferring a %.2f ms sleep (%ld/%.2f).\n",
|
||||
slp, limit_data.bytes, limit_data.dltime));
|
||||
slp, limit_data.chunk_bytes, delta_t));
|
||||
return;
|
||||
}
|
||||
DEBUGP (("sleeping %.2f ms\n", slp));
|
||||
DEBUGP (("\nsleeping %.2f ms for %ld bytes, adjust %.2f ms\n",
|
||||
slp, limit_data.chunk_bytes, limit_data.sleep_adjust));
|
||||
|
||||
t0 = *dltime;
|
||||
usleep ((unsigned long) (1000 * slp));
|
||||
t1 = wtimer_elapsed (timer);
|
||||
|
||||
/* Due to scheduling, we probably slept slightly longer (or
|
||||
shorter) than desired. Calculate the difference between the
|
||||
desired and the actual sleep, and adjust the next sleep by
|
||||
that amount. */
|
||||
limit_data.sleep_adjust = slp - (t1 - t0);
|
||||
|
||||
/* Since we've called wtimer_elapsed, we might as well update
|
||||
the caller's dltime. */
|
||||
*dltime = t1;
|
||||
}
|
||||
|
||||
limit_data.bytes = 0;
|
||||
limit_data.dltime = 0;
|
||||
limit_data.chunk_bytes = 0;
|
||||
limit_data.chunk_start = *dltime;
|
||||
}
|
||||
|
||||
#define MIN(i, j) ((i) <= (j) ? (i) : (j))
|
||||
@ -143,7 +162,7 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
|
||||
|
||||
void *progress = NULL;
|
||||
struct wget_timer *timer = wtimer_allocate ();
|
||||
double dltime = 0, last_dltime = 0;
|
||||
double dltime = 0;
|
||||
|
||||
*len = restval;
|
||||
|
||||
@ -210,15 +229,9 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If bandwidth is not limited, one call to wtimer_elapsed is
|
||||
sufficient. */
|
||||
dltime = wtimer_elapsed (timer);
|
||||
if (opt.limit_rate)
|
||||
{
|
||||
limit_bandwidth (res, dltime - last_dltime);
|
||||
dltime = wtimer_elapsed (timer);
|
||||
last_dltime = dltime;
|
||||
}
|
||||
limit_bandwidth (res, &dltime, timer);
|
||||
|
||||
if (progress)
|
||||
progress_update (progress, res, dltime);
|
||||
|
Loading…
Reference in New Issue
Block a user