Skip to content

Commit bd2c39f

Browse files
Nicolas PitreLinus Torvalds
authored andcommitted
[PATCH] don't load and decompress objects twice with parse_object()
It turns out that parse_object() is loading and decompressing given object to free it just before calling the specific object parsing function which does mmap and decompress the same object again. This patch introduces the ability to parse specific objects directly from a memory buffer. Without this patch, running git-fsck-cache on the kernel repositorytake: real 0m13.006s user 0m11.421s sys 0m1.218s With this patch applied: real 0m8.060s user 0m7.071s sys 0m0.710s The performance increase is significant, and this is kind of a prerequisite for sane delta object support with fsck. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent f4f21ce commit bd2c39f

File tree

9 files changed

+115
-70
lines changed

9 files changed

+115
-70
lines changed

blob.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,29 @@ struct blob *lookup_blob(unsigned char *sha1)
2222
return (struct blob *) obj;
2323
}
2424

25+
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
26+
{
27+
item->object.parsed = 1;
28+
return 0;
29+
}
30+
2531
int parse_blob(struct blob *item)
2632
{
2733
char type[20];
2834
void *buffer;
2935
unsigned long size;
36+
int ret;
37+
3038
if (item->object.parsed)
3139
return 0;
32-
item->object.parsed = 1;
3340
buffer = read_sha1_file(item->object.sha1, type, &size);
3441
if (!buffer)
3542
return error("Could not read %s",
3643
sha1_to_hex(item->object.sha1));
37-
free(buffer);
3844
if (strcmp(type, blob_type))
3945
return error("Object %s not a blob",
4046
sha1_to_hex(item->object.sha1));
41-
return 0;
47+
ret = parse_blob_buffer(item, buffer, size);
48+
free(buffer);
49+
return ret;
4250
}

blob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ struct blob {
1111

1212
struct blob *lookup_blob(unsigned char *sha1);
1313

14+
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
15+
1416
int parse_blob(struct blob *item);
1517

1618
#endif /* BLOB_H */

commit.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,14 @@ static unsigned long parse_commit_date(const char *buf)
4141
return date;
4242
}
4343

44-
int parse_commit(struct commit *item)
44+
int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
4545
{
46-
char type[20];
47-
void * buffer, *bufptr;
48-
unsigned long size;
46+
void *bufptr = buffer;
4947
unsigned char parent[20];
48+
5049
if (item->object.parsed)
5150
return 0;
5251
item->object.parsed = 1;
53-
buffer = bufptr = read_sha1_file(item->object.sha1, type, &size);
54-
if (!buffer)
55-
return error("Could not read %s",
56-
sha1_to_hex(item->object.sha1));
57-
if (strcmp(type, commit_type)) {
58-
free(buffer);
59-
return error("Object %s not a commit",
60-
sha1_to_hex(item->object.sha1));
61-
}
6252
get_sha1_hex(bufptr + 5, parent);
6353
item->tree = lookup_tree(parent);
6454
if (item->tree)
@@ -74,10 +64,32 @@ int parse_commit(struct commit *item)
7464
bufptr += 48;
7565
}
7666
item->date = parse_commit_date(bufptr);
77-
free(buffer);
7867
return 0;
7968
}
8069

