Skip to content

Commit 63417bd

Browse files
committed
bundle-uri: store fetch.bundleCreationToken
When a bundle list specifies the "creationToken" heuristic, the Git client downloads the list and then starts downloading bundles in descending creationToken order. This process stops as soon as all downloaded bundles can be applied to the repository (because all required commits are present in the repository or in the downloaded bundles). When checking the same bundle list twice, this strategy requires downloading the bundle with the maximum creationToken again, which is wasteful. The creationToken heuristic promises that the client will not have a use for that bundle if its creationToken value is the at most the previous creationToken value. To prevent these wasteful downloads, create a fetch.bundleCreationToken config setting that the Git client sets after downloading bundles. This value allows skipping that maximum bundle download when this config value is the same value (or larger). To test that this works correctly, we can insert some "duplicate" fetches into existing tests and demonstrate that only the bundle list is downloaded. The previous logic for downloading bundles by creationToken worked even if the bundle list was empty, but now we have logic that depends on the first entry of the list. Terminate early in the (non-sensical) case of an empty bundle list. Signed-off-by: Derrick Stolee <[email protected]>
1 parent 730cea7 commit 63417bd

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

Documentation/config/fetch.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,11 @@ fetch.bundleURI::
104104
first running `git fetch --bundle-uri=<uri>` immediately before
105105
`git fetch <args>`. See details of the `--bundle-uri` option in
106106
linkgit:git-fetch[1].
107+
108+
fetch.bundleCreationToken::
109+
When using `fetch.bundleURI` to fetch incrementally from a bundle
110+
list that uses the "creationToken" heuristic, this config value
111+
stores the maximum `creationToken` value of the downloaded bundles.
112+
This value is used to prevent downloading bundles in the future
113+
if the advertised `creationToken` is not strictly larger than this
114+
value.

bundle-uri.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@ static int fetch_bundles_by_token(struct repository *r,
481481
{
482482
int cur;
483483
int pop_or_push = 0;
484+
const char *creationTokenStr;
485+
uint64_t maxCreationToken;
484486
struct bundle_list_context ctx = {
485487
.r = r,
486488
.list = list,
@@ -494,8 +496,27 @@ static int fetch_bundles_by_token(struct repository *r,
494496

495497
for_all_bundles_in_list(list, append_bundle, &bundles);
496498

499+
if (!bundles.nr) {
500+
free(bundles.items);
501+
return 0;
502+
}
503+
497504
QSORT(bundles.items, bundles.nr, compare_creation_token_decreasing);
498505

506+
/*
507+
* If fetch.bundleCreationToken exists, parses to a uint64t, and
508+
* is not strictly smaller than the maximum creation token in the
509+
* bundle list, then do not download any bundles.
510+
*/
511+
if (!repo_config_get_value(r,
512+
"fetch.bundlecreationtoken",
513+
&creationTokenStr) &&
514+
sscanf(creationTokenStr, "%"PRIu64, &maxCreationToken) == 1 &&
515+
bundles.items[0]->creationToken <= maxCreationToken) {
516+
free(bundles.items);
517+
return 0;
518+
}
519+
499520
/*
500521
* Use a stack-based approach to download the bundles and attempt
501522
* to unbundle them in decreasing order by creation token. If we
@@ -558,14 +579,24 @@ static int fetch_bundles_by_token(struct repository *r,
558579
cur += pop_or_push;
559580
}
560581

561-
free(bundles.items);
562-
563582
/*
564583
* We succeed if the loop terminates because 'cur' drops below
565584
* zero. The other case is that we terminate because 'cur'
566585
* reaches the end of the list, so we have a failure no matter
567586
* which bundles we apply from the list.
568587
*/
588+
if (cur < 0) {
589+
struct strbuf value = STRBUF_INIT;
590+
strbuf_addf(&value, "%"PRIu64"", bundles.items[0]->creationToken);
591+
if (repo_config_set_multivar_gently(ctx.r,
592+
"fetch.bundleCreationToken",
593+
value.buf, NULL, 0))
594+
warning(_("failed to store maximum creation token"));
595+
596+
strbuf_release(&value);
597+
}
598+
599+
free(bundles.items);
569600
return cur >= 0;
570601
}
571602

t/t5558-clone-bundle-uri.sh

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
455455
"$HTTPD_URL/smart/fetch.git" fetch-http-4 &&
456456
457457
test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri &&
458+
test_cmp_config -C fetch-http-4 1 fetch.bundlecreationtoken &&
458459
459460
# The clone should copy two files: the list and bundle-1.
460461
test_bundle_downloaded bundle-list trace-clone.txt &&
@@ -479,6 +480,8 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
479480
refs/heads/left:refs/heads/left \
480481
refs/heads/right:refs/heads/right &&
481482
483+
test_cmp_config -C fetch-http-4 2 fetch.bundlecreationtoken &&
484+
482485
# This fetch should copy two files: the list and bundle-2.
483486
test_bundle_downloaded bundle-list trace1.txt &&
484487
test_bundle_downloaded bundle-2.bundle trace1.txt &&
@@ -492,6 +495,15 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
492495
EOF
493496
test_cmp expect refs &&
494497
498+
# No-op fetch
499+
GIT_TRACE2_EVENT="$(pwd)/trace1b.txt" \
500+
git -C fetch-http-4 fetch origin --no-tags \
501+
refs/heads/left:refs/heads/left \
502+
refs/heads/right:refs/heads/right &&
503+
test_bundle_downloaded bundle-list trace1b.txt &&
504+
! test_bundle_downloaded bundle-1.bundle trace1b.txt &&
505+
! test_bundle_downloaded bundle-2.bundle trace1b.txt &&
506+
495507
cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF &&
496508
[bundle "bundle-3"]
497509
uri = bundle-3.bundle
@@ -508,6 +520,8 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
508520
git -C fetch-http-4 fetch origin --no-tags \
509521
refs/heads/merge:refs/heads/merge &&
510522
523+
test_cmp_config -C fetch-http-4 4 fetch.bundlecreationtoken &&
524+
511525
# This fetch should copy three files: the list, bundle-3, and bundle-4.
512526
test_bundle_downloaded bundle-list trace2.txt &&
513527
test_bundle_downloaded bundle-4.bundle trace2.txt &&
@@ -524,7 +538,16 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
524538
refs/bundles/left
525539
refs/bundles/merge
526540
EOF
527-
test_cmp expect refs
541+
test_cmp expect refs &&
542+
543+
# No-op fetch
544+
GIT_TRACE2_EVENT="$(pwd)/trace2b.txt" \
545+
git -C fetch-http-4 fetch origin &&
546+
test_bundle_downloaded bundle-list trace2b.txt &&
547+
! test_bundle_downloaded bundle-1.bundle trace2b.txt &&
548+
! test_bundle_downloaded bundle-2.bundle trace2b.txt &&
549+
! test_bundle_downloaded bundle-3.bundle trace2b.txt &&
550+
! test_bundle_downloaded bundle-4.bundle trace2b.txt
528551
'
529552

530553
# Do not add tests here unless they use the HTTP server, as they will

0 commit comments

Comments
 (0)