Skip to content

Commit 00ee4fe

Browse files
Merge tb/codex/packfile-uri-concurrency into codex
Integrate the current tb/codex/packfile-uri-concurrency topic into the internally distributed codex branch. Codex-Integration: tb/codex/packfile-uri-concurrency@4cc8b3223b233aa3b795b1265e6e7cf3d63c7170
2 parents 971177f + 4cc8b32 commit 00ee4fe

8 files changed

Lines changed: 305 additions & 46 deletions

File tree

Documentation/git-http-fetch.adoc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ commit-id::
4848
line (which is not expected in
4949
this case), 'git http-fetch' fetches the packfile directly at the given
5050
URL and uses index-pack to generate corresponding .idx and .keep files.
51-
The hash is used to determine the name of the temporary file and is
52-
arbitrary. The output of index-pack is printed to stdout. Requires
53-
--index-pack-args.
51+
The hash is used to determine the name of the temporary file. It need
52+
not be the pack hash, but it must uniquely identify the pack contents
53+
for resumption. The output of index-pack is printed to stdout. Requires
54+
one or more --index-pack-arg options.
5455

55-
--index-pack-args=<args>::
56-
For internal use only. The command to run on the contents of the
57-
downloaded pack. Arguments are URL-encoded separated by spaces.
56+
--index-pack-arg=<arg>::
57+
For internal use only. The first instance specifies the command run on
58+
the contents of the downloaded pack. Subsequent instances specify its
59+
arguments.
5860

5961
--recover::
6062
Verify that everything reachable from target is fetched. Used after

fetch-pack.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,9 +1854,10 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
18541854
}
18551855

