зеркало из https://github.com/microsoft/git.git
Merge branch 'jk/repack-tempfile-cleanup'
The way "git repack" creared temporary files when it received a signal was prone to deadlocking, which has been corrected. * jk/repack-tempfile-cleanup: t7700: annotate cruft-pack failure with ok=sigpipe repack: drop remove_temporary_files() repack: use tempfiles for signal cleanup repack: expand error message for missing pack files repack: populate extension bits incrementally repack: convert "names" util bitfield to array
This commit is contained in:
Коммит
c88895e67b
|
@ -91,44 +91,6 @@ static int repack_config(const char *var, const char *value, void *cb)
|
|||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove temporary $GIT_OBJECT_DIRECTORY/pack/.tmp-$$-pack-* files.
|
||||
*/
|
||||
static void remove_temporary_files(void)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
size_t dirlen, prefixlen;
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
|
||||
dir = opendir(packdir);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
/* Point at the slash at the end of ".../objects/pack/" */
|
||||
dirlen = strlen(packdir) + 1;
|
||||
strbuf_addstr(&buf, packtmp);
|
||||
/* Hold the length of ".tmp-%d-pack-" */
|
||||
prefixlen = buf.len - dirlen;
|
||||
|
||||
while ((e = readdir(dir))) {
|
||||
if (strncmp(e->d_name, buf.buf + dirlen, prefixlen))
|
||||
continue;
|
||||
strbuf_setlen(&buf, dirlen);
|
||||
strbuf_addstr(&buf, e->d_name);
|
||||
unlink(buf.buf);
|
||||
}
|
||||
closedir(dir);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
static void remove_pack_on_signal(int signo)
|
||||
{
|
||||
remove_temporary_files();
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds all packs hex strings to either fname_nonkept_list or
|
||||
* fname_kept_list based on whether each pack has a corresponding
|
||||
|
@ -247,11 +209,15 @@ static struct {
|
|||
{".idx"},
|
||||
};
|
||||
|
||||
static unsigned populate_pack_exts(char *name)
|
||||
struct generated_pack_data {
|
||||
struct tempfile *tempfiles[ARRAY_SIZE(exts)];
|
||||
};
|
||||
|
||||
static struct generated_pack_data *populate_pack_exts(const char *name)
|
||||
{
|
||||
struct stat statbuf;
|
||||
struct strbuf path = STRBUF_INIT;
|
||||
unsigned ret = 0;
|
||||
struct generated_pack_data *data = xcalloc(1, sizeof(*data));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(exts); i++) {
|
||||
|
@ -261,11 +227,11 @@ static unsigned populate_pack_exts(char *name)
|
|||
if (stat(path.buf, &statbuf))
|
||||
continue;
|
||||
|
||||
ret |= (1 << i);
|
||||
data->tempfiles[i] = register_tempfile(path.buf);
|
||||
}
|
||||
|
||||
strbuf_release(&path);
|
||||
return ret;
|
||||
return data;
|
||||
}
|
||||
|
||||
static void repack_promisor_objects(const struct pack_objects_args *args,
|
||||
|
@ -320,7 +286,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
|
|||
line.buf);
|
||||
write_promisor_file(promisor_name, NULL, 0);
|
||||
|
||||
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
|
||||
item->util = populate_pack_exts(item->string);
|
||||
|
||||
free(promisor_name);
|
||||
}
|
||||
|
@ -739,10 +705,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
|
|||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
|
||||
if (line.len != the_hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only "
|
||||
"from pack-objects."));
|
||||
string_list_append(names, line.buf);
|
||||
|
||||
item = string_list_append(names, line.buf);
|
||||
item->util = populate_pack_exts(line.buf);
|
||||
}
|
||||
fclose(out);
|
||||
|
||||
|
@ -888,8 +858,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
split_pack_geometry(geometry, geometric_factor);
|
||||
}
|
||||
|
||||
sigchain_push_common(remove_pack_on_signal);
|
||||
|
||||
prepare_pack_objects(&cmd, &po_args);
|
||||
|
||||
show_progress = !po_args.quiet && isatty(2);
|
||||
|
@ -981,9 +949,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
|
||||
out = xfdopen(cmd.out, "r");
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
struct string_list_item *item;
|
||||
|
||||
if (line.len != the_hash_algo->hexsz)
|
||||
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
|
||||
string_list_append(&names, line.buf);
|
||||
item = string_list_append(&names, line.buf);
|
||||
item->util = populate_pack_exts(item->string);
|
||||
}
|
||||
fclose(out);
|
||||
ret = finish_command(&cmd);
|
||||
|
@ -1022,40 +993,38 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
|
||||
string_list_sort(&names);
|
||||
|
||||
for_each_string_list_item(item, &names) {
|
||||
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
|
||||
}
|
||||
|
||||
close_object_store(the_repository->objects);
|
||||
|
||||
/*
|
||||
* Ok we have prepared all new packfiles.
|
||||
*/
|
||||
for_each_string_list_item(item, &names) {
|
||||
struct generated_pack_data *data = item->util;
|
||||
|
||||
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
|
||||
char *fname, *fname_old;
|
||||
char *fname;
|
||||
|
||||
fname = mkpathdup("%s/pack-%s%s",
|
||||
packdir, item->string, exts[ext].name);
|
||||
fname_old = mkpathdup("%s-%s%s",
|
||||
packtmp, item->string, exts[ext].name);
|
||||
|
||||
if (((uintptr_t)item->util) & ((uintptr_t)1 << ext)) {
|
||||
if (data->tempfiles[ext]) {
|
||||
const char *fname_old = get_tempfile_path(data->tempfiles[ext]);
|
||||
struct stat statbuffer;
|
||||
|
||||
if (!stat(fname_old, &statbuffer)) {
|
||||
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
chmod(fname_old, statbuffer.st_mode);
|
||||
}
|
||||
|
||||
if (rename(fname_old, fname))
|
||||
die_errno(_("renaming '%s' failed"), fname_old);
|
||||
if (rename_tempfile(&data->tempfiles[ext], fname))
|
||||
die_errno(_("renaming pack to '%s' failed"), fname);
|
||||
} else if (!exts[ext].optional)
|
||||
die(_("missing required file: %s"), fname_old);
|
||||
die(_("pack-objects did not write a '%s' file for pack %s-%s"),
|
||||
exts[ext].name, packtmp, item->string);
|
||||
else if (unlink(fname) < 0 && errno != ENOENT)
|
||||
die_errno(_("could not unlink: %s"), fname);
|
||||
|
||||
free(fname);
|
||||
free(fname_old);
|
||||
}
|
||||
}
|
||||
/* End of pack replacement. */
|
||||
|
@ -1143,7 +1112,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (run_update_server_info)
|
||||
update_server_info(0);
|
||||
remove_temporary_files();
|
||||
|
||||
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
|
||||
unsigned flags = 0;
|
||||
|
@ -1152,7 +1120,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
write_midx_file(get_object_directory(), NULL, NULL, flags);
|
||||
}
|
||||
|
||||
string_list_clear(&names, 0);
|
||||
string_list_clear(&names, 1);
|
||||
string_list_clear(&existing_nonkept_packs, 0);
|
||||
string_list_clear(&existing_kept_packs, 0);
|
||||
clear_pack_geometry(geometry);
|
||||
|
|
|
@ -477,6 +477,22 @@ test_expect_success TTY '--quiet disables progress' '
|
|||
test_must_be_empty stderr
|
||||
'
|
||||
|
||||
test_expect_success 'clean up .tmp-* packs on error' '
|
||||
test_must_fail ok=sigpipe git \
|
||||
-c repack.cruftwindow=bogus \
|
||||
repack -ad --cruft &&
|
||||
find $objdir/pack -name '.tmp-*' >tmpfiles &&
|
||||
test_must_be_empty tmpfiles
|
||||
'
|
||||
|
||||
test_expect_success 'repack -ad cleans up old .tmp-* packs' '
|
||||
git rev-parse HEAD >input &&
|
||||
git pack-objects $objdir/pack/.tmp-1234 <input &&
|
||||
git repack -ad &&
|
||||
find $objdir/pack -name '.tmp-*' >tmpfiles &&
|
||||
test_must_be_empty tmpfiles
|
||||
'
|
||||
|
||||
test_expect_success 'setup for update-server-info' '
|
||||
git init update-server-info &&
|
||||
test_commit -C update-server-info message
|
||||
|
|
Загрузка…
Ссылка в новой задаче