Fix for multiple alternates requests in http-fetch

Stop additional alternates requests from starting if one is already in
progress.  This adds an optional callback which is processed after a slot
has finished running.

Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Nick Hengeveld 2005-11-12 09:11:32 -08:00 коммит произвёл Junio C Hamano
Родитель 7765e7ebda
Коммит acc075a8ad
1 изменённых файлов: 116 добавлений и 60 удалений

Просмотреть файл

@ -25,7 +25,7 @@
#define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
static int got_alternates = 0;
static int got_alternates = -1;
static int active_requests = 0;
static int data_received;
@ -87,9 +87,19 @@ struct active_request_slot
int done;
CURLcode curl_result;
long http_code;
void *callback_data;
void (*callback_func)(void *data);
struct active_request_slot *next;
};
struct alt_request {
char *base;
char *url;
struct buffer *buffer;
struct active_request_slot *slot;
int http_specific;
};
static struct transfer_request *request_queue_head = NULL;
static struct active_request_slot *active_queue_head = NULL;
@ -237,7 +247,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
static void process_curl_messages(void);
static void process_request_queue(void);
#endif
static int fetch_alternates(char *base);
static void fetch_alternates(char *base);
static CURL* get_curl_handle(void)
{
@ -324,6 +334,8 @@ static struct active_request_slot *get_active_slot(void)
slot->in_use = 1;
slot->done = 0;
slot->local = NULL;
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_range_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
@ -601,6 +613,12 @@ static void process_curl_messages(void)
} else {
fprintf(stderr, "Received DONE message for unknown request!\n");
}
/* Process slot callback if appropriate */
if (slot->callback_func != NULL) {
slot->callback_func(slot->callback_data);
}
if (request != NULL) {
request->curl_result = curl_result;
request->http_code = slot->http_code;
@ -766,72 +784,51 @@ static int setup_index(struct alt_base *repo, unsigned char *sha1)
return 0;
}
static int fetch_alternates(char *base)
static void process_alternates(void *callback_data)
{
int ret = 0;
struct buffer buffer;
char *url;
struct alt_request *alt_req = (struct alt_request *)callback_data;
struct active_request_slot *slot = alt_req->slot;
struct alt_base *tail = alt;
char *base = alt_req->base;
static const char null_byte = '\0';
char *data;
int i = 0;
int http_specific = 1;
struct alt_base *tail = alt;
static const char null_byte = '\0';
struct active_request_slot *slot;
if (alt_req->http_specific) {
if (slot->curl_result != CURLE_OK ||
!alt_req->buffer->posn) {
if (got_alternates)
return 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list for %s\n", base);
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
/* Try reusing the slot to get non-http alternates */
alt_req->http_specific = 0;
sprintf(alt_req->url, "%s/objects/info/alternates",
base);
curl_easy_setopt(slot->curl, CURLOPT_URL,
alt_req->url);
active_requests++;
slot->in_use = 1;
slot->done = 0;
if (start_active_slot(slot)) {
run_active_slot(slot);
if (slot->curl_result != CURLE_OK || !buffer.posn) {
http_specific = 0;
sprintf(url, "%s/objects/info/alternates", base);
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
if (start_active_slot(slot)) {
run_active_slot(slot);
if (slot->curl_result != CURLE_OK) {
free(buffer.buffer);
if (slot->http_code == 404)
got_alternates = 1;
return 0;
}
}
}
return;
} else {
free(buffer.buffer);
return 0;
got_alternates = -1;
slot->done = 1;
return;
}
}
} else if (slot->curl_result != CURLE_OK) {
if (slot->http_code != 404) {
got_alternates = -1;
return;
}
}
fwrite_buffer_dynamic(&null_byte, 1, 1, &buffer);
buffer.posn--;
data = buffer.buffer;
fwrite_buffer_dynamic(&null_byte, 1, 1, alt_req->buffer);
alt_req->buffer->posn--;
data = alt_req->buffer->buffer;
while (i < buffer.posn) {
while (i < alt_req->buffer->posn) {
int posn = i;
while (posn < buffer.posn && data[posn] != '\n')
while (posn < alt_req->buffer->posn && data[posn] != '\n')
posn++;
if (data[posn] == '\n') {
int okay = 0;
@ -855,7 +852,7 @@ static int fetch_alternates(char *base)
// If the server got removed, give up.
okay = strchr(base, ':') - base + 3 <
serverlen;
} else if (http_specific) {
} else if (alt_req->http_specific) {
char *colon = strchr(data + i, ':');
char *slash = strchr(data + i, '/');
if (colon && slash && colon < data + posn &&
@ -881,15 +878,74 @@ static int fetch_alternates(char *base)
while (tail->next != NULL)
tail = tail->next;
tail->next = newalt;
ret++;
}
}
i = posn + 1;
}
got_alternates = 1;
free(buffer.buffer);
return ret;
}
static void fetch_alternates(char *base)
{
struct buffer buffer;
char *url;
char *data;
struct active_request_slot *slot;
static struct alt_request alt_req;
int num_transfers;
/* If another request has already started fetching alternates,
wait for them to arrive and return to processing this request's
curl message */
while (got_alternates == 0) {
curl_multi_perform(curlm, &num_transfers);
process_curl_messages();
process_request_queue();
}
/* Nothing to do if they've already been fetched */
if (got_alternates == 1)
return;
/* Start the fetch */
got_alternates = 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list for %s\n", base);
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
/* Use a callback to process the result, since another request
may fail and need to have alternates loaded before continuing */
slot = get_active_slot();
slot->callback_func = process_alternates;
slot->callback_data = &alt_req;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
alt_req.base = base;
alt_req.url = url;
alt_req.buffer = &buffer;
alt_req.http_specific = 1;
alt_req.slot = slot;
if (start_active_slot(slot))
run_active_slot(slot);
else
got_alternates = -1;
free(data);
free(url);
}
static int fetch_indices(struct alt_base *repo)