Skip to content

Commit 054f5f4

Browse files
pks-tgitster
authored andcommitted
ref-filter: parse objects on demand
When formatting an arbitrary 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 <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 0029167 commit 054f5f4

File tree

1 file changed

+106
-36
lines changed

1 file changed

+106
-36
lines changed

ref-filter.c

Lines changed: 106 additions & 36 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,44 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_
14751476
}
14761477
}
14771478

1479+
static struct object *get_or_parse_object(struct expand_data *data, const char *refname,
1480+
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+
strbuf_addf(err, _("parse_object_buffer failed on %s for %s"),
1487+
oid_to_hex(&data->oid), refname);
1488+
return NULL;
1489+
}
1490+
}
1491+
1492+
return data->maybe_object;
1493+
}
1494+
14781495
/* See grab_values */
1479-
static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
1496+
static int grab_tag_values(struct atom_value *val, int deref,
1497+
struct expand_data *data, const char *refname,
1498+
struct strbuf *err, int *eaten)
14801499
{
1500+
struct tag *tag = NULL;
14811501
int i;
1482-
struct tag *tag = (struct tag *) obj;
14831502

14841503
for (i = 0; i < used_atom_cnt; i++) {
14851504
const char *name = used_atom[i].name;
14861505
enum atom_type atom_type = used_atom[i].atom_type;
14871506
struct atom_value *v = &val[i];
14881507
if (!!deref != (*name == '*'))
14891508
continue;
1509+
1510+
if (!tag) {
1511+
tag = (struct tag *) get_or_parse_object(data, refname,
1512+
err, eaten);
1513+
if (!tag)
1514+
return -1;
1515+
}
1516+
14901517
if (deref)
14911518
name++;
14921519
if (atom_type == ATOM_TAG)
@@ -1496,22 +1523,35 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob
14961523
else if (atom_type == ATOM_OBJECT && tag->tagged)
14971524
v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
14981525
}
1526+
1527+
return 0;
14991528
}
15001529

15011530
/* See grab_values */
1502-
static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
1531+
static int grab_commit_values(struct atom_value *val, int deref,
1532+
struct expand_data *data, const char *refname,
1533+
struct strbuf *err, int *eaten)
15031534
{
15041535
int i;
1505-
struct commit *commit = (struct commit *) obj;
1536+
struct commit *commit = NULL;
15061537

15071538
for (i = 0; i < used_atom_cnt; i++) {
15081539
const char *name = used_atom[i].name;
15091540
enum atom_type atom_type = used_atom[i].atom_type;
15101541
struct atom_value *v = &val[i];
1542+
15111543
if (!!deref != (*name == '*'))
15121544
continue;
15131545
if (deref)
15141546
name++;
1547+
1548+
if (!commit) {
1549+
commit = (struct commit *) get_or_parse_object(data, refname,
1550+
err, eaten);
1551+
if (!commit)
1552+
return -1;
1553+
}
1554+
15151555
if (atom_type == ATOM_TREE &&
15161556
grab_oid(name, "tree", get_commit_tree_oid(commit), v, &used_atom[i]))
15171557
continue;
@@ -1531,6 +1571,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
15311571
v->s = strbuf_detach(&s, NULL);
15321572
}
15331573
}
1574+
1575+
return 0;
15341576
}
15351577

15361578
static const char *find_wholine(const char *who, int wholen, const char *buf)
@@ -1759,10 +1801,12 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
17591801
}
17601802
}
17611803

