Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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>
  • Loading branch information...
commit 543c5caa6c93bb3d42545aeef334c6a175384db8 1 parent d90906a
Nguyễn Thái Ngọc Duy authored February 15, 2013 gitster committed February 15, 2013
4  Documentation/git-count-objects.txt
@@ -33,8 +33,8 @@ size-pack: disk space consumed by the packs, in KiB
33 33
 prune-packable: the number of loose objects that are also present in
34 34
 the packs. These objects could be pruned using `git prune-packed`.
35 35
 +
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
38 38
 
39 39
 GIT
40 40
 ---
12  builtin/count-objects.c
@@ -9,6 +9,14 @@
9 9
 #include "builtin.h"
10 10
 #include "parse-options.h"
11 11
 
  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
+
12 20
 static void count_objects(DIR *d, char *path, int len, int verbose,
13 21
 			  unsigned long *loose,
14 22
 			  off_t *loose_size,
@@ -76,7 +84,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
76 84
 	const char *objdir = get_object_directory();
77 85
 	int len = strlen(objdir);
78 86
 	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;
80 88
 	off_t loose_size = 0;
81 89
 	struct option opts[] = {
82 90
 		OPT__VERBOSE(&verbose, N_("be verbose")),
@@ -87,6 +95,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
87 95
 	/* we do not take arguments other than flags for now */
88 96
 	if (argc)
89 97
 		usage_with_options(count_objects_usage, opts);
  98
+	if (verbose)
  99
+		report_garbage = real_report_garbage;
90 100
 	memcpy(path, objdir, len);
91 101
 	if (len && objdir[len-1] != '/')
92 102
 		path[len++] = '/';
3  cache.h
@@ -1057,6 +1057,9 @@ extern const char *parse_feature_value(const char *feature_list, const char *fea
1057 1057
 
1058 1058
 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
1059 1059
 
  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
+
1060 1063
 extern void prepare_packed_git(void);
1061 1064
 extern void reprepare_packed_git(void);
1062 1065
 extern void install_packed_git(struct packed_git *pack);
83  sha1_file.c
@@ -21,6 +21,7 @@
21 21
 #include "sha1-lookup.h"
22 22
 #include "bulk-checkin.h"
23 23
 #include "streaming.h"
  24
+#include "dir.h"
24 25
 
25 26
 #ifndef O_NOATIME
26 27
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -1000,6 +1001,63 @@ void install_packed_git(struct packed_git *pack)
1000 1001
 	packed_git = pack;
1001 1002
 }
1002 1003
 
  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
+
1003 1061
 static void prepare_packed_git_one(char *objdir, int local)
1004 1062
 {
1005 1063
 	/* 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)
1009 1067
 	int len;
1010 1068
 	DIR *dir;
1011 1069
 	struct dirent *de;
  1070
+	struct string_list garbage = STRING_LIST_INIT_DUP;
1012 1071
 
1013 1072
 	sprintf(path, "%s/pack", objdir);
1014 1073
 	len = strlen(path);
@@ -1024,7 +1083,17 @@ static void prepare_packed_git_one(char *objdir, int local)
1024 1083
 		int namelen = strlen(de->d_name);
1025 1084
 		struct packed_git *p;
1026 1085
 
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))
1028 1097
 			continue;
1029 1098
 
1030 1099
 		strcpy(path + len, de->d_name);
@@ -1043,8 +1112,20 @@ static void prepare_packed_git_one(char *objdir, int local)
1043 1112
 			    (p = add_packed_git(path, len + namelen, local)) != NULL)
1044 1113
 				install_packed_git(p);
1045 1114
 		}
  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);
1046 1125
 	}
1047 1126
 	closedir(dir);
  1127
+	report_pack_garbage(&garbage);
  1128
+	string_list_clear(&garbage, 0);
1048 1129
 }
1049 1130
 
1050 1131
 static int sort_pack(const void *a_, const void *b_)
26  t/t5304-prune.sh
@@ -195,4 +195,30 @@ test_expect_success 'gc: prune old objects after local clone' '
195 195
 	)
196 196
 '
197 197
 
  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
+
198 224
 test_done

Git Notes

amlog

Message-Id: <1360930030-21211-1-git-send-email-pclouds@gmail.com>

0 notes on commit 543c5ca

Please sign in to comment.
Something went wrong with that request. Please try again.