libalpm: fix download rates becoming negative
When a download fails on one mirror a new download is started on the next mirror. This causes the ammount downloaded to reset, confusing the rate math and making it display a negative rate. This is further complicated by the fact that a download may be resumed from where it is or started over. To account for this we alert the frontend that the download was restarted. Pacman then starts the progress bar over. Signed-off-by: Allan McRae <allan@archlinux.org>
This commit is contained in:
parent
4fead44e3c
commit
8bf17b29a2
3 changed files with 62 additions and 8 deletions
|
@ -1172,6 +1172,8 @@ typedef enum _alpm_download_event_type_t {
|
||||||
ALPM_DOWNLOAD_INIT,
|
ALPM_DOWNLOAD_INIT,
|
||||||
/** A download made progress */
|
/** A download made progress */
|
||||||
ALPM_DOWNLOAD_PROGRESS,
|
ALPM_DOWNLOAD_PROGRESS,
|
||||||
|
/** Download will be retried */
|
||||||
|
ALPM_DOWNLOAD_RETRY,
|
||||||
/** A download completed */
|
/** A download completed */
|
||||||
ALPM_DOWNLOAD_COMPLETED
|
ALPM_DOWNLOAD_COMPLETED
|
||||||
} alpm_download_event_type_t;
|
} alpm_download_event_type_t;
|
||||||
|
@ -1190,6 +1192,11 @@ typedef struct _alpm_download_event_progress_t {
|
||||||
off_t total;
|
off_t total;
|
||||||
} alpm_download_event_progress_t;
|
} alpm_download_event_progress_t;
|
||||||
|
|
||||||
|
/** Context struct for when a download retries. */
|
||||||
|
typedef struct _alpm_download_event_retry_t {
|
||||||
|
/** If the download will resume or start over */
|
||||||
|
int resume;
|
||||||
|
} alpm_download_event_retry_t;
|
||||||
|
|
||||||
/** Context struct for when a download completes. */
|
/** Context struct for when a download completes. */
|
||||||
typedef struct _alpm_download_event_completed_t {
|
typedef struct _alpm_download_event_completed_t {
|
||||||
|
|
|
@ -408,6 +408,7 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload
|
||||||
{
|
{
|
||||||
const char *server;
|
const char *server;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
struct stat st;
|
||||||
alpm_handle_t *handle = payload->handle;
|
alpm_handle_t *handle = payload->handle;
|
||||||
|
|
||||||
while(payload->servers && should_skip_server(handle, payload->servers->data)) {
|
while(payload->servers && should_skip_server(handle, payload->servers->data)) {
|
||||||
|
@ -427,15 +428,31 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload
|
||||||
MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
|
MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
|
||||||
snprintf(payload->fileurl, len, "%s/%s", server, payload->filepath);
|
snprintf(payload->fileurl, len, "%s/%s", server, payload->filepath);
|
||||||
|
|
||||||
if(payload->unlink_on_fail) {
|
|
||||||
/* we keep the file for a new retry but remove its data if any */
|
|
||||||
fflush(payload->localf);
|
fflush(payload->localf);
|
||||||
|
|
||||||
|
if(payload->allow_resume && stat(payload->tempfile_name, &st) == 0) {
|
||||||
|
/* a previous partial download exists, resume from end of file. */
|
||||||
|
payload->tempfile_openmode = "ab";
|
||||||
|
curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)st.st_size);
|
||||||
|
_alpm_log(handle, ALPM_LOG_DEBUG,
|
||||||
|
"%s: tempfile found, attempting continuation from %jd bytes\n",
|
||||||
|
payload->remote_name, (intmax_t)st.st_size);
|
||||||
|
payload->initial_size = st.st_size;
|
||||||
|
} else {
|
||||||
|
/* we keep the file for a new retry but remove its data if any */
|
||||||
if(ftruncate(fileno(payload->localf), 0)) {
|
if(ftruncate(fileno(payload->localf), 0)) {
|
||||||
RET_ERR(handle, ALPM_ERR_SYSTEM, -1);
|
RET_ERR(handle, ALPM_ERR_SYSTEM, -1);
|
||||||
}
|
}
|
||||||
fseek(payload->localf, 0, SEEK_SET);
|
fseek(payload->localf, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(handle->dlcb && !payload->signature) {
|
||||||
|
alpm_download_event_retry_t cb_data;
|
||||||
|
cb_data.resume = payload->allow_resume;
|
||||||
|
handle->dlcb(handle->dlcb_ctx, payload->remote_name, ALPM_DOWNLOAD_RETRY, &cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set curl with the new URL */
|
/* Set curl with the new URL */
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, payload->fileurl);
|
curl_easy_setopt(curl, CURLOPT_URL, payload->fileurl);
|
||||||
|
|
||||||
|
@ -483,7 +500,6 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg,
|
||||||
_alpm_log(handle, ALPM_LOG_DEBUG, "%s: response code %ld\n",
|
_alpm_log(handle, ALPM_LOG_DEBUG, "%s: response code %ld\n",
|
||||||
payload->remote_name, payload->respcode);
|
payload->remote_name, payload->respcode);
|
||||||
if(payload->respcode >= 400) {
|
if(payload->respcode >= 400) {
|
||||||
payload->unlink_on_fail = 1;
|
|
||||||
if(!payload->errors_ok) {
|
if(!payload->errors_ok) {
|
||||||
handle->pm_errno = ALPM_ERR_RETRIEVE;
|
handle->pm_errno = ALPM_ERR_RETRIEVE;
|
||||||
/* non-translated message is same as libcurl */
|
/* non-translated message is same as libcurl */
|
||||||
|
@ -498,6 +514,7 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg,
|
||||||
(*active_downloads_num)++;
|
(*active_downloads_num)++;
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
|
payload->unlink_on_fail = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +532,6 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg,
|
||||||
}
|
}
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
case CURLE_COULDNT_RESOLVE_HOST:
|
case CURLE_COULDNT_RESOLVE_HOST:
|
||||||
payload->unlink_on_fail = 1;
|
|
||||||
handle->pm_errno = ALPM_ERR_SERVER_BAD_URL;
|
handle->pm_errno = ALPM_ERR_SERVER_BAD_URL;
|
||||||
_alpm_log(handle, ALPM_LOG_ERROR,
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
||||||
_("failed retrieving file '%s' from %s : %s\n"),
|
_("failed retrieving file '%s' from %s : %s\n"),
|
||||||
|
@ -525,13 +541,10 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg,
|
||||||
(*active_downloads_num)++;
|
(*active_downloads_num)++;
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
|
payload->unlink_on_fail = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* delete zero length downloads */
|
|
||||||
if(fstat(fileno(payload->localf), &st) == 0 && st.st_size == 0) {
|
|
||||||
payload->unlink_on_fail = 1;
|
|
||||||
}
|
|
||||||
if(!payload->errors_ok) {
|
if(!payload->errors_ok) {
|
||||||
handle->pm_errno = ALPM_ERR_LIBCURL;
|
handle->pm_errno = ALPM_ERR_LIBCURL;
|
||||||
_alpm_log(handle, ALPM_LOG_ERROR,
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
||||||
|
@ -547,6 +560,10 @@ static int curl_check_finished_download(CURLM *curlm, CURLMsg *msg,
|
||||||
(*active_downloads_num)++;
|
(*active_downloads_num)++;
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
|
/* delete zero length downloads */
|
||||||
|
if(fstat(fileno(payload->localf), &st) == 0 && st.st_size == 0) {
|
||||||
|
payload->unlink_on_fail = 1;
|
||||||
|
}
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -994,6 +994,34 @@ static void dload_progress_event(const char *filename, alpm_download_event_progr
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* download retried */
|
||||||
|
static void dload_retry_event(const char *filename, alpm_download_event_retry_t *data) {
|
||||||
|
if(!dload_progressbar_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index;
|
||||||
|
struct pacman_progress_bar *bar;
|
||||||
|
bool ok = find_bar_for_filename(filename, &index, &bar);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
if(!data->resume) {
|
||||||
|
if(total_enabled) {
|
||||||
|
/* note total download does not reflect partial downloads that are restarted */
|
||||||
|
totalbar->xfered -= bar->xfered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bar->xfered = 0;
|
||||||
|
bar->total_size = 0;
|
||||||
|
bar->init_time = get_time_ms();
|
||||||
|
bar->sync_time = 0;
|
||||||
|
bar->sync_xfered = 0;
|
||||||
|
bar->rate = 0.0;
|
||||||
|
bar->eta = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* download completed */
|
/* download completed */
|
||||||
static void dload_complete_event(const char *filename, alpm_download_event_completed_t *data)
|
static void dload_complete_event(const char *filename, alpm_download_event_completed_t *data)
|
||||||
{
|
{
|
||||||
|
@ -1090,6 +1118,8 @@ void cb_download(void *ctx, const char *filename, alpm_download_event_type_t eve
|
||||||
dload_init_event(filename, data);
|
dload_init_event(filename, data);
|
||||||
} else if(event == ALPM_DOWNLOAD_PROGRESS) {
|
} else if(event == ALPM_DOWNLOAD_PROGRESS) {
|
||||||
dload_progress_event(filename, data);
|
dload_progress_event(filename, data);
|
||||||
|
} else if(event == ALPM_DOWNLOAD_RETRY) {
|
||||||
|
dload_retry_event(filename, data);
|
||||||
} else if(event == ALPM_DOWNLOAD_COMPLETED) {
|
} else if(event == ALPM_DOWNLOAD_COMPLETED) {
|
||||||
dload_complete_event(filename, data);
|
dload_complete_event(filename, data);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue