Skip to content

Commit c88895e

Browse files
committed
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
2 parents 75f416e + 9b3fadf commit c88895e

File tree

2 files changed

+45
-61
lines changed

2 files changed

+45
-61
lines changed

builtin/repack.c

Lines changed: 29 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -91,44 +91,6 @@ static int repack_config(const char *var, const char *value, void *cb)
9191
return git_default_config(var, value, cb);
9292
}
9393

94-
/*
95-
* Remove temporary $GIT_OBJECT_DIRECTORY/pack/.tmp-$$-pack-* files.
96-
*/
97-
static void remove_temporary_files(void)
98-
{
99-
struct strbuf buf = STRBUF_INIT;
100-
size_t dirlen, prefixlen;
101-
DIR *dir;
102-
struct dirent *e;
103-
104-
dir = opendir(packdir);
105-
if (!dir)
106-
return;
107-
108-
/* Point at the slash at the end of ".../objects/pack/" */
109-
dirlen = strlen(packdir) + 1;
110-
strbuf_addstr(&buf, packtmp);
111-
/* Hold the length of ".tmp-%d-pack-" */
112-
prefixlen = buf.len - dirlen;
113-
114-
while ((e = readdir(dir))) {
115-
if (strncmp(e->d_name, buf.buf + dirlen, prefixlen))
116-
continue;
117-
strbuf_setlen(&buf, dirlen);
118-
strbuf_addstr(&buf, e->d_name);
119-
unlink(buf.buf);
120-
}
121-
closedir(dir);
122-
strbuf_release(&buf);
123-
}
124-
125-
static void remove_pack_on_signal(int signo)
126-
{
127-
remove_temporary_files();
128-
sigchain_pop(signo);
129-
raise(signo);
130-
}
131-
13294
/*
13395
* Adds all packs hex strings to either fname_nonkept_list or
13496
* fname_kept_list based on whether each pack has a corresponding
@@ -247,11 +209,15 @@ static struct {
247209
{".idx"},
248210
};
249211

250-
static unsigned populate_pack_exts(char *name)
212+
struct generated_pack_data {
213+
struct tempfile *tempfiles[ARRAY_SIZE(exts)];
214+
};
215+
216+
static struct generated_pack_data *populate_pack_exts(const char *name)
251217
{
252218
struct stat statbuf;
253219
struct strbuf path = STRBUF_INIT;
254-
unsigned ret = 0;
220+
struct generated_pack_data *data = xcalloc(1, sizeof(*data));
255221
int i;
256222

257223
for (i = 0; i < ARRAY_SIZE(exts); i++) {
@@ -261,11 +227,11 @@ static unsigned populate_pack_exts(char *name)
261227
if (stat(path.buf, &statbuf))
262228
continue;
263229

264-
ret |= (1 << i);
230+
data->tempfiles[i] = register_tempfile(path.buf);
265231
}
266232

267233
strbuf_release(&path);
268-
return ret;
234+
return data;
269235
}
270236

271237
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,
320286
line.buf);
321287
write_promisor_file(promisor_name, NULL, 0);
322288

323-
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
289+
item->util = populate_pack_exts(item->string);
324290

325291
free(promisor_name);
326292
}
@@ -739,10 +705,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
739705

740706
out = xfdopen(cmd.out, "r");
741707
while (strbuf_getline_lf(&line, out) != EOF) {
708+
struct string_list_item *item;
709+
742710
if (line.len != the_hash_algo->hexsz)
743711
die(_("repack: Expecting full hex object ID lines only "
744712
"from pack-objects."));
745-
string_list_append(names, line.buf);
713+
714+
item = string_list_append(names, line.buf);
715+
item->util = populate_pack_exts(line.buf);
746716
}
747717
fclose(out);
748718

@@ -888,8 +858,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
888858
split_pack_geometry(geometry, geometric_factor);
889859
}
890860

891-
sigchain_push_common(remove_pack_on_signal);
892-
893861
prepare_pack_objects(&cmd, &po_args);
894862

895863
show_progress = !po_args.quiet && isatty(2);
@@ -981,9 +949,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
981949

982950
out = xfdopen(cmd.out, "r");
983951
while (strbuf_getline_lf(&line, out) != EOF) {
952+
struct string_list_item *item;
953+
984954
if (line.len != the_hash_algo->hexsz)
985955
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
986-
string_list_append(&names, line.buf);
956+
item = string_list_append(&names, line.buf);
957+
item->util = populate_pack_exts(item->string);
987958
}
988959
fclose(out);
989960
ret = finish_command(&cmd);
@@ -1022,40 +993,38 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
1022993

1023994
string_list_sort(&names);
1024995

1025-
for_each_string_list_item(item, &names) {
1026-
item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
1027-
}
1028-
1029996
close_object_store(the_repository->objects);
1030997

1031998
/*
1032999
* Ok we have prepared all new packfiles.
10331000
*/
10341001
for_each_string_list_item(item, &names) {
1002+
struct generated_pack_data *data = item->util;
1003+
10351004
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
1036-
char *fname, *fname_old;
1005+
char *fname;
10371006

10381007
fname = mkpathdup("%s/pack-%s%s",
10391008
packdir, item->string, exts[ext].name);
1040-
fname_old = mkpathdup("%s-%s%s",
1041-
packtmp, item->string, exts[ext].name);
10421009

1043-
if (((uintptr_t)item->util) & ((uintptr_t)1 << ext)) {
1010+
if (data->tempfiles[ext]) {
1011+
const char *fname_old = get_tempfile_path(data->tempfiles[ext]);
10441012
struct stat statbuffer;
1013+
10451014
if (!stat(fname_old, &statbuffer)) {
10461015
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
10471016
chmod(fname_old, statbuffer.st_mode);
10481017
}
10491018

1050-
if (rename(fname_old, fname))
1051-
die_errno(_("renaming '%s' failed"), fname_old);
1019+
if (rename_tempfile(&data->tempfiles[ext], fname))
1020+
die_errno(_("renaming pack to '%s' failed"), fname);
10521021
} else if (!exts[ext].optional)
1053-
die(_("missing required file: %s"), fname_old);
1022+
die(_("pack-objects did not write a '%s' file for pack %s-%s"),
1023+
exts[ext].name, packtmp, item->string);
10541024
else if (unlink(fname) < 0 && errno != ENOENT)
10551025
die_errno(_("could not unlink: %s"), fname);
10561026

10571027
free(fname);
1058-
free(fname_old);
10591028
}
10601029
}
10611030
/* End of pack replacement. */
@@ -1143,7 +1112,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
11431112

