upload-pack: generate packfiles via the object database

When serving a fetch, git-upload-pack(1) spawns git-pack-objects(1)
directly to generate the packfile that gets sent to the client. This
hard-codes the assumption that the object database is able to serve
packfiles via git-pack-objects(1), which is specific to the "files"
backend.

Convert git-upload-pack(1) to instead use the pack generation interface
of the object database.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
Patrick Steinhardt 2026-08-21 08:30:02 +02:00 committed by Junio C Hamano
parent a316d615da
commit f0de4ab248
1 changed files with 44 additions and 79 deletions

View File

@ -197,11 +197,11 @@ static void send_client_data(int fd, const char *data, ssize_t sz,
write_or_die(fd, data, sz);
}

static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
static int append_one_shallow(const struct commit_graft *graft, void *cb_data)
{
FILE *fp = cb_data;
struct oid_array *shallows = cb_data;
if (graft->nr_parent == -1)
fprintf(fp, "--shallow %s\n", oid_to_hex(&graft->oid));
oid_array_append(shallows, &graft->oid);
return 0;
}

@ -299,7 +299,8 @@ static int relay_pack_data(int pack_objects_out, struct output_state *os,
static void create_pack_file(struct upload_pack_data *pack_data,
const struct string_list *uri_protocols)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
struct odb_generate_pack_options opts = ODB_GENERATE_PACK_OPTIONS_INIT;
struct odb_pack_generator *generator;
struct output_state *output_state = xcalloc(1, sizeof(struct output_state));
char progress[128];
char abort_msg[] = "aborting due to possible repository "
@ -307,78 +308,42 @@ static void create_pack_file(struct upload_pack_data *pack_data,
uint64_t last_sent_ms = 0;
ssize_t sz;
int i;
FILE *pipe_fd;

if (!pack_data->pack_objects_hook)
pack_objects.git_cmd = 1;
else {
strvec_push(&pack_objects.args, pack_data->pack_objects_hook);
strvec_push(&pack_objects.args, "git");
pack_objects.use_shell = 1;
}

if (pack_data->shallow_nr) {
strvec_push(&pack_objects.args, "--shallow-file");
strvec_push(&pack_objects.args, "");
for_each_commit_graft(append_one_shallow, &opts.shallows);
opts.shallow = 1;
}
strvec_push(&pack_objects.args, "pack-objects");
strvec_push(&pack_objects.args, "--revs");
if (pack_data->use_thin_pack)
strvec_push(&pack_objects.args, "--thin");

strvec_push(&pack_objects.args, "--stdout");
if (pack_data->shallow_nr)
strvec_push(&pack_objects.args, "--shallow");
if (!pack_data->no_progress)
strvec_push(&pack_objects.args, "--progress");
if (pack_data->use_ofs_delta)
strvec_push(&pack_objects.args, "--delta-base-offset");
if (pack_data->use_include_tag)
strvec_push(&pack_objects.args, "--include-tag");
if (repo_has_accepted_promisor_remote(the_repository))
strvec_push(&pack_objects.args, "--missing=allow-promisor");
if (pack_data->filter_options.choice) {
const char *spec =
expand_list_objects_filter_spec(&pack_data->filter_options);
strvec_pushf(&pack_objects.args, "--filter=%s", spec);
}
if (uri_protocols) {
for (i = 0; i < uri_protocols->nr; i++)
strvec_pushf(&pack_objects.args, "--uri-protocol=%s",
uri_protocols->items[i].string);
}

pack_objects.in = -1;
pack_objects.out = -1;
pack_objects.err = -1;
pack_objects.clean_on_exit = 1;

if (start_command(&pack_objects))
die("git upload-pack: unable to fork git-pack-objects");

pipe_fd = xfdopen(pack_objects.in, "w");

if (pack_data->shallow_nr)
for_each_commit_graft(write_one_shallow, pipe_fd);

for (i = 0; i < pack_data->want_obj.nr; i++)
fprintf(pipe_fd, "%s\n",
oid_to_hex(&pack_data->want_obj.objects[i].item->oid));
fprintf(pipe_fd, "--not\n");
oid_array_append(&opts.wants,
&pack_data->want_obj.objects[i].item->oid);
for (i = 0; i < pack_data->have_obj.nr; i++)
fprintf(pipe_fd, "%s\n",
oid_to_hex(&pack_data->have_obj.objects[i].item->oid));
oid_array_append(&opts.haves,
&pack_data->have_obj.objects[i].item->oid);
for (i = 0; i < pack_data->extra_edge_obj.nr; i++)
fprintf(pipe_fd, "%s\n",
oid_to_hex(&pack_data->extra_edge_obj.objects[i].item->oid));
fprintf(pipe_fd, "\n");
fflush(pipe_fd);
fclose(pipe_fd);
oid_array_append(&opts.haves,
&pack_data->extra_edge_obj.objects[i].item->oid);

/* We read from pack_objects.err to capture stderr output for
* progress bar, and pack_objects.out to capture the pack data.
opts.thin = pack_data->use_thin_pack;
if (!pack_data->no_progress)
opts.progress = ODB_GENERATE_PACK_PROGRESS_STANDARD;
opts.ofs_delta = pack_data->use_ofs_delta;
opts.include_tag = pack_data->use_include_tag;
opts.missing_allow_promisor = repo_has_accepted_promisor_remote(the_repository);
if (pack_data->filter_options.choice)
opts.filter_spec = expand_list_objects_filter_spec(&pack_data->filter_options);
opts.uri_protocols = uri_protocols;
opts.pack_objects_hook = pack_data->pack_objects_hook;
opts.pack_fd = -1;
opts.progress_fd = -1;

if (odb_generate_pack(the_repository->objects, &generator, &opts))
die("git upload-pack: unable to generate pack");
odb_generate_pack_options_release(&opts);

/*
* We read from generator->err to capture stderr output for the
* progress bar, and generator->out to capture the pack data.
*/

while (1) {
uint64_t now_ms = getnanotime() / 1000000;
struct pollfd pfd[2];
@ -393,14 +358,14 @@ static void create_pack_file(struct upload_pack_data *pack_data,
pollsize = 0;
pe = pu = -1;

if (0 <= pack_objects.out) {
pfd[pollsize].fd = pack_objects.out;
if (0 <= generator->out) {
pfd[pollsize].fd = generator->out;
pfd[pollsize].events = POLLIN;
pu = pollsize;
pollsize++;
}
if (0 <= pack_objects.err) {
pfd[pollsize].fd = pack_objects.err;
if (0 <= generator->err) {
pfd[pollsize].fd = generator->err;
pfd[pollsize].events = POLLIN;
pe = pollsize;
pollsize++;
@ -437,15 +402,15 @@ static void create_pack_file(struct upload_pack_data *pack_data,
/* Status ready; we ship that in the side-band
* or dump to the standard error.
*/
sz = xread(pack_objects.err, progress,
sz = xread(generator->err, progress,
sizeof(progress));
if (0 < sz) {
send_client_data(2, progress, sz,
pack_data->use_sideband);
last_sent_ms = now_ms;
} else if (sz == 0) {
close(pack_objects.err);
pack_objects.err = -1;
close(generator->err);
generator->err = -1;
}
else
goto fail;
@ -455,15 +420,15 @@ static void create_pack_file(struct upload_pack_data *pack_data,

if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
bool did_send_data;
int result = relay_pack_data(pack_objects.out,
int result = relay_pack_data(generator->out,
output_state,
pack_data->use_sideband,
!!uri_protocols,
&did_send_data);

if (result == 0) {
close(pack_objects.out);
pack_objects.out = -1;
close(generator->out);
generator->out = -1;
} else if (result < 0) {
goto fail;
}
@ -498,7 +463,7 @@ static void create_pack_file(struct upload_pack_data *pack_data,
}
}

if (finish_command(&pack_objects)) {
if (odb_pack_generator_finish(generator)) {
error("git upload-pack: git-pack-objects died with error.");
goto fail;
}