Merge branch 'tb/ls-refs-optim'
The ls-refs protocol operation has been optimized to narrow the sub-hierarchy of refs/ it walks to produce response. * tb/ls-refs-optim: ls-refs.c: traverse prefixes of disjoint "ref-prefix" sets ls-refs.c: initialize 'prefixes' before using it refs: expose 'for_each_fullref_in_prefixes'
This commit is contained in:
commit
6254fa1359
@ -90,6 +90,7 @@ int ls_refs(struct repository *r, struct strvec *keys,
|
||||
struct ls_refs_data data;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
strvec_init(&data.prefixes);
|
||||
|
||||
git_config(ls_refs_config, NULL);
|
||||
|
||||
@ -109,7 +110,10 @@ int ls_refs(struct repository *r, struct strvec *keys,
|
||||
die(_("expected flush after ls-refs arguments"));
|
||||
|
||||
head_ref_namespaced(send_ref, &data);
|
||||
for_each_namespaced_ref(send_ref, &data);
|
||||
if (!data.prefixes.nr)
|
||||
strvec_push(&data.prefixes, "");
|
||||
for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v,
|
||||
send_ref, &data, 0);
|
||||
packet_flush(1);
|
||||
strvec_clear(&data.prefixes);
|
||||
return 0;
|
||||
|
74
ref-filter.c
74
ref-filter.c
@ -1920,64 +1920,6 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
|
||||
return match_pattern(filter, refname);
|
||||
}
|
||||
|
||||
static int qsort_strcmp(const void *va, const void *vb)
|
||||
{
|
||||
const char *a = *(const char **)va;
|
||||
const char *b = *(const char **)vb;
|
||||
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
static void find_longest_prefixes_1(struct string_list *out,
|
||||
struct strbuf *prefix,
|
||||
const char **patterns, size_t nr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
char c = patterns[i][prefix->len];
|
||||
if (!c || is_glob_special(c)) {
|
||||
string_list_append(out, prefix->buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < nr) {
|
||||
size_t end;
|
||||
|
||||
/*
|
||||
* Set "end" to the index of the element _after_ the last one
|
||||
* in our group.
|
||||
*/
|
||||
for (end = i + 1; end < nr; end++) {
|
||||
if (patterns[i][prefix->len] != patterns[end][prefix->len])
|
||||
break;
|
||||
}
|
||||
|
||||
strbuf_addch(prefix, patterns[i][prefix->len]);
|
||||
find_longest_prefixes_1(out, prefix, patterns + i, end - i);
|
||||
strbuf_setlen(prefix, prefix->len - 1);
|
||||
|
||||
i = end;
|
||||
}
|
||||
}
|
||||
|
||||
static void find_longest_prefixes(struct string_list *out,
|
||||
const char **patterns)
|
||||
{
|
||||
struct strvec sorted = STRVEC_INIT;
|
||||
struct strbuf prefix = STRBUF_INIT;
|
||||
|
||||
strvec_pushv(&sorted, patterns);
|
||||
QSORT(sorted.v, sorted.nr, qsort_strcmp);
|
||||
|
||||
find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
|
||||
|
||||
strvec_clear(&sorted);
|
||||
strbuf_release(&prefix);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the same as for_each_fullref_in(), but it tries to iterate
|
||||
* only over the patterns we'll care about. Note that it _doesn't_ do a full
|
||||
@ -1988,10 +1930,6 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
void *cb_data,
|
||||
int broken)
|
||||
{
|
||||
struct string_list prefixes = STRING_LIST_INIT_DUP;
|
||||
struct string_list_item *prefix;
|
||||
int ret;
|
||||
|
||||
if (!filter->match_as_path) {
|
||||
/*
|
||||
* in this case, the patterns are applied after
|
||||
@ -2015,16 +1953,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
|
||||
return for_each_fullref_in("", cb, cb_data, broken);
|
||||
}
|
||||
|
||||
find_longest_prefixes(&prefixes, filter->name_patterns);
|
||||
|
||||
for_each_string_list_item(prefix, &prefixes) {
|
||||
ret = for_each_fullref_in(prefix->string, cb, cb_data, broken);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
string_list_clear(&prefixes, 0);
|
||||
return ret;
|
||||
return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
|
||||
cb, cb_data, broken);
|
||||
}
|
||||
|
||||
/*
|
||||
|
87
refs.c
87
refs.c
@ -1564,6 +1564,93 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
|
||||
return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
|
||||
}
|
||||
|
||||
static int qsort_strcmp(const void *va, const void *vb)
|
||||
{
|
||||
const char *a = *(const char **)va;
|
||||
const char *b = *(const char **)vb;
|
||||
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
static void find_longest_prefixes_1(struct string_list *out,
|
||||
struct strbuf *prefix,
|
||||
const char **patterns, size_t nr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
char c = patterns[i][prefix->len];
|
||||
if (!c || is_glob_special(c)) {
|
||||
string_list_append(out, prefix->buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < nr) {
|
||||
size_t end;
|
||||
|
||||
/*
|
||||
* Set "end" to the index of the element _after_ the last one
|
||||
* in our group.
|
||||
*/
|
||||
for (end = i + 1; end < nr; end++) {
|
||||
if (patterns[i][prefix->len] != patterns[end][prefix->len])
|
||||
break;
|
||||
}
|
||||
|
||||
strbuf_addch(prefix, patterns[i][prefix->len]);
|
||||
find_longest_prefixes_1(out, prefix, patterns + i, end - i);
|
||||
strbuf_setlen(prefix, prefix->len - 1);
|
||||
|
||||
i = end;
|
||||
}
|
||||
}
|
||||
|
||||
static void find_longest_prefixes(struct string_list *out,
|
||||
const char **patterns)
|
||||
{
|
||||
struct strvec sorted = STRVEC_INIT;
|
||||
struct strbuf prefix = STRBUF_INIT;
|
||||
|
||||
strvec_pushv(&sorted, patterns);
|
||||
QSORT(sorted.v, sorted.nr, qsort_strcmp);
|
||||
|
||||
find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
|
||||
|
||||
strvec_clear(&sorted);
|
||||
strbuf_release(&prefix);
|
||||
}
|
||||
|
||||
int for_each_fullref_in_prefixes(const char *namespace,
|
||||
const char **patterns,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken)
|
||||
{
|
||||
struct string_list prefixes = STRING_LIST_INIT_DUP;
|
||||
struct string_list_item *prefix;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int ret = 0, namespace_len;
|
||||
|
||||
find_longest_prefixes(&prefixes, patterns);
|
||||
|
||||
if (namespace)
|
||||
strbuf_addstr(&buf, namespace);
|
||||
namespace_len = buf.len;
|
||||
|
||||
for_each_string_list_item(prefix, &prefixes) {
|
||||
strbuf_addstr(&buf, prefix->string);
|
||||
ret = for_each_fullref_in(buf.buf, fn, cb_data, broken);
|
||||
if (ret)
|
||||
break;
|
||||
strbuf_setlen(&buf, namespace_len);
|
||||
}
|
||||
|
||||
string_list_clear(&prefixes, 0);
|
||||
strbuf_release(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int refs_read_special_head(struct ref_store *ref_store,
|
||||
const char *refname, struct object_id *oid,
|
||||
struct strbuf *referent, unsigned int *type)
|
||||
|
9
refs.h
9
refs.h
@ -347,6 +347,15 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken);
|
||||
|
||||
/**
|
||||
* iterate all refs in "patterns" by partitioning patterns into disjoint sets
|
||||
* and iterating the longest-common prefix of each set.
|
||||
*
|
||||
* callers should be prepared to ignore references that they did not ask for.
|
||||
*/
|
||||
int for_each_fullref_in_prefixes(const char *namespace, const char **patterns,
|
||||
each_ref_fn fn, void *cb_data,
|
||||
unsigned int broken);
|
||||
/**
|
||||
* iterate refs from the respective area.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user