Skip to content

Commit 6254fa1

Browse files
committed
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'
2 parents 5198426 + b3970c7 commit 6254fa1

File tree

4 files changed

+103
-73
lines changed

4 files changed

+103
-73
lines changed

ls-refs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ int ls_refs(struct repository *r, struct strvec *keys,
9090
struct ls_refs_data data;
9191

9292
memset(&data, 0, sizeof(data));
93+
strvec_init(&data.prefixes);
9394

9495
git_config(ls_refs_config, NULL);
9596

@@ -109,7 +110,10 @@ int ls_refs(struct repository *r, struct strvec *keys,
109110
die(_("expected flush after ls-refs arguments"));
110111

111112
head_ref_namespaced(send_ref, &data);
112-
for_each_namespaced_ref(send_ref, &data);
113+
if (!data.prefixes.nr)
114+
strvec_push(&data.prefixes, "");
115+
for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v,
116+
send_ref, &data, 0);
113117
packet_flush(1);
114118
strvec_clear(&data.prefixes);
115119
return 0;

ref-filter.c

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,64 +1920,6 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
19201920
return match_pattern(filter, refname);
19211921
}
19221922

1923-
static int qsort_strcmp(const void *va, const void *vb)
1924-
{
1925-
const char *a = *(const char **)va;
1926-
const char *b = *(const char **)vb;
1927-
1928-
return strcmp(a, b);
1929-
}
1930-
1931-
static void find_longest_prefixes_1(struct string_list *out,
1932-
struct strbuf *prefix,
1933-
const char **patterns, size_t nr)
1934-
{
1935-
size_t i;
1936-
1937-
for (i = 0; i < nr; i++) {
1938-
char c = patterns[i][prefix->len];
1939-
if (!c || is_glob_special(c)) {
1940-
string_list_append(out, prefix->buf);
1941-
return;
1942-
}
1943-
}
1944-
1945-
i = 0;
1946-
while (i < nr) {
1947-
size_t end;
1948-
1949-
/*
1950-
* Set "end" to the index of the element _after_ the last one
1951-
* in our group.
1952-
*/
1953-
for (end = i + 1; end < nr; end++) {
1954-
if (patterns[i][prefix->len] != patterns[end][prefix->len])
1955-
break;
1956-
}
1957-
1958-
strbuf_addch(prefix, patterns[i][prefix->len]);
1959-
find_longest_prefixes_1(out, prefix, patterns + i, end - i);
1960-
strbuf_setlen(prefix, prefix->len - 1);
1961-
1962-
i = end;
1963-
}
1964-
}
1965-
1966-
static void find_longest_prefixes(struct string_list *out,
1967-
const char **patterns)
1968-
{
1969-
struct strvec sorted = STRVEC_INIT;
1970-
struct strbuf prefix = STRBUF_INIT;
1971-
1972-
strvec_pushv(&sorted, patterns);
1973-
QSORT(sorted.v, sorted.nr, qsort_strcmp);
1974-
1975-
find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
1976-
1977-
strvec_clear(&sorted);
1978-
strbuf_release(&prefix);
1979-
}
1980-
19811923
/*
19821924
* This is the same as for_each_fullref_in(), but it tries to iterate
19831925
* 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,
19881930
void *cb_data,
19891931
int broken)
19901932
{
1991-
struct string_list prefixes = STRING_LIST_INIT_DUP;
1992-
struct string_list_item *prefix;
1993-
int ret;
1994-
19951933
if (!filter->match_as_path) {
19961934
/*
19971935
* in this case, the patterns are applied after
@@ -2015,16 +1953,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
20151953
return for_each_fullref_in("", cb, cb_data, broken);
20161954
}
20171955

2018-
find_longest_prefixes(&prefixes, filter->name_patterns);
2019-
2020-
for_each_string_list_item(prefix, &prefixes) {
2021-
ret = for_each_fullref_in(prefix->string, cb, cb_data, broken);
2022-
if (ret)
2023-
break;
2024-
}
2025-
2026-
string_list_clear(&prefixes, 0);
2027-
return ret;
1956+
return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
1957+
cb, cb_data, broken);
20281958
}
20291959

20301960
/*

refs.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,93 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
15641564
return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
15651565
}
15661566

1567+
static int qsort_strcmp(const void *va, const void *vb)
1568+
{
1569+
const char *a = *(const char **)va;
1570+
const char *b = *(const char **)vb;
1571+
1572+
return strcmp(a, b);
1573+
}
1574+
1575+
static void find_longest_prefixes_1(struct string_list *out,
1576+
struct strbuf *prefix,
1577+
const char **patterns, size_t nr)
1578+
{
1579+
size_t i;
1580+
1581+
for (i = 0; i < nr; i++) {
1582+
char c = patterns[i][prefix->len];
1583+
if (!c || is_glob_special(c)) {
1584+
string_list_append(out, prefix->buf);
1585+
return;
1586+
}
1587+
}
1588+
1589+
i = 0;
1590+
while (i < nr) {
1591+
size_t end;
1592+
1593+
/*
1594+
* Set "end" to the index of the element _after_ the last one
1595+
* in our group.
1596+
*/
1597+
for (end = i + 1; end < nr; end++) {
1598+
if (patterns[i][prefix->len] != patterns[end][prefix->len])
1599+
break;
1600+
}
1601+
1602+
strbuf_addch(prefix, patterns[i][prefix->len]);
1603+
find_longest_prefixes_1(out, prefix, patterns + i, end - i);
1604+
strbuf_setlen(prefix, prefix->len - 1);
1605+
1606+
i = end;
1607+
}
1608+
}
1609+
1610+
static void find_longest_prefixes(struct string_list *out,
1611+
const char **patterns)
1612+
{
1613+
struct strvec sorted = STRVEC_INIT;
1614+
struct strbuf prefix = STRBUF_INIT;
1615+
1616+
strvec_pushv(&sorted, patterns);
1617+
QSORT(sorted.v, sorted.nr, qsort_strcmp);
1618+
1619+
find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
1620+
1621+
strvec_clear(&sorted);
1622+
strbuf_release(&prefix);
1623+
}
1624+
1625+
int for_each_fullref_in_prefixes(const char *namespace,
1626+
const char **patterns,
1627+
each_ref_fn fn, void *cb_data,
1628+
unsigned int broken)
1629+
{
1630+
struct string_list prefixes = STRING_LIST_INIT_DUP;
1631+
struct string_list_item *prefix;
1632+
struct strbuf buf = STRBUF_INIT;
1633+
int ret = 0, namespace_len;
1634+
1635+
find_longest_prefixes(&prefixes, patterns);
1636+
1637+
if (namespace)
1638+
strbuf_addstr(&buf, namespace);
1639+
namespace_len = buf.len;
1640+
1641+
for_each_string_list_item(prefix, &prefixes) {
1642+
strbuf_addstr(&buf, prefix->string);
1643+
ret = for_each_fullref_in(buf.buf, fn, cb_data, broken);
1644+
if (ret)
1645+
break;
1646+
strbuf_setlen(&buf, namespace_len);
1647+
}
1648+
1649+
string_list_clear(&prefixes, 0);
1650+
strbuf_release(&buf);
1651+
return ret;
1652+
}
1653+
15671654
static int refs_read_special_head(struct ref_store *ref_store,
15681655
const char *refname, struct object_id *oid,
15691656
struct strbuf *referent, unsigned int *type)

refs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,15 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
347347
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
348348
unsigned int broken);
349349

350+
/**
351+
* iterate all refs in "patterns" by partitioning patterns into disjoint sets
352+
* and iterating the longest-common prefix of each set.
353+
*
354+
* callers should be prepared to ignore references that they did not ask for.
355+
*/
356+
int for_each_fullref_in_prefixes(const char *namespace, const char **patterns,
357+
each_ref_fn fn, void *cb_data,
358+
unsigned int broken);
350359
/**
351360
* iterate refs from the respective area.
352361
*/

0 commit comments

Comments
 (0)