Skip to content

Commit 84e6569

Browse files
pks-tgitster
authored andcommitted
refs/iterator: implement seeking for ref-cache iterators
Implement seeking of ref-cache iterators. This is done by splitting most of the logic to seek iterators out of `cache_ref_iterator_begin()` and putting it into `cache_ref_iterator_seek()` so that we can reuse the logic. Note that we cannot use the optimization anymore where we return an empty ref iterator when there aren't any references, as otherwise it wouldn't be possible to reseek the iterator to a different prefix that may exist. This shouldn't be much of a performance concern though as we now start to bail out early in case `advance()` sees that there are no more directories to be searched. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 53de20c commit 84e6569

File tree

1 file changed

+51
-28
lines changed

1 file changed

+51
-28
lines changed

refs/ref-cache.c

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,7 @@ struct cache_ref_iterator {
362362
struct ref_iterator base;
363363

364364
/*
365-
* The number of levels currently on the stack. This is always
366-
* at least 1, because when it becomes zero the iteration is
367-
* ended and this struct is freed.
365+
* The number of levels currently on the stack.
368366
*/
369367
size_t levels_nr;
370368

@@ -376,7 +374,7 @@ struct cache_ref_iterator {
376374
* The prefix is matched textually, without regard for path
377375
* component boundaries.
378376
*/
379-
const char *prefix;
377+
char *prefix;
380378

381379
/*
382380
* A stack of levels. levels[0] is the uppermost level that is
@@ -389,13 +387,19 @@ struct cache_ref_iterator {
389387
struct cache_ref_iterator_level *levels;
390388

391389
struct repository *repo;
390+
struct ref_cache *cache;
391+
392+
int prime_dir;
392393
};
393394

394395
static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
395396
{
396397
struct cache_ref_iterator *iter =
397398
(struct cache_ref_iterator *)ref_iterator;
398399

400+
if (!iter->levels_nr)
401+
return ITER_DONE;
402+
399403
while (1) {
400404
struct cache_ref_iterator_level *level =
401405
&iter->levels[iter->levels_nr - 1];
@@ -444,6 +448,41 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
444448
}
445449
}
446450

451+
static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
452+
const char *prefix)
453+
{
454+
struct cache_ref_iterator *iter =
455+
(struct cache_ref_iterator *)ref_iterator;
456+
struct cache_ref_iterator_level *level;
457+
struct ref_dir *dir;
458+
459+
dir = get_ref_dir(iter->cache->root);
460+
if (prefix && *prefix)
461+
dir = find_containing_dir(dir, prefix);
462+
if (!dir) {
463+
iter->levels_nr = 0;
464+
return 0;
465+
}
466+
467+
if (iter->prime_dir)
468+
prime_ref_dir(dir, prefix);
469+
iter->levels_nr = 1;
470+
level = &iter->levels[0];
471+
level->index = -1;
472+
level->dir = dir;
473+
474+
if (prefix && *prefix) {
475+
free(iter->prefix);
476+
iter->prefix = xstrdup(prefix);
477+
level->prefix_state = PREFIX_WITHIN_DIR;
478+
} else {
479+
FREE_AND_NULL(iter->prefix);
480+
level->prefix_state = PREFIX_CONTAINS_DIR;
481+
}
482+
483+
return 0;
484+
}
485+
447486
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
448487
struct object_id *peeled)
449488
{
@@ -456,12 +495,13 @@ static void cache_ref_iterator_release(struct ref_iterator *ref_iterator)
456495
{
457496
struct cache_ref_iterator *iter =
458497
(struct cache_ref_iterator *)ref_iterator;
459-
free((char *)iter->prefix);
498+
free(iter->prefix);
460499
free(iter->levels);
461500
}
462501

463502
static struct ref_iterator_vtable cache_ref_iterator_vtable = {
464503
.advance = cache_ref_iterator_advance,
504+
.seek = cache_ref_iterator_seek,
465505
.peel = cache_ref_iterator_peel,
466506
.release = cache_ref_iterator_release,
467507
};
@@ -471,39 +511,22 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
471511
struct repository *repo,
472512
int prime_dir)
473513
{
474-
struct ref_dir *dir;
475514
struct cache_ref_iterator *iter;
476515
struct ref_iterator *ref_iterator;
477-
struct cache_ref_iterator_level *level;
478-
479-
dir = get_ref_dir(cache->root);
480-
if (prefix && *prefix)
481-
dir = find_containing_dir(dir, prefix);
482-
if (!dir)
483-
/* There's nothing to iterate over. */
484-
return empty_ref_iterator_begin();
485-
486-
if (prime_dir)
487-
prime_ref_dir(dir, prefix);
488516

489517
CALLOC_ARRAY(iter, 1);
490518
ref_iterator = &iter->base;
491519
base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
492520
ALLOC_GROW(iter->levels, 10, iter->levels_alloc);
493521

494-
iter->levels_nr = 1;
495-
level = &iter->levels[0];
496-
level->index = -1;
497-
level->dir = dir;
522+
iter->repo = repo;
523+
iter->cache = cache;
524+
iter->prime_dir = prime_dir;
498525

499-
if (prefix && *prefix) {
500-
iter->prefix = xstrdup(prefix);
501-
level->prefix_state = PREFIX_WITHIN_DIR;
502-
} else {
503-
level->prefix_state = PREFIX_CONTAINS_DIR;
526+
if (cache_ref_iterator_seek(&iter->base, prefix) < 0) {
527+
ref_iterator_free(&iter->base);
528+
return NULL;
504529
}
505530

506-
iter->repo = repo;
507-
508531
return ref_iterator;
509532
}

0 commit comments

Comments
 (0)