Skip to content

Commit 45014be

Browse files
committed
Merge branch 'dk/gc-idx-wo-pack'
Having a leftover .idx file without corresponding .pack file in the repository hurts performance; "git gc" learned to prune them. * dk/gc-idx-wo-pack: gc: remove garbage .idx files from pack dir t5304: test cleaning pack garbage prepare_packed_git(): refactor garbage reporting in pack directory
2 parents f34be46 + 478f34d commit 45014be

File tree

6 files changed

+78
-22
lines changed

6 files changed

+78
-22
lines changed

builtin/count-objects.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,31 @@ static int verbose;
1515
static unsigned long loose, packed, packed_loose;
1616
static off_t loose_size;
1717

18-
static void real_report_garbage(const char *desc, const char *path)
18+
static const char *bits_to_msg(unsigned seen_bits)
19+
{
20+
switch (seen_bits) {
21+
case 0:
22+
return "no corresponding .idx or .pack";
23+
case PACKDIR_FILE_GARBAGE:
24+
return "garbage found";
25+
case PACKDIR_FILE_PACK:
26+
return "no corresponding .idx";
27+
case PACKDIR_FILE_IDX:
28+
return "no corresponding .pack";
29+
case PACKDIR_FILE_PACK|PACKDIR_FILE_IDX:
30+
default:
31+
return NULL;
32+
}
33+
}
34+
35+
static void real_report_garbage(unsigned seen_bits, const char *path)
1936
{
2037
struct stat st;
38+
const char *desc = bits_to_msg(seen_bits);
39+
40+
if (!desc)
41+
return;
42+
2143
if (!stat(path, &st))
2244
size_garbage += st.st_size;
2345
warning("%s: %s", desc, path);
@@ -27,7 +49,7 @@ static void real_report_garbage(const char *desc, const char *path)
2749
static void loose_garbage(const char *path)
2850
{
2951
if (verbose)
30-
report_garbage("garbage found", path);
52+
report_garbage(PACKDIR_FILE_GARBAGE, path);
3153
}
3254

3355
static int count_loose(const unsigned char *sha1, const char *path, void *data)

builtin/gc.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ static struct argv_array rerere = ARGV_ARRAY_INIT;
4646
static struct tempfile pidfile;
4747
static struct lock_file log_lock;
4848

49+
static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
50+
51+
static void clean_pack_garbage(void)
52+
{
53+
int i;
54+
for (i = 0; i < pack_garbage.nr; i++)
55+
unlink_or_warn(pack_garbage.items[i].string);
56+
string_list_clear(&pack_garbage, 0);
57+
}
58+
59+
static void report_pack_garbage(unsigned seen_bits, const char *path)
60+
{
61+
if (seen_bits == PACKDIR_FILE_IDX)
62+
string_list_append(&pack_garbage, path);
63+
}
64+
4965
static void git_config_date_string(const char *key, const char **output)
5066
{
5167
if (git_config_get_string_const(key, output))
@@ -416,6 +432,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
416432
if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
417433
return error(FAILED_RUN, rerere.argv[0]);
418434

435+
report_garbage = report_pack_garbage;
436+
reprepare_packed_git();
437+
if (pack_garbage.nr > 0)
438+
clean_pack_garbage();
439+
419440
if (auto_gc && too_many_loose_objects())
420441
warning(_("There are too many unreachable loose objects; "
421442
"run 'git prune' to remove them."));

cache.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,8 +1289,11 @@ struct pack_entry {
12891289

12901290
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
12911291

1292-
/* A hook for count-objects to report invalid files in pack directory */
1293-
extern void (*report_garbage)(const char *desc, const char *path);
1292+
/* A hook to report invalid files in pack directory */
1293+
#define PACKDIR_FILE_PACK 1
1294+
#define PACKDIR_FILE_IDX 2
1295+
#define PACKDIR_FILE_GARBAGE 4
1296+
extern void (*report_garbage)(unsigned seen_bits, const char *path);
12941297

12951298
extern void prepare_packed_git(void);
12961299
extern void reprepare_packed_git(void);

path.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ void report_linked_checkout_garbage(void)
363363
strbuf_setlen(&sb, len);
364364
strbuf_addstr(&sb, path);
365365
if (file_exists(sb.buf))
366-
report_garbage("unused in linked checkout", sb.buf);
366+
report_garbage(PACKDIR_FILE_GARBAGE, sb.buf);
367367
}
368368
strbuf_release(&sb);
369369
}

sha1_file.c

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,27 +1217,16 @@ void install_packed_git(struct packed_git *pack)
12171217
packed_git = pack;
12181218
}
12191219

