Skip to content

Commit 44d49b2

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 'set_prefix' field to the function, which when set, will set the prefix for the iteration in-line with the existing behavior. But when the 'set_prefix' field is not set, the reference backends will simply seek to the specified reference without setting 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 `set_prefix` is set. We then parse the provided seek string and set the required levels and their indexes to ensure that seeking is possible. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 676ea6e commit 44d49b2

File tree

9 files changed

+134
-45
lines changed

9 files changed

+134
-45
lines changed

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2669,7 +2669,7 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
26692669
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, 1) < 0) {
26732673
goto cleanup;
26742674
}
26752675

refs.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,20 +1300,25 @@ struct ref_iterator *refs_ref_iterator_begin(
13001300
int ref_iterator_advance(struct ref_iterator *ref_iterator);
13011301

13021302
/*
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
1303+
* Seek the iterator to the first reference matching the given seek string.
1304+
* The seek string is matched as a literal string, without regard for path
13051305
* separators. If prefix is NULL or the empty string, seek the iterator to the
13061306
* first reference again.
13071307
*
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.
1308+
* When set_prefix is true, this function behaves as if a new ref iterator
1309+
* with the same prefix had been created, setting the prefix for subsequent
1310+
* iteration. When set_prefix is false, the iterator simply seeks to the
1311+
* specified reference without changing the existing prefix, allowing
1312+
* iteration to start from that specific reference.
1313+
*
1314+
* This function allows reuse of iterators and thus may allow the backend
1315+
* to optimize. Parameters other than the prefix that have been passed when
1316+
* creating the iterator will remain unchanged.
13121317
*
13131318
* Returns 0 on success, a negative error code otherwise.
13141319
*/
13151320
int ref_iterator_seek(struct ref_iterator *ref_iterator,
1316-
const char *prefix);
1321+
const char *seek, int set_prefix);
13171322

