Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'bulk-checkin.c')
-rw-r--r--bulk-checkin.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/bulk-checkin.c b/bulk-checkin.c
index ad855267d2..df451bdf42 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -3,15 +3,20 @@
*/
#include "cache.h"
#include "bulk-checkin.h"
+#include "lockfile.h"
#include "repository.h"
#include "csum-file.h"
#include "pack.h"
#include "strbuf.h"
+#include "string-list.h"
+#include "tmp-objdir.h"
#include "packfile.h"
#include "object-store.h"
static int odb_transaction_nesting;
+static struct tmp_objdir *bulk_fsync_objdir;
+
static struct bulk_checkin_packfile {
char *pack_tmp_name;
struct hashfile *f;
@@ -80,6 +85,40 @@ clear_exit:
reprepare_packed_git(the_repository);
}
+/*
+ * Cleanup after batch-mode fsync_object_files.
+ */
+static void flush_batch_fsync(void)
+{
+ struct strbuf temp_path = STRBUF_INIT;
+ struct tempfile *temp;
+
+ if (!bulk_fsync_objdir)
+ return;
+
+ /*
+ * Issue a full hardware flush against a temporary file to ensure
+ * that all objects are durable before any renames occur. The code in
+ * fsync_loose_object_bulk_checkin has already issued a writeout
+ * request, but it has not flushed any writeback cache in the storage
+ * hardware or any filesystem logs. This fsync call acts as a barrier
+ * to ensure that the data in each new object file is durable before
+ * the final name is visible.
+ */
+ strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", get_object_directory());
+ temp = xmks_tempfile(temp_path.buf);
+ fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
+ delete_tempfile(&temp);
+ strbuf_release(&temp_path);
+
+ /*
+ * Make the object files visible in the primary ODB after their data is
+ * fully durable.
+ */
+ tmp_objdir_migrate(bulk_fsync_objdir);
+ bulk_fsync_objdir = NULL;
+}
+
static int already_written(struct bulk_checkin_packfile *state, struct object_id *oid)
{
int i;
@@ -274,6 +313,37 @@ static int deflate_to_pack(struct bulk_checkin_packfile *state,
return 0;
}
+void prepare_loose_object_bulk_checkin(void)
+{
+ /*
+ * We lazily create the temporary object directory
+ * the first time an object might be added, since
+ * callers may not know whether any objects will be
+ * added at the time they call begin_odb_transaction.
+ */
+ if (!odb_transaction_nesting || bulk_fsync_objdir)
+ return;
+
+ bulk_fsync_objdir = tmp_objdir_create("bulk-fsync");
+ if (bulk_fsync_objdir)
+ tmp_objdir_replace_primary_odb(bulk_fsync_objdir, 0);
+}
+
+void fsync_loose_object_bulk_checkin(int fd, const char *filename)
+{
+ /*
+ * If we have an active ODB transaction, we issue a call that
+ * cleans the filesystem page cache but avoids a hardware flush
+ * command. Later on we will issue a single hardware flush
+ * before renaming the objects to their final names as part of
+ * flush_batch_fsync.
+ */
+ if (!bulk_fsync_objdir ||
+ git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
+ fsync_or_die(fd, filename);
+ }
+}
+
int index_bulk_checkin(struct object_id *oid,
int fd, size_t size, enum object_type type,
const char *path, unsigned flags)
@@ -292,6 +362,7 @@ void begin_odb_transaction(void)
void flush_odb_transaction(void)
{
+ flush_batch_fsync();
flush_bulk_checkin_packfile(&bulk_checkin_packfile);
}