git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] odb: do not use "blank" substitute for NULL

From
Aaron Plattner <aplattner@nvidia.com>
Date
Dec 18, 2025, 04:51 UTC
Message-ID
<a31e054e-0eb2-48b9-a802-3592a737d1e3@nvidia.com>
In-Reply-To
<xmqqpl8cxy0j.fsf@gitster.g>
On 12/17/25 7:35 PM, Junio C Hamano wrote:
Show 21 quoted lines
> When various *object_info() functions are given an extended object
> info structure as NULL by a caller that does not want any details,
> the code uses a file-scope static blank_oi to pass it down to the
> helper functions they use, to avoid handling NULL specifically.
> 
> The ps/object-read-stream topic graduated to 'master' recently
> however had a bug that assumed that two identically named file-scope
> static variables in two functions are the same, which of course is
> not the case.  This made "git commit" take 0.38 seconds to 1508
> seconds in some case, as reported by Aaron Plattner here:
> 
>    https://lore.kernel.org/git/f4ba7e89-4717-4b36-921f-56537131fd69@nvidia.com/
> 
> We _could_ move the blank_oi variable to a global scope in BSS to
> fix this regression, but explicitly handling the NULL is a much
> safer fix.  It would also reduce the chance of errors that somebody
> accidentally writes into blank_oi, making its contents dirty, which
> potentially will make subsequent calls into the callpath misbehave.
> 
> By explicitly handling NULL input, we no longer have to worry about
> it.
This reasoning makes sense to me.
Would it make sense to add a
Fixes: 385e18810f10 ("packfile: introduce function to read object info 
from a store")
line?
Show 111 quoted lines
> Reported-by: Aaron Plattner <aplattner@nvidia.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>   object-file.c |  8 ++++----
>   odb.c         | 29 +++++++++++++----------------
>   packfile.c    |  3 +--
>   3 files changed, 18 insertions(+), 22 deletions(-)
> 
> diff --git a/object-file.c b/object-file.c
> index 12177a7dd7..e0cce3a62a 100644
> --- a/object-file.c
> +++ b/object-file.c
> @@ -426,7 +426,7 @@ int odb_source_loose_read_object_info(struct odb_source *source,
>   	unsigned long size_scratch;
>   	enum object_type type_scratch;
>   
> -	if (oi->delta_base_oid)
> +	if (oi && oi->delta_base_oid)
>   		oidclr(oi->delta_base_oid, source->odb->repo->hash_algo);
>   
>   	/*
> @@ -437,13 +437,13 @@ int odb_source_loose_read_object_info(struct odb_source *source,
>   	 * return value implicitly indicates whether the
>   	 * object even exists.
>   	 */
> -	if (!oi->typep && !oi->sizep && !oi->contentp) {
> +	if (!oi || (!oi->typep && !oi->sizep && !oi->contentp)) {
>   		struct stat st;
> -		if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
> +		if ((!oi || !oi->disk_sizep) && (flags & OBJECT_INFO_QUICK))
>   			return quick_has_loose(source->loose, oid) ? 0 : -1;
>   		if (stat_loose_object(source->loose, oid, &st, &path) < 0)
>   			return -1;
> -		if (oi->disk_sizep)
> +		if (oi && oi->disk_sizep)
>   			*oi->disk_sizep = st.st_size;
>   		return 0;
>   	}
> diff --git a/odb.c b/odb.c
> index f4cbee4b04..85dc21b104 100644
> --- a/odb.c
> +++ b/odb.c
> @@ -664,34 +664,31 @@ static int do_oid_object_info_extended(struct object_database *odb,
>   				       const struct object_id *oid,
>   				       struct object_info *oi, unsigned flags)
>   {
> -	static struct object_info blank_oi = OBJECT_INFO_INIT;
>   	const struct cached_object *co;
>   	const struct object_id *real = oid;
>   	int already_retried = 0;
>   
> -
>   	if (flags & OBJECT_INFO_LOOKUP_REPLACE)
>   		real = lookup_replace_object(odb->repo, oid);
>   
>   	if (is_null_oid(real))
>   		return -1;
>   
> -	if (!oi)
> -		oi = &blank_oi;
> -
>   	co = find_cached_object(odb, real);
>   	if (co) {
> -		if (oi->typep)
> -			*(oi->typep) = co->type;
> -		if (oi->sizep)
> -			*(oi->sizep) = co->size;
> -		if (oi->disk_sizep)
> -			*(oi->disk_sizep) = 0;
> -		if (oi->delta_base_oid)
> -			oidclr(oi->delta_base_oid, odb->repo->hash_algo);
> -		if (oi->contentp)
> -			*oi->contentp = xmemdupz(co->buf, co->size);
> -		oi->whence = OI_CACHED;
> +		if (oi) {
> +			if (oi->typep)
> +				*(oi->typep) = co->type;
> +			if (oi->sizep)
> +				*(oi->sizep) = co->size;
> +			if (oi->disk_sizep)
> +				*(oi->disk_sizep) = 0;
> +			if (oi->delta_base_oid)
> +				oidclr(oi->delta_base_oid, odb->repo->hash_algo);
> +			if (oi->contentp)
> +				*oi->contentp = xmemdupz(co->buf, co->size);
> +			oi->whence = OI_CACHED;
> +		}
>   		return 0;
>   	}
>   
> diff --git a/packfile.c b/packfile.c
> index 7a16aaa90d..2aa6135c3a 100644
> --- a/packfile.c
> +++ b/packfile.c
> @@ -2095,7 +2095,6 @@ int packfile_store_read_object_info(struct packfile_store *store,
>   				    struct object_info *oi,
>   				    unsigned flags UNUSED)
>   {
> -	static struct object_info blank_oi = OBJECT_INFO_INIT;
>   	struct pack_entry e;
>   	int rtype;
>   
> @@ -2106,7 +2105,7 @@ int packfile_store_read_object_info(struct packfile_store *store,
>   	 * We know that the caller doesn't actually need the
>   	 * information below, so return early.
>   	 */
> -	if (oi == &blank_oi)
> +	if (!oi)
>   		return 0;
>   
>   	rtype = packed_object_info(store->odb->repo, e.p, e.offset, oi);

This looks good to me and I verified it restores the original performance, so,

Tested-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
Thanks!
-- Aaron
Previous: Patrick SteinhardtNext: Kristoffer Haugsbakk
Message 3 of 8 in “odb: do not use "blank" substitute for NULL”
  1. odb: do not use "blank" substitute for NULLJunio C Hamano, Dec 18, 2025
  2. Patrick SteinhardtDec 18, 2025
  3. Aaron PlattnerDec 18, 2025
  4. Kristoffer HaugsbakkDec 18, 2025
  5. Carlo Marcelo Arenas BelónDec 18, 2025
  6. Kristoffer HaugsbakkDec 19, 2025
  7. Junio C HamanoDec 19, 2025
  8. Patrick SteinhardtDec 18, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.