]> git.ipfire.org Git - thirdparty/git.git/commitdiff
odb/transaction: introduce ODB transaction flags
authorJustin Tobler <jltobler@gmail.com>
Fri, 10 Jul 2026 16:37:20 +0000 (11:37 -0500)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Jul 2026 20:21:53 +0000 (13:21 -0700)
The temporary directory used by git-receive-pack(1) to write objects is
managed slightly differently than how it is done via ODB transactions:

  - The temporary directory is eagerly created upfront, instead of
    waiting for the first object write.

  - The prefix name of the temporary directory is "incoming" instead of
    "bulk-fsync".

In a subsequent commit, git-receive-pack(1) will use ODB transactions
instead of `tmp_objdir` directly. To provide a means to configure the
same transaction behavior, introduce `enum odb_transaction_flags` and
the ODB_TRANSACTION_RECEIVE flag intended as a signal for ODB
transactions using the "files" backend to be set up for
git-receive-pack(1). Transaction call sites are updated accordingly to
provide the required flag parameter.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 files changed:
builtin/add.c
builtin/unpack-objects.c
builtin/update-index.c
cache-tree.c
object-file.c
object-file.h
odb/source-files.c
odb/source-inmemory.c
odb/source-loose.c
odb/source.h
odb/transaction.c
odb/transaction.h
read-cache.c

index 3d5d9cfdb9e30cc24d93d8e3d5ccb294a6fb1e88..60ffbede2be58a933292cfb92e9c4be0fee50945 100644 (file)
@@ -581,7 +581,7 @@ int cmd_add(int argc,
                string_list_clear(&only_match_skip_worktree, 0);
        }
 
-       odb_transaction_begin_or_die(repo->objects, &transaction);
+       odb_transaction_begin_or_die(repo->objects, &transaction, 0);
 
        ps_matched = xcalloc(pathspec.nr, 1);
        if (add_renormalize)
index 1a195bf0451c1a34bd313fb935b2e88104f33efa..39c44282e5d1ee064ad8f937f7c1aa28584ebbef 100644 (file)
@@ -596,7 +596,7 @@ static void unpack_all(void)
                progress = start_progress(the_repository,
                                          _("Unpacking objects"), nr_objects);
        CALLOC_ARRAY(obj_list, nr_objects);
