Skip to content

Commit d9839e0

Browse files
author
Linus Torvalds
committed
Make "fsck-cache" use the same revision tracking structure as "rev-tree".
This makes things a lot more efficient, and makes it trivial to do things like reachability analysis. Add command line flags to tell what the head is, and whether to warn about unreachable objects.
1 parent 33b238d commit d9839e0

File tree

1 file changed

+133
-76
lines changed

1 file changed

+133
-76
lines changed

fsck-cache.c

Lines changed: 133 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,159 @@
33
#include <sys/types.h>
44
#include <dirent.h>
55

6-
struct needs {
7-
unsigned char parent[20];
8-
unsigned char needs[20];
9-
char tag[10];
6+
/*
7+
* The low 16 bits of the "flags" field shows whether
8+
* a commit is part of the path to the root for that
9+
* parent.
10+
*
11+
* Bit 16 is an internal flag that we've seen the
12+
* definition for this rev, and not just seen it as
13+
* a parent target.
14+
*/
15+
#define MAX_COMMITS (16)
16+
#define marked(rev) ((rev)->flags & 0xffff)
17+
#define SEEN 0x10000
18+
#define USED 0x20000
19+
#define REACHABLE 0x40000
20+
21+
static int show_unreachable = 0;
22+
static int head_supplied = 0;
23+
static unsigned char head_sha1[20];
24+
25+
struct parent {
26+
struct revision *parent;
27+
struct parent *next;
1028
};
1129

12-
struct seen {
30+
struct revision {
31+
unsigned int flags;
1332
unsigned char sha1[20];
14-
char tag[10];
15-
unsigned needed;
33+
unsigned long date;
34+
struct parent *parent;
1635
};
1736

18-
static struct needs *needs;
19-
static struct seen *seen;
37+
static struct revision **revs;
38+
static int nr_revs, rev_allocs;
2039

21-
static int nr_seen, alloc_seen, nr_needs, alloc_needs;
22-
23-
/*
24-
* These two functions build up a graph in memory about
25-
* what objects we've referenced, and found, and types..
26-
*/
27-
static int compare_seen(const void *s1, const void *s2)
40+
static int find_rev(unsigned char *sha1)
2841
{
29-
return memcmp(s1, s2, 20);
30-
}
42+
int first = 0, last = nr_revs;
3143

32-
static int lookup_seen(unsigned char *sha1, char *tag)
33-
{
34-
int first = 0, last = nr_seen;
35-
36-
while (last > first) {
37-
int next = (last + first) / 2;
38-
struct seen *s = seen + next;
39-
int cmp = memcmp(sha1, s->sha1, 20);
44+
while (first < last) {
45+
int next = (first + last) / 2;
46+
struct revision *rev = revs[next];
47+
int cmp;
4048

49+
cmp = memcmp(sha1, rev->sha1, 20);
50+
if (!cmp)
51+
return next;
4152
if (cmp < 0) {
4253
last = next;
4354
continue;
4455
}
45-
if (cmp > 0) {
46-
first = next+1;
47-
continue;
48-
}
49-
if (strcmp(tag, s->tag))
50-
break;
51-
s->needed++;
52-
return 1;
56+
first = next+1;
57+
}
58+
return -first-1;
59+
}
60+
61+
static struct revision *lookup_rev(unsigned char *sha1)
62+
{
63+
int pos = find_rev(sha1);
64+
struct revision *n;
65+
66+
if (pos >= 0)
67+
return revs[pos];
68+
69+
pos = -pos-1;
70+
71+
if (rev_allocs == nr_revs) {
72+
rev_allocs = alloc_nr(rev_allocs);
73+
revs = realloc(revs, rev_allocs * sizeof(struct revision *));
74+
}
75+
n = malloc(sizeof(struct revision));
76+
77+
n->flags = 0;
78+
memcpy(n->sha1, sha1, 20);
79+
n->parent = NULL;
80+
81+
/* Insert it into the right place */
82+
memmove(revs + pos + 1, revs + pos, (nr_revs - pos) * sizeof(struct revision *));
83+
revs[pos] = n;
84+
nr_revs++;
85+
86+
return n;
87+
}
88+
89+
static struct revision *add_relationship(struct revision *rev, unsigned char *needs)
90+
{
91+
struct revision *parent_rev = lookup_rev(needs);
92+
struct parent **pp = &rev->parent, *p;
93+
94+
while ((p = *pp) != NULL) {
95+
if (p->parent == parent_rev)
96+
return parent_rev;
97+
pp = &p->next;
98+
}
99+
100+
p = malloc(sizeof(*p));
101+
p->parent = parent_rev;
102+
p->next = NULL;
103+
*pp = p;
104+
return parent_rev;
105+
}
106+
107+
static void mark_reachable(struct revision *rev)
108+
{
109+
struct parent *p = rev->parent;
110+
111+
rev->flags |= REACHABLE | USED;
112+
while (p) {
113+
mark_reachable(p->parent);
114+
p = p->next;
53115
}
54-
return 0;
55116
}
56117

57118
static void check_connectivity(void)
58119
{
59120
int i;
60121

61-
/* Sort the "seen" tags for quicker lookup */
62-
qsort(seen, nr_seen, sizeof(struct seen), compare_seen);
122+
if (head_supplied)
123+
mark_reachable(lookup_rev(head_sha1));
63124

64125
/* Look up all the requirements, warn about missing objects.. */
65-
for (i = 0; i < nr_needs; i++) {
66-
struct needs *n = needs + i;
67-
char hex[60];
126+
for (i = 0; i < nr_revs; i++) {
127+
struct revision *rev = revs[i];
68128

69-
if (lookup_seen(n->needs, n->tag))
129+
if (show_unreachable && !(rev->flags & REACHABLE)) {
130+
printf("unreachable %s\n", sha1_to_hex(rev->sha1));
70131
continue;
71-
strcpy(hex, sha1_to_hex(n->parent));
72-
printf("missing %s: %s referenced by %s\n", n->tag, sha1_to_hex(n->needs), hex);
73-
}
74-
75-
/* Tell the user about things not referenced.. */
76-
for (i = 0; i < nr_seen; i++) {
77-
struct seen *s = seen + i;
132+
}
78133

79-
if (s->needed)
80-
continue;
81-
printf("unreferenced %s: %s\n", s->tag, sha1_to_hex(s->sha1));
134+
switch (rev->flags & (SEEN | USED)) {
135+
case 0:
136+
printf("bad %s\n", sha1_to_hex(rev->sha1));
137+
break;
138+
case USED:
139+
printf("missing %s\n", sha1_to_hex(rev->sha1));
140+
break;
141+
case SEEN:
142+
printf("dangling %s\n", sha1_to_hex(rev->sha1));
143+
break;
144+
}
82145
}
83146
}
84147

85148
static void mark_needs_sha1(unsigned char *parent, const char * tag, unsigned char *child)
86149
{
87-
struct needs *n;
88-
89-
if (nr_needs == alloc_needs) {
90-
alloc_needs = alloc_nr(alloc_needs);
91-
needs = realloc(needs, alloc_needs*sizeof(struct needs));
92-
}
93-
n = needs + nr_needs;
94-
nr_needs++;
95-
memcpy(n->parent, parent, 20);
96-
memcpy(n->needs, child, 20);
97-
strncpy(n->tag, tag, sizeof(n->tag));
150+
struct revision * child_rev = add_relationship(lookup_rev(parent), child);
151+
child_rev->flags |= USED;
98152
}
99153

100154
static int mark_sha1_seen(unsigned char *sha1, char *tag)
101155
{
102-
struct seen *s;
156+
struct revision *rev = lookup_rev(sha1);
103157

104-
if (nr_seen == alloc_seen) {
105-
alloc_seen = alloc_nr(alloc_seen);
106-
seen = realloc(seen, alloc_seen*sizeof(struct seen));
107-
}
108-
s = seen + nr_seen;
109-
memset(s, 0, sizeof(*s));
110-
nr_seen++;
111-
memcpy(s->sha1, sha1, 20);
112-
strncpy(s->tag, tag, sizeof(s->tag));
113-
158+
rev->flags |= SEEN;
114159
return 0;
115160
}
116161

@@ -160,7 +205,7 @@ static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)
160205
parents++;
161206
}
162207
if (!parents)
163-
printf("root: %s\n", sha1_to_hex(sha1));
208+
printf("root %s\n", sha1_to_hex(sha1));
164209
return 0;
165210
}
166211

@@ -237,8 +282,20 @@ int main(int argc, char **argv)
237282
int i;
238283
char *sha1_dir;
239284

240-
if (argc != 1)
241-
usage("fsck-cache");
285+
for (i = 1; i < argc; i++) {
286+
if (!strcmp(argv[i], "--unreachable")) {
287+
show_unreachable = 1;
288+
continue;
289+
}
290+
if (!get_sha1_hex(argv[i], head_sha1)) {
291+
head_supplied = 1;
292+
continue;
293+
}
294+
usage("fsck-cache [[--unreachable] <head-sha1>]");
295+
}
296+
if (show_unreachable && !head_supplied)
297+
usage("unable to do reachability checks without a head");
298+
242299
sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
243300
for (i = 0; i < 256; i++) {
244301
static char dir[4096];

0 commit comments

Comments
 (0)