bulk-checkin: remove global transaction state
Object database transactions in the bulk-checkin subsystem rely on global state to track transaction status. Stop relying on global state and instead store the transaction in the `struct object_database`. Functions that operate on transactions are updated to now wire transaction state. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Justin Tobler committed
Aug 22, 2025 at 16:34 UTC
b3361447256bb92a1dbdda910a33cfb1d6fc8f88
9 files changed
+94
-52
builtin/add.c
+3
-2
@@ -389,6 +389,7 @@ int cmd_add(int argc,
389
char *seen = NULL;
390
char *ps_matched = NULL;
391
struct lock_file lock_file = LOCK_INIT;
392
+ struct odb_transaction *transaction;
393
394
repo_config(repo, add_config, NULL);
395
@@ -574,7 +575,7 @@ int cmd_add(int argc,
575
string_list_clear(&only_match_skip_worktree, 0);
576
}
577
577
- begin_odb_transaction();
578
+ transaction = begin_odb_transaction(repo->objects);
579
580
ps_matched = xcalloc(pathspec.nr, 1);
581
if (add_renormalize)
@@ -593,7 +594,7 @@ int cmd_add(int argc,
594
595
if (chmod_arg && pathspec.nr)
596
exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
596
- end_odb_transaction();
597
+ end_odb_transaction(transaction);
598
599
finish:
600
if (write_locked_index(repo->index, &lock_file,
builtin/unpack-objects.c
+3
-2
@@ -584,6 +584,7 @@ static void unpack_all(void)
584
{
585
int i;
586
unsigned char *hdr = fill(sizeof(struct pack_header));
587
+ struct odb_transaction *transaction;
588
589
if (get_be32(hdr) != PACK_SIGNATURE)
590
die("bad pack file");
@@ -599,12 +600,12 @@ static void unpack_all(void)
600
progress = start_progress(the_repository,
601
_("Unpacking objects"), nr_objects);
602
CALLOC_ARRAY(obj_list, nr_objects);
602
- begin_odb_transaction();
603
+ transaction = begin_odb_transaction(the_repository->objects);
604
for (i = 0; i < nr_objects; i++) {
605
unpack_one(i);
606
display_progress(progress, i + 1);
607
}
607
- end_odb_transaction();
608
+ end_odb_transaction(transaction);
609
stop_progress(&progress);
610
611
if (delta_list)
builtin/update-index.c
+4
-3
@@ -77,7 +77,7 @@ static void report(const char *fmt, ...)
77
* objects invisible while a transaction is active, so flush the
78
* transaction here before reporting a change made by update-index.
79
*/
80
- flush_odb_transaction();
80
+ flush_odb_transaction(the_repository->objects->transaction);
81
va_start(vp, fmt);
82
vprintf(fmt, vp);
83
putchar('\n');
@@ -940,6 +940,7 @@ int cmd_update_index(int argc,
940
strbuf_getline_fn getline_fn;
941
int parseopt_state = PARSE_OPT_UNKNOWN;
942
struct repository *r = the_repository;
943
+ struct odb_transaction *transaction;
944
struct option options[] = {
945
OPT_BIT('q', NULL, &refresh_args.flags,
946
N_("continue refresh even when index needs update"),
@@ -1130,7 +1131,7 @@ int cmd_update_index(int argc,
1131
* Allow the object layer to optimize adding multiple objects in
1132
* a batch.
1133
*/
1133
- begin_odb_transaction();
1134
+ transaction = begin_odb_transaction(the_repository->objects);
1135
while (ctx.argc) {
1136
if (parseopt_state != PARSE_OPT_DONE)
1137
parseopt_state = parse_options_step(&ctx, options,
@@ -1213,7 +1214,7 @@ int cmd_update_index(int argc,
1214
/*
1215
* By now we have added all of the new objects
1216
*/
1216
- end_odb_transaction();
1217
+ end_odb_transaction(transaction);
1218
1219
if (split_index > 0) {
1220
if (repo_config_get_split_index(the_repository) == 0)
bulk-checkin.c
+53
-29
@@ -30,11 +30,13 @@ struct bulk_checkin_packfile {
30
uint32_t nr_written;
31
};
32
33
-static struct odb_transaction {
33
+struct odb_transaction {
34
+ struct object_database *odb;
35
+
36
int nesting;
37
struct tmp_objdir *objdir;
38
struct bulk_checkin_packfile packfile;
37
-} transaction;
39
+};
40
41
static void finish_tmp_packfile(struct strbuf *basename,
42
const char *pack_tmp_name,
@@ -98,12 +100,12 @@ clear_exit:
100
/*
101
* Cleanup after batch-mode fsync_object_files.
102
*/
101
-static void flush_batch_fsync(void)
103
+static void flush_batch_fsync(struct odb_transaction *transaction)
104
{
105
struct strbuf temp_path = STRBUF_INIT;
106
struct tempfile *temp;
107
106
- if (!transaction.objdir)
108
+ if (!transaction->objdir)
109
return;
110
111
/*
@@ -125,8 +127,8 @@ static void flush_batch_fsync(void)
127
* Make the object files visible in the primary ODB after their data is
128
* fully durable.
129
*/
128
- tmp_objdir_migrate(transaction.objdir);
129
- transaction.objdir = NULL;
130
+ tmp_objdir_migrate(transaction->objdir);
131
+ transaction->objdir = NULL;
132
}
133
134
static int already_written(struct bulk_checkin_packfile *state, struct object_id *oid)
@@ -325,7 +327,7 @@ static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
327
return 0;
328
}
329
328
-void prepare_loose_object_bulk_checkin(void)
330
+void prepare_loose_object_bulk_checkin(struct odb_transaction *transaction)
331
{
332
/*
333
* We lazily create the temporary object directory
@@ -333,15 +335,16 @@ void prepare_loose_object_bulk_checkin(void)
335
* callers may not know whether any objects will be
336
* added at the time they call begin_odb_transaction.
337
*/
336
- if (!transaction.nesting || transaction.objdir)
338
+ if (!transaction || transaction->objdir)
339
return;
340
339
- transaction.objdir = tmp_objdir_create(the_repository, "bulk-fsync");
340
- if (transaction.objdir)
341
- tmp_objdir_replace_primary_odb(transaction.objdir, 0);
341
+ transaction->objdir = tmp_objdir_create(the_repository, "bulk-fsync");
342
+ if (transaction->objdir)
343
+ tmp_objdir_replace_primary_odb(transaction->objdir, 0);
344
}
345
344
-void fsync_loose_object_bulk_checkin(int fd, const char *filename)
346
+void fsync_loose_object_bulk_checkin(struct odb_transaction *transaction,
347
+ int fd, const char *filename)
348
{
349
/*
350
* If we have an active ODB transaction, we issue a call that
@@ -350,7 +353,7 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename)
353
* before renaming the objects to their final names as part of
354
* flush_batch_fsync.
355
*/
353
- if (!transaction.objdir ||
356
+ if (!transaction || !transaction->objdir ||
357
git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
358
if (errno == ENOSYS)
359
warning(_("core.fsyncMethod = batch is unsupported on this platform"));
@@ -358,36 +361,57 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename)
361
}
362
}
363
361
-int index_blob_bulk_checkin(struct object_id *oid,
362
- int fd, size_t size,
364
+int index_blob_bulk_checkin(struct odb_transaction *transaction,
365
+ struct object_id *oid, int fd, size_t size,
366
const char *path, unsigned flags)
367
{
365
- int status = deflate_blob_to_pack(&transaction.packfile, oid, fd, size,
366
- path, flags);
367
- if (!transaction.nesting)
368
- flush_bulk_checkin_packfile(&transaction.packfile);
368
+ int status;
369
+
370
+ if (transaction) {
371
+ status = deflate_blob_to_pack(&transaction->packfile, oid, fd,
372
+ size, path, flags);
373
+ } else {
374
+ struct bulk_checkin_packfile state = { 0 };
375
+
376
+ status = deflate_blob_to_pack(&state, oid, fd, size, path, flags);
377
+ flush_bulk_checkin_packfile(&state);
378
+ }
379
+
380
return status;
381
}
382
372
-void begin_odb_transaction(void)
383
+struct odb_transaction *begin_odb_transaction(struct object_database *odb)
384
{
374
- transaction.nesting += 1;
385
+ if (!odb->transaction) {
386
+ CALLOC_ARRAY(odb->transaction, 1);
387
+ odb->transaction->odb = odb;
388
+ }
389
+
390
+ odb->transaction->nesting += 1;
391
+
392
+ return odb->transaction;
393
}
394
377
-void flush_odb_transaction(void)
395
+void flush_odb_transaction(struct odb_transaction *transaction)
396
{
379
- flush_batch_fsync();
380
- flush_bulk_checkin_packfile(&transaction.packfile);
397
+ if (!transaction)
398
+ return;
399
+
400
+ flush_batch_fsync(transaction);
401
+ flush_bulk_checkin_packfile(&transaction->packfile);
402
}
403
383
-void end_odb_transaction(void)
404
+void end_odb_transaction(struct odb_transaction *transaction)
405
{
385
- transaction.nesting -= 1;
386
- if (transaction.nesting < 0)
406
+ if (!transaction || transaction->nesting == 0)
407
BUG("Unbalanced ODB transaction nesting");
408
389
- if (transaction.nesting)
409
+ transaction->nesting -= 1;
410
+
411
+ if (transaction->nesting)
412
return;
413
392
- flush_odb_transaction();
414
+ flush_odb_transaction(transaction);
415
+ transaction->odb->transaction = NULL;
416
+ free(transaction);
417
}
bulk-checkin.h
+11
-7
@@ -5,9 +5,13 @@
5
#define BULK_CHECKIN_H
6
7
#include "object.h"
8
+#include "odb.h"
9
9
-void prepare_loose_object_bulk_checkin(void);
10
-void fsync_loose_object_bulk_checkin(int fd, const char *filename);
10
+struct odb_transaction;
11
+
12
+void prepare_loose_object_bulk_checkin(struct odb_transaction *transaction);
13
+void fsync_loose_object_bulk_checkin(struct odb_transaction *transaction,
14
+ int fd, const char *filename);
15
16
/*
17
* This creates one packfile per large blob unless bulk-checkin
@@ -24,8 +28,8 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename);
28
* binary blobs, they generally do not want to get any conversion, and
29
* callers should avoid this code path when filters are requested.
30
*/
27
-int index_blob_bulk_checkin(struct object_id *oid,
28
- int fd, size_t size,
31
+int index_blob_bulk_checkin(struct odb_transaction *transaction,
32
+ struct object_id *oid, int fd, size_t size,
33
const char *path, unsigned flags);
34
35
/*
@@ -35,20 +39,20 @@ int index_blob_bulk_checkin(struct object_id *oid,
39
* and objects are only visible after the outermost transaction
40
* is complete or the transaction is flushed.
41
*/
38
-void begin_odb_transaction(void);
42
+struct odb_transaction *begin_odb_transaction(struct object_database *odb);
43
44
/*
45
* Make any objects that are currently part of a pending object
46
* database transaction visible. It is valid to call this function
47
* even if no transaction is active.
48
*/
45
-void flush_odb_transaction(void);
49
+void flush_odb_transaction(struct odb_transaction *transaction);
50
51
/*
52
* Tell the object database to make any objects from the
53
* current transaction visible if this is the final nested
54
* transaction.
55
*/
52
-void end_odb_transaction(void);
56
+void end_odb_transaction(struct odb_transaction *transaction);
57
58
#endif
cache-tree.c
+3
-2
@@ -474,6 +474,7 @@ static int update_one(struct cache_tree *it,
474
475
int cache_tree_update(struct index_state *istate, int flags)
476
{
477
+ struct odb_transaction *transaction;
478
int skip, i;
479
480
i = verify_cache(istate, flags);
@@ -489,10 +490,10 @@ int cache_tree_update(struct index_state *istate, int flags)
490
491
trace_performance_enter();
492
trace2_region_enter("cache_tree", "update", the_repository);
492
- begin_odb_transaction();
493
+ transaction = begin_odb_transaction(the_repository->objects);
494
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
495
"", 0, &skip, flags);
495
- end_odb_transaction();
496
+ end_odb_transaction(transaction);
497
trace2_region_leave("cache_tree", "update", the_repository);
498
trace_performance_leave("cache_tree_update");
499
if (i < 0)
object-file.c
+6
-5
@@ -674,7 +674,7 @@ static void close_loose_object(struct odb_source *source,
674
goto out;
675
676
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
677
- fsync_loose_object_bulk_checkin(fd, filename);
677
+ fsync_loose_object_bulk_checkin(source->odb->transaction, fd, filename);
678
else if (fsync_object_files > 0)
679
fsync_or_die(fd, filename);
680
else
@@ -852,7 +852,7 @@ static int write_loose_object(struct odb_source *source,
852
static struct strbuf filename = STRBUF_INIT;
853
854
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
855
- prepare_loose_object_bulk_checkin();
855
+ prepare_loose_object_bulk_checkin(source->odb->transaction);
856
857
odb_loose_path(source, &filename, oid);
858
@@ -941,7 +941,7 @@ int stream_loose_object(struct odb_source *source,
941
int hdrlen;
942
943
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
944
- prepare_loose_object_bulk_checkin();
944
+ prepare_loose_object_bulk_checkin(source->odb->transaction);
945
946
/* Since oid is not determined, save tmp file to odb path. */
947
strbuf_addf(&filename, "%s/", source->path);
@@ -1263,8 +1263,9 @@ int index_fd(struct index_state *istate, struct object_id *oid,
1263
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
1264
type, path, flags);
1265
else
1266
- ret = index_blob_bulk_checkin(oid, fd, xsize_t(st->st_size), path,
1267
- flags);
1266
+ ret = index_blob_bulk_checkin(the_repository->objects->transaction,
1267
+ oid, fd, xsize_t(st->st_size),
1268
+ path, flags);
1269
close(fd);
1270
return ret;
1271
}
odb.h
+8
@@ -84,6 +84,7 @@ struct odb_source {
84
85
struct packed_git;
86
struct cached_object_entry;
87
+struct odb_transaction;
88
89
/*
90
* The object database encapsulates access to objects in a repository. It
@@ -94,6 +95,13 @@ struct object_database {
95
/* Repository that owns this database. */
96
struct repository *repo;
97
98
+ /*
99
+ * State of current current object database transaction. Only one
100
+ * transaction may be pending at a time. Is NULL when no transaction is
101
+ * configured.
102
+ */
103
+ struct odb_transaction *transaction;
104
+
105
/*
106
* Set of all object directories; the main directory is first (and
107
* cannot be NULL after initialization). Subsequent directories are
read-cache.c
+3
-2
@@ -3947,6 +3947,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
3947
const struct pathspec *pathspec, char *ps_matched,
3948
int include_sparse, int flags)
3949
{
3950
+ struct odb_transaction *transaction;
3951
struct update_callback_data data;
3952
struct rev_info rev;
3953
@@ -3972,9 +3973,9 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
3973
* This function is invoked from commands other than 'add', which
3974
* may not have their own transaction active.
3975
*/
3975
- begin_odb_transaction();
3976
+ transaction = begin_odb_transaction(repo->objects);
3977
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
3977
- end_odb_transaction();
3978
+ end_odb_transaction(transaction);
3979
3980
release_revisions(&rev);
3981
return !!data.add_errors;