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
next prev parent 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.