odb: add transaction interface

Transactions are managed via the {begin,end}_odb_transaction() function
in the object-file subsystem and its implementation is specific to the
files object source. Introduce odb_transaction_{begin,commit}() in the
odb subsystem to provide an eventual object source agnostic means to
manage transactions.

Update call sites to instead manage transactions through the odb
subsystem. Also rename {begin,end}_odb_transaction() functions to
object_file_transaction_{begin,commit}() to clarify the object source it
supports.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
Justin Tobler 2025-09-16 13:29:38 -05:00 committed by Junio C Hamano
parent ed0f5f93e9
commit ce1661f9da
9 changed files with 46 additions and 19 deletions

View File

@ -15,6 +15,7 @@
#include "pathspec.h" #include "pathspec.h"
#include "run-command.h" #include "run-command.h"
#include "object-file.h" #include "object-file.h"
#include "odb.h"
#include "parse-options.h" #include "parse-options.h"
#include "path.h" #include "path.h"
#include "preload-index.h" #include "preload-index.h"
@ -575,7 +576,7 @@ int cmd_add(int argc,
string_list_clear(&only_match_skip_worktree, 0); string_list_clear(&only_match_skip_worktree, 0);
} }


transaction = begin_odb_transaction(repo->objects); transaction = odb_transaction_begin(repo->objects);


ps_matched = xcalloc(pathspec.nr, 1); ps_matched = xcalloc(pathspec.nr, 1);
if (add_renormalize) if (add_renormalize)
@ -594,7 +595,7 @@ int cmd_add(int argc,


if (chmod_arg && pathspec.nr) if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only); exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
end_odb_transaction(transaction); odb_transaction_commit(transaction);


