Git development
 help / color / mirror / Atom feed
From: Justin Tobler <jltobler@gmail.com>
To: git@vger.kernel.org
Cc: ps@pks.im, gitster@pobox.com, Justin Tobler <jltobler@gmail.com>
Subject: [PATCH v2 11/11] builtin/receive-pack: stage incoming objects via ODB transactions
Date: Tue,  7 Jul 2026 23:14:12 -0500	[thread overview]
Message-ID: <20260708041412.1157499-12-jltobler@gmail.com> (raw)
In-Reply-To: <20260708041412.1157499-1-jltobler@gmail.com>

Objects received by git-receive-pack(1) are quarantined in a temporary
"incoming" directory and migrated into the object database prior to the
reference updates. The quarantine is currently managed through
`tmp_objdir` directly. In a pluggable ODB future, how exactly an object
gets written to a transaction may vary for a given ODB source. Refactor
git-receive-pack(1) to use the ODB transaction interfaces to manage the
object staging area in a more agnostic manner accordingly.

Note that the ODB transaction is now responsible for managing the
primary and alternate ODBs for the repository. One small change as a
result is that the temporary directory is now applied as the primary ODB
in the main process instead of an alternate. This does not change
anything for git-receive-pack(1) though because it only needs access to
the newly written objects and doesn't care how exactly it is set up.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
 builtin/receive-pack.c | 68 ++++++++++++++++++++++--------------------
 1 file changed, 35 insertions(+), 33 deletions(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 50bc05c70c..8b8c20dc1a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -37,7 +37,6 @@
 #include "sigchain.h"
 #include "string-list.h"
 #include "strvec.h"
-#include "tmp-objdir.h"
 #include "trace.h"
 #include "trace2.h"
 #include "version.h"
@@ -112,8 +111,6 @@ static enum {
 } use_keepalive;
 static int keepalive_in_sec = 5;
 
-static struct tmp_objdir *tmp_objdir;
-
 static struct proc_receive_ref {
 	unsigned int want_add:1,
 		     want_delete:1,
@@ -926,6 +923,7 @@ static void receive_hook_feed_state_free(void *data)
 static int run_receive_hook(struct command *commands,
 			    const char *hook_name,
 			    int skip_broken,
+			    struct odb_transaction *transaction,
 			    const struct string_list *push_options)
 {
 	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
@@ -959,8 +957,8 @@ static int run_receive_hook(struct command *commands,
 		strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
 	}
 
-	if (tmp_objdir)
-		strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
+	if (transaction)
+		odb_transaction_env(transaction, &opt.env);
 
 	prepare_push_cert_sha1(&opt);
 
@@ -1789,24 +1787,30 @@ static const struct object_id *command_singleton_iterator(void *cb_data)
 }
 
 static void set_connectivity_errors(struct command *commands,
-				    struct shallow_info *si)
+				    struct shallow_info *si,
+				    struct odb_transaction *transaction)
 {
 	struct command *cmd;
 
 	for (cmd = commands; cmd; cmd = cmd->next) {
 		struct command *singleton = cmd;
 		struct check_connected_options opt = CHECK_CONNECTED_INIT;
+		struct strvec env = STRVEC_INIT;
 
 		if (shallow_update && si->shallow_ref[cmd->index])
 			/* to be checked in update_shallow_ref() */
 			continue;
 
-		opt.env = tmp_objdir_env(tmp_objdir);
+		odb_transaction_env(transaction, &env);
+		opt.env = env.v;
+
 		if (!check_connected(command_singleton_iterator, &singleton,
 				     &opt))
 			continue;
 
 		cmd->error_string = "missing necessary objects";
+
+		strvec_clear(&env);
 	}
 }
 
@@ -2027,6 +2031,7 @@ static void execute_commands_atomic(struct command *commands,
 static void execute_commands(struct command *commands,
 			     const char *unpacker_error,
 			     struct shallow_info *si,
+			     struct odb_transaction *transaction,
 			     const struct string_list *push_options)
 {
 	struct check_connected_options opt = CHECK_CONNECTED_INIT;
@@ -2043,6 +2048,8 @@ static void execute_commands(struct command *commands,
 	}
 
 	if (!skip_connectivity_check) {
+		struct strvec env = STRVEC_INIT;
+
 		if (use_sideband) {
 			memset(&muxer, 0, sizeof(muxer));
 			muxer.proc = copy_to_sideband;
@@ -2056,14 +2063,17 @@ static void execute_commands(struct command *commands,
 		data.si = si;
 		opt.err_fd = err_fd;
 		opt.progress = err_fd && !quiet;
-		opt.env = tmp_objdir_env(tmp_objdir);
+		odb_transaction_env(transaction, &env);
+		opt.env = env.v;
 		opt.exclude_hidden_refs_section = "receive";
 
 		if (check_connected(iterate_receive_command_list, &data, &opt))
-			set_connectivity_errors(commands, si);
+			set_connectivity_errors(commands, si, transaction);
 
 		if (use_sideband)
 			finish_async(&muxer);
+
+		strvec_clear(&env);
 	}
 
 	reject_updates_to_hidden(commands);
@@ -2084,7 +2094,7 @@ static void execute_commands(struct command *commands,
 		}
 	}
 
-	if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
+	if (run_receive_hook(commands, "pre-receive", 0, transaction, push_options)) {
 		for (cmd = commands; cmd; cmd = cmd->next) {
 			if (!cmd->error_string)
 				cmd->error_string = "pre-receive hook declined";
@@ -2105,14 +2115,13 @@ static void execute_commands(struct command *commands,
 	 * Now we'll start writing out refs, which means the objects need
 	 * to be in their final positions so that other processes can see them.
 	 */
-	if (tmp_objdir_migrate(tmp_objdir) < 0) {
+	if (odb_transaction_commit(transaction)) {
 		for (cmd = commands; cmd; cmd = cmd->next) {
 			if (!cmd->error_string)
 				cmd->error_string = "unable to migrate objects to permanent storage";
 		}
 		return;
 	}
-	tmp_objdir = NULL;
 
 	check_aliased_updates(commands);
 
@@ -2325,7 +2334,8 @@ static void push_header_arg(struct strvec *args, struct pack_header *hdr)
 		     ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
 }
 
-static const char *unpack(int err_fd, struct shallow_info *si)
+static const char *unpack(int err_fd, struct shallow_info *si,
+			  struct odb_transaction *transaction)
 {
 	struct pack_header hdr;
 	const char *hdr_err;
@@ -2350,20 +2360,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
 		strvec_push(&child.args, alt_shallow_file);
 	}
 
-	tmp_objdir = tmp_objdir_create(the_repository, "incoming");
-	if (!tmp_objdir) {
-		if (err_fd > 0)
-			close(err_fd);
-		return "unable to create temporary object directory";
-	}
-	strvec_pushv(&child.env, tmp_objdir_env(tmp_objdir));
-
-	/*
-	 * Normally we just pass the tmp_objdir environment to the child
-	 * processes that do the heavy lifting, but we may need to see these
-	 * objects ourselves to set up shallow information.
-	 */
-	tmp_objdir_add_as_alternate(tmp_objdir);
+	odb_transaction_env(transaction, &child.env);
 
 	if (ntohl(hdr.hdr_entries) < unpack_limit) {
 		strvec_push(&child.args, "unpack-objects");
@@ -2430,13 +2427,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
 	return NULL;
 }
 
-static const char *unpack_with_sideband(struct shallow_info *si)
+static const char *unpack_with_sideband(struct shallow_info *si,
+					struct odb_transaction *transaction)
 {
 	struct async muxer;
 	const char *ret;
 
 	if (!use_sideband)
-		return unpack(0, si);
+		return unpack(0, si, transaction);
 
 	use_keepalive = KEEPALIVE_AFTER_NUL;
 	memset(&muxer, 0, sizeof(muxer));
@@ -2445,7 +2443,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
 	if (start_async(&muxer))
 		return NULL;
 
-	ret = unpack(muxer.in, si);
+	ret = unpack(muxer.in, si, transaction);
 
 	finish_async(&muxer);
 	return ret;
@@ -2622,6 +2620,7 @@ int cmd_receive_pack(int argc,
 	struct oid_array ref = OID_ARRAY_INIT;
 	struct shallow_info si;
 	struct packet_reader reader;
+	struct odb_transaction *transaction = NULL;
 
 	struct option options[] = {
 		OPT__QUIET(&quiet, N_("quiet")),
@@ -2706,11 +2705,14 @@ int cmd_receive_pack(int argc,
 		if (!si.nr_ours && !si.nr_theirs)
 			shallow_update = 0;
 		if (!delete_only(commands)) {
-			unpack_status = unpack_with_sideband(&si);
+			if (odb_transaction_begin(the_repository->objects, &transaction, ODB_TRANSACTION_RECEIVE))
+				unpack_status = "unable to start object transaction";
+			else
+				unpack_status = unpack_with_sideband(&si, transaction);
 			update_shallow_info(commands, &si, &ref);
 		}
 		use_keepalive = KEEPALIVE_ALWAYS;
-		execute_commands(commands, unpack_status, &si,
+		execute_commands(commands, unpack_status, &si, transaction,
 				 &push_options);
 		delete_tempfile(&pack_lockfile);
 		sigchain_push(SIGPIPE, SIG_IGN);
@@ -2719,7 +2721,7 @@ int cmd_receive_pack(int argc,
 		else if (report_status)
 			report(commands, unpack_status);
 		sigchain_pop(SIGPIPE);
-		run_receive_hook(commands, "post-receive", 1,
+		run_receive_hook(commands, "post-receive", 1, NULL,
 				 &push_options);
 		run_update_post_hook(commands);
 		free_commands(commands);
-- 
2.55.0.122.gf85a7e6620


  parent reply	other threads:[~2026-07-08  4:14 UTC|newest]

Thread overview: 90+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-24  4:19 [PATCH 0/6] receive-pack: use ODB transactions to stage object writes Justin Tobler
2026-06-24  4:19 ` [PATCH 1/6] object-file: rename files transaction prepare function Justin Tobler
2026-06-24 18:26   ` Junio C Hamano
2026-06-29 18:11     ` Justin Tobler
2026-06-24  4:19 ` [PATCH 2/6] object-file: propagate files transaction errors Justin Tobler
2026-06-24 11:26   ` Patrick Steinhardt
2026-06-29 18:58     ` Justin Tobler
2026-06-29 19:04       ` Justin Tobler
2026-06-30  8:45         ` Patrick Steinhardt
2026-06-30 14:14           ` Justin Tobler
2026-06-30  8:45       ` Patrick Steinhardt
2026-06-24 18:35   ` Junio C Hamano
2026-06-29 19:10     ` Justin Tobler
2026-06-24  4:19 ` [PATCH 3/6] odb/transaction: propagate begin errors Justin Tobler
2026-06-24 11:26   ` Patrick Steinhardt
2026-06-29 19:15     ` Justin Tobler
2026-06-24  4:19 ` [PATCH 4/6] odb/transaction: propagate commit errors Justin Tobler
2026-06-24 11:26   ` Patrick Steinhardt
2026-06-29 19:16     ` Justin Tobler
2026-06-24  4:19 ` [PATCH 5/6] odb/transaction: add transaction env interface Justin Tobler
2026-06-24 11:26   ` Patrick Steinhardt
2026-06-29 19:20     ` Justin Tobler
2026-06-24  4:19 ` [PATCH 6/6] builtin/receive-pack: stage incoming objects via ODB transactions Justin Tobler
2026-06-24 11:26   ` Patrick Steinhardt
2026-06-29 20:25     ` Justin Tobler
2026-06-30  8:45       ` Patrick Steinhardt
2026-06-24 11:27 ` [PATCH 0/6] receive-pack: use ODB transactions to stage object writes Patrick Steinhardt
2026-06-24 20:09 ` Junio C Hamano
2026-07-08  4:14 ` [PATCH v2 00/11] " Justin Tobler
2026-07-08  4:14   ` [PATCH v2 01/11] object-file: rename files transaction prepare function Justin Tobler
2026-07-08  4:14   ` [PATCH v2 02/11] object-file: rename files transaction fsync function Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08  4:14   ` [PATCH v2 03/11] object-file: embed transaction flush logic in commit function Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08 16:08       ` Justin Tobler
2026-07-08  4:14   ` [PATCH v2 04/11] object-file: drop check for inflight transactions Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08  4:14   ` [PATCH v2 05/11] object-file: propagate files transaction errors Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08 16:21       ` Justin Tobler
2026-07-08  4:14   ` [PATCH v2 06/11] odb/transaction: propagate begin errors Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08 16:56       ` Justin Tobler
2026-07-09  9:39         ` Patrick Steinhardt
2026-07-08  4:14   ` [PATCH v2 07/11] odb/transaction: propagate commit errors Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08 17:24       ` Justin Tobler
2026-07-08  4:14   ` [PATCH v2 08/11] odb/transaction: add transaction env interface Justin Tobler
2026-07-08  4:14   ` [PATCH v2 09/11] odb/transaction: introduce ODB transaction flags Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08 17:34       ` Justin Tobler
2026-07-08  4:14   ` [PATCH v2 10/11] builtin/receive-pack: drop redundant tmpdir env Justin Tobler
2026-07-08  6:41     ` Patrick Steinhardt
2026-07-08  4:14   ` Justin Tobler [this message]
2026-07-08  6:42   ` [PATCH v2 00/11] receive-pack: use ODB transactions to stage object writes Patrick Steinhardt
2026-07-08 17:36     ` Justin Tobler
2026-07-08 23:59   ` [PATCH v3 " Justin Tobler
2026-07-08 23:59     ` [PATCH v3 01/11] object-file: rename files transaction prepare function Justin Tobler
2026-07-08 23:59     ` [PATCH v3 02/11] object-file: rename files transaction fsync function Justin Tobler
2026-07-08 23:59     ` [PATCH v3 03/11] object-file: embed transaction flush logic in commit function Justin Tobler
2026-07-09  9:38       ` Patrick Steinhardt
2026-07-08 23:59     ` [PATCH v3 04/11] object-file: drop check for inflight transactions Justin Tobler
2026-07-08 23:59     ` [PATCH v3 05/11] object-file: propagate files transaction errors Justin Tobler
2026-07-08 23:59     ` [PATCH v3 06/11] odb/transaction: propagate begin errors Justin Tobler
2026-07-09  3:32       ` Junio C Hamano
2026-07-09 14:03         ` Justin Tobler
2026-07-08 23:59     ` [PATCH v3 07/11] odb/transaction: propagate commit errors Justin Tobler
2026-07-08 23:59     ` [PATCH v3 08/11] odb/transaction: add transaction env interface Justin Tobler
2026-07-09  3:36       ` Junio C Hamano
2026-07-09 15:02         ` Justin Tobler
2026-07-08 23:59     ` [PATCH v3 09/11] odb/transaction: introduce ODB transaction flags Justin Tobler
2026-07-08 23:59     ` [PATCH v3 10/11] builtin/receive-pack: drop redundant tmpdir env Justin Tobler
2026-07-08 23:59     ` [PATCH v3 11/11] builtin/receive-pack: stage incoming objects via ODB transactions Justin Tobler
2026-07-09  3:49       ` Junio C Hamano
2026-07-10 14:37         ` Justin Tobler
2026-07-10 16:52           ` Junio C Hamano
2026-07-09  9:39     ` [PATCH v3 00/11] receive-pack: use ODB transactions to stage object writes Patrick Steinhardt
2026-07-10 16:37     ` [PATCH v4 " Justin Tobler
2026-07-10 16:37       ` [PATCH v4 01/11] object-file: rename files transaction prepare function Justin Tobler
2026-07-10 16:37       ` [PATCH v4 02/11] object-file: rename files transaction fsync function Justin Tobler
2026-07-10 16:37       ` [PATCH v4 03/11] object-file: embed transaction flush logic in commit function Justin Tobler
2026-07-10 16:37       ` [PATCH v4 04/11] object-file: drop check for inflight transactions Justin Tobler
2026-07-10 16:37       ` [PATCH v4 05/11] object-file: propagate files transaction errors Justin Tobler
2026-07-10 16:37       ` [PATCH v4 06/11] odb/transaction: propagate begin errors Justin Tobler
2026-07-10 16:37       ` [PATCH v4 07/11] odb/transaction: propagate commit errors Justin Tobler
2026-07-10 16:37       ` [PATCH v4 08/11] odb/transaction: add transaction env interface Justin Tobler
2026-07-10 16:37       ` [PATCH v4 09/11] odb/transaction: introduce ODB transaction flags Justin Tobler
2026-07-10 16:37       ` [PATCH v4 10/11] builtin/receive-pack: drop redundant tmpdir env Justin Tobler
2026-07-10 16:37       ` [PATCH v4 11/11] builtin/receive-pack: stage incoming objects via ODB transactions Justin Tobler
2026-07-13  5:18       ` [PATCH v4 00/11] receive-pack: use ODB transactions to stage object writes Patrick Steinhardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260708041412.1157499-12-jltobler@gmail.com \
    --to=jltobler@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox