reference-transaction: use hook API instead of run-command
Convert the reference-transaction hook to the new hook API, so it doesn't need to set up a struct child_process, call find_hook or toggle the pipe signals. The stdin feed callback is processing one ref update per call. I haven't noticed any performance degradation due to this, however we can batch as many we want in each call, to ensure a good pipe throughtput (i.e. the child does not wait after stdin). Helped-by: Emily Shaffer <nasamuffin@google.com> Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Adrian Ratiu committed
Dec 26, 2025 at 14:23 UTC
7a7717427ea7253003d221c47b462d9334429053
1 file changed
+52
-48
refs.c
+52
-48
@@ -2405,68 +2405,72 @@ static int ref_update_reject_duplicates(struct string_list *refnames,
2405
return 0;
2406
}
2407
2408
-static int run_transaction_hook(struct ref_transaction *transaction,
2409
- const char *state)
2408
+struct transaction_feed_cb_data {
2409
+ size_t index;
2410
+ struct strbuf buf;
2411
+};
2412
+
2413
+static int transaction_hook_feed_stdin(int hook_stdin_fd, void *pp_cb, void *pp_task_cb)
2414
{
2411
- struct child_process proc = CHILD_PROCESS_INIT;
2412
- struct strbuf buf = STRBUF_INIT;
2413
- const char *hook;
2414
- int ret = 0;
2415
+ struct hook_cb_data *hook_cb = pp_cb;
2416
+ struct ref_transaction *transaction = hook_cb->options->feed_pipe_ctx;
2417
+ struct transaction_feed_cb_data *feed_cb_data = pp_task_cb;
2418
+ struct strbuf *buf = &feed_cb_data->buf;
2419
+ struct ref_update *update;
2420
+ size_t i = feed_cb_data->index++;
2421
+ int ret;
2422
2416
- hook = find_hook(transaction->ref_store->repo, "reference-transaction");
2417
- if (!hook)
2418
- return ret;
2423
+ if (i >= transaction->nr)
2424
+ return 1; /* No more refs to process */
2425
2420
- strvec_pushl(&proc.args, hook, state, NULL);
2421
- proc.in = -1;
2422
- proc.stdout_to_stderr = 1;
2423
- proc.trace2_hook_name = "reference-transaction";
2426
+ update = transaction->updates[i];
2427
2425
- ret = start_command(&proc);
2426
- if (ret)
2427
- return ret;
2428
+ if (update->flags & REF_LOG_ONLY)
2429
+ return 0;
2430
2429
- sigchain_push(SIGPIPE, SIG_IGN);
2431
+ strbuf_reset(buf);
2432
2431
- for (size_t i = 0; i < transaction->nr; i++) {
2432
- struct ref_update *update = transaction->updates[i];
2433
+ if (!(update->flags & REF_HAVE_OLD))
2434
+ strbuf_addf(buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
2435
+ else if (update->old_target)
2436
+ strbuf_addf(buf, "ref:%s ", update->old_target);
2437
+ else
2438
+ strbuf_addf(buf, "%s ", oid_to_hex(&update->old_oid));
2439
2434
- if (update->flags & REF_LOG_ONLY)
2435
- continue;
2440
+ if (!(update->flags & REF_HAVE_NEW))
2441
+ strbuf_addf(buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
2442
+ else if (update->new_target)
2443
+ strbuf_addf(buf, "ref:%s ", update->new_target);
2444
+ else
2445
+ strbuf_addf(buf, "%s ", oid_to_hex(&update->new_oid));
2446
2437
- strbuf_reset(&buf);
2447
+ strbuf_addf(buf, "%s\n", update->refname);
2448
2439
- if (!(update->flags & REF_HAVE_OLD))
2440
- strbuf_addf(&buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
2441
- else if (update->old_target)
2442
- strbuf_addf(&buf, "ref:%s ", update->old_target);
2443
- else
2444
- strbuf_addf(&buf, "%s ", oid_to_hex(&update->old_oid));
2449
+ ret = write_in_full(hook_stdin_fd, buf->buf, buf->len);
2450
+ if (ret < 0 && errno != EPIPE)
2451
+ return ret;
2452
2446
- if (!(update->flags & REF_HAVE_NEW))
2447
- strbuf_addf(&buf, "%s ", oid_to_hex(null_oid(the_hash_algo)));
2448
- else if (update->new_target)
2449
- strbuf_addf(&buf, "ref:%s ", update->new_target);
2450
- else
2451
- strbuf_addf(&buf, "%s ", oid_to_hex(&update->new_oid));
2453
+ return 0; /* no more input to feed */
2454
+}
2455
+
2456
+static int run_transaction_hook(struct ref_transaction *transaction,
2457
+ const char *state)
2458
+{
2459
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
2460
+ struct transaction_feed_cb_data feed_ctx = { 0 };
2461
+ int ret = 0;
2462
2453
- strbuf_addf(&buf, "%s\n", update->refname);
2463
+ strvec_push(&opt.args, state);
2464
2455
- if (write_in_full(proc.in, buf.buf, buf.len) < 0) {
2456
- if (errno != EPIPE) {
2457
- /* Don't leak errno outside this API */
2458
- errno = 0;
2459
- ret = -1;
2460
- }
2461
- break;
2462
- }
2463
- }
2465
+ opt.feed_pipe = transaction_hook_feed_stdin;
2466
+ opt.feed_pipe_ctx = transaction;
2467
+ opt.feed_pipe_cb_data = &feed_ctx;
2468
2465
- close(proc.in);
2466
- sigchain_pop(SIGPIPE);
2467
- strbuf_release(&buf);
2469
+ strbuf_init(&feed_ctx.buf, 0);
2470
+
2471
+ ret = run_hooks_opt(transaction->ref_store->repo, "reference-transaction", &opt);
2472
2469
- ret |= finish_command(&proc);
2473
+ strbuf_release(&feed_ctx.buf);
2474
return ret;
2475
}
2476