refs: selectively set prefix in the seek functions

The ref iterator exposes a `ref_iterator_seek()` function. The name
suggests that this would seek the iterator to a specific reference in
some ways similar to how `fseek()` works for the filesystem.

However, the function actually sets the prefix for refs iteration. So
further iteration would only yield references which match the particular
prefix. This is a bit confusing.

Let's add a 'flags' field to the function, which when set with the
'REF_ITERATOR_SEEK_SET_PREFIX' flag, will set the prefix for the
iteration in-line with the existing behavior. Otherwise, the reference
backends will simply seek to the specified reference and clears any
previously set prefix. This allows users to start iteration from a
specific reference.

In the packed and reftable backend, since references are available in a
sorted list, the changes are simply setting the prefix if needed. The
changes on the files-backend are a little more involved, since the files
backend uses the 'ref-cache' mechanism. We move out the existing logic
within `cache_ref_iterator_seek()` to `cache_ref_iterator_set_prefix()`
which is called when the 'REF_ITERATOR_SEEK_SET_PREFIX' flag is set. We
then parse the provided seek string and set the required levels and
their indexes to ensure that seeking is possible.

Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Karthik Nayak
2025-07-15 13:28:28 +02:00
committed by Junio C Hamano
parent 883a7ea054
commit 2b4648b919
9 changed files with 152 additions and 50 deletions

26
refs.h
View File

@@ -1299,21 +1299,29 @@ struct ref_iterator *refs_ref_iterator_begin(
*/
int ref_iterator_advance(struct ref_iterator *ref_iterator);
enum ref_iterator_seek_flag {
/*
* When the REF_ITERATOR_SEEK_SET_PREFIX flag is set, the iterator's prefix is
* updated to match the provided string, affecting all subsequent iterations. If
* not, the iterator seeks to the specified reference and clears any previously
* set prefix.
*/
REF_ITERATOR_SEEK_SET_PREFIX = (1 << 0),
};
/*
* Seek the iterator to the first reference with the given prefix.
* The prefix is matched as a literal string, without regard for path
* separators. If prefix is NULL or the empty string, seek the iterator to the
* Seek the iterator to the first reference matching the given seek string.
* The seek string is matched as a literal string, without regard for path
* separators. If seek is NULL or the empty string, seek the iterator to the
* first reference again.
*
* This function is expected to behave as if a new ref iterator with the same
* prefix had been created, but allows reuse of iterators and thus may allow
* the backend to optimize. Parameters other than the prefix that have been
* passed when creating the iterator will remain unchanged.
* This function is expected to behave as if a new ref iterator has been
* created, but allows reuse of existing iterators for optimization.
*
* Returns 0 on success, a negative error code otherwise.
*/
int ref_iterator_seek(struct ref_iterator *ref_iterator,
const char *prefix);
int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
unsigned int flags);
/*
* If possible, peel the reference currently being viewed by the