Merge branch 'bc/racy-4gb-files' into next
The index file has room only for lower 32-bit of the file size in the cached stat information, which means cached stat information will have 0 in its sd_size member for a file whose size is multiple of 4GiB. This is mistaken for a racily clean path. Avoid it by storing a bogus sd_size value instead for such files. * bc/racy-4gb-files: Prevent git from rehashing 4GiB files t: add a test helper to truncate files
This commit is contained in:
1
Makefile
1
Makefile
@ -852,6 +852,7 @@ TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
|
||||
TEST_BUILTINS_OBJS += test-submodule.o
|
||||
TEST_BUILTINS_OBJS += test-subprocess.o
|
||||
TEST_BUILTINS_OBJS += test-trace2.o
|
||||
TEST_BUILTINS_OBJS += test-truncate.o
|
||||
TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
|
||||
TEST_BUILTINS_OBJS += test-userdiff.o
|
||||
TEST_BUILTINS_OBJS += test-wildmatch.o
|
||||
|
20
statinfo.c
20
statinfo.c
@ -2,6 +2,22 @@
|
||||
#include "environment.h"
|
||||
#include "statinfo.h"
|
||||
|
||||
/*
|
||||
* Munge st_size into an unsigned int.
|
||||
*/
|
||||
static unsigned int munge_st_size(off_t st_size) {
|
||||
unsigned int sd_size = st_size;
|
||||
|
||||
/*
|
||||
* If the file is an exact multiple of 4 GiB, modify the value so it
|
||||
* doesn't get marked as racily clean (zero).
|
||||
*/
|
||||
if (!sd_size && st_size)
|
||||
return 0x80000000;
|
||||
else
|
||||
return sd_size;
|
||||
}
|
||||
|
||||
void fill_stat_data(struct stat_data *sd, struct stat *st)
|
||||
{
|
||||
sd->sd_ctime.sec = (unsigned int)st->st_ctime;
|
||||
@ -12,7 +28,7 @@ void fill_stat_data(struct stat_data *sd, struct stat *st)
|
||||
sd->sd_ino = st->st_ino;
|
||||
sd->sd_uid = st->st_uid;
|
||||
sd->sd_gid = st->st_gid;
|
||||
sd->sd_size = st->st_size;
|
||||
sd->sd_size = munge_st_size(st->st_size);
|
||||
}
|
||||
|
||||
int match_stat_data(const struct stat_data *sd, struct stat *st)
|
||||
@ -51,7 +67,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
|
||||
changed |= INODE_CHANGED;
|
||||
#endif
|
||||
|
||||
if (sd->sd_size != (unsigned int) st->st_size)
|
||||
if (sd->sd_size != munge_st_size(st->st_size))
|
||||
changed |= DATA_CHANGED;
|
||||
|
||||
return changed;
|
||||
|
@ -86,6 +86,7 @@ static struct test_cmd cmds[] = {
|
||||
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
|
||||
{ "subprocess", cmd__subprocess },
|
||||
{ "trace2", cmd__trace2 },
|
||||
{ "truncate", cmd__truncate },
|
||||
{ "userdiff", cmd__userdiff },
|
||||
{ "urlmatch-normalization", cmd__urlmatch_normalization },
|
||||
{ "xml-encode", cmd__xml_encode },
|
||||
|
@ -79,6 +79,7 @@ int cmd__submodule_config(int argc, const char **argv);
|
||||
int cmd__submodule_nested_repo_config(int argc, const char **argv);
|
||||
int cmd__subprocess(int argc, const char **argv);
|
||||
int cmd__trace2(int argc, const char **argv);
|
||||
int cmd__truncate(int argc, const char **argv);
|
||||
int cmd__userdiff(int argc, const char **argv);
|
||||
int cmd__urlmatch_normalization(int argc, const char **argv);
|
||||
int cmd__xml_encode(int argc, const char **argv);
|
||||
|
25
t/helper/test-truncate.c
Normal file
25
t/helper/test-truncate.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "test-tool.h"
|
||||
#include "git-compat-util.h"
|
||||
|
||||
/*
|
||||
* Truncate a file to the given size.
|
||||
*/
|
||||
int cmd__truncate(int argc, const char **argv)
|
||||
{
|
||||
char *p = NULL;
|
||||
uintmax_t sz = 0;
|
||||
int fd = -1;
|
||||
|
||||
if (argc != 3)
|
||||
die("expected filename and size");
|
||||
|
||||
sz = strtoumax(argv[2], &p, 0);
|
||||
if (*p)
|
||||
die("invalid size");
|
||||
|
||||
fd = xopen(argv[1], O_WRONLY | O_CREAT, 0600);
|
||||
|
||||
if (ftruncate(fd, (off_t) sz) < 0)
|
||||
die_errno("failed to truncate file");
|
||||
return 0;
|
||||
}
|
@ -1745,4 +1745,20 @@ test_expect_success 'slow status advice when core.untrackedCache true, and fsmon
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success EXPENSIVE 'status does not re-read unchanged 4 or 8 GiB file' '
|
||||
(
|
||||
mkdir large-file &&
|
||||
cd large-file &&
|
||||
# Files are 2 GiB, 4 GiB, and 8 GiB sparse files.
|
||||
test-tool truncate file-a 0x080000000 &&
|
||||
test-tool truncate file-b 0x100000000 &&
|
||||
test-tool truncate file-c 0x200000000 &&
|
||||
# This will be slow.
|
||||
git add file-a file-b file-c &&
|
||||
git commit -m "add large files" &&
|
||||
git diff-index HEAD file-a file-b file-c >actual &&
|
||||
test_must_be_empty actual
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Reference in New Issue
Block a user