if (!initial_transaction) {
int ok;
- if (!iter) {
+ if (!iter)
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
- } else if (ref_iterator_seek(iter, dirname.buf) < 0) {
+ else if (ref_iterator_seek(iter, dirname.buf,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0)
goto cleanup;
- }
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
if (skip &&
*/
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
}
static int debug_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct debug_ref_iterator *diter =
(struct debug_ref_iterator *)ref_iterator;
- int res = diter->iter->vtable->seek(diter->iter, prefix);
- trace_printf_key(&trace_refs, "iterator_seek: %s: %d\n", prefix ? prefix : "", res);
+ int res = diter->iter->vtable->seek(diter->iter, refname, flags);
+ trace_printf_key(&trace_refs, "iterator_seek: %s flags: %d: %d\n",
+ refname ? refname : "", flags, res);
return res;
}
}
static int files_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct files_ref_iterator *iter =
(struct files_ref_iterator *)ref_iterator;
- return ref_iterator_seek(iter->iter0, prefix);
+ return ref_iterator_seek(iter->iter0, refname, flags);
}
static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
}
static int files_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
BUG("ref_iterator_seek() called for reflog_iterator");
}
return ref_iterator->vtable->advance(ref_iterator);
}
-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)
{
- return ref_iterator->vtable->seek(ref_iterator, prefix);
+ return ref_iterator->vtable->seek(ref_iterator, refname, flags);
}
int ref_iterator_peel(struct ref_iterator *ref_iterator,
}
static int empty_ref_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
return 0;
}
}
static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct merge_ref_iterator *iter =
(struct merge_ref_iterator *)ref_iterator;
iter->iter0 = iter->iter0_owned;
iter->iter1 = iter->iter1_owned;
- ret = ref_iterator_seek(iter->iter0, prefix);
+ ret = ref_iterator_seek(iter->iter0, refname, flags);
if (ret < 0)
return ret;
- ret = ref_iterator_seek(iter->iter1, prefix);
+ ret = ref_iterator_seek(iter->iter1, refname, flags);
if (ret < 0)
return ret;
}
static int prefix_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct prefix_ref_iterator *iter =
(struct prefix_ref_iterator *)ref_iterator;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
- return ref_iterator_seek(iter->iter0, prefix);
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ free(iter->prefix);
+ iter->prefix = xstrdup_or_null(refname);
+ }
+ return ref_iterator_seek(iter->iter0, refname, flags);
}
static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,
}
static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct packed_ref_iterator *iter =
(struct packed_ref_iterator *)ref_iterator;
const char *start;
- if (prefix && *prefix)
- start = find_reference_location(iter->snapshot, prefix, 0);
+ if (refname && *refname)
+ start = find_reference_location(iter->snapshot, refname, 0);
else
start = iter->snapshot->start;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX)
+ iter->prefix = xstrdup_or_null(refname);
+
iter->pos = start;
iter->eof = iter->snapshot->eof;
iter->repo = ref_store->repo;
iter->flags = flags;
- if (packed_ref_iterator_seek(&iter->base, prefix) < 0) {
+ if (packed_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
ref_iterator_free(&iter->base);
return NULL;
}
}
}
-static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+static int cache_ref_iterator_set_prefix(struct cache_ref_iterator *iter,
+ const char *prefix)
{
- struct cache_ref_iterator *iter =
- (struct cache_ref_iterator *)ref_iterator;
struct cache_ref_iterator_level *level;
struct ref_dir *dir;
return 0;
}
+static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
+ const char *refname, unsigned int flags)
+{
+ struct cache_ref_iterator *iter =
+ (struct cache_ref_iterator *)ref_iterator;
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ return cache_ref_iterator_set_prefix(iter, refname);
+ } else if (refname && *refname) {
+ struct cache_ref_iterator_level *level;
+ const char *slash = refname;
+ struct ref_dir *dir;
+
+ dir = get_ref_dir(iter->cache->root);
+
+ if (iter->prime_dir)
+ prime_ref_dir(dir, refname);
+
+ iter->levels_nr = 1;
+ level = &iter->levels[0];
+ level->index = -1;
+ level->dir = dir;
+
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+
+ /*
+ * Breakdown the provided seek path and assign the correct
+ * indexing to each level as needed.
+ */
+ do {
+ int len, idx;
+ int cmp = 0;
+
+ sort_ref_dir(dir);
+
+ slash = strchr(slash, '/');
+ len = slash ? slash - refname : (int)strlen(refname);
+
+ for (idx = 0; idx < dir->nr; idx++) {
+ cmp = strncmp(refname, dir->entries[idx]->name, len);
+ if (cmp <= 0)
+ break;
+ }
+ /* don't overflow the index */
+ idx = idx >= dir->nr ? dir->nr - 1 : idx;
+
+ if (slash)
+ slash = slash + 1;
+
+ level->index = idx;
+ if (dir->entries[idx]->flag & REF_DIR) {
+ /* push down a level */
+ dir = get_ref_dir(dir->entries[idx]);
+
+ ALLOC_GROW(iter->levels, iter->levels_nr + 1,
+ iter->levels_alloc);
+ level = &iter->levels[iter->levels_nr++];
+ level->dir = dir;
+ level->index = -1;
+ } else {
+ /* reduce the index so the leaf node is iterated over */
+ if (cmp <= 0 && !slash)
+ level->index = idx - 1;
+ /*
+ * while the seek path may not be exhausted, our
+ * match is exhausted at a leaf node.
+ */
+ break;
+ }
+ } while (slash);
+ }
+
+ return 0;
+}
+
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct object_id *peeled)
{
iter->cache = cache;
iter->prime_dir = prime_dir;
- if (cache_ref_iterator_seek(&iter->base, prefix) < 0) {
+ if (cache_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
ref_iterator_free(&iter->base);
return NULL;
}
typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
/*
- * Seek the iterator to the first reference matching the given prefix. Should
- * behave the same as if a new iterator was created with the same prefix.
+ * Seek the iterator to the first matching reference. If the
+ * REF_ITERATOR_SEEK_SET_PREFIX flag is set, it would behave the same as if a
+ * new iterator was created with the provided refname as prefix.
*/
typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator,
- const char *prefix);
+ const char *refname, unsigned int flags);
/*
* Peels the current ref, returning 0 for success or -1 for failure.
}
static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct reftable_ref_iterator *iter =
(struct reftable_ref_iterator *)ref_iterator;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
- iter->prefix_len = prefix ? strlen(prefix) : 0;
- iter->err = reftable_iterator_seek_ref(&iter->iter, prefix);
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+ iter->prefix_len = 0;
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ iter->prefix = xstrdup_or_null(refname);
+ iter->prefix_len = refname ? strlen(refname) : 0;
+ }
+ iter->err = reftable_iterator_seek_ref(&iter->iter, refname);
return iter->err;
}
if (ret)
goto done;
- ret = reftable_ref_iterator_seek(&iter->base, prefix);
+ ret = reftable_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX);
if (ret)
goto done;
}
static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
BUG("reftable reflog iterator cannot be seeked");
return -1;