1762-
static void grab_signature(struct atom_value *val, int deref, struct object *obj)
1804+
static int grab_signature(struct atom_value *val, int deref,
1805+
struct expand_data *data, const char *refname,
1806+
struct strbuf *err, int *eaten)
17631807
{
17641808
int i;
1765-
struct commit *commit = (struct commit *) obj;
1809+
struct commit *commit = NULL;
17661810
struct signature_check sigc = { 0 };
17671811
int signature_checked = 0;
17681812

@@ -1790,6 +1834,13 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
17901834
continue;
17911835

17921836
if (!signature_checked) {
1837+
if (!commit) {
1838+
commit = (struct commit *) get_or_parse_object(data, refname,
1839+
err, eaten);
1840+
if (!commit)
1841+
return -1;
1842+
}
1843+
17931844
check_commit_signature(commit, &sigc);
17941845
signature_checked = 1;
17951846
}
@@ -1843,6 +1894,8 @@ static void grab_signature(struct atom_value *val, int deref, struct object *obj
18431894

18441895
if (signature_checked)
18451896
signature_check_clear(&sigc);
1897+
1898+
return 0;
18461899
}
18471900

18481901
static void find_subpos(const char *buf,
@@ -1920,9 +1973,8 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
19201973
}
19211974

19221975
static void grab_describe_values(struct atom_value *val, int deref,
1923-
struct object *obj)
1976+
struct expand_data *data)
19241977
{
1925-
struct commit *commit = (struct commit *)obj;
19261978
int i;
19271979

19281980
for (i = 0; i < used_atom_cnt; i++) {
@@ -1944,7 +1996,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
19441996
cmd.git_cmd = 1;
19451997
strvec_push(&cmd.args, "describe");
19461998
strvec_pushv(&cmd.args, atom->u.describe_args.v);
1947-
strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
1999+
strvec_push(&cmd.args, oid_to_hex(&data->oid));
19482000
if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
19492001
error(_("failed to run 'describe'"));
19502002
v->s = xstrdup("");
@@ -2066,24 +2118,36 @@ static void fill_missing_values(struct atom_value *val)
20662118
* pointed at by the ref itself; otherwise it is the object the
20672119
* ref (which is a tag) refers to.
20682120
*/
2069-
static void grab_values(struct atom_value *val, int deref, struct object *obj, struct expand_data *data)
2121+
static int grab_values(struct atom_value *val, int deref, struct expand_data *data,
2122+
const char *refname, struct strbuf *err, int *eaten)
20702123
{
20712124
void *buf = data->content;
2125+
int ret;
20722126

2073-
switch (obj->type) {
2127+
switch (data->type) {
20742128
case OBJ_TAG:
2075-
grab_tag_values(val, deref, obj);
2129+
ret = grab_tag_values(val, deref, data, refname, err, eaten);
2130+
if (ret < 0)
2131+
goto out;
2132+
20762133
grab_sub_body_contents(val, deref, data);
20772134
grab_person("tagger", val, deref, buf);
2078-
grab_describe_values(val, deref, obj);
2135+
grab_describe_values(val, deref, data);
20792136
break;
20802137
case OBJ_COMMIT:
2081-
grab_commit_values(val, deref, obj);
2138+
ret = grab_commit_values(val, deref, data, refname, err, eaten);
2139+
if (ret < 0)
2140+
goto out;
2141+
20822142
grab_sub_body_contents(val, deref, data);
20832143
grab_person("author", val, deref, buf);
20842144
grab_person("committer", val, deref, buf);
2085-
grab_signature(val, deref, obj);
2086-
grab_describe_values(val, deref, obj);
2145+
2146+
ret = grab_signature(val, deref, data, refname, err, eaten);
2147+
if (ret < 0)
2148+
goto out;
2149+
2150+
grab_describe_values(val, deref, data);
20872151
break;
20882152
case OBJ_TREE:
20892153
/* grab_tree_values(val, deref, obj, buf, sz); */
@@ -2094,8 +2158,12 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
20942158
grab_sub_body_contents(val, deref, data);
20952159
break;
20962160
default:
2097-
die("Eh? Object of type %d?", obj->type);
2161+
die("Eh? Object of type %d?", data->type);
20982162
}
2163+
2164+
ret = 0;
2165+
out:
2166+
return ret;
20992167
}
21002168

21012169
static inline char *copy_advance(char *dst, const char *src)
@@ -2292,38 +2360,41 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re
22922360
return show_ref(&atom->u.refname, ref->refname);
22932361
}
22942362

2295-
static int get_object(struct ref_array_item *ref, int deref, struct object **obj,
2363+
static int get_object(struct ref_array_item *ref, int deref,
22962364
struct expand_data *oi, struct strbuf *err)
22972365
{
2298-
/* parse_object_buffer() will set eaten to 0 if free() will be needed */
2299-
int eaten = 1;
2366+
/* parse_object_buffer() will set eaten to 1 if free() will be needed */
2367+
int eaten = 0;
2368+
int ret;
2369+
23002370
if (oi->info.contentp) {
23012371
/* We need to know that to use parse_object_buffer properly */
23022372
oi->info.sizep = &oi->size;
23032373
oi->info.typep = &oi->type;
23042374
}
2375+
23052376
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);
2377+
OBJECT_INFO_LOOKUP_REPLACE)) {
2378+
ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
2379+
oid_to_hex(&oi->oid), ref->refname);
2380+
goto out;
2381+
}
23092382
if (oi->info.disk_sizep && oi->disk_size < 0)
23102383
BUG("Object size is less than zero.");
23112384

23122385
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);
2386+
ret = grab_values(ref->value, deref, oi, ref->refname, err, &eaten);
2387+
if (ret < 0)
2388+
goto out;
23212389
}
23222390

23232391
grab_common_values(ref->value, deref, oi);
2392+
ret = 0;
2393+
2394+
out:
23242395
if (!eaten)
23252396
free(oi->content);
2326-
return 0;
2397+
return ret;
23272398
}
23282399

23292400
static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
@@ -2376,7 +2447,6 @@ static char *get_worktree_path(const struct ref_array_item *ref)
23762447
*/
23772448
static int populate_value(struct ref_array_item *ref, struct strbuf *err)
23782449
{
2379-
struct object *obj;
23802450
int i;
23812451
struct object_info empty = OBJECT_INFO_INIT;
23822452
int ahead_behind_atoms = 0;
@@ -2564,14 +2634,14 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
25642634

25652635

25662636
oi.oid = ref->objectname;
2567-
if (get_object(ref, 0, &obj, &oi, err))
2637+
if (get_object(ref, 0, &oi, err))
25682638
return -1;
25692639

25702640
/*
25712641
* If there is no atom that wants to know about tagged
25722642
* object, we are done.
25732643
*/
2574-
if (!need_tagged || (obj->type != OBJ_TAG))
2644+
if (!need_tagged || (oi.type != OBJ_TAG))
25752645
return 0;
25762646

25772647
/*
@@ -2589,7 +2659,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
25892659
}
25902660
}
25912661

2592-
return get_object(ref, 1, &obj, &oi_deref, err);
2662+
return get_object(ref, 1, &oi_deref, err);
25932663
}
25942664

25952665
/*

0 commit comments

Comments
 (0)