Skip to content

Commit 2b4648b

Browse files
KarthikNayakgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 883a7ea commit 2b4648b

File tree

9 files changed

+152
-50
lines changed

9 files changed

+152
-50
lines changed

refs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,12 +2666,12 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
26662666
if (!initial_transaction) {
26672667
int ok;
26682668

2669-
if (!iter) {
2669+
if (!iter)
26702670
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
26712671
DO_FOR_EACH_INCLUDE_BROKEN);
2672-
} else if (ref_iterator_seek(iter, dirname.buf) < 0) {
2672+
else if (ref_iterator_seek(iter, dirname.buf,
2673+
REF_ITERATOR_SEEK_SET_PREFIX) < 0)
26732674
goto cleanup;
2674-
}
26752675

26762676
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
26772677
if (skip &&

refs.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,21 +1299,29 @@ struct ref_iterator *refs_ref_iterator_begin(
12991299
*/
13001300
int ref_iterator_advance(struct ref_iterator *ref_iterator);
13011301

1302+
enum ref_iterator_seek_flag {
1303+
/*
1304+
* When the REF_ITERATOR_SEEK_SET_PREFIX flag is set, the iterator's prefix is
1305+
* updated to match the provided string, affecting all subsequent iterations. If
1306+
* not, the iterator seeks to the specified reference and clears any previously
1307+
* set prefix.
1308+
*/
1309+
REF_ITERATOR_SEEK_SET_PREFIX = (1 << 0),
1310+
};
1311+
13021312
/*
1303-
* Seek the iterator to the first reference with the given prefix.
1304-
* The prefix is matched as a literal string, without regard for path
1305-
* separators. If prefix is NULL or the empty string, seek the iterator to the
1313+
* Seek the iterator to the first reference matching the given seek string.
1314+
* The seek string is matched as a literal string, without regard for path
1315+
* separators. If seek is NULL or the empty string, seek the iterator to the
13061316
* first reference again.
13071317
*
1308-
* This function is expected to behave as if a new ref iterator with the same
1309-
* prefix had been created, but allows reuse of iterators and thus may allow
1310-
* the backend to optimize. Parameters other than the prefix that have been
1311-
* passed when creating the iterator will remain unchanged.
1318+
* This function is expected to behave as if a new ref iterator has been
1319+
* created, but allows reuse of existing iterators for optimization.
13121320
*
13131321
* Returns 0 on success, a negative error code otherwise.
13141322
*/
1315-
int ref_iterator_seek(struct ref_iterator *ref_iterator,
1316-
const char *prefix);
1323+
int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
1324+
unsigned int flags);
13171325

13181326
/*
13191327
* If possible, peel the reference currently being viewed by the

refs/debug.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,13 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
170170
}
171171

172172
static int debug_ref_iterator_seek(struct ref_iterator *ref_iterator,
173-
const char *prefix)
173+
const char *refname, unsigned int flags)
174174
{
175175
struct debug_ref_iterator *diter =
176176
(struct debug_ref_iterator *)ref_iterator;
177-
int res = diter->iter->vtable->seek(diter->iter, prefix);
178-
trace_printf_key(&trace_refs, "iterator_seek: %s: %d\n", prefix ? prefix : "", res);
177+
int res = diter->iter->vtable->seek(diter->iter, refname, flags);
178+
trace_printf_key(&trace_refs, "iterator_seek: %s flags: %d: %d\n",
179+
refname ? refname : "", flags, res);
179180
return res;
180181
}
181182

refs/files-backend.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -929,11 +929,11 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
929929
}
930930

931931
static int files_ref_iterator_seek(struct ref_iterator *ref_iterator,
932-
const char *prefix)
932+
const char *refname, unsigned int flags)
933933
{
934934
struct files_ref_iterator *iter =
935935
(struct files_ref_iterator *)ref_iterator;
936-
return ref_iterator_seek(iter->iter0, prefix);
936+
return ref_iterator_seek(iter->iter0, refname, flags);
937937
}
938938

939939
static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
@@ -2316,7 +2316,8 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
23162316
}
23172317

23182318
static int files_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
2319-
const char *prefix UNUSED)
2319+
const char *refname UNUSED,
2320+
unsigned int flags UNUSED)
23202321
{
23212322
BUG("ref_iterator_seek() called for reflog_iterator");
23222323
}

refs/iterator.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ int ref_iterator_advance(struct ref_iterator *ref_iterator)
1515
return ref_iterator->vtable->advance(ref_iterator);
1616
}
1717

18-
int ref_iterator_seek(struct ref_iterator *ref_iterator,
19-
const char *prefix)
18+
int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
19+
unsigned int flags)
2020
{
21-
return ref_iterator->vtable->seek(ref_iterator, prefix);
21+
return ref_iterator->vtable->seek(ref_iterator, refname, flags);
2222
}
2323

2424
int ref_iterator_peel(struct ref_iterator *ref_iterator,
@@ -57,7 +57,8 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator UNUSED)
5757
}
5858

5959
static int empty_ref_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
60-
const char *prefix UNUSED)
60+
const char *refname UNUSED,
61+
unsigned int flags UNUSED)
6162
{
6263
return 0;
6364
}
@@ -224,7 +225,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
224225
}
225226

226227
static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
227-
const char *prefix)
228+
const char *refname, unsigned int flags)
228229
{
229230
struct merge_ref_iterator *iter =
230231
(struct merge_ref_iterator *)ref_iterator;
@@ -234,11 +235,11 @@ static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
234235
iter->iter0 = iter->iter0_owned;
235236
iter->iter1 = iter->iter1_owned;
236237

237-
ret = ref_iterator_seek(iter->iter0, prefix);
238+
ret = ref_iterator_seek(iter->iter0, refname, flags);
238239
if (ret < 0)
239240
return ret;
240241

241-
ret = ref_iterator_seek(iter->iter1, prefix);
242+
ret = ref_iterator_seek(iter->iter1, refname, flags);
242243
if (ret < 0)
243244
return ret;
244245

@@ -407,13 +408,16 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
407408
}
408409

409410
static int prefix_ref_iterator_seek(struct ref_iterator *ref_iterator,
410-
const char *prefix)
411+
const char *refname, unsigned int flags)
411412
{
412413
struct prefix_ref_iterator *iter =
413414
(struct prefix_ref_iterator *)ref_iterator;
414-
free(iter->prefix);
415-
iter->prefix = xstrdup_or_null(prefix);
416-
return ref_iterator_seek(iter->iter0, prefix);
415+
416+
if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
417+
free(iter->prefix);
418+
iter->prefix = xstrdup_or_null(refname);
419+
}
420+
return ref_iterator_seek(iter->iter0, refname, flags);
417421
}
418422

419423
static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,

refs/packed-backend.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,19 +1004,23 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
10041004
}
10051005

10061006
static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator,
1007-
const char *prefix)
1007+
const char *refname, unsigned int flags)
10081008
{
10091009
struct packed_ref_iterator *iter =
10101010
(struct packed_ref_iterator *)ref_iterator;
10111011
const char *start;
10121012

1013-
if (prefix && *prefix)
1014-
start = find_reference_location(iter->snapshot, prefix, 0);
1013+
if (refname && *refname)
1014+
start = find_reference_location(iter->snapshot, refname, 0);
10151015
else
10161016
start = iter->snapshot->start;
10171017

1018-
free(iter->prefix);
1019-
iter->prefix = xstrdup_or_null(prefix);
1018+
/* Unset any previously set prefix */
1019+
FREE_AND_NULL(iter->prefix);
1020+
1021+
if (flags & REF_ITERATOR_SEEK_SET_PREFIX)
1022+
iter->prefix = xstrdup_or_null(refname);
1023+
10201024
iter->pos = start;
10211025
iter->eof = iter->snapshot->eof;
10221026

@@ -1194,7 +1198,8 @@ static struct ref_iterator *packed_ref_iterator_begin(
11941198
iter->repo = ref_store->repo;
11951199
iter->flags = flags;
11961200

1197-
if (packed_ref_iterator_seek(&iter->base, prefix) < 0) {
1201+
if (packed_ref_iterator_seek(&iter->base, prefix,
1202+
REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
11981203
ref_iterator_free(&iter->base);
11991204
return NULL;
12001205
}

refs/ref-cache.c

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,9 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
434434
}
435435
}
436436

437-
static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
438-
const char *prefix)
437+
static int cache_ref_iterator_set_prefix(struct cache_ref_iterator *iter,
438+
const char *prefix)
439439
{
440-
struct cache_ref_iterator *iter =
441-
(struct cache_ref_iterator *)ref_iterator;
442440
struct cache_ref_iterator_level *level;
443441
struct ref_dir *dir;
444442

@@ -469,6 +467,82 @@ static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
469467
return 0;
470468
}
471469

470+
static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
471+
const char *refname, unsigned int flags)
472+
{
473+
struct cache_ref_iterator *iter =
474+
(struct cache_ref_iterator *)ref_iterator;
475+
476+
if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
477+
return cache_ref_iterator_set_prefix(iter, refname);
478+
} else if (refname && *refname) {
479+
struct cache_ref_iterator_level *level;
480+
const char *slash = refname;
481+
struct ref_dir *dir;
482+
483+
dir = get_ref_dir(iter->cache->root);
484+
485+
if (iter->prime_dir)
486+
prime_ref_dir(dir, refname);
487+
488+
iter->levels_nr = 1;
489+
level = &iter->levels[0];
490+
level->index = -1;
491+
level->dir = dir;
492+
493+
/* Unset any previously set prefix */
494+
FREE_AND_NULL(iter->prefix);
495+
496+
/*
497+
* Breakdown the provided seek path and assign the correct
498+
* indexing to each level as needed.
499+
*/
500+
do {
501+
int len, idx;
502+
int cmp = 0;
503+
504+
sort_ref_dir(dir);
505+
506+
slash = strchr(slash, '/');
507+
len = slash ? slash - refname : (int)strlen(refname);
508+
509+
for (idx = 0; idx < dir->nr; idx++) {
510+
cmp = strncmp(refname, dir->entries[idx]->name, len);
511+
if (cmp <= 0)
512+
break;
513+
}
514+
/* don't overflow the index */
515+
idx = idx >= dir->nr ? dir->nr - 1 : idx;
516+
517+
if (slash)
518+
slash = slash + 1;
519+
520+
level->index = idx;
521+
if (dir->entries[idx]->flag & REF_DIR) {
522+
/* push down a level */
523+
dir = get_ref_dir(dir->entries[idx]);
524+
525+
ALLOC_GROW(iter->levels, iter->levels_nr + 1,
526+
iter->levels_alloc);
527+
level = &iter->levels[iter->levels_nr++];
528+
level->dir = dir;
529+
level->index = -1;
530+
} else {
531+
/* reduce the index so the leaf node is iterated over */
532+
if (cmp <= 0 && !slash)
533+
level->index = idx - 1;
534+
/*
535+
* while the seek path may not be exhausted, our
536+
* match is exhausted at a leaf node.
537+
*/
538+
break;
539+
}
540+
} while (slash);
541+
}
542+
543+
return 0;
544+
}
545+
472546
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
473547
struct object_id *peeled)
474548
{
@@ -509,7 +583,8 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
509583
iter->cache = cache;
510584
iter->prime_dir = prime_dir;
511585

512-
if (cache_ref_iterator_seek(&iter->base, prefix) < 0) {
586+
if (cache_ref_iterator_seek(&iter->base, prefix,
587+
REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
513588
ref_iterator_free(&iter->base);
514589
return NULL;
515590
}

refs/refs-internal.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,12 @@ void base_ref_iterator_init(struct ref_iterator *iter,
353353
typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
354354

355355
/*
356-
* Seek the iterator to the first reference matching the given prefix. Should
357-
* behave the same as if a new iterator was created with the same prefix.
356+
* Seek the iterator to the first matching reference. If the
357+
* REF_ITERATOR_SEEK_SET_PREFIX flag is set, it would behave the same as if a
358+
* new iterator was created with the provided refname as prefix.
358359
*/
359360
typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator,
360-
const char *prefix);
361+
const char *refname, unsigned int flags);
361362

362363
/*
363364
* Peels the current ref, returning 0 for success or -1 for failure.

refs/reftable-backend.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -719,15 +719,20 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
719719
}
720720

721721
static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator,
722-
const char *prefix)
722+
const char *refname, unsigned int flags)
723723
{
724724
struct reftable_ref_iterator *iter =
725725
(struct reftable_ref_iterator *)ref_iterator;
726726

727-
free(iter->prefix);
728-
iter->prefix = xstrdup_or_null(prefix);
729-
iter->prefix_len = prefix ? strlen(prefix) : 0;
730-
iter->err = reftable_iterator_seek_ref(&iter->iter, prefix);
727+
/* Unset any previously set prefix */
728+
FREE_AND_NULL(iter->prefix);
729+
iter->prefix_len = 0;
730+
731+
if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
732+
iter->prefix = xstrdup_or_null(refname);
733+
iter->prefix_len = refname ? strlen(refname) : 0;
734+
}
735+
iter->err = reftable_iterator_seek_ref(&iter->iter, refname);
731736

732737
return iter->err;
733738
}
@@ -839,7 +844,8 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
839844
if (ret)
840845
goto done;
841846

842-
ret = reftable_ref_iterator_seek(&iter->base, prefix);
847+
ret = reftable_ref_iterator_seek(&iter->base, prefix,
848+
REF_ITERATOR_SEEK_SET_PREFIX);
843849
if (ret)
844850
goto done;
845851

@@ -2042,7 +2048,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
20422048
}
20432049

20442050
static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
2045-
const char *prefix UNUSED)
2051+
const char *refname UNUSED,
2052+
unsigned int flags UNUSED)
20462053
{
20472054
BUG("reftable reflog iterator cannot be seeked");
20482055
return -1;

0 commit comments

Comments
 (0)