Skip to content

Commit 7e8c174

Browse files
author
Linus Torvalds
committed
fsck-cache: sort entries by inode number
This improves the cold-cache behaviour on most filesystems, since it makes the fsck access patterns more regular on the disk, rather than seeking back and forth. Note the "most". Not all filesystems have any relationship between inode number and location on disk.
1 parent 0980d9b commit 7e8c174

File tree

1 file changed

+73
-16
lines changed

1 file changed

+73
-16
lines changed

fsck-cache.c

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,76 @@ static int fsck_tag(struct tag *tag)
8888
return 0;
8989
}
9090

91-
static int fsck_name(char *hex)
91+
static int fsck_sha1(unsigned char *sha1)
9292
{
93+
struct object *obj = parse_object(sha1);
94+
if (!obj)
95+
return -1;
96+
if (obj->type == blob_type)
97+
return 0;
98+
if (obj->type == tree_type)
99+
return fsck_tree((struct tree *) obj);
100+
if (obj->type == commit_type)
101+
return fsck_commit((struct commit *) obj);
102+
if (obj->type == tag_type)
103+
return fsck_tag((struct tag *) obj);
104+
return -1;
105+
}
106+
107+
/*
108+
* This is the sorting chunk size: make it reasonably
109+
* big so that we can sort well..
110+
*/
111+
#define MAX_SHA1_ENTRIES (1024)
112+
113+
struct sha1_entry {
114+
unsigned long ino;
93115
unsigned char sha1[20];
94-
if (!get_sha1_hex(hex, sha1)) {
95-
struct object *obj = parse_object(sha1);
96-
if (!obj)
97-
return -1;
98-
if (obj->type == blob_type)
99-
return 0;
100-
if (obj->type == tree_type)
101-
return fsck_tree((struct tree *) obj);
102-
if (obj->type == commit_type)
103-
return fsck_commit((struct commit *) obj);
104-
if (obj->type == tag_type)
105-
return fsck_tag((struct tag *) obj);
116+
};
117+
118+
static struct {
119+
unsigned long nr;
120+
struct sha1_entry *entry[MAX_SHA1_ENTRIES];
121+
} sha1_list;
122+
123+
static int ino_compare(const void *_a, const void *_b)
124+
{
125+
const struct sha1_entry *a = _a, *b = _b;
126+
unsigned long ino1 = a->ino, ino2 = b->ino;
127+
return ino1 < ino2 ? -1 : ino1 > ino2 ? 1 : 0;
128+
}
129+
130+
static void fsck_sha1_list(void)
131+
{
132+
int i, nr = sha1_list.nr;
133+
134+
qsort(sha1_list.entry, nr, sizeof(struct sha1_entry *), ino_compare);
135+
for (i = 0; i < nr; i++) {
136+
struct sha1_entry *entry = sha1_list.entry[i];
137+
unsigned char *sha1 = entry->sha1;
138+
139+
sha1_list.entry[i] = NULL;
140+
if (fsck_sha1(sha1) < 0)
141+
fprintf(stderr, "bad sha1 entry '%s'\n", sha1_to_hex(sha1));
142+
free(entry);
106143
}
107-
return -1;
144+
sha1_list.nr = 0;
145+
}
146+
147+
static void add_sha1_list(unsigned char *sha1, unsigned long ino)
148+
{
149+
struct sha1_entry *entry = xmalloc(sizeof(*entry));
150+
int nr;
151+
152+
entry->ino = ino;
153+
memcpy(entry->sha1, sha1, 20);
154+
nr = sha1_list.nr;
155+
if (nr == MAX_SHA1_ENTRIES) {
156+
fsck_sha1_list();
157+
nr = 0;
158+
}
159+
sha1_list.entry[nr] = entry;
160+
sha1_list.nr = ++nr;
108161
}
109162

110163
static int fsck_dir(int i, char *path)
@@ -118,6 +171,7 @@ static int fsck_dir(int i, char *path)
118171

119172
while ((de = readdir(dir)) != NULL) {
120173
char name[100];
174+
unsigned char sha1[20];
121175
int len = strlen(de->d_name);
122176

123177
switch (len) {
@@ -131,8 +185,10 @@ static int fsck_dir(int i, char *path)
131185
case 38:
132186
sprintf(name, "%02x", i);
133187
memcpy(name+2, de->d_name, len+1);
134-
if (!fsck_name(name))
135-
continue;
188+
if (get_sha1_hex(name, sha1) < 0)
189+
break;
190+
add_sha1_list(sha1, de->d_ino);
191+
continue;
136192
}
137193
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
138194
}
@@ -170,6 +226,7 @@ int main(int argc, char **argv)
170226
sprintf(dir, "%s/%02x", sha1_dir, i);
171227
fsck_dir(i, dir);
172228
}
229+
fsck_sha1_list();
173230

174231
heads = 0;
175232
for (i = 1; i < argc; i++) {

0 commit comments

Comments
 (0)