finish: finish:
if (write_locked_index(repo->index, &lock_file, if (write_locked_index(repo->index, &lock_file,

View File

@ -599,12 +599,12 @@ static void unpack_all(void)
progress = start_progress(the_repository, progress = start_progress(the_repository,
_("Unpacking objects"), nr_objects); _("Unpacking objects"), nr_objects);
CALLOC_ARRAY(obj_list, nr_objects); CALLOC_ARRAY(obj_list, nr_objects);
transaction = begin_odb_transaction(the_repository->objects); transaction = odb_transaction_begin(the_repository->objects);
for (i = 0; i < nr_objects; i++) { for (i = 0; i < nr_objects; i++) {
unpack_one(i); unpack_one(i);
display_progress(progress, i + 1); display_progress(progress, i + 1);
} }
end_odb_transaction(transaction); odb_transaction_commit(transaction);
stop_progress(&progress); stop_progress(&progress);


if (delta_list) if (delta_list)

View File

@ -18,6 +18,7 @@
#include "cache-tree.h" #include "cache-tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "object-file.h" #include "object-file.h"
#include "odb.h"
#include "refs.h" #include "refs.h"
#include "resolve-undo.h" #include "resolve-undo.h"
#include "parse-options.h" #include "parse-options.h"
@ -1122,7 +1123,7 @@ int cmd_update_index(int argc,
* Allow the object layer to optimize adding multiple objects in * Allow the object layer to optimize adding multiple objects in
* a batch. * a batch.
*/ */
transaction = begin_odb_transaction(the_repository->objects); transaction = odb_transaction_begin(the_repository->objects);
while (ctx.argc) { while (ctx.argc) {
if (parseopt_state != PARSE_OPT_DONE) if (parseopt_state != PARSE_OPT_DONE)
parseopt_state = parse_options_step(&ctx, options, parseopt_state = parse_options_step(&ctx, options,
@ -1152,7 +1153,7 @@ int cmd_update_index(int argc,
* a transaction. * a transaction.
*/ */
if (transaction && verbose) { if (transaction && verbose) {
end_odb_transaction(transaction); odb_transaction_commit(transaction);
transaction = NULL; transaction = NULL;
} }


@ -1220,7 +1221,7 @@ int cmd_update_index(int argc,
/* /*
* By now we have added all of the new objects * By now we have added all of the new objects
*/ */
end_odb_transaction(transaction); odb_transaction_commit(transaction);


if (split_index > 0) { if (split_index > 0) {
if (repo_config_get_split_index(the_repository) == 0) if (repo_config_get_split_index(the_repository) == 0)

View File

@ -489,10 +489,10 @@ int cache_tree_update(struct index_state *istate, int flags)


trace_performance_enter(); trace_performance_enter();
trace2_region_enter("cache_tree", "update", the_repository); trace2_region_enter("cache_tree", "update", the_repository);
transaction = begin_odb_transaction(the_repository->objects); transaction = odb_transaction_begin(the_repository->objects);
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr, i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
"", 0, &skip, flags); "", 0, &skip, flags);
end_odb_transaction(transaction); odb_transaction_commit(transaction);
trace2_region_leave("cache_tree", "update", the_repository); trace2_region_leave("cache_tree", "update", the_repository);
trace_performance_leave("cache_tree_update"); trace_performance_leave("cache_tree_update");
if (i < 0) if (i < 0)

View File

@ -691,7 +691,7 @@ static void prepare_loose_object_transaction(struct odb_transaction *transaction
* We lazily create the temporary object directory * We lazily create the temporary object directory
* the first time an object might be added, since * the first time an object might be added, since
* callers may not know whether any objects will be * callers may not know whether any objects will be
* added at the time they call begin_odb_transaction. * added at the time they call object_file_transaction_begin.
*/ */
if (!transaction || transaction->objdir) if (!transaction || transaction->objdir)
return; return;
@ -1622,12 +1622,12 @@ int index_fd(struct index_state *istate, struct object_id *oid,
} else { } else {
struct odb_transaction *transaction; struct odb_transaction *transaction;


transaction = begin_odb_transaction(the_repository->objects); transaction = odb_transaction_begin(the_repository->objects);
ret = index_blob_packfile_transaction(the_repository->objects->transaction, ret = index_blob_packfile_transaction(the_repository->objects->transaction,
oid, fd, oid, fd,
xsize_t(st->st_size), xsize_t(st->st_size),
path, flags); path, flags);
end_odb_transaction(transaction); odb_transaction_commit(transaction);
} }


close(fd); close(fd);
@ -1967,8 +1967,10 @@ out:
return ret; return ret;
} }


struct odb_transaction *begin_odb_transaction(struct object_database *odb) struct odb_transaction *object_file_transaction_begin(struct odb_source *source)
{ {
struct object_database *odb = source->odb;

if (odb->transaction) if (odb->transaction)
return NULL; return NULL;


@ -1978,7 +1980,7 @@ struct odb_transaction *begin_odb_transaction(struct object_database *odb)
return odb->transaction; return odb->transaction;
} }


void end_odb_transaction(struct odb_transaction *transaction) void object_file_transaction_commit(struct odb_transaction *transaction)
{ {
if (!transaction) if (!transaction)
return; return;

View File

@ -222,16 +222,16 @@ struct odb_transaction;


/* /*
* Tell the object database to optimize for adding * Tell the object database to optimize for adding
* multiple objects. end_odb_transaction must be called * multiple objects. object_file_transaction_commit must be called
* to make new objects visible. If a transaction is already * to make new objects visible. If a transaction is already
* pending, NULL is returned. * pending, NULL is returned.
*/ */
struct odb_transaction *begin_odb_transaction(struct object_database *odb); struct odb_transaction *object_file_transaction_begin(struct odb_source *source);


/* /*
* Tell the object database to make any objects from the * Tell the object database to make any objects from the
* current transaction visible. * current transaction visible.
*/ */
void end_odb_transaction(struct odb_transaction *transaction); void object_file_transaction_commit(struct odb_transaction *transaction);


#endif /* OBJECT_FILE_H */ #endif /* OBJECT_FILE_H */

10
odb.c
View File

@ -1051,3 +1051,13 @@ void odb_clear(struct object_database *o)
hashmap_clear(&o->pack_map); hashmap_clear(&o->pack_map);
string_list_clear(&o->submodule_source_paths, 0); string_list_clear(&o->submodule_source_paths, 0);
} }

struct odb_transaction *odb_transaction_begin(struct object_database *odb)
{
return object_file_transaction_begin(odb->sources);
}

void odb_transaction_commit(struct odb_transaction *transaction)
{
object_file_transaction_commit(transaction);
}

13
odb.h
View File

@ -185,6 +185,19 @@ struct object_database {
struct object_database *odb_new(struct repository *repo); struct object_database *odb_new(struct repository *repo);
void odb_clear(struct object_database *o); void odb_clear(struct object_database *o);


/*
* Starts an ODB transaction. Subsequent objects are written to the transaction
* and not committed until odb_transaction_commit() is invoked on the
* transaction. If the ODB already has a pending transaction, NULL is returned.
*/
struct odb_transaction *odb_transaction_begin(struct object_database *odb);

/*
* Commits an ODB transaction making the written objects visible. If the
* specified transaction is NULL, the function is a no-op.
*/
void odb_transaction_commit(struct odb_transaction *transaction);

/* /*
* Find source by its object directory path. Dies in case the source couldn't * Find source by its object directory path. Dies in case the source couldn't
* be found. * be found.

View File

@ -3972,9 +3972,9 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
* This function is invoked from commands other than 'add', which * This function is invoked from commands other than 'add', which
* may not have their own transaction active. * may not have their own transaction active.
*/ */
transaction = begin_odb_transaction(repo->objects); transaction = odb_transaction_begin(repo->objects);
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
end_odb_transaction(transaction); odb_transaction_commit(transaction);


release_revisions(&rev); release_revisions(&rev);
return !!data.add_errors; return !!data.add_errors;