From 1788c39cd0742439b9bedc28bc10bc4d105b6c0f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:23 -0400 Subject: [PATCH] Remove pack.keep after ref updates in git-fetch If we are using a native packfile to perform a git-fetch invocation and the received packfile contained more than the configured limits of fetch.unpackLimit/transfer.unpackLimit then index-pack will output a single line saying "keep\t$sha1\n" to stdout. This line needs to be captured and retained so we can delete the corresponding .keep file ("$GIT_DIR/objects/pack/pack-$sha1.keep") once all refs have been safely updated. This trick has long been in use with git-fetch.sh and its lower level helper git-fetch--tool as a way to allow index-pack to save the new packfile before the refs have been updated and yet avoid a race with any concurrently running git-repack process. It was unfortunately lost when git-fetch.sh was converted to pure C and fetch--tool was no longer being invoked. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch-pack.c | 31 +++++++++++++++++++++++++------ builtin-fetch.c | 1 + fetch-pack.h | 2 +- transport.c | 18 ++++++++++++++---- transport.h | 5 +++-- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index e77cd2671..b0936ccf0 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -493,7 +493,7 @@ static pid_t setup_sideband(int fd[2], int xd[2]) return side_pid; } -static int get_pack(int xd[2]) +static int get_pack(int xd[2], char **pack_lockfile) { int status; pid_t pid, side_pid; @@ -503,6 +503,7 @@ static int get_pack(int xd[2]) char hdr_arg[256]; const char **av; int do_keep = keep_pack; + int keep_pipe[2]; side_pid = setup_sideband(fd, xd); @@ -522,6 +523,8 @@ static int get_pack(int xd[2]) } if (do_keep) { + if (pack_lockfile && pipe(keep_pipe)) + die("fetch-pack: pipe setup failure: %s", strerror(errno)); *av++ = "index-pack"; *av++ = "--stdin"; if (!quiet && !no_progress) @@ -550,6 +553,11 @@ static int get_pack(int xd[2]) die("fetch-pack: unable to fork off %s", argv[0]); if (!pid) { dup2(fd[0], 0); + if (do_keep && pack_lockfile) { + dup2(keep_pipe[1], 1); + close(keep_pipe[0]); + close(keep_pipe[1]); + } close(fd[0]); close(fd[1]); execv_git_cmd(argv); @@ -557,6 +565,11 @@ static int get_pack(int xd[2]) } close(fd[0]); close(fd[1]); + if (do_keep && pack_lockfile) { + close(keep_pipe[1]); + *pack_lockfile = index_pack_lockfile(keep_pipe[0]); + close(keep_pipe[0]); + } while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) die("waiting for %s: %s", argv[0], strerror(errno)); @@ -574,7 +587,10 @@ static int get_pack(int xd[2]) die("%s died of unnatural causes %d", argv[0], status); } -static struct ref *do_fetch_pack(int fd[2], int nr_match, char **match) +static struct ref *do_fetch_pack(int fd[2], + int nr_match, + char **match, + char **pack_lockfile) { struct ref *ref; unsigned char sha1[20]; @@ -612,7 +628,7 @@ static struct ref *do_fetch_pack(int fd[2], int nr_match, char **match) */ fprintf(stderr, "warning: no common commits\n"); - if (get_pack(fd)) + if (get_pack(fd, pack_lockfile)) die("git-fetch-pack: fetch failed."); all_done: @@ -741,7 +757,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) if (!dest) usage(fetch_pack_usage); - ref = fetch_pack(dest, nr_heads, heads); + ref = fetch_pack(dest, nr_heads, heads, NULL); ret = !ref; @@ -754,7 +770,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) return ret; } -struct ref *fetch_pack(const char *dest, int nr_heads, char **heads) +struct ref *fetch_pack(const char *dest, + int nr_heads, + char **heads, + char **pack_lockfile) { int i, ret; int fd[2]; @@ -773,7 +792,7 @@ struct ref *fetch_pack(const char *dest, int nr_heads, char **heads) return NULL; if (heads && nr_heads) nr_heads = remove_duplicates(nr_heads, heads); - ref = do_fetch_pack(fd, nr_heads, heads); + ref = do_fetch_pack(fd, nr_heads, heads, pack_lockfile); close(fd[0]); close(fd[1]); ret = finish_connect(pid); diff --git a/builtin-fetch.c b/builtin-fetch.c index f5a2718ac..8e433d1bf 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -274,6 +274,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) int ret = transport_fetch_refs(transport, ref_map); if (!ret) store_updated_refs(transport->url, ref_map); + transport_unlock_pack(transport); return ret; } diff --git a/fetch-pack.h b/fetch-pack.h index e06bf5b5c..cdcd84f2b 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -16,6 +16,6 @@ struct fetch_pack_args void setup_fetch_pack(struct fetch_pack_args *args); -struct ref *fetch_pack(const char *dest, int nr_heads, char **heads); +struct ref *fetch_pack(const char *dest, int nr_heads, char **heads, char **pack_lockfile); #endif diff --git a/transport.c b/transport.c index d2cbf3acc..0882edd38 100644 --- a/transport.c +++ b/transport.c @@ -9,7 +9,7 @@ /* Generic functions for using commit walkers */ -static int fetch_objs_via_walker(const struct transport *transport, +static int fetch_objs_via_walker(struct transport *transport, int nr_objs, struct ref **to_fetch) { char *dest = xstrdup(transport->url); @@ -219,7 +219,7 @@ static struct ref *get_refs_from_bundle(const struct transport *transport) return result; } -static int fetch_refs_from_bundle(const struct transport *transport, +static int fetch_refs_from_bundle(struct transport *transport, int nr_heads, struct ref **to_fetch) { struct bundle_transport_data *data = transport->data; @@ -306,7 +306,7 @@ static struct ref *get_refs_via_connect(const struct transport *transport) return refs; } -static int fetch_refs_via_pack(const struct transport *transport, +static int fetch_refs_via_pack(struct transport *transport, int nr_heads, struct ref **to_fetch) { struct git_transport_data *data = transport->data; @@ -330,7 +330,7 @@ static int fetch_refs_via_pack(const struct transport *transport, for (i = 0; i < nr_heads; i++) heads[i] = xstrdup(to_fetch[i]->name); - refs = fetch_pack(dest, nr_heads, heads); + refs = fetch_pack(dest, nr_heads, heads, &transport->pack_lockfile); for (i = 0; i < nr_heads; i++) free(heads[i]); @@ -445,6 +445,7 @@ struct transport *transport_get(struct remote *remote, const char *url, ret->url = url; ret->remote_refs = NULL; ret->fetch = !!fetch; + ret->pack_lockfile = NULL; } return ret; } @@ -500,6 +501,15 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs) return rc; } +void transport_unlock_pack(struct transport *transport) +{ + if (transport->pack_lockfile) { + unlink(transport->pack_lockfile); + free(transport->pack_lockfile); + transport->pack_lockfile = NULL; + } +} + int transport_disconnect(struct transport *transport) { int ret = 0; diff --git a/transport.h b/transport.h index b354a8fd1..f2bbdf778 100644 --- a/transport.h +++ b/transport.h @@ -15,6 +15,7 @@ struct transport { struct ref *remote_refs; const struct transport_ops *ops; + char *pack_lockfile; }; #define TRANSPORT_PUSH_ALL 1 @@ -30,7 +31,7 @@ struct transport_ops { const char *value); struct ref *(*get_refs_list)(const struct transport *transport); - int (*fetch)(const struct transport *transport, int refs_nr, struct ref **refs); + int (*fetch)(struct transport *transport, int refs_nr, struct ref **refs); int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags); int (*disconnect)(struct transport *connection); @@ -73,7 +74,7 @@ int transport_push(struct transport *connection, struct ref *transport_get_remote_refs(struct transport *transport); int transport_fetch_refs(struct transport *transport, struct ref *refs); - +void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); #endif -- 2.26.2