-       odb_transaction_begin_or_die(the_repository->objects, &transaction);
+       odb_transaction_begin_or_die(the_repository->objects, &transaction, 0);
        for (i = 0; i < nr_objects; i++) {
                unpack_one(i);
                display_progress(progress, i + 1);
index 17f3ea284cbb2cd725f93f53081c1f37cbf3a96e..bf6ea60ef44aaf9282f4456139dbb4768ef5a838 100644 (file)
@@ -1124,7 +1124,7 @@ int cmd_update_index(int argc,
         * Allow the object layer to optimize adding multiple objects in
         * a batch.
         */
-       odb_transaction_begin_or_die(the_repository->objects, &transaction);
+       odb_transaction_begin_or_die(the_repository->objects, &transaction, 0);
        while (ctx.argc) {
                if (parseopt_state != PARSE_OPT_DONE)
                        parseopt_state = parse_options_step(&ctx, options,
index 8eec1d4d5247e70533a0c4fde15f5d54d843f0c1..99c6a0a7d0efce783fb9844d80e1bd54bd1b0fdf 100644 (file)
@@ -492,7 +492,7 @@ int cache_tree_update(struct index_state *istate, int flags)
        trace_performance_enter();
        trace2_region_enter("cache_tree", "update", istate->repo);
        if (!inflight)
-               odb_transaction_begin_or_die(the_repository->objects, &transaction);
+               odb_transaction_begin_or_die(the_repository->objects, &transaction, 0);
        i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
                       "", 0, &skip, flags);
        if (!inflight)
index 7426a0c891a22c2989d2572669184638d73277a7..bf263f546d313e06bbb60ce7f0dd8c5797f669ae 100644 (file)
@@ -498,6 +498,7 @@ struct odb_transaction_files {
 
        struct tmp_objdir *objdir;
        struct transaction_packfile packfile;
+       const char *prefix;
 };
 
 static int odb_transaction_files_prepare(struct odb_transaction *base)
@@ -514,7 +515,7 @@ static int odb_transaction_files_prepare(struct odb_transaction *base)
        if (!transaction || transaction->objdir)
                return 0;
 
-       transaction->objdir = tmp_objdir_create(base->source->odb->repo, "bulk-fsync");
+       transaction->objdir = tmp_objdir_create(base->source->odb->repo, transaction->prefix);
        if (!transaction->objdir)
                return error(_("unable to create temporary object directory"));
 
@@ -1357,7 +1358,7 @@ int index_fd(struct index_state *istate, struct object_id *oid,
                        int inflight = !!transaction;
 
                        if (!inflight)
-                               odb_transaction_begin_or_die(odb, &transaction);
+                               odb_transaction_begin_or_die(odb, &transaction, 0);
                        ret = odb_transaction_write_object_stream(transaction,
                                                                  &stream,
                                                                  xsize_t(st->st_size),
@@ -1701,7 +1702,8 @@ static int odb_transaction_files_env(struct odb_transaction *base,
 }
 
 int odb_transaction_files_begin(struct odb_source *source,
-                               struct odb_transaction **out)
+                               struct odb_transaction **out,
+                               enum odb_transaction_flags flags)
 {
        struct odb_transaction_files *transaction;
 
@@ -1710,6 +1712,27 @@ int odb_transaction_files_begin(struct odb_source *source,
        transaction->base.commit = odb_transaction_files_commit;
        transaction->base.write_object_stream = odb_transaction_files_write_object_stream;
        transaction->base.env = odb_transaction_files_env;
+
+       transaction->prefix = "bulk-fsync";
+       if (flags & ODB_TRANSACTION_RECEIVE) {
+               /*
+                * ODB transactions for git-receive-pack(1) eagerly create a
+                * temporary directory and use a different temporary directory
+                * prefix.
+                *
+                * NEEDSWORK: This transaction flag is only used by the "files"
+                * backend to special case temporary directory set up and
+                * handling. Ideally transaction users should not have to care
+                * though. To avoid this, we could eagerly create the temporary
+                * directory and use the same prefix name for all transactions.
+                */
+               transaction->prefix = "incoming";
+               if (odb_transaction_files_prepare(&transaction->base)) {
+                       free(transaction);
+                       return -1;
+               }
+       }
+
        *out = &transaction->base;
 
        return 0;
index 1a023226ac7cd330ac4edbd4aae72e71783ead6c..bdd2d67a2e604752c5842baf7576543e01148289 100644 (file)
@@ -5,6 +5,7 @@
 #include "object.h"
 #include "odb.h"
 #include "odb/source-loose.h"
+#include "odb/transaction.h"
 
 /* The maximum size for an object header. */
 #define MAX_HEADER_LEN 32
@@ -197,6 +198,7 @@ struct odb_transaction;
  * to make new objects visible.
  */
 int odb_transaction_files_begin(struct odb_source *source,
-                               struct odb_transaction **out);
+                               struct odb_transaction **out,
+                               enum odb_transaction_flags flags);
 
 #endif /* OBJECT_FILE_H */
index 2545bd81d448b0b0bdc3689d30a036bb3d7a5247..534f48aad9554e9886ba66908c932dd7928c342b 100644 (file)
@@ -180,9 +180,10 @@ static int odb_source_files_write_object_stream(struct odb_source *source,
 }
 
 static int odb_source_files_begin_transaction(struct odb_source *source,
-                                             struct odb_transaction **out)
+                                             struct odb_transaction **out,
+                                             enum odb_transaction_flags flags)
 {
-       return odb_transaction_files_begin(source, out);
+       return odb_transaction_files_begin(source, out, flags);
 }
 
 static int odb_source_files_read_alternates(struct odb_source *source,
index e004566d768b01c62163c9cfef34a664ba102a56..9644d9d474b59ad767ca64403d89635132d43906 100644 (file)
@@ -304,7 +304,8 @@ static int odb_source_inmemory_freshen_object(struct odb_source *source,
 }
 
 static int odb_source_inmemory_begin_transaction(struct odb_source *source UNUSED,
-                                                struct odb_transaction **out UNUSED)
+                                                struct odb_transaction **out UNUSED,
+                                                enum odb_transaction_flags flags UNUSED)
 {
        return error("in-memory source does not support transactions");
 }
index 7d7ea2fb842537fe924e4761d5b56f8bbfde1e4d..f4eac801e04b2fdb8964023427ce418f992e1470 100644 (file)
@@ -646,7 +646,8 @@ static int odb_source_loose_write_object_stream(struct odb_source *source,
 }
 
 static int odb_source_loose_begin_transaction(struct odb_source *source UNUSED,
-                                             struct odb_transaction **out UNUSED)
+                                             struct odb_transaction **out UNUSED,
+                                             enum odb_transaction_flags flags UNUSED)
 {
        /* TODO: this is a known omission that we'll want to address eventually. */
        return error("loose source does not support transactions");
index 8bcb67787ebafd5fd53fa51ac7620b4497ad993a..c013762d33fc8d70e68856ae76edb248fb726333 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "object.h"
 #include "odb.h"
+#include "odb/transaction.h"
 
 enum odb_source_type {
        /*
@@ -228,7 +229,8 @@ struct odb_source {
         * negative error code otherwise.
         */
        int (*begin_transaction)(struct odb_source *source,
-                                struct odb_transaction **out);
+                                struct odb_transaction **out,
+                                enum odb_transaction_flags flags);
 
        /*
         * This callback is expected to read the list of alternate object
@@ -467,9 +469,10 @@ static inline int odb_source_write_alternate(struct odb_source *source,
  * Returns 0 on success, a negative error code otherwise.
  */
 static inline int odb_source_begin_transaction(struct odb_source *source,
-                                              struct odb_transaction **out)
+                                              struct odb_transaction **out,
+                                              enum odb_transaction_flags flags)
 {
-       return source->begin_transaction(source, out);
+       return source->begin_transaction(source, out, flags);
 }
 
 #endif
index 92ec8786a124612099a4f3a2b63f2ace3d3ee6a3..dab7da6a9a4f55b1c415a99233b3df73bfb9e278 100644 (file)
@@ -4,14 +4,15 @@
 #include "odb/transaction.h"
 
 int odb_transaction_begin(struct object_database *odb,
-                         struct odb_transaction **out)
+                         struct odb_transaction **out,
+                         enum odb_transaction_flags flags)
 {
        int ret;
 
        if (odb->transaction)
                return error(_("object database transaction already pending"));
 
-       ret = odb_source_begin_transaction(odb->sources, out);
+       ret = odb_source_begin_transaction(odb->sources, out, flags);
        if (!ret)
                odb->transaction = *out;
 
index 5e51ce5ca44b83bd5aeebaf34676a35bc6a81026..4cb2eafcbf08f54ee12e694e42378b4864b2c8c3 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "gettext.h"
 #include "odb.h"
-#include "odb/source.h"
 
 /*
  * A transaction may be started for an object database prior to writing new
@@ -44,6 +43,12 @@ struct odb_transaction {
        int (*env)(struct odb_transaction *transaction, struct strvec *env);
 };
 
+/* Flags used to configure an ODB transaction. */
+enum odb_transaction_flags {
+       /* Configures the transaction for use with git-receive-pack(1). */
+       ODB_TRANSACTION_RECEIVE = (1 << 0),
+};
+
 /*
  * Starts an ODB transaction and returns it via `out`. Subsequent objects are
  * written to the transaction and not committed until odb_transaction_commit()
@@ -52,12 +57,14 @@ struct odb_transaction {
  * ODB already has an inflight transaction pending.
  */
 int odb_transaction_begin(struct object_database *odb,
-                         struct odb_transaction **out);
+                         struct odb_transaction **out,
+                         enum odb_transaction_flags flags);
 
 static inline void odb_transaction_begin_or_die(struct object_database *odb,
-                                               struct odb_transaction **out)
+                                               struct odb_transaction **out,
+                                               enum odb_transaction_flags flags)
 {
-       if (odb_transaction_begin(odb, out))
+       if (odb_transaction_begin(odb, out, flags))
                die(_("failed to start ODB transaction"));
 }
 
index bf25989956b5f4d2ed54b61fd5e37092e169194c..94d7416f584992fe1fa1d67a32f4f47d1002cfb2 100644 (file)
@@ -4044,7 +4044,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
         * may not have their own transaction active.
         */
        if (!inflight)
-               odb_transaction_begin_or_die(repo->objects, &transaction);
+               odb_transaction_begin_or_die(repo->objects, &transaction, 0);
        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
        if (!inflight)
                odb_transaction_commit(transaction);