11441113
if (run_update_server_info)
11451114
update_server_info(0);
1146-
remove_temporary_files();
11471115

11481116
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
11491117
unsigned flags = 0;
@@ -1152,7 +1120,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
11521120
write_midx_file(get_object_directory(), NULL, NULL, flags);
11531121
}
11541122

1155-
string_list_clear(&names, 0);
1123+
string_list_clear(&names, 1);
11561124
string_list_clear(&existing_nonkept_packs, 0);
11571125
string_list_clear(&existing_kept_packs, 0);
11581126
clear_pack_geometry(geometry);

t/t7700-repack.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,22 @@ test_expect_success TTY '--quiet disables progress' '
477477
test_must_be_empty stderr
478478
'
479479

480+
test_expect_success 'clean up .tmp-* packs on error' '
481+
test_must_fail ok=sigpipe git \
482+
-c repack.cruftwindow=bogus \
483+
repack -ad --cruft &&
484+
find $objdir/pack -name '.tmp-*' >tmpfiles &&
485+
test_must_be_empty tmpfiles
486+
'
487+
488+
test_expect_success 'repack -ad cleans up old .tmp-* packs' '
489+
git rev-parse HEAD >input &&
490+
git pack-objects $objdir/pack/.tmp-1234 <input &&
491+
git repack -ad &&
492+
find $objdir/pack -name '.tmp-*' >tmpfiles &&
493+
test_must_be_empty tmpfiles
494+
'
495+
480496
test_expect_success 'setup for update-server-info' '
481497
git init update-server-info &&
482498
test_commit -C update-server-info message

0 commit comments

Comments
 (0)