attr: don't recompute default attribute source

The `default_attr_source()` function lazily computes the attr source supposedly once, only. This is done via a static variable `attr_source` that contains the resolved object ID of the attr source's tree. If the variable is the null object ID then we try to look up the attr source, otherwise we skip over it. This approach is flawed though: the variable will never be set to anything else but the null object ID in case there is no attr source. Consequently, we re-compute the information on every call. And in the worst case, when we silently ignore bad trees, this will cause us to try and look up the treeish every single time. Improve this by introducing a separate variable `has_attr_source` to track whether we already computed the attr source and, if so, whether we have an attr source or not. This also allows us to convert the `ignore_bad_attr_tree` to not be static anymore as the code will only be executed once anyway. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed May 7, 2024 at 06:53 UTC bbb82f8dc88aee588a35615fdb10862f3b41e16c
1 file changed +16 -9
attr.c
+16 -9
@@ -1206,15 +1206,16 @@ static void collect_some_attrs(struct index_state *istate,
1206 }
1207
1208 static const char *default_attr_source_tree_object_name;
1209 -static int ignore_bad_attr_tree;
1209
1210 void set_git_attr_source(const char *tree_object_name)
1211 {
1212 default_attr_source_tree_object_name = xstrdup(tree_object_name);
1213 }
1214
1216 -static void compute_default_attr_source(struct object_id *attr_source)
1215 +static int compute_default_attr_source(struct object_id *attr_source)
1216 {
1217 + int ignore_bad_attr_tree = 0;
1218 +
1219 if (!default_attr_source_tree_object_name)
1220 default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
1221
@@ -1223,22 +1224,28 @@ static void compute_default_attr_source(struct object_id *attr_source)
1224 ignore_bad_attr_tree = 1;
1225 }
1226
1226 - if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
1227 - return;
1227 + if (!default_attr_source_tree_object_name)
1228 + return 0;
1229
1230 if (repo_get_oid_treeish(the_repository,
1231 default_attr_source_tree_object_name,
1231 - attr_source) && !ignore_bad_attr_tree)
1232 - die(_("bad --attr-source or GIT_ATTR_SOURCE"));
1232 + attr_source)) {
1233 + if (!ignore_bad_attr_tree)
1234 + die(_("bad --attr-source or GIT_ATTR_SOURCE"));
1235 + return 0;
1236 + }
1237 +
1238 + return 1;
1239 }
1240
1241 static struct object_id *default_attr_source(void)
1242 {
1243 static struct object_id attr_source;
1244 + static int has_attr_source = -1;
1245
1239 - if (is_null_oid(&attr_source))
1240 - compute_default_attr_source(&attr_source);
1241 - if (is_null_oid(&attr_source))
1246 + if (has_attr_source < 0)
1247 + has_attr_source = compute_default_attr_source(&attr_source);
1248 + if (!has_attr_source)
1249 return NULL;
1250 return &attr_source;
1251 }