Skip to content

Commit 543c5ca

Browse files
pcloudsgitster
authored andcommitted
count-objects: report garbage files in pack directory too
prepare_packed_git_one() is modified to allow count-objects to hook a report function to so we don't need to duplicate the pack searching logic in count-objects.c. When report_pack_garbage is NULL, the overhead is insignificant. The garbage is reported with warning() instead of error() in packed garbage case because it's not an error to have garbage. Loose garbage is still reported as errors and will be converted to warnings later. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent d90906a commit 543c5ca

File tree

5 files changed

+124
-4
lines changed

5 files changed

+124
-4
lines changed

Documentation/git-count-objects.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ size-pack: disk space consumed by the packs, in KiB
3333
prune-packable: the number of loose objects that are also present in
3434
the packs. These objects could be pruned using `git prune-packed`.
3535
+
36-
garbage: the number of files in loose object database that are not
37-
valid loose objects
36+
garbage: the number of files in object database that are not valid
37+
loose objects nor valid packs
3838

3939
GIT
4040
---

builtin/count-objects.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
#include "builtin.h"
1010
#include "parse-options.h"
1111

12+
static unsigned long garbage;
13+
14+
static void real_report_garbage(const char *desc, const char *path)
15+
{
16+
warning("%s: %s", desc, path);
17+
garbage++;
18+
}
19+
1220
static void count_objects(DIR *d, char *path, int len, int verbose,
1321
unsigned long *loose,
1422
off_t *loose_size,
@@ -76,7 +84,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
7684
const char *objdir = get_object_directory();
7785
int len = strlen(objdir);
7886
char *path = xmalloc(len + 50);
79-
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
87+
unsigned long loose = 0, packed = 0, packed_loose = 0;
8088
off_t loose_size = 0;
8189
struct option opts[] = {
8290
OPT__VERBOSE(&verbose, N_("be verbose")),
@@ -87,6 +95,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
8795
/* we do not take arguments other than flags for now */
8896
if (argc)
8997
usage_with_options(count_objects_usage, opts);
98+
if (verbose)
99+
report_garbage = real_report_garbage;
90100
memcpy(path, objdir, len);
91101
if (len && objdir[len-1] != '/')
92102
path[len++] = '/';

cache.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,9 @@ extern const char *parse_feature_value(const char *feature_list, const char *fea
10571057

10581058
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
10591059

1060+
/* A hook for count-objects to report invalid files in pack directory */
1061+
extern void (*report_garbage)(const char *desc, const char *path);
1062+
10601063
extern void prepare_packed_git(void);
10611064
extern void reprepare_packed_git(void);
10621065
extern void install_packed_git(struct packed_git *pack);

sha1_file.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "sha1-lookup.h"
2222
#include "bulk-checkin.h"
2323
#include "streaming.h"
24+
#include "dir.h"
2425

2526
#ifndef O_NOATIME
2627
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -1000,6 +1001,63 @@ void install_packed_git(struct packed_git *pack)
10001001
packed_git = pack;
10011002
}
10021003

1004+
void (*report_garbage)(const char *desc, const char *path);
1005+
1006+
static void report_helper(const struct string_list *list,
1007+
int seen_bits, int first, int last)
1008+
{
1009+
const char *msg;
1010+
switch (seen_bits) {
1011+
case 0:
1012+
msg = "no corresponding .idx nor .pack";
1013+
break;
1014+
case 1:
1015+
msg = "no corresponding .idx";
1016+
break;
1017+
case 2:
1018+
msg = "no corresponding .pack";
1019+
break;
1020+
default:
1021+
return;
1022+
}
1023+
for (; first < last; first++)
1024+
report_garbage(msg, list->items[first].string);
1025+
}
1026+
1027+
static void report_pack_garbage(struct string_list *list)
1028+
{
1029+
int i, baselen = -1, first = 0, seen_bits = 0;
1030+
1031+
if (!report_garbage)
1032+
return;
1033+
1034+
sort_string_list(list);
1035+
1036+
for (i = 0; i < list->nr; i++) {
1037+
const char *path = list->items[i].string;
1038+
if (baselen != -1 &&
1039+
strncmp(path, list->items[first].string, baselen)) {
1040+
report_helper(list, seen_bits, first, i);
1041+
baselen = -1;
1042+
seen_bits = 0;
1043+
}
1044+
if (baselen == -1) {
1045+
const char *dot = strrchr(path, '.');
1046+
if (!dot) {
1047+
report_garbage("garbage found", path);
1048+
continue;
1049+
}
1050+
baselen = dot - path + 1;
1051+
first = i;
1052+
}
1053+
if (!strcmp(path + baselen, "pack"))
1054+
seen_bits |= 1;
1055+
else if (!strcmp(path + baselen, "idx"))
1056+
seen_bits |= 2;
1057+
}
1058+
report_helper(list, seen_bits, first, list->nr);
1059+
}
1060+
10031061
static void prepare_packed_git_one(char *objdir, int local)
10041062
{
10051063
/* Ensure that this buffer is large enough so that we can
@@ -1009,6 +1067,7 @@ static void prepare_packed_git_one(char *objdir, int local)
10091067
int len;
10101068
DIR *dir;
10111069
struct dirent *de;
1070+
struct string_list garbage = STRING_LIST_INIT_DUP;
10121071

10131072
sprintf(path, "%s/pack", objdir);
10141073
len = strlen(path);
@@ -1024,7 +1083,17 @@ static void prepare_packed_git_one(char *objdir, int local)
10241083
int namelen = strlen(de->d_name);
10251084
struct packed_git *p;
10261085

1027-
if (len + namelen + 1 > sizeof(path))
1086+
if (len + namelen + 1 > sizeof(path)) {
1087+
if (report_garbage) {
1088+
struct strbuf sb = STRBUF_INIT;
1089+
strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
1090+
report_garbage("path too long", sb.buf);
1091+
strbuf_release(&sb);
1092+
}
1093+
continue;
1094+
}
1095+
1096+
if (is_dot_or_dotdot(de->d_name))
10281097
continue;
10291098

10301099
strcpy(path + len, de->d_name);
@@ -1043,8 +1112,20 @@ static void prepare_packed_git_one(char *objdir, int local)
10431112
(p = add_packed_git(path, len + namelen, local)) != NULL)
10441113
install_packed_git(p);
10451114
}
1115+
1116+
if (!report_garbage)
1117+
continue;
1118+
1119+
if (has_extension(de->d_name, ".idx") ||
1120+
has_extension(de->d_name, ".pack") ||
1121+
has_extension(de->d_name, ".keep"))
1122+
string_list_append(&garbage, path);
1123+
else
1124+
report_garbage("garbage found", path);
10461125
}
10471126
closedir(dir);
1127+
report_pack_garbage(&garbage);
1128+
string_list_clear(&garbage, 0);
10481129
}
10491130

10501131
static int sort_pack(const void *a_, const void *b_)

t/t5304-prune.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,30 @@ test_expect_success 'gc: prune old objects after local clone' '
195195
)
196196
'
197197

198+
test_expect_success 'garbage report in count-objects -v' '
199+
: >.git/objects/pack/foo &&
200+
: >.git/objects/pack/foo.bar &&
201+
: >.git/objects/pack/foo.keep &&
202+
: >.git/objects/pack/foo.pack &&
203+
: >.git/objects/pack/fake.bar &&
204+
: >.git/objects/pack/fake.keep &&
205+
: >.git/objects/pack/fake.pack &&
206+
: >.git/objects/pack/fake.idx &&
207+
: >.git/objects/pack/fake2.keep &&
208+
: >.git/objects/pack/fake3.idx &&
209+
git count-objects -v 2>stderr &&
210+
grep "index file .git/objects/pack/fake.idx is too small" stderr &&
211+
grep "^warning:" stderr | sort >actual &&
212+
cat >expected <<\EOF &&
213+
warning: garbage found: .git/objects/pack/fake.bar
214+
warning: garbage found: .git/objects/pack/foo
215+
warning: garbage found: .git/objects/pack/foo.bar
216+
warning: no corresponding .idx nor .pack: .git/objects/pack/fake2.keep
217+
warning: no corresponding .idx: .git/objects/pack/foo.keep
218+
warning: no corresponding .idx: .git/objects/pack/foo.pack
219+
warning: no corresponding .pack: .git/objects/pack/fake3.idx
220+
EOF
221+
test_cmp expected actual
222+
'
223+
198224
test_done

0 commit comments

Comments
 (0)