{"thread":{"id":"48844","subject":"[PATCH 1/4] ref-filter: add info_source to valid_atom","startedAt":"2018-07-09T08:13:00Z","lastAt":"2018-07-10T10:41:36Z","messageCount":10,"participants":["Olga Telezhnaya","Junio C Hamano","Оля Тележная","SZEDER Gábor","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"351928","messageId":"010201647e19c0f0-68cd728f-c86a-4be2-be6b-fd7e19e930fa-000000@eu-west-1.amazonses.com","threadId":"48844","inReplyTo":null,"subject":"[PATCH 1/4] ref-filter: add info_source to valid_atom","fromName":"Olga Telezhnaya","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-09T08:12:54Z","receivedAt":"2018-07-09T08:13:00Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"Add the source of object data to prevent parsing of unneeded data.\nThe goal is to improve performance by avoiding calling expensive\nfunctions when we don't need the information they provide\nor when we could get it by using a cheaper function.\n\nIt is stored in valid_atoms because it depends on the atoms we are\ninterested in.\n\nSigned-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n---\n ref-filter.c | 82 +++++++++++++++++++++++++++++++-----------------------------\n 1 file changed, 43 insertions(+), 39 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex fa3685d91f046..8611c24fd57d1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -41,6 +41,7 @@ void setup_ref_filter_porcelain_msg(void)\n \n typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;\n+typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;\n \n struct align {\n \talign_type position;\n@@ -73,6 +74,7 @@ struct refname_atom {\n static struct used_atom {\n \tconst char *name;\n \tcmp_type type;\n+\tinfo_source source;\n \tunion {\n \t\tchar color[COLOR_MAXLEN];\n \t\tstruct align align;\n@@ -380,49 +382,50 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \n static struct {\n \tconst char *name;\n+\tinfo_source source;\n \tcmp_type cmp_type;\n \tint (*parser)(const struct ref_format *format, struct used_atom *atom,\n \t\t      const char *arg, struct strbuf *err);\n } valid_atom[] = {\n-\t{ \"refname\" , FIELD_STR, refname_atom_parser },\n-\t{ \"objecttype\" },\n-\t{ \"objectsize\", FIELD_ULONG },\n-\t{ \"objectname\", FIELD_STR, objectname_atom_parser },\n-\t{ \"tree\" },\n-\t{ \"parent\" },\n-\t{ \"numparent\", FIELD_ULONG },\n-\t{ \"object\" },\n-\t{ \"type\" },\n-\t{ \"tag\" },\n-\t{ \"author\" },\n-\t{ \"authorname\" },\n-\t{ \"authoremail\" },\n-\t{ \"authordate\", FIELD_TIME },\n-\t{ \"committer\" },\n-\t{ \"committername\" },\n-\t{ \"committeremail\" },\n-\t{ \"committerdate\", FIELD_TIME },\n-\t{ \"tagger\" },\n-\t{ \"taggername\" },\n-\t{ \"taggeremail\" },\n-\t{ \"taggerdate\", FIELD_TIME },\n-\t{ \"creator\" },\n-\t{ \"creatordate\", FIELD_TIME },\n-\t{ \"subject\", FIELD_STR, subject_atom_parser },\n-\t{ \"body\", FIELD_STR, body_atom_parser },\n-\t{ \"trailers\", FIELD_STR, trailers_atom_parser },\n-\t{ \"contents\", FIELD_STR, contents_atom_parser },\n-\t{ \"upstream\", FIELD_STR, remote_ref_atom_parser },\n-\t{ \"push\", FIELD_STR, remote_ref_atom_parser },\n-\t{ \"symref\", FIELD_STR, refname_atom_parser },\n-\t{ \"flag\" },\n-\t{ \"HEAD\", FIELD_STR, head_atom_parser },\n-\t{ \"color\", FIELD_STR, color_atom_parser },\n-\t{ \"align\", FIELD_STR, align_atom_parser },\n-\t{ \"end\" },\n-\t{ \"if\", FIELD_STR, if_atom_parser },\n-\t{ \"then\" },\n-\t{ \"else\" },\n+\t{ \"refname\", SOURCE_NONE, FIELD_STR, refname_atom_parser },\n+\t{ \"objecttype\", SOURCE_OTHER },\n+\t{ \"objectsize\", SOURCE_OTHER, FIELD_ULONG },\n+\t{ \"objectname\", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },\n+\t{ \"tree\", SOURCE_OBJ },\n+\t{ \"parent\", SOURCE_OBJ },\n+\t{ \"numparent\", SOURCE_OBJ, FIELD_ULONG },\n+\t{ \"object\", SOURCE_OBJ },\n+\t{ \"type\", SOURCE_OBJ },\n+\t{ \"tag\", SOURCE_OBJ },\n+\t{ \"author\", SOURCE_OBJ },\n+\t{ \"authorname\", SOURCE_OBJ },\n+\t{ \"authoremail\", SOURCE_OBJ },\n+\t{ \"authordate\", SOURCE_OBJ, FIELD_TIME },\n+\t{ \"committer\", SOURCE_OBJ },\n+\t{ \"committername\", SOURCE_OBJ },\n+\t{ \"committeremail\", SOURCE_OBJ },\n+\t{ \"committerdate\", SOURCE_OBJ, FIELD_TIME },\n+\t{ \"tagger\", SOURCE_OBJ },\n+\t{ \"taggername\", SOURCE_OBJ },\n+\t{ \"taggeremail\", SOURCE_OBJ },\n+\t{ \"taggerdate\", SOURCE_OBJ, FIELD_TIME },\n+\t{ \"creator\", SOURCE_OBJ },\n+\t{ \"creatordate\", SOURCE_OBJ, FIELD_TIME },\n+\t{ \"subject\", SOURCE_OBJ, FIELD_STR, subject_atom_parser },\n+\t{ \"body\", SOURCE_OBJ, FIELD_STR, body_atom_parser },\n+\t{ \"trailers\", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },\n+\t{ \"contents\", SOURCE_OBJ, FIELD_STR, contents_atom_parser },\n+\t{ \"upstream\", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },\n+\t{ \"push\", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },\n+\t{ \"symref\", SOURCE_NONE, FIELD_STR, refname_atom_parser },\n+\t{ \"flag\", SOURCE_NONE },\n+\t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n+\t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n+\t{ \"end\", SOURCE_NONE },\n+\t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n+\t{ \"then\", SOURCE_NONE },\n+\t{ \"else\", SOURCE_NONE },\n };\n \n #define REF_FORMATTING_STATE_INIT  { 0, NULL }\n@@ -498,6 +501,7 @@ static int parse_ref_filter_atom(const struct ref_format *format,\n \tREALLOC_ARRAY(used_atom, used_atom_cnt);\n \tused_atom[at].name = xmemdupz(atom, ep - atom);\n \tused_atom[at].type = valid_atom[i].cmp_type;\n+\tused_atom[at].source = valid_atom[i].source;\n \tif (arg) {\n \t\targ = used_atom[at].name + (arg - atom) + 1;\n \t\tif (!*arg) {\n\n--\nhttps://github.com/git/git/pull/520\n"},{"id":"351929","messageId":"010201647e19c24c-fd353913-225a-4153-aa0f-6ddf41ae6354-000000@eu-west-1.amazonses.com","threadId":"48844","inReplyTo":"010201647e19c0f0-68cd728f-c86a-4be2-be6b-fd7e19e930fa-000000@eu-west-1.amazonses.com","subject":"[PATCH 3/4] ref-filter: merge get_obj and get_object","fromName":"Olga Telezhnaya","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-09T08:12:54Z","receivedAt":"2018-07-09T08:13:05Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"Inline get_obj(): it would be easier to edit the code\nwithout this split.\n\nSigned-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n---\n ref-filter.c | 36 +++++++++++-------------------------\n 1 file changed, 11 insertions(+), 25 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 27733ef013bed..f04169f0ea0e3 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -797,24 +797,6 @@ int verify_ref_format(struct ref_format *format)\n \treturn 0;\n }\n \n-/*\n- * Given an object name, read the object data and size, and return a\n- * \"struct object\".  If the object data we are returning is also borrowed\n- * by the \"struct object\" representation, set *eaten as well---it is a\n- * signal from parse_object_buffer to us not to free the buffer.\n- */\n-static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten)\n-{\n-\tenum object_type type;\n-\tvoid *buf = read_object_file(oid, &type, sz);\n-\n-\tif (buf)\n-\t\t*obj = parse_object_buffer(oid, type, *sz, buf, eaten);\n-\telse\n-\t\t*obj = NULL;\n-\treturn buf;\n-}\n-\n static int grab_objectname(const char *name, const struct object_id *oid,\n \t\t\t   struct atom_value *v, struct used_atom *atom)\n {\n@@ -1437,20 +1419,24 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re\n }\n \n static int get_object(struct ref_array_item *ref, const struct object_id *oid,\n-\t\t       int deref, struct object **obj, struct strbuf *err)\n+\t\t      int deref, struct object **obj, struct strbuf *err)\n {\n \tint eaten;\n \tint ret = 0;\n \tunsigned long size;\n-\tvoid *buf = get_obj(oid, obj, &size, &eaten);\n+\tenum object_type type;\n+\tvoid *buf = read_object_file(oid, &type, &size);\n \tif (!buf)\n \t\tret = strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n \t\t\t\t      oid_to_hex(oid), ref->refname);\n-\telse if (!*obj)\n-\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n-\t\t\t\t      oid_to_hex(oid), ref->refname);\n-\telse\n-\t\tgrab_values(ref->value, deref, *obj, buf, size);\n+\telse {\n+\t\t*obj = parse_object_buffer(oid, type, size, buf, &eaten);\n+\t\tif (!*obj)\n+\t\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n+\t\t\t\t\t      oid_to_hex(oid), ref->refname);\n+\t\telse\n+\t\t\tgrab_values(ref->value, deref, *obj, buf, size);\n+\t}\n \tif (!eaten)\n \t\tfree(buf);\n \treturn ret;\n\n--\nhttps://github.com/git/git/pull/520\n"},{"id":"351930","messageId":"010201647e19c191-8c24e128-8822-4c77-b3bf-60fe17ecb62b-000000@eu-west-1.amazonses.com","threadId":"48844","inReplyTo":"010201647e19c0f0-68cd728f-c86a-4be2-be6b-fd7e19e930fa-000000@eu-west-1.amazonses.com","subject":"[PATCH 2/4] ref-filter: add empty values to technical fields","fromName":"Olga Telezhnaya","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-09T08:12:54Z","receivedAt":"2018-07-09T08:13:07Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"Atoms like \"align\" or \"end\" do not have string representation.\nEarlier we had to go and parse whole object with a hope that we\ncould fill their string representations. It's easier to fill them\nwith an empty string before we start to work with whole object.\n\nSigned-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n---\n ref-filter.c | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 8611c24fd57d1..27733ef013bed 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n \t\t\tconst char *branch_name;\n+\t\t\tv->s = \"\";\n \t\t\t/* only local branches may have an upstream */\n \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n \t\t\t\t\t &branch_name))\n@@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t\t\tcontinue;\n \t\t} else if (atom->u.remote_ref.push) {\n \t\t\tconst char *branch_name;\n+\t\t\tv->s = \"\";\n \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n \t\t\t\t\t &branch_name))\n \t\t\t\tcontinue;\n@@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"align\")) {\n \t\t\tv->handler = align_atom_handler;\n+\t\t\tv->s = \"\";\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"end\")) {\n \t\t\tv->handler = end_atom_handler;\n+\t\t\tv->s = \"\";\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"if\")) {\n \t\t\tconst char *s;\n-\n+\t\t\tv->s = \"\";\n \t\t\tif (skip_prefix(name, \"if:\", &s))\n \t\t\t\tv->s = xstrdup(s);\n \t\t\tv->handler = if_atom_handler;\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"then\")) {\n \t\t\tv->handler = then_atom_handler;\n+\t\t\tv->s = \"\";\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"else\")) {\n \t\t\tv->handler = else_atom_handler;\n+\t\t\tv->s = \"\";\n \t\t\tcontinue;\n \t\t} else\n \t\t\tcontinue;\n\n--\nhttps://github.com/git/git/pull/520\n"},{"id":"351931","messageId":"010201647e19c1cf-c33f2a5c-4741-4bc7-a548-5f76fb83aa97-000000@eu-west-1.amazonses.com","threadId":"48844","inReplyTo":"010201647e19c0f0-68cd728f-c86a-4be2-be6b-fd7e19e930fa-000000@eu-west-1.amazonses.com","subject":"[PATCH 4/4] ref-filter: use oid_object_info() to get object","fromName":"Olga Telezhnaya","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-09T08:12:54Z","receivedAt":"2018-07-09T08:13:11Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"Use oid_object_info_extended() to get object info instead of\nread_object_file().\nIt will help to handle some requests faster (e.g., we do not need to\nparse whole object if we need to know %(objectsize)).\nIt could also help us to add new atoms such as %(objectsize:disk)\nand %(deltabase).\n\nSigned-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n---\n ref-filter.c | 120 +++++++++++++++++++++++++++++++++++++++++++----------------\n 1 file changed, 87 insertions(+), 33 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f04169f0ea0e3..9bf7de4c561cb 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -61,6 +61,17 @@ struct refname_atom {\n \tint lstrip, rstrip;\n };\n \n+struct expand_data {\n+\tstruct object_id oid;\n+\tenum object_type type;\n+\tunsigned long size;\n+\toff_t disk_size;\n+\tstruct object_id delta_base_oid;\n+\tvoid *content;\n+\n+\tstruct object_info info;\n+} oi, oi_deref;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -202,6 +213,30 @@ static int remote_ref_atom_parser(const struct ref_format *format, struct used_a\n \treturn 0;\n }\n \n+static int objecttype_atom_parser(const struct ref_format *format, struct used_atom *atom,\n+\t\t\t\t  const char *arg, struct strbuf *err)\n+{\n+\tif (arg)\n+\t\treturn strbuf_addf_ret(err, -1, _(\"%%(objecttype) does not take arguments\"));\n+\tif (*atom->name == '*')\n+\t\toi_deref.info.typep = &oi_deref.type;\n+\telse\n+\t\toi.info.typep = &oi.type;\n+\treturn 0;\n+}\n+\n+static int objectsize_atom_parser(const struct ref_format *format, struct used_atom *atom,\n+\t\t\t\t  const char *arg, struct strbuf *err)\n+{\n+\tif (arg)\n+\t\treturn strbuf_addf_ret(err, -1, _(\"%%(objectsize) does not take arguments\"));\n+\tif (*atom->name == '*')\n+\t\toi_deref.info.sizep = &oi_deref.size;\n+\telse\n+\t\toi.info.sizep = &oi.size;\n+\treturn 0;\n+}\n+\n static int body_atom_parser(const struct ref_format *format, struct used_atom *atom,\n \t\t\t    const char *arg, struct strbuf *err)\n {\n@@ -388,8 +423,8 @@ static struct {\n \t\t      const char *arg, struct strbuf *err);\n } valid_atom[] = {\n \t{ \"refname\", SOURCE_NONE, FIELD_STR, refname_atom_parser },\n-\t{ \"objecttype\", SOURCE_OTHER },\n-\t{ \"objectsize\", SOURCE_OTHER, FIELD_ULONG },\n+\t{ \"objecttype\", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },\n+\t{ \"objectsize\", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },\n \t{ \"objectname\", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },\n \t{ \"tree\", SOURCE_OBJ },\n \t{ \"parent\", SOURCE_OBJ },\n@@ -502,6 +537,12 @@ static int parse_ref_filter_atom(const struct ref_format *format,\n \tused_atom[at].name = xmemdupz(atom, ep - atom);\n \tused_atom[at].type = valid_atom[i].cmp_type;\n \tused_atom[at].source = valid_atom[i].source;\n+\tif (used_atom[at].source == SOURCE_OBJ) {\n+\t\tif (*atom == '*')\n+\t\t\toi_deref.info.contentp = &oi_deref.content;\n+\t\telse\n+\t\t\toi.info.contentp = &oi.content;\n+\t}\n \tif (arg) {\n \t\targ = used_atom[at].name + (arg - atom) + 1;\n \t\tif (!*arg) {\n@@ -817,7 +858,7 @@ static int grab_objectname(const char *name, const struct object_id *oid,\n }\n \n /* See grab_values */\n-static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+static void grab_common_values(struct atom_value *val, int deref, struct expand_data *oi)\n {\n \tint i;\n \n@@ -829,13 +870,13 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (deref)\n \t\t\tname++;\n \t\tif (!strcmp(name, \"objecttype\"))\n-\t\t\tv->s = type_name(obj->type);\n+\t\t\tv->s = type_name(oi->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->value = sz;\n-\t\t\tv->s = xstrfmt(\"%lu\", sz);\n+\t\t\tv->value = oi->size;\n+\t\t\tv->s = xstrfmt(\"%lu\", oi->size);\n \t\t}\n \t\telse if (deref)\n-\t\t\tgrab_objectname(name, &obj->oid, v, &used_atom[i]);\n+\t\t\tgrab_objectname(name, &oi->oid, v, &used_atom[i]);\n \t}\n }\n \n@@ -1194,7 +1235,6 @@ static void fill_missing_values(struct atom_value *val)\n  */\n static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n {\n-\tgrab_common_values(val, deref, obj, buf, sz);\n \tswitch (obj->type) {\n \tcase OBJ_TAG:\n \t\tgrab_tag_values(val, deref, obj, buf, sz);\n@@ -1418,28 +1458,35 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re\n \treturn show_ref(&atom->u.refname, ref->refname);\n }\n \n-static int get_object(struct ref_array_item *ref, const struct object_id *oid,\n-\t\t      int deref, struct object **obj, struct strbuf *err)\n+static int get_object(struct ref_array_item *ref, int deref, struct object **obj,\n+\t\t      struct expand_data *oi, struct strbuf *err)\n {\n \tint eaten;\n-\tint ret = 0;\n-\tunsigned long size;\n-\tenum object_type type;\n-\tvoid *buf = read_object_file(oid, &type, &size);\n-\tif (!buf)\n-\t\tret = strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n-\t\t\t\t      oid_to_hex(oid), ref->refname);\n-\telse {\n-\t\t*obj = parse_object_buffer(oid, type, size, buf, &eaten);\n-\t\tif (!*obj)\n-\t\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n-\t\t\t\t\t      oid_to_hex(oid), ref->refname);\n-\t\telse\n-\t\t\tgrab_values(ref->value, deref, *obj, buf, size);\n+\tif (oi->info.contentp) {\n+\t\t/* We need to know that to use parse_object_buffer properly */\n+\t\toi->info.sizep = &oi->size;\n+\t\toi->info.typep = &oi->type;\n \t}\n+\tif (oid_object_info_extended(the_repository, &oi->oid, &oi->info,\n+\t\t\t\t     OBJECT_INFO_LOOKUP_REPLACE))\n+\t\treturn strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n+\t\t\t\t       oid_to_hex(&oi->oid), ref->refname);\n+\n+\tif (oi->info.contentp) {\n+\t\t*obj = parse_object_buffer(&oi->oid, oi->type, oi->size, oi->content, &eaten);\n+\t\tif (!obj) {\n+\t\t\tif (!eaten)\n+\t\t\t\tfree(oi->content);\n+\t\t\treturn strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n+\t\t\t\t\t      oid_to_hex(&oi->oid), ref->refname);\n+\t\t}\n+\t\tgrab_values(ref->value, deref, *obj, oi->content, oi->size);\n+\t}\n+\n+\tgrab_common_values(ref->value, deref, oi);\n \tif (!eaten)\n-\t\tfree(buf);\n-\treturn ret;\n+\t\tfree(oi->content);\n+\treturn 0;\n }\n \n /*\n@@ -1449,7 +1496,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n {\n \tstruct object *obj;\n \tint i;\n-\tconst struct object_id *tagged;\n+\tstruct object_info empty = OBJECT_INFO_INIT;\n \n \tref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));\n \n@@ -1569,13 +1616,20 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \tfor (i = 0; i < used_atom_cnt; i++) {\n \t\tstruct atom_value *v = &ref->value[i];\n-\t\tif (v->s == NULL)\n-\t\t\tbreak;\n+\t\tif (v->s == NULL && used_atom[i].source == SOURCE_NONE)\n+\t\t\treturn strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n+\t\t\t\t\t       oid_to_hex(&ref->objectname), ref->refname);\n \t}\n-\tif (used_atom_cnt <= i)\n+\n+\tif (need_tagged)\n+\t\toi.info.contentp = &oi.content;\n+\tif (!memcmp(&oi.info, &empty, sizeof(empty)) &&\n+\t    !memcmp(&oi_deref.info, &empty, sizeof(empty)))\n \t\treturn 0;\n \n-\tif (get_object(ref, &ref->objectname, 0, &obj, err))\n+\n+\toi.oid = ref->objectname;\n+\tif (get_object(ref, 0, &obj, &oi, err))\n \t\treturn -1;\n \n \t/*\n@@ -1589,7 +1643,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t * If it is a tag object, see if we use a value that derefs\n \t * the object, and if we do grab the object it refers to.\n \t */\n-\ttagged = &((struct tag *)obj)->tagged->oid;\n+\toi_deref.oid = ((struct tag *)obj)->tagged->oid;\n \n \t/*\n \t * NEEDSWORK: This derefs tag only once, which\n@@ -1597,7 +1651,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t * is not consistent with what deref_tag() does\n \t * which peels the onion to the core.\n \t */\n-\treturn get_object(ref, tagged, 1, &obj, err);\n+\treturn get_object(ref, 1, &obj, &oi_deref, err);\n }\n \n /*\n\n--\nhttps://github.com/git/git/pull/520\n"},{"id":"352045","messageId":"xmqqzhz09gqj.fsf@gitster-ct.c.googlers.com","threadId":"48844","inReplyTo":"010201647e19c191-8c24e128-8822-4c77-b3bf-60fe17ecb62b-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH 2/4] ref-filter: add empty values to technical fields","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-09T22:39:00Z","receivedAt":"2018-07-09T22:39:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Olga Telezhnaya <olyatelezhnaya@gmail.com> writes:\n\n> Atoms like \"align\" or \"end\" do not have string representation.\n> Earlier we had to go and parse whole object with a hope that we\n> could fill their string representations. It's easier to fill them\n> with an empty string before we start to work with whole object.\n>\n> Signed-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n> ---\n\nJust being curious, but is there any meaningful relationship between\nwhat was labelled as SOURCE_NONE in the previous step and what this\nstep calls \"technical fields\"?  Things like \"upstream\" (which is not\naffected by the contents of the object, but is affected by the ref\nin question) and \"if\" (which merely exists to construct the language\nsyntax) would fall into quite different category, so one might be\nsubset/superset of the other, but I am wondering if we can take\nadvantage of more table-driven approach taken by the previous step. \n\n\n>  ref-filter.c | 8 +++++++-\n>  1 file changed, 7 insertions(+), 1 deletion(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 8611c24fd57d1..27733ef013bed 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \t\t\trefname = get_symref(atom, ref);\n>  \t\telse if (starts_with(name, \"upstream\")) {\n>  \t\t\tconst char *branch_name;\n> +\t\t\tv->s = \"\";\n>  \t\t\t/* only local branches may have an upstream */\n>  \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n>  \t\t\t\t\t &branch_name))\n> @@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \t\t\tcontinue;\n>  \t\t} else if (atom->u.remote_ref.push) {\n>  \t\t\tconst char *branch_name;\n> +\t\t\tv->s = \"\";\n>  \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n>  \t\t\t\t\t &branch_name))\n>  \t\t\t\tcontinue;\n> @@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \t\t\tcontinue;\n>  \t\t} else if (starts_with(name, \"align\")) {\n>  \t\t\tv->handler = align_atom_handler;\n> +\t\t\tv->s = \"\";\n>  \t\t\tcontinue;\n>  \t\t} else if (!strcmp(name, \"end\")) {\n>  \t\t\tv->handler = end_atom_handler;\n> +\t\t\tv->s = \"\";\n>  \t\t\tcontinue;\n>  \t\t} else if (starts_with(name, \"if\")) {\n>  \t\t\tconst char *s;\n> -\n> +\t\t\tv->s = \"\";\n>  \t\t\tif (skip_prefix(name, \"if:\", &s))\n>  \t\t\t\tv->s = xstrdup(s);\n>  \t\t\tv->handler = if_atom_handler;\n>  \t\t\tcontinue;\n>  \t\t} else if (!strcmp(name, \"then\")) {\n>  \t\t\tv->handler = then_atom_handler;\n> +\t\t\tv->s = \"\";\n>  \t\t\tcontinue;\n>  \t\t} else if (!strcmp(name, \"else\")) {\n>  \t\t\tv->handler = else_atom_handler;\n> +\t\t\tv->s = \"\";\n>  \t\t\tcontinue;\n>  \t\t} else\n>  \t\t\tcontinue;\n>\n> --\n> https://github.com/git/git/pull/520\n"},{"id":"352065","messageId":"CAL21Bm=jHiwcau=KoX5cmnZ+8NwQi5ms=GqK52s6GWdaXddraA@mail.gmail.com","threadId":"48844","inReplyTo":"xmqqzhz09gqj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 2/4] ref-filter: add empty values to technical fields","fromName":"Оля Тележная","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-10T07:51:40Z","receivedAt":"2018-07-10T07:51:45Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"2018-07-10 1:39 GMT+03:00 Junio C Hamano <gitster@pobox.com>:\n> Olga Telezhnaya <olyatelezhnaya@gmail.com> writes:\n>\n>> Atoms like \"align\" or \"end\" do not have string representation.\n>> Earlier we had to go and parse whole object with a hope that we\n>> could fill their string representations. It's easier to fill them\n>> with an empty string before we start to work with whole object.\n>>\n>> Signed-off-by: Olga Telezhnaia <olyatelezhnaya@gmail.com>\n>> ---\n>\n> Just being curious, but is there any meaningful relationship between\n> what was labelled as SOURCE_NONE in the previous step and what this\n> step calls \"technical fields\"?  Things like \"upstream\" (which is not\n> affected by the contents of the object, but is affected by the ref\n> in question) and \"if\" (which merely exists to construct the language\n> syntax) would fall into quite different category, so one might be\n> subset/superset of the other, but I am wondering if we can take\n> advantage of more table-driven approach taken by the previous step.\n\nSorry that it was not clear enough.\nSOURCE_NONE fields are the fields that do not require object info.\nBy \"technical fields\" in this particular commit I mean fields that\nwill never be filled. So, it's a good idea to fill such fields with an\nempty string and do not take them into account later (when we are\nthinking whether we need to get and parse an object or not). I guess\nwe do not need to mark these \"technical fields\" in a special way: we\ndon't need this information. Moreover, some of the fields that I\nfilled with an empty string here, sometimes have non-empty\nrepresentation, and I changed nothing for such cases.\n\n>\n>\n>>  ref-filter.c | 8 +++++++-\n>>  1 file changed, 7 insertions(+), 1 deletion(-)\n>>\n>> diff --git a/ref-filter.c b/ref-filter.c\n>> index 8611c24fd57d1..27733ef013bed 100644\n>> --- a/ref-filter.c\n>> +++ b/ref-filter.c\n>> @@ -1497,6 +1497,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>>                       refname = get_symref(atom, ref);\n>>               else if (starts_with(name, \"upstream\")) {\n>>                       const char *branch_name;\n>> +                     v->s = \"\";\n>>                       /* only local branches may have an upstream */\n>>                       if (!skip_prefix(ref->refname, \"refs/heads/\",\n>>                                        &branch_name))\n>> @@ -1509,6 +1510,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>>                       continue;\n>>               } else if (atom->u.remote_ref.push) {\n>>                       const char *branch_name;\n>> +                     v->s = \"\";\n>>                       if (!skip_prefix(ref->refname, \"refs/heads/\",\n>>                                        &branch_name))\n>>                               continue;\n>> @@ -1549,22 +1551,26 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>>                       continue;\n>>               } else if (starts_with(name, \"align\")) {\n>>                       v->handler = align_atom_handler;\n>> +                     v->s = \"\";\n>>                       continue;\n>>               } else if (!strcmp(name, \"end\")) {\n>>                       v->handler = end_atom_handler;\n>> +                     v->s = \"\";\n>>                       continue;\n>>               } else if (starts_with(name, \"if\")) {\n>>                       const char *s;\n>> -\n>> +                     v->s = \"\";\n>>                       if (skip_prefix(name, \"if:\", &s))\n>>                               v->s = xstrdup(s);\n>>                       v->handler = if_atom_handler;\n>>                       continue;\n>>               } else if (!strcmp(name, \"then\")) {\n>>                       v->handler = then_atom_handler;\n>> +                     v->s = \"\";\n>>                       continue;\n>>               } else if (!strcmp(name, \"else\")) {\n>>                       v->handler = else_atom_handler;\n>> +                     v->s = \"\";\n>>                       continue;\n>>               } else\n>>                       continue;\n>>\n>> --\n>> https://github.com/git/git/pull/520\n"},{"id":"352077","messageId":"20180710091925.11061-1-szeder.dev@gmail.com","threadId":"48844","inReplyTo":"010201647e19c24c-fd353913-225a-4153-aa0f-6ddf41ae6354-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH 3/4] ref-filter: merge get_obj and get_object","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-07-10T09:19:25Z","receivedAt":"2018-07-10T09:19:40Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"\n>  static int get_object(struct ref_array_item *ref, const struct object_id *oid,\n> -\t\t       int deref, struct object **obj, struct strbuf *err)\n> +\t\t      int deref, struct object **obj, struct strbuf *err)\n>  {\n>  \tint eaten;\n\nHere the variable 'eaten' is declared, but left uninitialized.  This\nwas fine until now, because ...\n\n>  \tint ret = 0;\n>  \tunsigned long size;\n> -\tvoid *buf = get_obj(oid, obj, &size, &eaten);\n\n... this line used to set it anyway.\n\n> +\tenum object_type type;\n> +\tvoid *buf = read_object_file(oid, &type, &size);\n>  \tif (!buf)\n>  \t\tret = strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n>  \t\t\t\t      oid_to_hex(oid), ref->refname);\n> -\telse if (!*obj)\n> -\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n> -\t\t\t\t      oid_to_hex(oid), ref->refname);\n> -\telse\n> -\t\tgrab_values(ref->value, deref, *obj, buf, size);\n> +\telse {\n> +\t\t*obj = parse_object_buffer(oid, type, size, buf, &eaten);\n\nHowever, with this change 'eaten' is only set here conditionally: if\nread_object_file() doesn't return a valid object buffer, then 'eaten'\nremains uninitialized.\n\n> +\t\tif (!*obj)\n> +\t\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n> +\t\t\t\t\t      oid_to_hex(oid), ref->refname);\n> +\t\telse\n> +\t\t\tgrab_values(ref->value, deref, *obj, buf, size);\n> +\t}\n>  \tif (!eaten)\n\nAnd ultimately this condition could depend on an uninitialized value.\n\n>  \t\tfree(buf);\n>  \treturn ret;\n> \n> --\n> https://github.com/git/git/pull/520\n> \n"},{"id":"352078","messageId":"nycvar.QRO.7.76.6.1807101115570.75@tvgsbejvaqbjf.bet","threadId":"48844","inReplyTo":"010201647e19c24c-fd353913-225a-4153-aa0f-6ddf41ae6354-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH 3/4] ref-filter: merge get_obj and get_object","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-10T09:23:18Z","receivedAt":"2018-07-10T09:23:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Olga,\n\nOn Mon, 9 Jul 2018, Olga Telezhnaya wrote:\n\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 27733ef013bed..f04169f0ea0e3 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1437,20 +1419,24 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re\n>  }\n>  \n>  static int get_object(struct ref_array_item *ref, const struct object_id *oid,\n> -\t\t       int deref, struct object **obj, struct strbuf *err)\n> +\t\t      int deref, struct object **obj, struct strbuf *err)\n>  {\n>  \tint eaten;\n>  \tint ret = 0;\n>  \tunsigned long size;\n> -\tvoid *buf = get_obj(oid, obj, &size, &eaten);\n\nSo previously, `eaten` has been assigned always... but...\n\n> +\tenum object_type type;\n> +\tvoid *buf = read_object_file(oid, &type, &size);\n>  \tif (!buf)\n>  \t\tret = strbuf_addf_ret(err, -1, _(\"missing object %s for %s\"),\n>  \t\t\t\t      oid_to_hex(oid), ref->refname);\n> -\telse if (!*obj)\n> -\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n> -\t\t\t\t      oid_to_hex(oid), ref->refname);\n> -\telse\n> -\t\tgrab_values(ref->value, deref, *obj, buf, size);\n> +\telse {\n> +\t\t*obj = parse_object_buffer(oid, type, size, buf, &eaten);\n\n... now it only gets assigned in case `buf` was non-`NULL`... yet...\n\n> +\t\tif (!*obj)\n> +\t\t\tret = strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n> +\t\t\t\t\t      oid_to_hex(oid), ref->refname);\n> +\t\telse\n> +\t\t\tgrab_values(ref->value, deref, *obj, buf, size);\n> +\t}\n>  \tif (!eaten)\n>\t\tfree(buf);\n\n... here, we still act on `eaten`. This causes GCC to complain thusly:\n\n\n```\n2018-07-10T04:59:38.6368270Z ref-filter.c:1477:6: error: variable 'eaten' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]\n2018-07-10T04:59:38.6468620Z         if (oi->info.contentp) {\n2018-07-10T04:59:38.6568710Z             ^~~~~~~~~~~~~~~~~\n2018-07-10T04:59:38.6669970Z ref-filter.c:1489:7: note: uninitialized use occurs here\n2018-07-10T04:59:38.6774240Z         if (!eaten)\n2018-07-10T04:59:38.6874860Z              ^~~~~\n2018-07-10T04:59:38.6976740Z ref-filter.c:1477:2: note: remove the 'if' if its condition is always true\n2018-07-10T04:59:38.7072330Z         if (oi->info.contentp) {\n2018-07-10T04:59:38.7172760Z         ^~~~~~~~~~~~~~~~~~~~~~~\n2018-07-10T04:59:38.7274040Z ref-filter.c:1466:11: note: initialize the variable 'eaten' to silence this warning\n2018-07-10T04:59:38.7374670Z         int eaten;\n2018-07-10T04:59:38.7474870Z                  ^\n2018-07-10T04:59:38.7575690Z                   = 0\n```\n\n(See\nhttps://mseng.visualstudio.com/VSOnline/_build/results?buildId=6640204&view=logs\nfor details)\n\nI think that GCC is correct, and at the same time, it isn't. Because it\ndoes not matter whether `eaten` is uninitialized here: if it is, then\n`buf` is NULL, and the `free(buf);` call does nothing in particular.\n\nHowever, it *is* sloppy to have a conditional block of code that acts on\nan uninitialized value, whether it has adverse consequences or not. So I\nwould suggest to initialize `eaten` to `1` (not `0` as suggested by GCC\nbecause we can avoid the no-op `free(buf)` while we're already touching\nthat code path).\n\nCiao,\nJohannes\n\n"},{"id":"352081","messageId":"20180710102937.12499-1-szeder.dev@gmail.com","threadId":"48844","inReplyTo":"nycvar.QRO.7.76.6.1807101115570.75@tvgsbejvaqbjf.bet","subject":"Re: [PATCH 3/4] ref-filter: merge get_obj and get_object","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-07-10T10:29:37Z","receivedAt":"2018-07-10T10:29:47Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"\n> This causes GCC to complain thusly:\n> \n> \n> ```\n> 2018-07-10T04:59:38.6368270Z ref-filter.c:1477:6: error: variable 'eaten' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]\n> 2018-07-10T04:59:38.6468620Z         if (oi->info.contentp) {\n> 2018-07-10T04:59:38.6568710Z             ^~~~~~~~~~~~~~~~~\n> 2018-07-10T04:59:38.6669970Z ref-filter.c:1489:7: note: uninitialized use occurs here\n> 2018-07-10T04:59:38.6774240Z         if (!eaten)\n> 2018-07-10T04:59:38.6874860Z              ^~~~~\n> 2018-07-10T04:59:38.6976740Z ref-filter.c:1477:2: note: remove the 'if' if its condition is always true\n> 2018-07-10T04:59:38.7072330Z         if (oi->info.contentp) {\n> 2018-07-10T04:59:38.7172760Z         ^~~~~~~~~~~~~~~~~~~~~~~\n> 2018-07-10T04:59:38.7274040Z ref-filter.c:1466:11: note: initialize the variable 'eaten' to silence this warning\n> 2018-07-10T04:59:38.7374670Z         int eaten;\n> 2018-07-10T04:59:38.7474870Z                  ^\n> 2018-07-10T04:59:38.7575690Z                   = 0\n> ```\n> \n> (See\n> https://mseng.visualstudio.com/VSOnline/_build/results?buildId=6640204&view=logs\n> for details)\n> \n> I think that GCC is correct, and at the same time, it isn't. Because it\n> does not matter whether `eaten` is uninitialized here: \n\nIt's undefined behaviour; 'eaten' is int, and an int may have padding\nbits and trap representations.\n\n> if it is, then\n> `buf` is NULL, and the `free(buf);` call does nothing in particular.\n\n"},{"id":"352082","messageId":"CAL21Bmmm3rO0DjE5aq1NNMJYcUViG4GEXHSgqqmWMnmZt478sg@mail.gmail.com","threadId":"48844","inReplyTo":"20180710102937.12499-1-szeder.dev@gmail.com","subject":"Re: [PATCH 3/4] ref-filter: merge get_obj and get_object","fromName":"Оля Тележная","fromEmail":"olyatelezhnaya@gmail.com","sentAt":"2018-07-10T10:41:32Z","receivedAt":"2018-07-10T10:41:36Z","isPatch":true,"sender":{"key":"olyatelezhnaya@gmail.com","avatar":"https://avatars.githubusercontent.com/u/11246099?v=4"},"body":"Fully agree, thank you so much.\nI have fixed it. Waiting for other issues that need to be fixed, then\nI will re-send the patch.\n\nThank you!\n"}]}