[PATCH 9/9] http-fetch: Paranoid sanity checking for the object queue.
From: Mark Wooding <mdw@distorted.org.uk>
Probably not wanted in the mainline, but useful for debugging.
Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
---
http-fetch.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/http-fetch.c b/http-fetch.c
index fa3eb4a..80eaa2f 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -3,6 +3,7 @@
#include "pack.h"
#include "fetch.h"
#include "http.h"
+#include <assert.h>
#define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
@@ -28,6 +29,13 @@ enum object_request_state {
COMPLETE,
};
+typedef struct stash {
+ struct stash *next;
+ unsigned char sha1[20];
+ int activep;
+ int tickp;
+} stash;
+
struct object_request
{
unsigned char sha1[20];
@@ -47,6 +55,7 @@ struct object_request
int rename;
struct active_request_slot *slot;
struct object_request *next;
+ stash *tick;
};
struct alternates_request {
@@ -57,8 +66,60 @@ struct alternates_request {
int http_specific;
};
+static stash *seen = 0;
+
+static stash *findstash(unsigned char *sha1)
+{
+ stash *s;
+ for (s = seen; s; s = s->next) {
+ if (memcmp(sha1, s->sha1, 20) == 0)
+ return s;
+ }
+ return NULL;
+}
+
+static stash *enstash(unsigned char *sha1)
+{
+ stash *s;
+ if ((s = findstash(sha1)) != NULL)
+ assert(!s->activep);
+ else {
+ s = xmalloc(sizeof(*s));
+ memcpy(s->sha1, sha1, 20);
+ s->next = seen;
+ seen = s;
+ }
+ s->activep = 1;
+ return s;
+}
+
+static void unstash(unsigned char *sha1)
+{
+ stash *s = findstash(sha1);
+ assert(s && s->activep);
+ s->activep = 0;
+}
+
static struct object_request *object_queue_head = NULL;
+static void sanity_check_stash(void)
+{
+ stash *s;
+ struct object_request *obj_req;
+
+ for (s = seen; s; s = s->next)
+ s->tickp = 0;
+ for (obj_req = object_queue_head; obj_req; obj_req = obj_req->next) {
+ assert(obj_req->tick);
+ s = obj_req->tick;
+ assert(memcmp(s->sha1, obj_req->sha1, 20) == 0);
+ assert(s->activep);
+ s->tickp = 1;
+ }
+ for (s = seen; s; s = s->next)
+ assert(!s->tickp == !s->activep);
+}
+
static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
void *data)
{
@@ -287,6 +348,7 @@ static void release_object_request(struc
{
struct object_request *entry = object_queue_head;
+ sanity_check_stash();
if (obj_req->local != -1)
error("fd leakage in release: %d", obj_req->local);
if (obj_req == object_queue_head) {
@@ -298,6 +360,8 @@ static void release_object_request(struc
entry->next = entry->next->next;
}
+ unstash(obj_req->sha1);
+ sanity_check_stash();
free(obj_req->url);
free(obj_req);
}
@@ -309,6 +373,7 @@ void fill_active_slots(void)
struct active_request_slot *slot = active_queue_head;
int num_transfers;
+ sanity_check_stash();
while (active_requests < max_requests && obj_req != NULL) {
if (obj_req->state == WAITING) {
if (has_sha1_file(obj_req->sha1))
@@ -327,6 +392,7 @@ void fill_active_slots(void)
}
slot = slot->next;
}
+ sanity_check_stash();
}
#endif
@@ -347,6 +413,7 @@ void prefetch(unsigned char *sha1)
"%s.temp", filename);
newreq->next = NULL;
+ sanity_check_stash();
if (object_queue_head == NULL) {
object_queue_head = newreq;
} else {
@@ -356,6 +423,8 @@ void prefetch(unsigned char *sha1)
}
tail->next = newreq;
}
+ newreq->tick = enstash(sha1);
+ sanity_check_stash();
#ifdef USE_CURL_MULTI
fill_active_slots();
@@ -789,6 +858,7 @@ static int fetch_object(struct alt_base
int ret = 0;
struct object_request *obj_req = object_queue_head;
+ sanity_check_stash();
while (obj_req != NULL && memcmp(obj_req->sha1, sha1, 20))
obj_req = obj_req->next;
if (obj_req == NULL)