builtin/receive-pack: avoid spinning no-op sideband async threads

Exit early if the hooks do not exist, to avoid spinning up/down
sideband async threads which no-op.

It is important to call the hook_exists() API provided by hook.[ch]
because it covers both config-defined hooks and the "traditional"
hooks from the hookdir. find_hook() only covers the hookdir hooks.

The regression happened because the no-op async threads add some
additional overhead which can be measured with the receive-refs test
of the benchmarks suite [1].

Reproduced using:
cd benchmarks/receive-refs && \
./run --revisions /path/to/git \
fc148b146ad41be71a7852c4867f0773cbfe1ff9~,fc148b146ad41be71a7852c4867f0773cbfe1ff9 \
--parameter-list refformat reftable --parameter-list refcount 10000

1: https://gitlab.com/gitlab-org/data-access/git/benchmarks

Fixes: fc148b146a ("receive-pack: convert update hooks to new API")
Reported-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
[jc: avoid duplicated hardcoded hook names]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Adrian Ratiu
2026-03-02 21:17:04 +02:00
committed by Junio C Hamano
parent b5e9ad508c
commit 005f3fbe07

View File

@@ -914,6 +914,9 @@ static int run_receive_hook(struct command *commands,
int saved_stderr = -1;
int ret;
if (!hook_exists(the_repository, hook_name))
return 0;
/* if there are no valid commands, don't invoke the hook at all. */
while (iter && skip_broken && (iter->error_string || iter->did_not_exist))
iter = iter->next;
@@ -955,12 +958,16 @@ static int run_receive_hook(struct command *commands,
static int run_update_hook(struct command *cmd)
{
static const char hook_name[] = "update";
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
struct async sideband_async;
int sideband_async_started = 0;
int saved_stderr = -1;
int code;
if (!hook_exists(the_repository, hook_name))
return 0;
strvec_pushl(&opt.args,
cmd->ref_name,
oid_to_hex(&cmd->old_oid),
@@ -969,7 +976,7 @@ static int run_update_hook(struct command *cmd)
prepare_sideband_async(&sideband_async, &saved_stderr, &sideband_async_started);
code = run_hooks_opt(the_repository, "update", &opt);
code = run_hooks_opt(the_repository, hook_name, &opt);
finish_sideband_async(&sideband_async, saved_stderr, sideband_async_started);
@@ -1649,12 +1656,16 @@ out:
static void run_update_post_hook(struct command *commands)
{
static const char hook_name[] = "post-update";
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
struct async sideband_async;
struct command *cmd;
int sideband_async_started = 0;
int saved_stderr = -1;
if (!hook_exists(the_repository, hook_name))
return;
for (cmd = commands; cmd; cmd = cmd->next) {
if (cmd->error_string || cmd->did_not_exist)
continue;
@@ -1665,7 +1676,7 @@ static void run_update_post_hook(struct command *commands)
prepare_sideband_async(&sideband_async, &saved_stderr, &sideband_async_started);
run_hooks_opt(the_repository, "post-update", &opt);
run_hooks_opt(the_repository, hook_name, &opt);
finish_sideband_async(&sideband_async, saved_stderr, sideband_async_started);
}