From abd149c794b7f0c9ac167fcdcdbd454114f3ba38 Mon Sep 17 00:00:00 2001 From: Teng Long Date: Mon, 21 Mar 2022 16:17:15 +0800 Subject: [PATCH 1/3] transport.h: introduct 'ref_suffixes' in struct 'transport_ls_refs_options' In contrast to 'ref_prefixes', 'ref_suffixes' is used on the server side to limit ref advertisement using tail-matching rules, only for protocol v2. This is a prepared-commit for the whole implementation, it does not break existing functionality, and the rest of implementation will be in subsequent commit. Signed-off-by: Teng Long --- transport.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/transport.h b/transport.h index a0bc6a1e9eba8f..3a9fc7dec8b2db 100644 --- a/transport.h +++ b/transport.h @@ -254,6 +254,14 @@ struct transport_ls_refs_options { */ struct strvec ref_prefixes; + /* + * Similar with 'ref_prefixes', list of ref suffixes can be sent to + * the server (when communicating using protocol v2) to limit the + * ref advetisement too. This also will speed up some tail-matching + * operations like `git ls-remote`. + */ + struct strvec ref_suffixes; + /* * If unborn_head_target is not NULL, and the remote reports HEAD as * pointing to an unborn branch, transport_get_remote_refs() stores the From 4ead1ebfb92bc5f443139a7b5f5bc2ed92d45b75 Mon Sep 17 00:00:00 2001 From: Teng Long Date: Mon, 21 Mar 2022 17:42:52 +0800 Subject: [PATCH 2/3] ls-refs: support ref-suffix in 'ls-refs' command It's proposed to let the client to support to send 'ref-suffix ' to the server during excuting 'ls-refs' commands in protocol v2. Multiple instances may be given and when they are specified, only references having a suffix matching one of the provided suffixes are displayed. Only protocol level extension implementations are covered here and no related changes to the refs filter ("for_each_fullref_in_prefixes") because this function needs to be extended or refactored, so we will put it in a later commit to make testing easy (no functional break). Furthur, the subcommands like 'clone' or 'fetch', etc. are not implemented here too, they will be implemented in subsequent commits. Signed-off-by: Teng Long --- connect.c | 6 ++++++ ls-refs.c | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index afc79a6236e8d5..8153a41100c2ac 100644 --- a/connect.c +++ b/connect.c @@ -483,6 +483,8 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, const char *hash_name; struct strvec *ref_prefixes = transport_options ? &transport_options->ref_prefixes : NULL; + struct strvec *ref_suffixes = transport_options ? + &transport_options->ref_suffixes : NULL; const char **unborn_head_target = transport_options ? &transport_options->unborn_head_target : NULL; *list = NULL; @@ -520,6 +522,10 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, packet_write_fmt(fd_out, "ref-prefix %s\n", ref_prefixes->v[i]); } + for (i = 0; ref_suffixes && i < ref_suffixes->nr; i++) { + packet_write_fmt(fd_out, "ref-suffix %s\n", + ref_suffixes->v[i]); + } packet_flush(fd_out); /* Process response from server */ diff --git a/ls-refs.c b/ls-refs.c index 98e69373c8404e..2074038aeb0ee8 100644 --- a/ls-refs.c +++ b/ls-refs.c @@ -42,10 +42,12 @@ static void ensure_config_read(void) } /* - * If we see this many or more "ref-prefix" lines from the client, we consider - * it "too many" and will avoid using the prefix feature entirely. + * If we see this many or more "ref-prefix" or "ref-suffix" lines from the + * client, we consider it "too many" and will avoid using the prefix or + * suffix feature entirely. */ #define TOO_MANY_PREFIXES 65536 +#define TOO_MANY_SUFFIXES 65536 /* * Check if one of the prefixes is a prefix of the ref. @@ -72,6 +74,7 @@ struct ls_refs_data { unsigned peel; unsigned symrefs; struct strvec prefixes; + struct strvec suffixes; struct strbuf buf; unsigned unborn : 1; }; @@ -152,6 +155,7 @@ int ls_refs(struct repository *r, struct packet_reader *request) memset(&data, 0, sizeof(data)); strvec_init(&data.prefixes); + strvec_init(&data.suffixes); strbuf_init(&data.buf, 0); ensure_config_read(); @@ -168,6 +172,9 @@ int ls_refs(struct repository *r, struct packet_reader *request) else if (skip_prefix(arg, "ref-prefix ", &out)) { if (data.prefixes.nr < TOO_MANY_PREFIXES) strvec_push(&data.prefixes, out); + }else if (skip_prefix(arg, "ref-suffix ", &out)) { + if (data.prefixes.nr < TOO_MANY_SUFFIXES) + strvec_push(&data.suffixes, out); } else if (!strcmp("unborn", arg)) data.unborn = allow_unborn; @@ -186,13 +193,19 @@ int ls_refs(struct repository *r, struct packet_reader *request) if (data.prefixes.nr >= TOO_MANY_PREFIXES) strvec_clear(&data.prefixes); + if (data.suffixes.nr >= TOO_MANY_SUFFIXES) + strvec_clear(&data.suffixes); + send_possibly_unborn_head(&data); if (!data.prefixes.nr) strvec_push(&data.prefixes, ""); + if (!data.suffixes.nr) + strvec_push(&data.suffixes, ""); for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v, send_ref, &data); packet_fflush(stdout); strvec_clear(&data.prefixes); + strvec_clear(&data.suffixes); strbuf_release(&data.buf); return 0; } From 360fe3d888f8b79e3629c294ade8e44563a37034 Mon Sep 17 00:00:00 2001 From: Teng Long Date: Mon, 21 Mar 2022 19:28:16 +0800 Subject: [PATCH 3/3] refs.h: Introduce struct "ref_patterns" Git protocol v2 support client to send one or many "ref-prefix " under "ls-refs" commands when negotiating with server, then the server side will use the prefix(es) to filter out the expected refs. Except the "prefix" pattern, there maybe other patterns in the future, such as `git ls-remote` use a "suffix" pattern to tail-matching the refs list. So, the struct "ref_patterns" is brought in, toreplace the original "char **ref_prefixes" and create a new fields "ref_suffixes" in the struct. Signed-off-by: Teng Long --- refs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/refs.h b/refs.h index 23479c7ee09b9c..f45a6368cde408 100644 --- a/refs.h +++ b/refs.h @@ -63,6 +63,16 @@ struct worktree; #define RESOLVE_REF_NO_RECURSE 0x02 #define RESOLVE_REF_ALLOW_BAD_NAME 0x04 +struct ref_patterns { + char **ref_prefixes; + char **ref_suffixes; +}; + +#define REF_PATTERNS_INIT { \ + .ref_prefixes = empty_strvec, \ + .ref_suffixes = empty_strvec, \ +} + const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, int resolve_flags,