Skip to content

Commit 41736c7

Browse files
pks-tgitster
authored andcommitted
ref-filter: parse objects on demand
When formatting an arbitray object we parse that object regardless of whether or not we actually need any parsed data. In fact, many of the atoms we have don't require any. Refactor the code so that we parse the data on demand when we see an atom that wants to access the objects. This leads to a small speedup, for example in the Chromium repository with around 40000 refs: Benchmark 1: for-each-ref --format='%(raw)' (HEAD~) Time (mean ± σ): 388.7 ms ± 1.1 ms [User: 322.2 ms, System: 65.0 ms] Range (min … max): 387.3 ms … 390.8 ms 10 runs Benchmark 2: for-each-ref --format='%(raw)' (HEAD) Time (mean ± σ): 344.7 ms ± 0.7 ms [User: 287.8 ms, System: 55.1 ms] Range (min … max): 343.9 ms … 345.7 ms 10 runs Summary for-each-ref --format='%(raw)' (HEAD) ran 1.13 ± 0.00 times faster than for-each-ref --format='%(raw)' (HEAD~) With this change, we now spend ~90% of the time decompressing objects, which is almost as good as it gets regarding git-for-each-ref(1)'s own infrastructure. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e18fd98 commit 41736c7

File tree

1 file changed

+117
-39
lines changed

1 file changed

+117
-39
lines changed

ref-filter.c

Lines changed: 117 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static struct expand_data {
9191
struct object_id delta_base_oid;
9292
void *content;
9393

94+
struct object *maybe_object;
9495
struct object_info info;
9596
} oi, oi_deref;
9697

@@ -1475,18 +1476,46 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_
14751476
}
14761477
}
14771478

1479+
static int get_or_parse_object(struct expand_data *data, const char *refname,
1480+
struct object **object, struct strbuf *err, int *eaten)
1481+
{
1482+
if (!data->maybe_object) {
1483+
data->maybe_object = parse_object_buffer(the_repository, &data->oid, data->type,
1484+
data->size, data->content, eaten);
1485+
if (!data->maybe_object)
1486+
return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
1487+
oid_to_hex(&data->oid), refname);
1488+
}
1489+
1490+
*object = data->maybe_object;
1491+
return 0;
1492+
}
1493+
14781494
/* See grab_values */
1479-
static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
1495+
static int grab_tag_values(struct atom_value *val, int deref,
1496+
struct expand_data *data, const char *refname,
1497+
struct strbuf *err, int *eaten)
14801498
{
1481-
int i;
1482-
struct tag *tag = (struct tag *) obj;
1499+
struct tag *tag = NULL;
1500+
int i, ret;
14831501

14841502
for (i = 0; i < used_atom_cnt; i++) {
14851503
const char *name = used_atom[i].name;
14861504
enum atom_type atom_type = used_atom[i].atom_type;
14871505
struct atom_value *v = &val[i];
14881506
if (!!deref != (*name == '*'))
14891507
continue;
1508+
1509+
if (!tag) {
1510+
struct object *object;
1511+
1512+
ret = get_or_parse_object(data, refname, &object, err, eaten);
1513+
if (ret < 0)
1514+
return ret;
1515+
1516+
tag = (struct tag *) object;
1517+
}
1518+
14901519
if (deref)
14911520
name++;
14921521
if (atom_type == ATOM_TAG)
@@ -1496,22 +1525,38 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob
14961525
else if (atom_type == ATOM_OBJECT && tag->tagged)
14971526
v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
14981527
}
1528+
1529+
return 0;
14991530
}
15001531

15011532
/* See grab_values */
1502-
static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
1533+
static int grab_commit_values(struct atom_value *val, int deref,
1534+
struct expand_data *data, const char *refname,
1535+
struct strbuf *err, int *eaten)
15031536
{
1504-
int i;
1505-
struct commit *commit = (struct commit *) obj;
1537+
int i, ret;
1538+
struct commit *commit = NULL;
15061539

15071540
for (i = 0; i < used_atom_cnt; i++) {
15081541
const char *name = used_atom[i].name;
15091542
enum atom_type atom_type = used_atom[i].atom_type;
15101543
struct atom_value *v = &val[i];
1544+
15111545
if (!!deref != (*name == '*'))
15121546
continue;
15131547
if (deref)
15141548
name++;
1549+
1550+
if (!commit) {
1551+
struct object *object;
1552+
1553+
ret = get_or_parse_object(data, refname, &object, err, eaten);
1554+
if (ret < 0)
1555+
return ret;
1556+
1557+
commit = (struct commit *) object;
1558+
}
1559+
15151560
if (atom_type == ATOM_TREE &&
15161561
grab_oid(name, "tree", get_commit_tree_oid(commit), v, &used_atom[i]))
15171562
continue;
@@ -1531,6 +1576,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
15311576
v->s = strbuf_detach(&s, NULL);
15321577
}
15331578
}
1579+
1580+
return 0;
15341581
}
15351582

