object-file: embed transaction flush logic in commit function

When a "files" transaction is committed, `flush_loose_object_transaction()` is invoked to handle performing a hardware flush along with migrating the temporary object directory into the primary and configuring the repository ODB source accordingly. The function name here is a bit misleading because the helper is doing a bit more than just "flushing" the transaction contents. Also, in a subsequent commit, the transaction temporary directory is used to stage packfiles and not just loose objects anymore. Lift the helper function logic into `odb_transaction_files_commit()` to more accurately signal to readers the operation being performed. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Justin Tobler committed Jul 10, 2026 at 11:37 UTC ee1785a49080943dcde9303c3771de04c873e93c
1 file changed +28 -36
object-file.c
+28 -36
@@ -543,41 +543,6 @@ static void odb_transaction_files_fsync(struct odb_transaction *base,
543 }
544 }
545
546 -/*
547 - * Cleanup after batch-mode fsync_object_files.
548 - */
549 -static void flush_loose_object_transaction(struct odb_transaction_files *transaction)
550 -{
551 - struct strbuf temp_path = STRBUF_INIT;
552 - struct tempfile *temp;
553 -
554 - if (!transaction->objdir)
555 - return;
556 -
557 - /*
558 - * Issue a full hardware flush against a temporary file to ensure
559 - * that all objects are durable before any renames occur. The code in
560 - * odb_transaction_files_fsync has already issued a writeout
561 - * request, but it has not flushed any writeback cache in the storage
562 - * hardware or any filesystem logs. This fsync call acts as a barrier
563 - * to ensure that the data in each new object file is durable before
564 - * the final name is visible.
565 - */
566 - strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX",
567 - repo_get_object_directory(transaction->base.source->odb->repo));
568 - temp = xmks_tempfile(temp_path.buf);
569 - fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
570 - delete_tempfile(&temp);
571 - strbuf_release(&temp_path);
572 -
573 - /*
574 - * Make the object files visible in the primary ODB after their data is
575 - * fully durable.
576 - */
577 - tmp_objdir_migrate(transaction->objdir);
578 - transaction->objdir = NULL;
579 -}
580 -
546 /* Finalize a file on disk, and close it. */
547 static void close_loose_object(struct odb_source_loose *loose,
548 int fd, const char *filename)
@@ -1677,7 +1642,34 @@ static void odb_transaction_files_commit(struct odb_transaction *base)
1642 struct odb_transaction_files *transaction =
1643 container_of(base, struct odb_transaction_files, base);
1644
1680 - flush_loose_object_transaction(transaction);
1645 + if (transaction->objdir) {
1646 + struct strbuf temp_path = STRBUF_INIT;
1647 + struct tempfile *temp;
1648 +
1649 + /*
1650 + * Issue a full hardware flush against a temporary file to ensure
1651 + * that all objects are durable before any renames occur. The code in
1652 + * odb_transaction_files_fsync has already issued a writeout
1653 + * request, but it has not flushed any writeback cache in the storage
1654 + * hardware or any filesystem logs. This fsync call acts as a barrier
1655 + * to ensure that the data in each new object file is durable before
1656 + * the final name is visible.
1657 + */
1658 + strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX",
1659 + repo_get_object_directory(transaction->base.source->odb->repo));
1660 + temp = xmks_tempfile(temp_path.buf);
1661 + fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
1662 + delete_tempfile(&temp);
1663 + strbuf_release(&temp_path);
1664 +
1665 + /*
1666 + * Make the object files visible in the primary ODB after their data is
1667 + * fully durable.
1668 + */
1669 + tmp_objdir_migrate(transaction->objdir);
1670 + transaction->objdir = NULL;
1671 + }
1672 +
1673 flush_packfile_transaction(transaction);
1674 }
1675