packfile: introduce function to load and add packfiles

We have a recurring pattern where we essentially perform an upsert of a
packfile in case it isn't yet known by the packfile store. The logic to
do so is non-trivial as we have to reconstruct the packfile's key, check
the map of packfiles, then create the new packfile and finally add it to
the store.

Introduce a new function that does this dance for us. Refactor callsites
to use it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
next
Patrick Steinhardt 2025-09-23 12:17:10 +02:00 committed by Junio C Hamano
parent f6f236d926
commit d67530f6bb
5 changed files with 48 additions and 41 deletions

View File

@ -897,11 +897,11 @@ static void end_packfile(void)
idx_name = keep_pack(create_index()); idx_name = keep_pack(create_index());


/* Register the packfile with core git's machinery. */ /* Register the packfile with core git's machinery. */
new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1); new_p = packfile_store_load_pack(pack_data->repo->objects->packfiles,
idx_name, 1);
if (!new_p) if (!new_p)
die("core git rejected index %s", idx_name); die("core git rejected index %s", idx_name);
all_packs[pack_id] = new_p; all_packs[pack_id] = new_p;
packfile_store_add_pack(the_repository->objects->packfiles, new_p);
free(idx_name); free(idx_name);


/* Print the boundary */ /* Print the boundary */

View File

@ -1640,13 +1640,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
rename_tmp_packfile(&final_index_name, curr_index_name, &index_name, rename_tmp_packfile(&final_index_name, curr_index_name, &index_name,
hash, "idx", 1); hash, "idx", 1);


if (do_fsck_object) { if (do_fsck_object)
struct packed_git *p; packfile_store_load_pack(the_repository->objects->packfiles,
p = add_packed_git(the_repository, final_index_name, final_index_name, 0);
strlen(final_index_name), 0);
if (p)
packfile_store_add_pack(the_repository->objects->packfiles, p);
}


if (!from_stdin) { if (!from_stdin) {
printf("%s\n", hash_to_hex(hash)); printf("%s\n", hash_to_hex(hash));

21
midx.c
View File

@ -443,7 +443,6 @@ int prepare_midx_pack(struct multi_pack_index *m,
{ {
struct repository *r = m->source->odb->repo; struct repository *r = m->source->odb->repo;
struct strbuf pack_name = STRBUF_INIT; struct strbuf pack_name = STRBUF_INIT;
struct strbuf key = STRBUF_INIT;
struct packed_git *p; struct packed_git *p;


pack_int_id = midx_for_pack(&m, pack_int_id); pack_int_id = midx_for_pack(&m, pack_int_id);
@ -455,25 +454,11 @@ int prepare_midx_pack(struct multi_pack_index *m,


strbuf_addf(&pack_name, "%s/pack/%s", m->source->path, strbuf_addf(&pack_name, "%s/pack/%s", m->source->path,
m->pack_names[pack_int_id]); m->pack_names[pack_int_id]);

p = packfile_store_load_pack(r->objects->packfiles,
/* pack_map holds the ".pack" name, but we have the .idx */ pack_name.buf, m->source->local);
strbuf_addbuf(&key, &pack_name); if (p)
strbuf_strip_suffix(&key, ".idx");
strbuf_addstr(&key, ".pack");
p = hashmap_get_entry_from_hash(&r->objects->packfiles->map,
strhash(key.buf), key.buf,
struct packed_git, packmap_ent);
if (!p) {
p = add_packed_git(r, pack_name.buf, pack_name.len,
m->source->local);
if (p) {
packfile_store_add_pack(r->objects->packfiles, p);
list_add_tail(&p->mru, &r->objects->packfiles->mru); list_add_tail(&p->mru, &r->objects->packfiles->mru);
}
}

strbuf_release(&pack_name); strbuf_release(&pack_name);
strbuf_release(&key);


if (!p) { if (!p) {
m->packs[pack_int_id] = MIDX_PACK_ERROR; m->packs[pack_int_id] = MIDX_PACK_ERROR;

View File

@ -792,6 +792,33 @@ void packfile_store_add_pack(struct packfile_store *store,
hashmap_add(&store->map, &pack->packmap_ent); hashmap_add(&store->map, &pack->packmap_ent);
} }


struct packed_git *packfile_store_load_pack(struct packfile_store *store,
const char *idx_path, int local)
{
struct strbuf key = STRBUF_INIT;
struct packed_git *p;

/*
* We're being called with the path to the index file, but `pack_map`
* holds the path to the packfile itself.
*/
strbuf_addstr(&key, idx_path);
strbuf_strip_suffix(&key, ".idx");
strbuf_addstr(&key, ".pack");

p = hashmap_get_entry_from_hash(&store->map, strhash(key.buf), key.buf,
struct packed_git, packmap_ent);
if (!p) {
p = add_packed_git(store->odb->repo, idx_path,
strlen(idx_path), local);
if (p)
packfile_store_add_pack(store, p);
}

strbuf_release(&key);
return p;
}

void (*report_garbage)(unsigned seen_bits, const char *path); void (*report_garbage)(unsigned seen_bits, const char *path);


static void report_helper(const struct string_list *list, static void report_helper(const struct string_list *list,
@ -891,23 +918,14 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
const char *file_name, void *_data) const char *file_name, void *_data)
{ {
struct prepare_pack_data *data = (struct prepare_pack_data *)_data; struct prepare_pack_data *data = (struct prepare_pack_data *)_data;
struct packed_git *p;
size_t base_len = full_name_len; size_t base_len = full_name_len;


if (strip_suffix_mem(full_name, &base_len, ".idx") && if (strip_suffix_mem(full_name, &base_len, ".idx") &&
!(data->m && midx_contains_pack(data->m, file_name))) { !(data->m && midx_contains_pack(data->m, file_name))) {
struct hashmap_entry hent; char *trimmed_path = xstrndup(full_name, full_name_len);
char *pack_name = xstrfmt("%.*s.pack", (int)base_len, full_name); packfile_store_load_pack(data->r->objects->packfiles,
unsigned int hash = strhash(pack_name); trimmed_path, data->local);
hashmap_entry_init(&hent, hash); free(trimmed_path);

/* Don't reopen a pack we already have. */
if (!hashmap_get(&data->r->objects->packfiles->map, &hent, pack_name)) {
p = add_packed_git(data->r, full_name, full_name_len, data->local);
if (p)
packfile_store_add_pack(data->r->objects->packfiles, p);
}
free(pack_name);
} }


if (!report_garbage) if (!report_garbage)

View File

@ -127,6 +127,14 @@ void packfile_store_reprepare(struct packfile_store *store);
void packfile_store_add_pack(struct packfile_store *store, void packfile_store_add_pack(struct packfile_store *store,
struct packed_git *pack); struct packed_git *pack);


/*
* Open the packfile and add it to the store if it isn't yet known. Returns
* either the newly opened packfile or the preexisting packfile. Returns a
* `NULL` pointer in case the packfile could not be opened.
*/
struct packed_git *packfile_store_load_pack(struct packfile_store *store,
const char *idx_path, int local);

struct pack_window { struct pack_window {
struct pack_window *next; struct pack_window *next;
unsigned char *base; unsigned char *base;