bundle-uri: parse bundle.heuristic=creationToken

The bundle.heuristic value communicates that the bundle list is organized to make use of the bundle.<id>.creationToken values that may be provided in the bundle list. Those values will create a total order on the bundles, allowing the Git client to download them in a specific order and even remember previously-downloaded bundles by storing the maximum creation token value. Before implementing any logic that parses or uses the bundle.<id>.creationToken values, teach Git to parse the bundle.heuristic value from a bundle list. We can use 'test-tool bundle-uri' to print the heuristic value and verify that the parsing works correctly. As an extra precaution, create the internal 'heuristics' array to be a list of (enum, string) pairs so we can iterate through the array entries carefully, regardless of the enum values. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jan 31, 2023 at 13:29 UTC c93c3d2fa42bec64948441cb339d78e2044ff9a3
4 files changed +74
Documentation/config/bundle.txt
+7
@@ -15,6 +15,13 @@ bundle.mode::
15 complete understanding of the bundled information (`all`) or if any one
16 of the listed bundle URIs is sufficient (`any`).
17
18 +bundle.heuristic::
19 + If this string-valued key exists, then the bundle list is designed to
20 + work well with incremental `git fetch` commands. The heuristic signals
21 + that there are additional keys available for each bundle that help
22 + determine which subset of bundles the client should download. The
23 + only value currently understood is `creationToken`.
24 +
25 bundle.<id>.*::
26 The `bundle.<id>.*` keys are used to describe a single item in the
27 bundle list, grouped under `<id>` for identification purposes.
bundle-uri.c
+34
@@ -9,6 +9,14 @@
9 #include "config.h"
10 #include "remote.h"
11
12 +static struct {
13 + enum bundle_list_heuristic heuristic;
14 + const char *name;
15 +} heuristics[BUNDLE_HEURISTIC__COUNT] = {
16 + { BUNDLE_HEURISTIC_NONE, ""},
17 + { BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
18 +};
19 +
20 static int compare_bundles(const void *hashmap_cmp_fn_data,
21 const struct hashmap_entry *he1,
22 const struct hashmap_entry *he2,
@@ -100,6 +108,17 @@ void print_bundle_list(FILE *fp, struct bundle_list *list)
108 fprintf(fp, "\tversion = %d\n", list->version);
109 fprintf(fp, "\tmode = %s\n", mode);
110
111 + if (list->heuristic) {
112 + int i;
113 + for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
114 + if (heuristics[i].heuristic == list->heuristic) {
115 + printf("\theuristic = %s\n",
116 + heuristics[list->heuristic].name);
117 + break;
118 + }
119 + }
120 + }
121 +
122 for_all_bundles_in_list(list, summarize_bundle, fp);
123 }
124
@@ -142,6 +161,21 @@ static int bundle_list_update(const char *key, const char *value,
161 return 0;
162 }
163
164 + if (!strcmp(subkey, "heuristic")) {
165 + int i;
166 + for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
167 + if (heuristics[i].heuristic &&
168 + heuristics[i].name &&
169 + !strcmp(value, heuristics[i].name)) {
170 + list->heuristic = heuristics[i].heuristic;
171 + return 0;
172 + }
173 + }
174 +
175 + /* Ignore unknown heuristics. */
176 + return 0;
177 + }
178 +
179 /* Ignore other unknown global keys. */
180 return 0;
181 }
bundle-uri.h
+14
@@ -52,6 +52,14 @@ enum bundle_list_mode {
52 BUNDLE_MODE_ANY
53 };
54
55 +enum bundle_list_heuristic {
56 + BUNDLE_HEURISTIC_NONE = 0,
57 + BUNDLE_HEURISTIC_CREATIONTOKEN,
58 +
59 + /* Must be last. */
60 + BUNDLE_HEURISTIC__COUNT
61 +};
62 +
63 /**
64 * A bundle_list contains an unordered set of remote_bundle_info structs,
65 * as well as information about the bundle listing, such as version and
@@ -75,6 +83,12 @@ struct bundle_list {
83 * advertised by the bundle list at that location.
84 */
85 char *baseURI;
86 +
87 + /**
88 + * A list can have a heuristic, which helps reduce the number of
89 + * downloaded bundles.
90 + */
91 + enum bundle_list_heuristic heuristic;
92 };
93
94 void init_bundle_list(struct bundle_list *list);
t/t5750-bundle-uri-parse.sh
+19
@@ -250,4 +250,23 @@ test_expect_success 'parse config format edge cases: empty key or value' '
250 test_cmp_config_output expect actual
251 '
252
253 +test_expect_success 'parse config format: creationToken heuristic' '
254 + cat >expect <<-\EOF &&
255 + [bundle]
256 + version = 1
257 + mode = all
258 + heuristic = creationToken
259 + [bundle "one"]
260 + uri = http://example.com/bundle.bdl
261 + [bundle "two"]
262 + uri = https://example.com/bundle.bdl
263 + [bundle "three"]
264 + uri = file:///usr/share/git/bundle.bdl
265 + EOF
266 +
267 + test-tool bundle-uri parse-config expect >actual 2>err &&
268 + test_must_be_empty err &&
269 + test_cmp_config_output expect actual
270 +'
271 +
272 test_done