git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/2] Make pack creation always fsync() the result

From
Linus Torvalds <torvalds@linux-foundation.org>
Date
May 30, 2008, 16:08 UTC
Message-ID
<alpine.LFD.1.10.0805300905080.3141@woody.linux-foundation.org>
In-Reply-To
<alpine.LFD.1.10.0805300844310.3141@woody.linux-foundation.org>
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Fri, 30 May 2008 08:42:16 -0700

This means that we can depend on packs always being stable on disk, simplifying a lot of the object serialization worries. And unlike loose objects, serializing pack creation IO isn't going to be a performance killer.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---

Ok, so this is pretty straightforward. I haven't given it a *lot* of testing, but while it can certainly also have bugs, it's not even trying to be "clever" like my previous attempt.

I was always a bit leery about doing a 'fsync()' on a read-only file descriptor, and in general about doing an fsync() on a file that was created by something else.

 builtin-pack-objects.c |    4 +++-
 cache.h                |    1 +
 csum-file.c            |    7 +++++--
 csum-file.h            |    6 +++++-
 fast-import.c          |    2 +-
 index-pack.c           |    1 +
 pack-write.c           |    2 +-
 write_or_die.c         |    7 +++++++
 8 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 70d2f5d..4c2e0cd 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -515,10 +515,12 @@ static void write_pack_file(void)
 		 * If so, rewrite it like in fast-import
 		 */
 		if (pack_to_stdout || nr_written == nr_remaining) {
-			sha1close(f, sha1, 1);
+			unsigned flags = pack_to_stdout ? CSUM_CLOSE : CSUM_FSYNC;
+			sha1close(f, sha1, flags);
 		} else {
 			int fd = sha1close(f, NULL, 0);
 			fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
+			fsync_or_die(fd, pack_tmp_name);
 			close(fd);
 		}
 
diff --git a/cache.h b/cache.h
index eab1a17..092a997 100644
--- a/cache.h
+++ b/cache.h
@@ -761,6 +761,7 @@ extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 extern void write_or_die(int fd, const void *buf, size_t count);
 extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
 extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
+extern void fsync_or_die(int fd, const char *);
 
 /* pager.c */
 extern void setup_pager(void);
diff --git a/csum-file.c b/csum-file.c
index 9728a99..ace64f1 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -32,21 +32,24 @@ static void sha1flush(struct sha1file *f, unsigned int count)
 	}
 }
 
-int sha1close(struct sha1file *f, unsigned char *result, int final)
+int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
 {
 	int fd;
 	unsigned offset = f->offset;
+
 	if (offset) {
 		SHA1_Update(&f->ctx, f->buffer, offset);
 		sha1flush(f, offset);
 		f->offset = 0;
 	}
-	if (final) {
+	if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
 		/* write checksum and close fd */
 		SHA1_Final(f->buffer, &f->ctx);
 		if (result)
 			hashcpy(result, f->buffer);
 		sha1flush(f, 20);
+		if (flags & CSUM_FSYNC)
+			fsync_or_die(f->fd, f->name);
 		if (close(f->fd))
 			die("%s: sha1 file error on close (%s)",
 			    f->name, strerror(errno));
diff --git a/csum-file.h b/csum-file.h
index 1af7656..72c9487 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -16,9 +16,13 @@ struct sha1file {
 	unsigned char buffer[8192];
 };
 
+/* sha1close flags */
+#define CSUM_CLOSE	1
+#define CSUM_FSYNC	2
+
 extern struct sha1file *sha1fd(int fd, const char *name);
 extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
-extern int sha1close(struct sha1file *, unsigned char *, int);
+extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
 extern int sha1write(struct sha1file *, void *, unsigned int);
 extern void crc32_begin(struct sha1file *);
 extern uint32_t crc32_end(struct sha1file *);
diff --git a/fast-import.c b/fast-import.c
index 93119bb..e72b286 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -890,7 +890,7 @@ static char *create_index(void)
 		SHA1_Update(&ctx, (*c)->sha1, 20);
 	}
 	sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
-	sha1close(f, NULL, 1);
+	sha1close(f, NULL, CSUM_FSYNC);
 	free(idx);
 	SHA1_Final(pack_data->sha1, &ctx);
 	return tmpfile;
diff --git a/index-pack.c b/index-pack.c
index aaba944..5ac91ba 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -694,6 +694,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
 	if (!from_stdin) {
 		close(input_fd);
 	} else {
+		fsync_or_die(output_fd, curr_pack_name);
 		err = close(output_fd);
 		if (err)
 			die("error while closing pack file: %s", strerror(errno));
diff --git a/pack-write.c b/pack-write.c
index c66c8af..f52cabe 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -139,7 +139,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
 	}
 
 	sha1write(f, sha1, 20);
-	sha1close(f, NULL, 1);
+	sha1close(f, NULL, CSUM_FSYNC);
 	SHA1_Final(sha1, &ctx);
 	return index_name;
 }
diff --git a/write_or_die.c b/write_or_die.c
index 32f9914..630be4c 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -78,6 +78,13 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
 	return total;
 }
 
+void fsync_or_die(int fd, const char *msg)
+{
+	if (fsync(fd) < 0) {
+		die("%s: fsync error (%s)", msg, strerror(errno));
+	}
+}
+
 void write_or_die(int fd, const void *buf, size_t count)
 {
 	if (write_in_full(fd, buf, count) < 0) {
-- 
1.5.6.rc0.48.g5eea
Previous: Linus TorvaldsNext: Linus Torvalds
Message 11 of 15 in “reducing prune sync()s”
  1. Frank Ch. EiglerMay 29, 2008
  2. Linus TorvaldsMay 30, 2008
  3. Linus TorvaldsMay 30, 2008
  4. Frank Ch. EiglerMay 30, 2008
  5. Florian WeimerMay 30, 2008
  6. David DillowMay 30, 2008
  7. Linus TorvaldsMay 30, 2008
  8. Linus TorvaldsMay 30, 2008
  9. Frank Ch. EiglerMay 30, 2008
  10. Linus TorvaldsMay 30, 2008
  11. 1/2 Make pack creation always fsync() the resultLinus Torvalds, May 30, 2008
  12. 2/2 Remove now unnecessary 'sync()' callsLinus Torvalds, May 30, 2008
  13. Nicolas PitreMay 30, 2008
  14. Frank Ch. EiglerMay 31, 2008
  15. Linus TorvaldsJun 2, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.