15361583
static const char *find_wholine(const char *who, int wholen, const char *buf)
@@ -1759,10 +1806,12 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
17591806
}
17601807
}
17611808

1762-
static void grab_signature(struct atom_value *val, int deref, struct object *obj)
1809+
static int grab_signature(struct atom_value *val, int deref,
1810+
struct expand_data *data, const char *refname,
1811+
struct strbuf *err, int *eaten)
17631812
{
1764-
int i;
1765-
struct commit *commit = (struct commit *) obj;
1813+
int i, ret;
1814+
struct commit *commit = NULL;
17661815
struct signature_check sigc = { 0 };
17671816
int signature_checked = 0;
17681817

@@ -1790,6 +1839,16 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
17901839
continue;
17911840

17921841
if (!signature_checked) {
1842+
if (!commit) {
1843+
struct object *object;
1844+
1845+
ret = get_or_parse_object(data, refname, &object, err, eaten);
1846+
if (ret < 0)
1847+
return ret;
1848+
1849+
commit = (struct commit *) object;
1850+
}
1851+
17931852
check_commit_signature(commit, &sigc);
17941853
signature_checked = 1;
17951854
}
@@ -1843,6 +1902,8 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
18431902

18441903
if (signature_checked)
18451904
signature_check_clear(&sigc);
1905+
1906+
return 0;
18461907
}
18471908

18481909
static void find_subpos(const char *buf,
@@ -1920,9 +1981,8 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
19201981
}
19211982

