Remove pack.keep after ref updates in git-fetch
authorShawn O. Pearce <spearce@spearce.org>
Fri, 14 Sep 2007 07:31:23 +0000 (03:31 -0400)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Sep 2007 10:22:30 +0000 (03:22 -0700)
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>
builtin-fetch-pack.c
builtin-fetch.c
fetch-pack.h
transport.c
transport.h

index e77cd267193843c19f75a5debfb57841b0d5f211..b0936ccf0c3f1346508ab702dfce0b857fa829de 100644 (file)
@@ -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);
index f5a2718acc490ce9c746d2bf12db84c5a5cc0481..8e433d1bf23e7c31aad43c13501c58bcd035cf2e 100644 (file)
@@ -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;
 }
 
index e06bf5b5c49e24e096ef322cfe3714ad0627113a..cdcd84f2b562d2f6a47a2ed2f4434034f639cbd5 100644 (file)
@@ -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
index d2cbf3acc117705888a81b27f53f2512e6a22db4..0882edd381fdd191974a0a5af64c2e1ff4b9015c 100644 (file)
@@ -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;
index b354a8fd18be48c826558a2052872eb56bb136f0..f2bbdf778a80e6d8099dd4001bf9dfdf39e43e9d 100644 (file)
@@ -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