aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2007-09-14 03:31:23 -0400
committerJunio C Hamano <gitster@pobox.com>2007-09-19 03:22:30 -0700
commit1788c39cd0742439b9bedc28bc10bc4d105b6c0f (patch)
tree7cb5e53238b90e0c9bdcc1812c9ca266af1a12b9
parent106764e6515dd0fb9fda8bb8cab523932ae903b3 (diff)
downloadgit-1788c39cd0742439b9bedc28bc10bc4d105b6c0f.tar.gz
git-1788c39cd0742439b9bedc28bc10bc4d105b6c0f.tar.xz
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 <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin-fetch-pack.c31
-rw-r--r--builtin-fetch.c1
-rw-r--r--fetch-pack.h2
-rw-r--r--transport.c18
-rw-r--r--transport.h5
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