[RFC PATCH 1/1] tempfile: invalid outdated temporary files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Han Xin <hanxin.hx@xxxxxxxxxxxxxxx>

When git quits unexpectedly, some temporary files(e.g. HEAD.lock,
packed-refs.lock, packed-refs.new) may remain in the repository. These
files will prevent us from performing the corresponding operations
again, even if they were created a long time ago before, until we
manually remove them.

In order for git to automatically fix this situation, let's add a config
named "core.tempfileExpire". When an attempt is made to create a
temporary file that exists and is older than this config value, the file
will be unlinked and recreated.

Signed-off-by: Han Xin <hanxin.hx@xxxxxxxxxxxxxxx>
---
 Documentation/config/core.txt |  6 ++++++
 cache.h                       |  1 +
 config.c                      |  5 +++++
 environment.c                 |  1 +
 t/t3210-pack-refs.sh          | 10 ++++++++++
 tempfile.c                    | 21 +++++++++++++++++++++
 6 files changed, 44 insertions(+)

diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index c04f62a54a..9907c9e6f3 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -424,6 +424,12 @@ be delta compressed, but larger binary media files won't be.
 +
 Common unit suffixes of 'k', 'm', or 'g' are supported.
 
+core.tempfileExpire::
+	When an attempt is made to create a temporary file that exists
+	and is older than this config value, the file will be unlinked
+	and recreated. This feature is used to ignore temporary files
+	(e.g. *.lock and *.new) remaining due to abnormal exits.
+
 core.excludesFile::
 	Specifies the pathname to the file that contains patterns to
 	describe paths that are not meant to be tracked, in addition
diff --git a/cache.h b/cache.h
index 0bc0a37cec..4264fe7960 100644
--- a/cache.h
+++ b/cache.h
@@ -972,6 +972,7 @@ extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern unsigned long big_file_threshold;
+extern const char *tempfile_expire;
 extern unsigned long pack_size_limit_cfg;
 
 /*
diff --git a/config.c b/config.c
index e78397725c..36a5bc1960 100644
--- a/config.c
+++ b/config.c
@@ -1518,6 +1518,11 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
 		return 0;
 	}
 
+	if (!strcmp(var, "core.tempfileexpire")) {
+		git_config_get_expiry(var, &tempfile_expire);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.packedgitlimit")) {
 		packed_git_limit = git_config_ulong(var, value);
 		return 0;
diff --git a/environment.c b/environment.c
index fb55bf6129..20b928e71b 100644
--- a/environment.c
+++ b/environment.c
@@ -48,6 +48,7 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 96 * 1024 * 1024;
 unsigned long big_file_threshold = 512 * 1024 * 1024;
+const char *tempfile_expire = "1.day.ago";
 int pager_use_color = 1;
 const char *editor_program;
 const char *askpass_program;
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 577f32dc71..7d443c1cfd 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -231,6 +231,16 @@ test_expect_success 'timeout if packed-refs.lock exists' '
 	test_must_fail git pack-refs --all --prune
 '
 
+test_expect_success 'success if packed-refs.lock expires' '
+	LOCK=.git/packed-refs.lock &&
+	>"$LOCK" &&
+	test_when_finished "rm -f $LOCK" &&
+	test-tool chmtime -86000 $LOCK &&
+	test_must_fail git pack-refs --all --prune &&
+	test-tool chmtime -400 $LOCK &&
+	git pack-refs --all --prune
+'
+
 test_expect_success 'retry acquiring packed-refs.lock' '
 	LOCK=.git/packed-refs.lock &&
 	>"$LOCK" &&
diff --git a/tempfile.c b/tempfile.c
index 94aa18f3f7..f18e0121d0 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -51,6 +51,7 @@
  */
 
 #include "cache.h"
+#include "date.h"
 #include "tempfile.h"
 #include "sigchain.h"
 
@@ -137,6 +138,26 @@ struct tempfile *create_tempfile_mode(const char *path, int mode)
 	strbuf_add_absolute_path(&tempfile->filename, path);
 	tempfile->fd = open(tempfile->filename.buf,
 			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+	if (tempfile->fd < 0 && errno == EEXIST) {
+		struct stat st;
+		int err = errno;
+		if (lstat(tempfile->filename.buf, &st) < 0) {
+			warning_errno(_("failed to stat %s"),
+				      tempfile->filename.buf);
+			errno = err;
+		} else if (st.st_mtime <= approxidate(tempfile_expire)) {
+			/*
+			 * If the file is older than core.tmpfileExpire, it is
+			 * probably outdated.  We'll try to remove it and try
+			 * again.
+			 */
+			warning(_("remove outdated tempfile %s"), tempfile->filename.buf);
+			unlink_or_warn(tempfile->filename.buf);
+			tempfile->fd = open(tempfile->filename.buf,
+					    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC,
+					    mode);
+		}
+	}
 	if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
 		/* Try again w/o O_CLOEXEC: the kernel might not support it */
 		tempfile->fd = open(tempfile->filename.buf,
-- 
2.35.1.55.gde4365fc52.agit.6.5.7




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux