Git development
 help / color / mirror / Atom feed
From: Patrick Steinhardt <ps@pks.im>
To: Kristofer Karlsson via GitGitGadget <gitgitgadget@gmail.com>
Cc: git@vger.kernel.org, Kristofer Karlsson <krka@spotify.com>
Subject: Re: [PATCH 2/2] reftable: fix quadratic behavior when re-creating deleted refs
Date: Tue, 7 Jul 2026 17:24:54 +0200	[thread overview]
Message-ID: <ak0aRtvSxSyIWieg@pks.im> (raw)
In-Reply-To: <1459371d3ab2f237152e20040987b4cb6a5eca77.1783344957.git.gitgitgadget@gmail.com>

On Mon, Jul 06, 2026 at 01:35:56PM +0000, Kristofer Karlsson via GitGitGadget wrote:
> From: Kristofer Karlsson <krka@spotify.com>
> 
> When many refs are deleted and then re-created, update-ref exhibits
> quadratic behavior.  With 8000 refs deleted and re-created, the
> runtime is ~15s, quadrupling for each doubling of input size.
> 
> The root cause is the merged iterator's suppress_deletions flag.
> When set, merged_iter_next_void() silently consumes tombstone records
> in a tight internal loop before returning to the caller.  This
> prevents higher-level code from checking iteration bounds (such as
> prefix or refname comparisons) until after all tombstones have been
> scanned.
> 
> This affects two code paths during ref creation:
> 
>  - refs_verify_refnames_available() seeks to "refs/tags/foo-1/" to
>    check for D/F conflicts and must scan through all subsequent
>    tombstones before the caller can see that they are past the prefix
>    of interest.
> 
>  - reftable_backend_read_ref() seeks to a specific refname and must
>    scan through all subsequent tombstones before returning "not
>    found", because the merged iterator skips the matching tombstone
>    and searches for the next live record.

It probably not only impacts reference creation, but also every reader
that wants to search for a specific reference that doesn't exist.

> Fix this by removing suppress_deletions from the merged iterator and
> instead handling deletion records at each call site in the reftable
> backend, where prefix and refname bounds are available.  Tombstones
> are now returned to callers, which skip them after their existing
> bounds checks.  This allows iteration to terminate as soon as a
> tombstone past the relevant bound is encountered.

This option is still used by downstream users of the reftable library,
like libgit2. So we shouldn't just delete it outright.

> diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
> index 4ae22922de..8c4f119ff1 100644
> --- a/refs/reftable-backend.c
> +++ b/refs/reftable-backend.c
> @@ -633,6 +633,9 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
>  			break;
>  		}
>  
> +		if (iter->ref.value_type == REFTABLE_REF_DELETION)
> +			continue;
> +
>  		if (iter->exclude_patterns && should_exclude_current_ref(iter))
>  			continue;
>  

Okay. I was first wondering whether we should move this call earlier.
But we actually don't want to, as this is the code that precedes the
above:

	if (iter->prefix_len &&
	    strncmp(iter->prefix, iter->ref.refname, iter->prefix_len)) {
		iter->err = 1;
		break;
	}

So this allows us to not only skip the current iteration, but completely
abort iteration by observing tombstones that sort after our prefix.

In any case, as far as I can see all sites where we iterate through
either ref or log records have been adapted to handle deletions.

Thanks!

Patrick

  reply	other threads:[~2026-07-07 15:24 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-06 13:35 [PATCH 0/2] reftable: fix quadratic behavior when re-creating deleted refs Kristofer Karlsson via GitGitGadget
2026-07-06 13:35 ` [PATCH 1/2] t: add tests for ref tombstone scenarios Kristofer Karlsson via GitGitGadget
2026-07-07 15:24   ` Patrick Steinhardt
2026-07-07 16:12     ` Kristofer Karlsson
2026-07-08  5:59       ` Patrick Steinhardt
2026-07-08  7:28         ` Kristofer Karlsson
2026-07-06 13:35 ` [PATCH 2/2] reftable: fix quadratic behavior when re-creating deleted refs Kristofer Karlsson via GitGitGadget
2026-07-07 15:24   ` Patrick Steinhardt [this message]
2026-07-07 16:04     ` Kristofer Karlsson
2026-07-08 11:15 ` [PATCH 0/2] " brian m. carlson
2026-07-09 12:08 ` [PATCH v2 " Kristofer Karlsson via GitGitGadget
2026-07-09 12:08   ` [PATCH v2 1/2] t/perf: add perf test for ref tombstone scenarios Kristofer Karlsson via GitGitGadget
2026-07-09 12:08   ` [PATCH v2 2/2] reftable: fix quadratic behavior in the presence of tombstones Kristofer Karlsson via GitGitGadget
2026-07-09 13:53     ` Patrick Steinhardt
2026-07-09 14:48       ` Kristofer Karlsson
2026-07-09 14:54         ` Patrick Steinhardt
2026-07-10 10:36   ` [PATCH v3 0/2] reftable: fix quadratic behavior when re-creating deleted refs Kristofer Karlsson via GitGitGadget
2026-07-10 10:36     ` [PATCH v3 1/2] t/perf: add perf test for ref tombstone scenarios Kristofer Karlsson via GitGitGadget
2026-07-10 10:36     ` [PATCH v3 2/2] reftable: fix quadratic behavior in the presence of tombstones Kristofer Karlsson via GitGitGadget
2026-07-10 14:32       ` Patrick Steinhardt
2026-07-10 15:03         ` Kristofer Karlsson
2026-07-13  5:14           ` Patrick Steinhardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ak0aRtvSxSyIWieg@pks.im \
    --to=ps@pks.im \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=krka@spotify.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox