From: Patrick Steinhardt <ps@pks.im>
To: Justin Tobler <jltobler@gmail.com>
Cc: git@vger.kernel.org, gitster@pobox.com
Subject: Re: [PATCH v3 2/9] odb/transaction: add transaction finalize interface
Date: Wed, 12 Aug 2026 08:07:35 +0200 [thread overview]
Message-ID: <anwNp8cbCOOuI7nK@pks.im> (raw)
In-Reply-To: <20260811175415.2044235-3-jltobler@gmail.com>
On Tue, Aug 11, 2026 at 12:54:08PM -0500, Justin Tobler wrote:
> When committing an ODB transaction via `odb_transaction_commit()`, the
> staged objects are made visible and the underlying transaction is freed
> at the same time. Coupling these two steps does not leave room for any
> post-commit transaction operations to be introduced though. Such a
> capability is useful if an ODB transaction backend needs to hold on to
> lockfiles after transaction commit until references are updated, as is
> the case with the existing "files" backend in git-receive-pack(1).
>
> Stop freeing the transaction in `odb_transaction_commit()` and introduce
> `odb_transaction_finalize()` to explicitly clean up the transaction
> accordingly. Note that the finalize interface also provides an optional
> callback for any backend-specific deferred cleanup. In a subsequent
> commit, the "files" transaction backend will use this to remove ".keep"
> files generated for packfiles received via git-receive-pack(1) after
> references have been updated. In preparation for this, the
> `odb_transaction_finalize()` call site in git-receive-pack(1) is made
> after the reference updates are finished.
>
> All other callers commit a transaction and immediately finalize it with
> no work in between and cannot meaningfully recover should either step
> fail, so introduce an `odb_transaction_commit_and_finalize_or_die()`
"step fail"? I guess this ought to just read "fail"?
> helper that performs both and dies on error. Call sites are updated
> accordingly.
>
> Signed-off-by: Justin Tobler <jltobler@gmail.com>
> ---
> builtin/add.c | 4 ++--
> builtin/receive-pack.c | 1 +
> builtin/unpack-objects.c | 2 +-
> builtin/update-index.c | 4 ++--
> cache-tree.c | 2 +-
> object-file.c | 2 +-
> odb/transaction.c | 14 ++++++++++++++
> odb/transaction.h | 23 +++++++++++++++++++++++
> read-cache.c | 2 +-
> 9 files changed, 46 insertions(+), 8 deletions(-)
>
> diff --git a/builtin/add.c b/builtin/add.c
> index 60ffbede2b..ad418a5952 100644
> --- a/builtin/add.c
> +++ b/builtin/add.c
> @@ -393,7 +393,7 @@ int cmd_add(int argc,
> char *seen = NULL;
> char *ps_matched = NULL;
> struct lock_file lock_file = LOCK_INIT;
> - struct odb_transaction *transaction;
> + struct odb_transaction *transaction = NULL;
>
> repo_config(repo, add_config, NULL);
>
> @@ -600,7 +600,7 @@ int cmd_add(int argc,
>
> if (chmod_arg && pathspec.nr)
> exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
>
> finish:
> if (write_locked_index(repo->index, &lock_file,
> diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
> index d74b787148..ed1edcbe93 100644
> --- a/builtin/receive-pack.c
> +++ b/builtin/receive-pack.c
> @@ -2720,6 +2720,7 @@ int cmd_receive_pack(int argc,
> use_keepalive = KEEPALIVE_ALWAYS;
> execute_commands(commands, unpack_status, &si, transaction,
> &push_options);
> + odb_transaction_finalize(transaction);
> delete_tempfile(&pack_lockfile);
> sigchain_push(SIGPIPE, SIG_IGN);
> if (report_status_v2)
> diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
> index 4263edfbec..d6a2d616d9 100644
> --- a/builtin/unpack-objects.c
> +++ b/builtin/unpack-objects.c
> @@ -603,7 +603,7 @@ static void unpack_all(void)
> unpack_one(i);
> display_progress(progress, i + 1);
> }
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
> stop_progress(&progress);
>
> if (delta_list)
> diff --git a/builtin/update-index.c b/builtin/update-index.c
> index 241abd4332..b25d4ecb10 100644
> --- a/builtin/update-index.c
> +++ b/builtin/update-index.c
> @@ -1156,7 +1156,7 @@ int cmd_update_index(int argc,
> * a transaction.
> */
> if (transaction && verbose) {
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
> transaction = NULL;
> }
>
> @@ -1224,7 +1224,7 @@ int cmd_update_index(int argc,
> /*
> * By now we have added all of the new objects
> */
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
>
> if (split_index > 0) {
> if (repo_config_get_split_index(the_repository) == 0)
> diff --git a/cache-tree.c b/cache-tree.c
> index d92f513286..a220372a42 100644
> --- a/cache-tree.c
> +++ b/cache-tree.c
> @@ -538,7 +538,7 @@ int cache_tree_update(struct index_state *istate, int flags)
> i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
> "", 0, &skip, flags);
> if (!inflight)
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
> trace2_region_leave("cache_tree", "update", istate->repo);
> trace_performance_leave("cache_tree_update");
> if (i < 0)
> diff --git a/object-file.c b/object-file.c
> index ec35c318bc..4d03c167d5 100644
> --- a/object-file.c
> +++ b/object-file.c
> @@ -965,7 +965,7 @@ int index_fd(struct index_state *istate, struct object_id *oid,
> xsize_t(st->st_size),
> oid);
> if (!inflight)
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
> } else {
> ret = hash_blob_stream(&stream,
> the_repository->hash_algo, oid,
> diff --git a/odb/transaction.c b/odb/transaction.c
> index dab7da6a9a..9e9a982778 100644
> --- a/odb/transaction.c
> +++ b/odb/transaction.c
> @@ -33,6 +33,20 @@ int odb_transaction_commit(struct odb_transaction *transaction)
>
> ret = transaction->commit(transaction);
> transaction->source->odb->transaction = NULL;
> +
> + return ret;
> +}
> +
> +int odb_transaction_finalize(struct odb_transaction *transaction)
> +{
> + int ret = 0;
> +
> + if (!transaction)
> + return 0;
> +
> + if (transaction->finalize)
> + ret = transaction->finalize(transaction);
> +
> free(transaction);
>
> return ret;
> diff --git a/odb/transaction.h b/odb/transaction.h
> index 4cb2eafcbf..6ed39b3d0e 100644
> --- a/odb/transaction.h
> +++ b/odb/transaction.h
> @@ -22,6 +22,13 @@ struct odb_transaction {
> */
> int (*commit)(struct odb_transaction *transaction);
>
> + /*
> + * Optional ODB source specific callback invoked when the transaction
> + * needs to perform any deferred cleanup after objects have been
> + * committed. Returns 0 on success, a negative error code otherwise.
> + */
> + int (*finalize)(struct odb_transaction *transaction);
> +
> /*
> * This callback is expected to write the given object stream into
> * the ODB transaction. Note that for now, only blobs support streaming.
> @@ -75,6 +82,22 @@ static inline void odb_transaction_begin_or_die(struct object_database *odb,
> */
> int odb_transaction_commit(struct odb_transaction *transaction);
>
> +/*
> + * Finalizes an ODB transaction, performing any deferred cleanup and freeing it.
> + * Must be called for every successfully started transaction. Note that, if the
> + * specified transaction is NULL, the function is a no-op. Returns 0 on success,
> + * a negative error code otherwise.
> + */
> +int odb_transaction_finalize(struct odb_transaction *transaction);
> +
> +static inline void odb_transaction_commit_and_finalize_or_die(struct odb_transaction *transaction)
> +{
> + if (odb_transaction_commit(transaction))
> + die(_("failed to commit ODB transaction"));
> + if (odb_transaction_finalize(transaction))
> + die(_("failed to finalize ODB transaction"));
> +}
> +
> /*
> * Writes the object in the provided stream into the transaction. The resulting
> * object ID is written into the out pointer. Returns 0 on success, a negative
> diff --git a/read-cache.c b/read-cache.c
> index 6c449f393d..0cd0ef85ec 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -4049,7 +4049,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
> odb_transaction_begin_or_die(repo->objects, &transaction, 0);
> run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
> if (!inflight)
> - odb_transaction_commit(transaction);
> + odb_transaction_commit_and_finalize_or_die(transaction);
>
> release_revisions(&rev);
> return !!data.add_errors;
> --
> 2.55.0.424.g13c7afec21
>
next prev parent reply other threads:[~2026-08-12 6:07 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-06 21:38 [PATCH 0/6] builtin/receive-pack: support pluggable packfile writes Justin Tobler
2026-08-06 21:38 ` [PATCH 1/6] odb/transaction: add transaction release interface Justin Tobler
2026-08-07 7:03 ` Patrick Steinhardt
2026-08-07 15:11 ` Justin Tobler
2026-08-06 21:38 ` [PATCH 2/6] builtin/receive-pack: pass shallow file explicitly Justin Tobler
2026-08-07 7:03 ` Patrick Steinhardt
2026-08-06 21:38 ` [PATCH 3/6] builtin/receive-pack: lift global state out of unpack() Justin Tobler
2026-08-07 7:03 ` Patrick Steinhardt
2026-08-07 15:33 ` Justin Tobler
2026-08-06 21:38 ` [PATCH 4/6] builtin/receive-pack: report unpack errors via strbuf Justin Tobler
2026-08-07 7:03 ` Patrick Steinhardt
2026-08-07 15:36 ` Justin Tobler
2026-08-09 19:00 ` Justin Tobler
2026-08-10 5:15 ` Patrick Steinhardt
2026-08-06 21:38 ` [PATCH 5/6] builtin/receive-pack: explicitly pass packfile fd Justin Tobler
2026-08-06 21:38 ` [PATCH 6/6] odb/transaction: add transaction interface to write packfiles Justin Tobler
2026-08-07 7:03 ` Patrick Steinhardt
2026-08-07 16:01 ` Justin Tobler
2026-08-09 19:00 ` [PATCH v2 0/7] builtin/receive-pack: support pluggable packfile writes Justin Tobler
2026-08-09 19:01 ` [PATCH v2 1/7] odb/transaction: add transaction finalize interface Justin Tobler
2026-08-10 3:38 ` Junio C Hamano
2026-08-10 19:10 ` Justin Tobler
2026-08-09 19:01 ` [PATCH v2 2/7] builtin/receive-pack: pass shallow file explicitly Justin Tobler
2026-08-09 19:01 ` [PATCH v2 3/7] builtin/receive-pack: read unpack limit config lazily Justin Tobler
2026-08-10 5:15 ` Patrick Steinhardt
2026-08-10 15:42 ` Justin Tobler
2026-08-10 17:54 ` Junio C Hamano
2026-08-10 19:16 ` Justin Tobler
2026-08-09 19:01 ` [PATCH v2 4/7] builtin/receive-pack: lift global state out of unpack() Justin Tobler
2026-08-09 19:01 ` [PATCH v2 5/7] builtin/receive-pack: report unpack errors via strbuf Justin Tobler
2026-08-09 19:01 ` [PATCH v2 6/7] builtin/receive-pack: explicitly pass packfile fd Justin Tobler
2026-08-09 19:01 ` [PATCH v2 7/7] odb/transaction: add transaction interface to write packfiles Justin Tobler
2026-08-10 1:54 ` Junio C Hamano
2026-08-10 19:29 ` Justin Tobler
2026-08-10 4:02 ` Junio C Hamano
2026-08-10 19:54 ` Justin Tobler
2026-08-11 17:54 ` [PATCH v3 0/9] builtin/receive-pack: support pluggable packfile writes Justin Tobler
2026-08-11 17:54 ` [PATCH v3 1/9] builtin/receive-pack: properly clean up keep files Justin Tobler
2026-08-12 6:07 ` Patrick Steinhardt
2026-08-11 17:54 ` [PATCH v3 2/9] odb/transaction: add transaction finalize interface Justin Tobler
2026-08-12 6:07 ` Patrick Steinhardt [this message]
2026-08-11 17:54 ` [PATCH v3 3/9] builtin/receive-pack: pass shallow file explicitly Justin Tobler
2026-08-11 17:54 ` [PATCH v3 4/9] builtin/receive-pack: read unpack limit config lazily Justin Tobler
2026-08-11 17:54 ` [PATCH v3 5/9] builtin/receive-pack: lift global state out of unpack() Justin Tobler
2026-08-11 17:54 ` [PATCH v3 6/9] builtin/receive-pack: report unpack errors via strbuf Justin Tobler
2026-08-11 17:54 ` [PATCH v3 7/9] builtin/receive-pack: explicitly pass packfile fd Justin Tobler
2026-08-11 17:54 ` [PATCH v3 8/9] odb: return temporary ODB source when set Justin Tobler
2026-08-12 6:07 ` Patrick Steinhardt
2026-08-11 17:54 ` [PATCH v3 9/9] odb/transaction: add transaction interface to write packfiles Justin Tobler
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=anwNp8cbCOOuI7nK@pks.im \
--to=ps@pks.im \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jltobler@gmail.com \
/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