http: refactor subsystem to use `packfile_list`s

The dumb HTTP protocol directly fetches packfiles from the remote server and temporarily stores them in a list of packfiles. Those packfiles are not yet added to the repository's packfile store until we finalize the whole fetch. Refactor the code to instead use a `struct packfile_list` to store those packs. This prepares us for a subsequent change where the `->next` pointer of `struct packed_git` will go away. Note that this refactoring creates some temporary duplication of code, as we now have both `packfile_list_find_oid()` and `find_oid_pack()`. The latter function will be removed in a subsequent commit though. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Oct 30, 2025 at 11:38 UTC 89219bc0cd09ada8a204e0ace0bd15decaea7d31
6 files changed +40 -35
http-push.c
+3 -3
@@ -104,7 +104,7 @@ struct repo {
104 int has_info_refs;
105 int can_update_info_refs;
106 int has_info_packs;
107 - struct packed_git *packs;
107 + struct packfile_list packs;
108 struct remote_lock *locks;
109 };
110
@@ -311,7 +311,7 @@ static void start_fetch_packed(struct transfer_request *request)
311 struct transfer_request *check_request = request_queue_head;
312 struct http_pack_request *preq;
313
314 - target = find_oid_pack(&request->obj->oid, repo->packs);
314 + target = packfile_list_find_oid(repo->packs.head, &request->obj->oid);
315 if (!target) {
316 fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", oid_to_hex(&request->obj->oid));
317 repo->can_update_info_refs = 0;
@@ -683,7 +683,7 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
683 get_remote_object_list(obj->oid.hash[0]);
684 if (obj->flags & (REMOTE | PUSHING))
685 return 0;
686 - target = find_oid_pack(&obj->oid, repo->packs);
686 + target = packfile_list_find_oid(repo->packs.head, &obj->oid);
687 if (target) {
688 obj->flags |= REMOTE;
689 return 0;
http-walker.c
+9 -17
@@ -15,7 +15,7 @@
15 struct alt_base {
16 char *base;
17 int got_indices;
18 - struct packed_git *packs;
18 + struct packfile_list packs;
19 struct alt_base *next;
20 };
21
@@ -324,11 +324,8 @@ static void process_alternates_response(void *callback_data)
324 } else if (is_alternate_allowed(target.buf)) {
325 warning("adding alternate object store: %s",
326 target.buf);
327 - newalt = xmalloc(sizeof(*newalt));
328 - newalt->next = NULL;
327 + CALLOC_ARRAY(newalt, 1);
328 newalt->base = strbuf_detach(&target, NULL);
330 - newalt->got_indices = 0;
331 - newalt->packs = NULL;
329
330 while (tail->next != NULL)
331 tail = tail->next;
@@ -435,7 +432,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo,
432
433 if (fetch_indices(walker, repo))
434 return -1;
438 - target = find_oid_pack(oid, repo->packs);
435 + target = packfile_list_find_oid(repo->packs.head, oid);
436 if (!target)
437 return -1;
438 close_pack_index(target);
@@ -584,17 +581,15 @@ static void cleanup(struct walker *walker)
581 if (data) {
582 alt = data->alt;
583 while (alt) {
587 - struct packed_git *pack;
584 + struct packfile_list_entry *e;
585
586 alt_next = alt->next;
587
591 - pack = alt->packs;
592 - while (pack) {
593 - struct packed_git *pack_next = pack->next;
594 - close_pack(pack);
595 - free(pack);
596 - pack = pack_next;
588 + for (e = alt->packs.head; e; e = e->next) {
589 + close_pack(e->pack);
590 + free(e->pack);
591 }
592 + packfile_list_clear(&alt->packs);
593
594 free(alt->base);
595 free(alt);
@@ -612,14 +607,11 @@ struct walker *get_http_walker(const char *url)
607 struct walker_data *data = xmalloc(sizeof(struct walker_data));
608 struct walker *walker = xmalloc(sizeof(struct walker));
609
615 - data->alt = xmalloc(sizeof(*data->alt));
610 + CALLOC_ARRAY(data->alt, 1);
611 data->alt->base = xstrdup(url);
612 for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s)
613 *s = 0;
614
620 - data->alt->got_indices = 0;
621 - data->alt->packs = NULL;
622 - data->alt->next = NULL;
615 data->got_alternates = -1;
616
617 walker->corrupt_object_found = 0;
http.c
+8 -13
@@ -2413,8 +2413,9 @@ static char *fetch_pack_index(unsigned char *hash, const char *base_url)
2413 return tmp;
2414 }
2415
2416 -static int fetch_and_setup_pack_index(struct packed_git **packs_head,
2417 - unsigned char *sha1, const char *base_url)
2416 +static int fetch_and_setup_pack_index(struct packfile_list *packs,
2417 + unsigned char *sha1,
2418 + const char *base_url)
2419 {
2420 struct packed_git *new_pack, *p;
2421 char *tmp_idx = NULL;
@@ -2448,12 +2449,11 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
2449 if (ret)
2450 return -1;
2451
2451 - new_pack->next = *packs_head;
2452 - *packs_head = new_pack;
2452 + packfile_list_prepend(packs, new_pack);
2453 return 0;
2454 }
2455
2456 -int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
2456 +int http_get_info_packs(const char *base_url, struct packfile_list *packs)
2457 {
2458 struct http_get_options options = {0};
2459 int ret = 0;
@@ -2477,7 +2477,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
2477 !parse_oid_hex(data, &oid, &data) &&
2478 skip_prefix(data, ".pack", &data) &&
2479 (*data == '\n' || *data == '\0')) {
2480 - fetch_and_setup_pack_index(packs_head, oid.hash, base_url);
2480 + fetch_and_setup_pack_index(packs, oid.hash, base_url);
2481 } else {
2482 data = strchrnul(data, '\n');
2483 }
@@ -2541,14 +2541,9 @@ cleanup:
2541 }
2542
2543 void http_install_packfile(struct packed_git *p,
2544 - struct packed_git **list_to_remove_from)
2544 + struct packfile_list *list_to_remove_from)
2545 {
2546 - struct packed_git **lst = list_to_remove_from;
2547 -
2548 - while (*lst != p)
2549 - lst = &((*lst)->next);
2550 - *lst = (*lst)->next;
2551 -
2546 + packfile_list_remove(list_to_remove_from, p);
2547 packfile_store_add_pack(the_repository->objects->packfiles, p);
2548 }
2549
http.h
+3 -2
@@ -2,6 +2,7 @@
2 #define HTTP_H
3
4 struct packed_git;
5 +struct packfile_list;
6
7 #include "git-zlib.h"
8
@@ -190,7 +191,7 @@ struct curl_slist *http_append_auth_header(const struct credential *c,
191
192 /* Helpers for fetching packs */
193 int http_get_info_packs(const char *base_url,
193 - struct packed_git **packs_head);
194 + struct packfile_list *packs);
195
196 /* Helper for getting Accept-Language header */
197 const char *http_get_accept_language_header(void);
@@ -226,7 +227,7 @@ void release_http_pack_request(struct http_pack_request *preq);
227 * from http_get_info_packs() and have chosen a specific pack to fetch.
228 */
229 void http_install_packfile(struct packed_git *p,
229 - struct packed_git **list_to_remove_from);
230 + struct packfile_list *list_to_remove_from);
231
232 /* Helpers for fetching object */
233 struct http_object_request {
packfile.c
+9
@@ -121,6 +121,15 @@ void packfile_list_append(struct packfile_list *list, struct packed_git *pack)
121 }
122 }
123
124 +struct packed_git *packfile_list_find_oid(struct packfile_list_entry *packs,
125 + const struct object_id *oid)
126 +{
127 + for (; packs; packs = packs->next)
128 + if (find_pack_entry_one(oid, packs->pack))
129 + return packs->pack;
130 + return NULL;
131 +}
132 +
133 void pack_report(struct repository *repo)
134 {
135 fprintf(stderr,
packfile.h
+8
@@ -65,6 +65,14 @@ void packfile_list_remove(struct packfile_list *list, struct packed_git *pack);
65 void packfile_list_prepend(struct packfile_list *list, struct packed_git *pack);
66 void packfile_list_append(struct packfile_list *list, struct packed_git *pack);
67
68 +/*
69 + * Find the pack within the "packs" list whose index contains the object
70 + * "oid". For general object lookups, you probably don't want this; use
71 + * find_pack_entry() instead.
72 + */
73 +struct packed_git *packfile_list_find_oid(struct packfile_list_entry *packs,
74 + const struct object_id *oid);
75 +
76 /*
77 * A store that manages packfiles for a given object database.
78 */