1220-
void (*report_garbage)(const char *desc, const char *path);
1220+
void (*report_garbage)(unsigned seen_bits, const char *path);
12211221

12221222
static void report_helper(const struct string_list *list,
12231223
int seen_bits, int first, int last)
12241224
{
1225-
const char *msg;
1226-
switch (seen_bits) {
1227-
case 0:
1228-
msg = "no corresponding .idx or .pack";
1229-
break;
1230-
case 1:
1231-
msg = "no corresponding .idx";
1232-
break;
1233-
case 2:
1234-
msg = "no corresponding .pack";
1235-
break;
1236-
default:
1225+
if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
12371226
return;
1238-
}
1227+
12391228
for (; first < last; first++)
1240-
report_garbage(msg, list->items[first].string);
1229+
report_garbage(seen_bits, list->items[first].string);
12411230
}
12421231

12431232
static void report_pack_garbage(struct string_list *list)
@@ -1260,7 +1249,7 @@ static void report_pack_garbage(struct string_list *list)
12601249
if (baselen == -1) {
12611250
const char *dot = strrchr(path, '.');
12621251
if (!dot) {
1263-
report_garbage("garbage found", path);
1252+
report_garbage(PACKDIR_FILE_GARBAGE, path);
12641253
continue;
12651254
}
12661255
baselen = dot - path + 1;
@@ -1332,7 +1321,7 @@ static void prepare_packed_git_one(char *objdir, int local)
13321321
ends_with(de->d_name, ".keep"))
13331322
string_list_append(&garbage, path.buf);
13341323
else
1335-
report_garbage("garbage found", path.buf);
1324+
report_garbage(PACKDIR_FILE_GARBAGE, path.buf);
13361325
}
13371326
closedir(dir);
13381327
report_pack_garbage(&garbage);

t/t5304-prune.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ test_expect_success 'gc: prune old objects after local clone' '
219219

220220
test_expect_success 'garbage report in count-objects -v' '
221221
test_when_finished "rm -f .git/objects/pack/fake*" &&
222+
test_when_finished "rm -f .git/objects/pack/foo*" &&
222223
: >.git/objects/pack/foo &&
223224
: >.git/objects/pack/foo.bar &&
224225
: >.git/objects/pack/foo.keep &&
@@ -244,6 +245,26 @@ EOF
244245
test_cmp expected actual
245246
'
246247

248+
test_expect_success 'clean pack garbage with gc' '
249+
test_when_finished "rm -f .git/objects/pack/fake*" &&
250+
test_when_finished "rm -f .git/objects/pack/foo*" &&
251+
: >.git/objects/pack/foo.keep &&
252+
: >.git/objects/pack/foo.pack &&
253+
: >.git/objects/pack/fake.idx &&
254+
: >.git/objects/pack/fake2.keep &&
255+
: >.git/objects/pack/fake2.idx &&
256+
: >.git/objects/pack/fake3.keep &&
257+
git gc &&
258+
git count-objects -v 2>stderr &&
259+
grep "^warning:" stderr | sort >actual &&
260+
cat >expected <<\EOF &&
261+
warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep
262+
warning: no corresponding .idx: .git/objects/pack/foo.keep
263+
warning: no corresponding .idx: .git/objects/pack/foo.pack
264+
EOF
265+
test_cmp expected actual
266+
'
267+
247268
test_expect_success 'prune .git/shallow' '
248269
SHA1=`echo hi|git commit-tree HEAD^{tree}` &&
249270
echo $SHA1 >.git/shallow &&

0 commit comments

Comments
 (0)