70+
int parse_commit(struct commit *item)
71+
{
72+
char type[20];
73+
void *buffer;
74+
unsigned long size;
75+
int ret;
76+
77+
if (item->object.parsed)
78+
return 0;
79+
buffer = read_sha1_file(item->object.sha1, type, &size);
80+
if (!buffer)
81+
return error("Could not read %s",
82+
sha1_to_hex(item->object.sha1));
83+
if (strcmp(type, commit_type)) {
84+
free(buffer);
85+
return error("Object %s not a commit",
86+
sha1_to_hex(item->object.sha1));
87+
}
88+
ret = parse_commit_buffer(item, buffer, size);
89+
free(buffer);
90+
return ret;
91+
}
92+
8193
void commit_list_insert(struct commit *item, struct commit_list **list_p)
8294
{
8395
struct commit_list *new_list = xmalloc(sizeof(struct commit_list));

commit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ extern const char *commit_type;
2020

2121
struct commit *lookup_commit(unsigned char *sha1);
2222

23+
int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
24+
2325
int parse_commit(struct commit *item);
2426

2527
void commit_list_insert(struct commit *item, struct commit_list **list_p);

object.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct object *parse_object(unsigned char *sha1)
104104
unsigned long mapsize;
105105
void *map = map_sha1_file(sha1, &mapsize);
106106
if (map) {
107+
struct object *obj;
107108
char type[100];
108109
unsigned long size;
109110
void *buffer = unpack_sha1_file(map, mapsize, type, &size);
@@ -112,26 +113,27 @@ struct object *parse_object(unsigned char *sha1)
112113
return NULL;
113114
if (check_sha1_signature(sha1, buffer, size, type) < 0)
114115
printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
115-
free(buffer);
116116
if (!strcmp(type, "blob")) {
117-
struct blob *ret = lookup_blob(sha1);
118-
parse_blob(ret);
119-
return &ret->object;
117+
struct blob *blob = lookup_blob(sha1);
118+
parse_blob_buffer(blob, buffer, size);
119+
obj = &blob->object;
120120
} else if (!strcmp(type, "tree")) {
121-
struct tree *ret = lookup_tree(sha1);
122-
parse_tree(ret);
123-
return &ret->object;
121+
struct tree *tree = lookup_tree(sha1);
122+
parse_tree_buffer(tree, buffer, size);
123+
obj = &tree->object;
124124
} else if (!strcmp(type, "commit")) {
125-
struct commit *ret = lookup_commit(sha1);
126-
parse_commit(ret);
127-
return &ret->object;
125+
struct commit *commit = lookup_commit(sha1);
126+
parse_commit_buffer(commit, buffer, size);
127+
obj = &commit->object;
128128
} else if (!strcmp(type, "tag")) {
129-
struct tag *ret = lookup_tag(sha1);
130-
parse_tag(ret);
131-
return &ret->object;
129+
struct tag *tag = lookup_tag(sha1);
130+
parse_tag_buffer(tag, buffer, size);
131+
obj = &tag->object;
132132
} else {
133-
return NULL;
133+
obj = NULL;
134134
}
135+
free(buffer);
136+
return obj;
135137
}
136138
return NULL;
137139
}

tag.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,62 +21,68 @@ struct tag *lookup_tag(unsigned char *sha1)
2121
return (struct tag *) obj;
2222
}
2323

24-
int parse_tag(struct tag *item)
24+
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
2525
{
26-
char type[20];
27-
void *data, *bufptr;
28-
unsigned long size;
2926
int typelen, taglen;
3027
unsigned char object[20];
3128
const char *type_line, *tag_line, *sig_line;
3229

3330
if (item->object.parsed)
3431
return 0;
3532
item->object.parsed = 1;
36-
data = bufptr = read_sha1_file(item->object.sha1, type, &size);
37-
if (!data)
38-
return error("Could not read %s",
39-
sha1_to_hex(item->object.sha1));
40-
if (strcmp(type, tag_type)) {
41-
free(data);
42-
return error("Object %s not a tag",
43-
sha1_to_hex(item->object.sha1));
44-
}
4533

4634
if (size < 64)
47-
goto err;
35+
return -1;
4836
if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object))
49-
goto err;
37+
return -1;
5038

5139
item->tagged = parse_object(object);
5240
if (item->tagged)
5341
add_ref(&item->object, item->tagged);
5442

5543
type_line = data + 48;
5644
if (memcmp("\ntype ", type_line-1, 6))
57-
goto err;
45+
return -1;
5846

5947
tag_line = strchr(type_line, '\n');
6048
if (!tag_line || memcmp("tag ", ++tag_line, 4))
61-
goto err;
49+
return -1;
6250

6351
sig_line = strchr(tag_line, '\n');
6452
if (!sig_line)
65-
goto err;
53+
return -1;
6654
sig_line++;
6755