19221983
static void grab_describe_values(struct atom_value *val, int deref,
1923-
struct object *obj)
1984+
struct expand_data *data)
19241985
{
1925-
struct commit *commit = (struct commit *)obj;
19261986
int i;
19271987

19281988
for (i = 0; i < used_atom_cnt; i++) {
@@ -1944,7 +2004,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
19442004
cmd.git_cmd = 1;
19452005
strvec_push(&cmd.args, "describe");
19462006
strvec_pushv(&cmd.args, atom->u.describe_args.v);
1947-
strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
2007+
strvec_push(&cmd.args, oid_to_hex(&data->oid));
19482008
if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
19492009
error(_("failed to run 'describe'"));
19502010
v->s = xstrdup("");
@@ -2066,24 +2126,36 @@ static void fill_missing_values(struct atom_value *val)
20662126
* pointed at by the ref itself; otherwise it is the object the
20672127
* ref (which is a tag) refers to.
20682128
*/
2069-
static void grab_values(struct atom_value *val, int deref, struct object *obj, struct expand_data *data)
2129+
static int grab_values(struct atom_value *val, int deref, struct expand_data *data,
2130+
const char *refname, struct strbuf *err, int *eaten)
20702131
{
20712132
void *buf = data->content;
2133+
int ret;
20722134

2073-
switch (obj->type) {
2135+
switch (data->type) {
20742136
case OBJ_TAG:
2075-
grab_tag_values(val, deref, obj);
2137+
ret = grab_tag_values(val, deref, data, refname, err, eaten);
2138+
if (ret < 0)
2139+
goto out;
2140+
20762141
grab_sub_body_contents(val, deref, data);
20772142
grab_person("tagger", val, deref, buf);
2078-
grab_describe_values(val, deref, obj);
2143+
grab_describe_values(val, deref, data);
20792144
break;
20802145
case OBJ_COMMIT:
2081-
grab_commit_values(val, deref, obj);
2146+
ret = grab_commit_values(val, deref, data, refname, err, eaten);
2147+
if (ret < 0)
2148+
goto out;
2149+
20822150
grab_sub_body_contents(val, deref, data);
20832151
grab_person("author", val, deref, buf);
20842152
grab_person("committer", val, deref, buf);
2085-
grab_signature(val, deref, obj);
2086-
grab_describe_values(val, deref, obj);
2153+
2154+
ret = grab_signature(val, deref, data, refname, err, eaten);
2155+
if (ret < 0)
2156+
goto out;
2157+
2158+
grab_describe_values(val, deref, data);
20872159
break;
20882160
case OBJ_TREE:
20892161
/* grab_tree_values(val, deref, obj, buf, sz); */
@@ -2094,8 +2166,12 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
20942166
grab_sub_body_contents(val, deref, data);
20952167
break;
20962168
default:
2097-
die("Eh? Object of type %d?", obj->type);
2169+
die("Eh? Object of type %d?", data->type);
20982170
}
2171+
2172+
ret = 0;
2173+
out:
2174+
return ret;
20992175
}
21002176

21012177
static inline char *copy_advance(char *dst, const char *src)
@@ -2292,38 +2368,41 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re
22922368
return show_ref(&atom->u.refname, ref->refname);
22932369
}
22942370

2295-
static int get_object(struct ref_array_item *ref, int deref, struct object **obj,
2371+
static int get_object(struct ref_array_item *ref, int deref,
22962372
struct expand_data *oi, struct strbuf *err)
22972373
{
2298-
/* parse_object_buffer() will set eaten to 0 if free() will be needed */
2299-
int eaten = 1;
2374+
/* parse_object_buffer() will set eaten to 1 if free() will be needed */
2375+
int eaten = 0;
2376+
int ret;
2377+
23002378
if (oi->info.contentp) {
23012379
/* We need to know that to use parse_object_buffer properly */
23022380
oi->info.sizep = &oi->size;
23032381
oi->info.typep = &oi->type;
23042382
}
2383+
23052384
if (odb_read_object_info_extended(the_repository->objects, &oi->oid, &oi->info,
2306-
OBJECT_INFO_LOOKUP_REPLACE))
2307-
return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
2308-
oid_to_hex(&oi->oid), ref->refname);
2385+
OBJECT_INFO_LOOKUP_REPLACE)) {
2386+
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
2387+
oid_to_hex(&oi->oid), ref->refname);
2388+
goto out;
2389+
}
23092390
if (oi->info.disk_sizep && oi->disk_size < 0)
23102391
BUG("Object size is less than zero.");
23112392

23122393
if (oi->info.contentp) {
2313-
*obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);
2314-
if (!*obj) {
2315-
if (!eaten)
2316-
free(oi->content);
2317-
return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
2318-
oid_to_hex(&oi->oid), ref->refname);
2319-
}
2320-
grab_values(ref->value, deref, *obj, oi);
2394+
ret = grab_values(ref->value, deref, oi, ref->refname, err, &eaten);
2395+
if (ret < 0)
2396+
goto out;
23212397
}
23222398

23232399
grab_common_values(ref->value, deref, oi);
2400+
ret = 0;
2401+
2402+
out:
23242403
if (!eaten)
23252404
free(oi->content);
2326-
return 0;
2405+
return ret;
23272406
}
23282407

23292408
static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
@@ -2376,7 +2455,6 @@ static char *get_worktree_path(const struct ref_array_item *ref)
23762455
*/
23772456
static int populate_value(struct ref_array_item *ref, struct strbuf *err)
23782457
{
2379-
struct object *obj;
23802458
int i;
23812459
struct object_info empty = OBJECT_INFO_INIT;
23822460
int ahead_behind_atoms = 0;
@@ -2564,14 +2642,14 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
25642642

25652643

25662644
oi.oid = ref->objectname;
2567-
if (get_object(ref, 0, &obj, &oi, err))
2645+
if (get_object(ref, 0, &oi, err))
25682646
return -1;
25692647

25702648
/*
25712649
* If there is no atom that wants to know about tagged
25722650
* object, we are done.
25732651
*/
2574-
if (!need_tagged || (obj->type != OBJ_TAG))
2652+
if (!need_tagged || (oi.type != OBJ_TAG))
25752653
return 0;
25762654

25772655
/*
@@ -2589,7 +2667,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
25892667
}
25902668
}
25912669

2592-
return get_object(ref, 1, &obj, &oi_deref, err);
2670+
return get_object(ref, 1, &oi_deref, err);
25932671
}
25942672

25952673
/*

0 commit comments

Comments
 (0)