18561856
for (i = 0; i < packfile_uris.nr; i++) {
1857+
bool created_keep;
18571858
int j;
18581859
struct child_process cmd = CHILD_PROCESS_INIT;
1859-
char packname[GIT_MAX_HEXSZ + 1];
1860+
char packhash[GIT_MAX_HEXSZ + 1];
18601861
const char *uri = packfile_uris.items[i].string +
18611862
the_hash_algo->hexsz + 1;
18621863

@@ -1874,16 +1875,17 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
18741875
if (start_command(&cmd))
18751876
die("fetch-pack: unable to spawn http-fetch");
18761877

1877-
if (read_in_full(cmd.out, packname, 5) < 0 ||
1878-
memcmp(packname, "keep\t", 5))
1879-
die("fetch-pack: expected keep then TAB at start of http-fetch output");
1878+
if (read_in_full(cmd.out, packhash, 5) != 5 ||
1879+
(memcmp(packhash, "keep\t", 5) &&
1880+
memcmp(packhash, "pack\t", 5)))
1881+
die("fetch-pack: expected pack or keep then TAB at start of http-fetch output");
1882+
created_keep = !memcmp(packhash, "keep\t", 5);
18801883

1881-
if (read_in_full(cmd.out, packname,
1882-
the_hash_algo->hexsz + 1) < 0 ||
1883-
packname[the_hash_algo->hexsz] != '\n')
1884-
die("fetch-pack: expected hash then LF at end of http-fetch output");
1885-
1886-
packname[the_hash_algo->hexsz] = '\0';
1884+
if (read_in_full(cmd.out, packhash,
1885+
the_hash_algo->hexsz + 1) != the_hash_algo->hexsz + 1 ||
1886+
packhash[the_hash_algo->hexsz] != '\n')
1887+
die("fetch-pack: expected hash then LF in http-fetch output");
1888+
packhash[the_hash_algo->hexsz] = '\0';
18871889

18881890
parse_gitmodules_oids(cmd.out, &fsck_options.gitmodules_found);
18891891

@@ -1892,16 +1894,17 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
18921894
if (finish_command(&cmd))
18931895
die("fetch-pack: unable to finish http-fetch");
18941896

1895-
if (memcmp(packfile_uris.items[i].string, packname,
1897+
if (memcmp(packfile_uris.items[i].string, packhash,
18961898
the_hash_algo->hexsz))
18971899
die("fetch-pack: pack downloaded from %s does not match expected hash %.*s",
18981900
uri, (int) the_hash_algo->hexsz,
18991901
packfile_uris.items[i].string);
19001902

1901-
string_list_append_nodup(pack_lockfiles,
1902-
xstrfmt("%s/pack/pack-%s.keep",
1903-
repo_get_object_directory(the_repository),
1904-
packname));
1903+
if (created_keep)
1904+
string_list_append_nodup(pack_lockfiles,
1905+
xstrfmt("%s/pack/pack-%s.keep",
1906+
repo_get_object_directory(the_repository),
1907+
packhash));
19051908
}
19061909
string_list_clear(&packfile_uris, 0);
19071910
strvec_clear(&index_pack_args);

http-fetch.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ static void fetch_single_packfile(struct object_id *packfile_hash,
7070

7171
if (start_active_slot(preq->slot)) {
7272
run_active_slot(preq->slot);
73-
if (results.curl_result != CURLE_OK) {
73+
if (results.curl_result != CURLE_OK &&
74+
results.http_code != 416) {
7475
struct url_info url;
7576
char *nurl = url_normalize(preq->url, &url);
7677
if (!nurl || !git_env_bool("GIT_TRACE_REDACT", 1)) {
@@ -155,7 +156,7 @@ int cmd_main(int argc, const char **argv)
155156

156157
if (packfile) {
157158
if (!index_pack_args.nr)
158-
die(_("the option '%s' requires '%s'"), "--packfile", "--index-pack-args");
159+
die(_("the option '%s' requires '%s'"), "--packfile", "--index-pack-arg");
159160

160161
fetch_single_packfile(&packfile_hash, argv[arg],
161162
index_pack_args.v);
@@ -164,7 +165,7 @@ int cmd_main(int argc, const char **argv)
164165
}
165166

166167
if (index_pack_args.nr)
167-
die(_("the option '%s' requires '%s'"), "--index-pack-args", "--packfile");
168+
die(_("the option '%s' requires '%s'"), "--index-pack-arg", "--packfile");
168169

169170
if (commits_on_stdin) {
170171
commits = walker_targets_stdin(&commit_id, &write_ref);

http-push.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,8 @@ static void finish_request(struct transfer_request *request)
595595

596596
} else if (request->state == RUN_FETCH_PACKED) {
597597
int fail = 1;
598-
if (request->curl_result != CURLE_OK) {
598+
if (request->curl_result != CURLE_OK &&
599+
request->http_code != 416) {
599600
fprintf(stderr, "Unable to get pack file %s\n%s",
600601
request->url, curl_errorstr);
601602
} else {

http-walker.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,8 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo,
451451

452452
if (start_active_slot(preq->slot)) {
453453
run_active_slot(preq->slot);
454-
if (results.curl_result != CURLE_OK) {
454+
if (results.curl_result != CURLE_OK &&
455+
results.http_code != 416) {
455456
error("Unable to get pack file %s\n%s", preq->url,
456457
curl_errorstr);
457458
goto abort;

http.c

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,10 +2688,13 @@ int finish_http_pack_request(struct http_pack_request *preq)
26882688
int tmpfile_fd;
26892689
int ret = 0;
26902690

2691+
/* Another downloader may unlink the staging path while we index it. */
2692+
tmpfile_fd = xdup(fileno(preq->packfile));
26912693
fclose(preq->packfile);
26922694
preq->packfile = NULL;
2693-
2694-
tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY);
2695+
if (lseek(tmpfile_fd, 0, SEEK_SET) < 0)
2696+
die_errno("unable to seek local file %s for pack",
2697+
preq->tmpfile.buf);
26952698

26962699
ip.git_cmd = 1;
26972700
ip.in = tmpfile_fd;
@@ -2704,13 +2707,8 @@ int finish_http_pack_request(struct http_pack_request *preq)
27042707
else
27052708
ip.no_stdout = 1;
27062709

2707-
if (run_command(&ip)) {
2710+
if (run_command(&ip))
27082711
ret = -1;
2709-
goto cleanup;
2710-
}
2711-
2712-
cleanup:
2713-
close(tmpfile_fd);
27142712
unlink(preq->tmpfile.buf);
27152713
return ret;
27162714
}
@@ -2738,22 +2736,45 @@ struct http_pack_request *new_http_pack_request(
27382736
struct http_pack_request *new_direct_http_pack_request(
27392737
const unsigned char *packed_git_hash, char *url)
27402738
{
2741-
off_t prev_posn = 0;
2739+
off_t prev_posn;
27422740
struct http_pack_request *preq;
2741+
int fd;
27432742

27442743
CALLOC_ARRAY(preq, 1);
27452744
strbuf_init(&preq->tmpfile, 0);
2746-
27472745
preq->url = url;
27482746

27492747
odb_pack_name(the_repository, &preq->tmpfile, packed_git_hash, "pack");
27502748
strbuf_addstr(&preq->tmpfile, ".temp");
2751-
preq->packfile = fopen(preq->tmpfile.buf, "a");
2752-
if (!preq->packfile) {
2753-
error("Unable to open local file %s for pack",
2754-
preq->tmpfile.buf);
2749+
/*
2750+
* MinGW's non-append O_RDWR open grants FILE_SHARE_DELETE only for an
2751+
* existing file; reopen a newly created file so others may unlink it.
2752+
*/
2753+
for (;;) {
2754+
fd = open(preq->tmpfile.buf, O_RDWR);
2755+
if (fd >= 0 || errno != ENOENT)
2756+
break;
2757+
fd = open(preq->tmpfile.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
2758+
if (fd >= 0) {
2759+
close(fd);
2760+
continue;
2761+
}
2762+
if (errno != EEXIST)
2763+
break;
2764+
}
2765+
if (fd < 0) {
2766+
error_errno("unable to open local file %s for pack",
2767+
preq->tmpfile.buf);
27552768
goto abort;
27562769
}
2770+
prev_posn = lseek(fd, 0, SEEK_END);
2771+
if (prev_posn < 0) {
2772+
error_errno("unable to seek local file %s for pack",
2773+
preq->tmpfile.buf);
2774+
close(fd);
2775+
goto abort;
2776+
}
2777+
preq->packfile = xfdopen(fd, "w");
27572778

27582779
preq->slot = get_active_slot();
27592780
preq->headers = object_request_headers();
@@ -2762,12 +2783,7 @@ struct http_pack_request *new_direct_http_pack_request(
27622783
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
27632784
curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
27642785

2765-
/*
2766-
* If there is data present from a previous transfer attempt,
2767-
* resume where it left off
2768-
*/
2769-
prev_posn = ftello(preq->packfile);
2770-
if (prev_posn>0) {
2786+
if (prev_posn > 0) {
27712787
if (http_is_verbose)
27722788
fprintf(stderr,
27732789
"Resuming fetch of pack %s at byte %"PRIuMAX"\n",

0 commit comments

Comments
 (0)