6856
typelen = tag_line - type_line - strlen("type \n");
6957
if (typelen >= 20)
70-
goto err;
58+
return -1;
7159
taglen = sig_line - tag_line - strlen("tag \n");
7260
item->tag = xmalloc(taglen + 1);
7361
memcpy(item->tag, tag_line + 4, taglen);
7462
item->tag[taglen] = '\0';
7563

76-
free(data);
7764
return 0;
65+
}
7866

79-
err:
67+
int parse_tag(struct tag *item)
68+
{
69+
char type[20];
70+
void *data;
71+
unsigned long size;
72+
int ret;
73+
74+
if (item->object.parsed)
75+
return 0;
76+
data = read_sha1_file(item->object.sha1, type, &size);
77+
if (!data)
78+
return error("Could not read %s",
79+
sha1_to_hex(item->object.sha1));
80+
if (strcmp(type, tag_type)) {
81+
free(data);
82+
return error("Object %s not a tag",
83+
sha1_to_hex(item->object.sha1));
84+
}
85+
ret = parse_tag_buffer(item, data, size);
8086
free(data);
81-
return -1;
87+
return ret;
8288
}

tag.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct tag {
1313
};
1414

1515
extern struct tag *lookup_tag(unsigned char *sha1);
16+
extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);
1617
extern int parse_tag(struct tag *item);
1718

1819
#endif /* TAG_H */

tree.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,14 @@ struct tree *lookup_tree(unsigned char *sha1)
8888
return (struct tree *) obj;
8989
}
9090

91-
int parse_tree(struct tree *item)
91+
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
9292
{
93-
char type[20];
94-
void *buffer, *bufptr;
95-
unsigned long size;
93+
void *bufptr = buffer;
9694
struct tree_entry_list **list_p;
95+
9796
if (item->object.parsed)
9897
return 0;
9998
item->object.parsed = 1;
100-
buffer = bufptr = read_sha1_file(item->object.sha1, type, &size);
101-
if (!buffer)
102-
return error("Could not read %s",
103-
sha1_to_hex(item->object.sha1));
104-
if (strcmp(type, tree_type)) {
105-
free(buffer);
106-
return error("Object %s not a tree",
107-
sha1_to_hex(item->object.sha1));
108-
}
10999
list_p = &item->entries;
110100
while (size) {
111101
struct object *obj;
@@ -115,10 +105,8 @@ int parse_tree(struct tree *item)
115105
char *path = strchr(bufptr, ' ');
116106
unsigned int mode;
117107
if (size < len + 20 || !path ||
118-
sscanf(bufptr, "%o", &mode) != 1) {
119-
free(buffer);
108+
sscanf(bufptr, "%o", &mode) != 1)
120109
return -1;
121-
}
122110

123111
entry = xmalloc(sizeof(struct tree_entry_list));
124112
entry->name = strdup(path + 1);
@@ -144,6 +132,28 @@ int parse_tree(struct tree *item)
144132
*list_p = entry;
145133
list_p = &entry->next;
146134
}
147-
free(buffer);
148135
return 0;
149136
}
137+
138+
int parse_tree(struct tree *item)
139+
{
140+
char type[20];
141+
void *buffer;
142+
unsigned long size;
143+
int ret;
144+
145+
if (item->object.parsed)
146+
return 0;
147+
buffer = read_sha1_file(item->object.sha1, type, &size);
148+
if (!buffer)
149+
return error("Could not read %s",
150+
sha1_to_hex(item->object.sha1));
151+
if (strcmp(type, tree_type)) {
152+
free(buffer);
153+
return error("Object %s not a tree",
154+
sha1_to_hex(item->object.sha1));
155+
}
156+
ret = parse_tree_buffer(item, buffer, size);
157+
free(buffer);
158+
return ret;
159+
}

tree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ struct tree {
2525

2626
struct tree *lookup_tree(unsigned char *sha1);
2727

28+
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
29+
2830
int parse_tree(struct tree *tree);
2931

3032
#endif /* TREE_H */

0 commit comments

Comments
 (0)