13181323
/*
13191324
* 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 *seek, int set_prefix)
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, seek, set_prefix);
178+
trace_printf_key(&trace_refs, "iterator_seek: %s set_prefix: %d: %d\n",
179+
seek ? seek : "", set_prefix, 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 *seek, int set_prefix)
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, seek, set_prefix);
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 *seek UNUSED,
2320+
int set_prefix UNUSED)
23202321
{
23212322
BUG("ref_iterator_seek() called for reflog_iterator");
23222323
}

refs/iterator.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ int ref_iterator_advance(struct ref_iterator *ref_iterator)
1616
}
1717

1818
int ref_iterator_seek(struct ref_iterator *ref_iterator,
19-
const char *prefix)
19+
const char *seek, int set_prefix)
2020
{
21-
return ref_iterator->vtable->seek(ref_iterator, prefix);
21+
return ref_iterator->vtable->seek(ref_iterator, seek, set_prefix);
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 *seek UNUSED,
61+
int set_prefix 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 *seek, int set_prefix)
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, seek, set_prefix);
238239
if (ret < 0)
239240
return ret;
240241

241-
ret = ref_iterator_seek(iter->iter1, prefix);
242+
ret = ref_iterator_seek(iter->iter1, seek, set_prefix);
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 *seek, int set_prefix)
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 (set_prefix) {
417+
free(iter->prefix);
418+
iter->prefix = xstrdup_or_null(seek);
419+
}
420+
return ref_iterator_seek(iter->iter0, seek, set_prefix);
417421
}
418422

419423
static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,

refs/packed-backend.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,19 +1004,22 @@ 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 *seek, int set_prefix)
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 (seek && *seek)
1014+
start = find_reference_location(iter->snapshot, seek, 0);
10151015
else
10161016
start = iter->snapshot->start;
10171017

1018-
free(iter->prefix);
1019-
iter->prefix = xstrdup_or_null(prefix);
1018+
if (set_prefix) {
1019+
free(iter->prefix);
1020+
iter->prefix = xstrdup_or_null(seek);
1021+
}
1022+
10201023
iter->pos = start;
10211024
iter->eof = iter->snapshot->eof;
10221025

@@ -1194,7 +1197,7 @@ static struct ref_iterator *packed_ref_iterator_begin(
11941197
iter->repo = ref_store->repo;
11951198
iter->flags = flags;
11961199

1197-
if (packed_ref_iterator_seek(&iter->base, prefix) < 0) {
1200+
if (packed_ref_iterator_seek(&iter->base, prefix, 1) < 0) {
11981201
ref_iterator_free(&iter->base);
11991202
return NULL;
12001203
}

refs/ref-cache.c

Lines changed: 76 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,79 @@ 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 *seek, int set_prefix)
472+
{
473+
struct cache_ref_iterator *iter =
474+
(struct cache_ref_iterator *)ref_iterator;
475+
476+
if (set_prefix) {
477+
return cache_ref_iterator_set_prefix(iter, seek);
478+
} else if (seek && *seek) {
479+
struct cache_ref_iterator_level *level;
480+
const char *slash = seek;
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, seek);
487+
488+
iter->levels_nr = 1;
489+
level = &iter->levels[0];
490+
level->index = -1;
491+
level->dir = dir;
492+
493+
/*
494+
* Breakdown the provided seek path and assign the correct
495+
* indexing to each level as needed.
496+
*/
497+
do {
498+
int len, idx;
499+
int cmp = 0;
500+
501+
sort_ref_dir(dir);
502+
503+
slash = strchr(slash, '/');
504+
len = slash ? slash - seek : (int)strlen(seek);
505+
506+
for (idx = 0; idx < dir->nr; idx++) {
507+
cmp = strncmp(seek, dir->entries[idx]->name, len);
508+
if (cmp <= 0)
509+
break;
510+
}
511+
/* don't overflow the index */
512+
idx = idx >= dir->nr ? dir->nr - 1 : idx;
513+
514+
if (slash)
515+
slash = slash + 1;
516+
517+
level->index = idx;
518+
if (dir->entries[idx]->flag & REF_DIR) {
519+
/* push down a level */
520+
dir = get_ref_dir(dir->entries[idx]);
521+
522+
ALLOC_GROW(iter->levels, iter->levels_nr + 1,
523+
iter->levels_alloc);
524+
level = &iter->levels[iter->levels_nr++];
525+
level->dir = dir;
526+
level->index = -1;
527+
} else {
528+
/* reduce the index so the leaf node is iterated over */
529+
if (cmp <= 0 && !slash)
530+
level->index = idx - 1;
531+
/*
532+
* while the seek path may not be exhausted, our
533+
* match is exhausted at a leaf node.
534+
*/
535+
break;
536+
}
537+
} while (slash);
538+
}
539+
540+
return 0;
541+
}
542+
472543
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
473544
struct object_id *peeled)
474545
{
@@ -509,7 +580,7 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
509580
iter->cache = cache;
510581
iter->prime_dir = prime_dir;
511582

512-
if (cache_ref_iterator_seek(&iter->base, prefix) < 0) {
583+
if (cache_ref_iterator_seek(&iter->base, prefix, 1) < 0) {
513584
ref_iterator_free(&iter->base);
514585
return NULL;
515586
}

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 set_prefix is set,
357+
* it would behave the same as if a new iterator was created with the same
358+
* prefix.
358359
*/
359360
typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator,
360-
const char *prefix);
361+
const char *seek, int set_prefix);
361362

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

refs/reftable-backend.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -719,15 +719,17 @@ 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 *seek, int set_prefix)
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+
if (set_prefix) {
728+
free(iter->prefix);
729+
iter->prefix = xstrdup_or_null(seek);
730+
iter->prefix_len = seek ? strlen(seek) : 0;
731+
}
732+
iter->err = reftable_iterator_seek_ref(&iter->iter, seek);
731733

732734
return iter->err;
733735
}
@@ -839,7 +841,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
839841
if (ret)
840842
goto done;
841843

842-
ret = reftable_ref_iterator_seek(&iter->base, prefix);
844+
ret = reftable_ref_iterator_seek(&iter->base, prefix, 1);
843845
if (ret)
844846
goto done;
845847

@@ -2042,7 +2044,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
20422044
}
20432045

20442046
static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
2045-
const char *prefix UNUSED)
2047+
const char *seek UNUSED,
2048+
int set_prefix UNUSED)
20462049
{
20472050
BUG("reftable reflog iterator cannot be seeked");
20482051
return -1;

0 commit comments

Comments
 (0)