summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9ca4a20)
raw | patch | inline | side by side (parent: 9ca4a20)
author | Nicolas Pitre <nico@cam.org> | |
Wed, 1 Nov 2006 22:06:25 +0000 (17:06 -0500) | ||
committer | Junio C Hamano <junkio@cox.net> | |
Fri, 3 Nov 2006 08:24:07 +0000 (00:24 -0800) |
This makes both git-fetch and git-push (fetch-pack and receive-pack)
safe against a possible race with aparallel git-repack -a -d that could
prune the new pack while it is not yet referenced, and remove the .keep
file after refs have been updated.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
safe against a possible race with aparallel git-repack -a -d that could
prune the new pack while it is not yet referenced, and remove the .keep
file after refs have been updated.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-index-pack.txt | patch | blob | history | |
git-fetch.sh | patch | blob | history | |
index-pack.c | patch | blob | history | |
receive-pack.c | patch | blob | history |
index 1235416e09d405b3bec118f6abe8e65e551fb696..2229ee86b72865c656112aae87b9593d199bc2b8 100644 (file)
locate any which have outlived their usefulness.
+Note
+----
+
+Once the index has been created, the list of object names is sorted
+and the SHA1 hash of that list is printed to stdout. If --stdin was
+also used then this is prefixed by either "pack\t", or "keep\t" if a
+new .keep file was successfully created. This is useful to remove a
+.keep file used as a lock to prevent the race with gitlink:git-repack[1]
+mentioned above.
+
+
Author
------
Written by Sergey Vlasov <vsu@altlinux.ru>
diff --git a/git-fetch.sh b/git-fetch.sh
index 2b5538f1764d8a9174a46a2d662a98f039b29c0d..7442dd2ca54ffc3744b260ee10309d2495afd5fd 100755 (executable)
--- a/git-fetch.sh
+++ b/git-fetch.sh
verbose=Yes
;;
-k|--k|--ke|--kee|--keep)
- keep=--keep
+ keep='-k -k'
;;
--reflog-action=*)
rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
;; # we are already done.
*)
( : subshell because we muck with IFS
+ pack_lockfile=
IFS=" $LF"
(
git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
failed)
echo >&2 "Fetch failure: $remote"
exit 1 ;;
+ # special line coming from index-pack with the pack name
+ pack)
+ continue ;;
+ keep)
+ pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
+ continue ;;
esac
found=
single_force=
append_fetch_head "$sha1" "$remote" \
"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
done
+ if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
) || exit ;;
esac
diff --git a/index-pack.c b/index-pack.c
index 8d64a883afe0b9868ae6c8d918986785ee3cdcfe..042aea8842b531254e9a2d0ec67cbaeb40990575 100644 (file)
--- a/index-pack.c
+++ b/index-pack.c
const char *keep_name, const char *keep_msg,
unsigned char *sha1)
{
+ char *report = "pack";
char name[PATH_MAX];
int err;
if (err)
die("error while closing pack file: %s", strerror(errno));
chmod(curr_pack_name, 0444);
-
- /*
- * Let's just mimic git-unpack-objects here and write
- * the last part of the buffer to stdout.
- */
- while (input_len) {
- err = xwrite(1, input_buffer + input_offset, input_len);
- if (err <= 0)
- break;
- input_len -= err;
- input_offset += err;
- }
}
if (keep_msg) {
write_or_die(keep_fd, "\n", 1);
}
close(keep_fd);
+ report = "keep";
}
}
if (move_temp_to_file(curr_index_name, final_index_name))
die("cannot store index file");
}
+
+ if (!from_stdin) {
+ printf("%s\n", sha1_to_hex(sha1));
+ } else {
+ char buf[48];
+ int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
+ report, sha1_to_hex(sha1));
+ xwrite(1, buf, len);
+
+ /*
+ * Let's just mimic git-unpack-objects here and write
+ * the last part of the input buffer to stdout.
+ */
+ while (input_len) {
+ err = xwrite(1, input_buffer + input_offset, input_len);
+ if (err <= 0)
+ break;
+ input_len -= err;
+ input_offset += err;
+ }
+ }
}
int main(int argc, char **argv)
free(index_name_buf);
free(keep_name_buf);
- if (!from_stdin)
- printf("%s\n", sha1_to_hex(sha1));
-
return 0;
}
diff --git a/receive-pack.c b/receive-pack.c
index b8d12700d80254e59ee8f1b017f19a465dfeccb7..d56898c9b29d3e5ea01fd5a211790141d0beac21 100644 (file)
--- a/receive-pack.c
+++ b/receive-pack.c
#include "refs.h"
#include "pkt-line.h"
#include "run-command.h"
+#include "exec_cmd.h"
#include "commit.h"
#include "object.h"
+#include <sys/wait.h>
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
return NULL;
}
+static const char *pack_lockfile;
+
static const char *unpack(void)
{
struct pack_header hdr;
const char *hdr_err;
char hdr_arg[38];
- int code;
hdr_err = parse_pack_header(&hdr);
if (hdr_err)
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
if (ntohl(hdr.hdr_entries) < unpack_limit) {
+ int code;
const char *unpacker[3];
unpacker[0] = "unpack-objects";
unpacker[1] = hdr_arg;
unpacker[2] = NULL;
code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
- } else {
- const char *keeper[6];
- char my_host[255], keep_arg[128 + 255];
-
- if (gethostname(my_host, sizeof(my_host)))
- strcpy(my_host, "localhost");
- snprintf(keep_arg, sizeof(keep_arg),
- "--keep=receive-pack %i on %s",
- getpid(), my_host);
-
- keeper[0] = "index-pack";
- keeper[1] = "--stdin";
- keeper[2] = "--fix-thin";
- keeper[3] = hdr_arg;
- keeper[4] = keep_arg;
- keeper[5] = NULL;
- code = run_command_v_opt(1, keeper, RUN_GIT_CMD);
- if (!code)
- reprepare_packed_git();
- }
-
- switch (code) {
+ switch (code) {
case 0:
return NULL;
case -ERR_RUN_COMMAND_FORK:
return "unpacker died strangely";
default:
return "unpacker exited with error code";
+ }
+ } else {
+ const char *keeper[6];
+ int fd[2], s, len, status;
+ pid_t pid;
+ char keep_arg[256];
+ char packname[46];
+
+ s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid());
+ if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
+ strcpy(keep_arg + s, "localhost");
+
+ keeper[0] = "index-pack";
+ keeper[1] = "--stdin";
+ keeper[2] = "--fix-thin";
+ keeper[3] = hdr_arg;
+ keeper[4] = keep_arg;
+ keeper[5] = NULL;
+
+ if (pipe(fd) < 0)
+ return "index-pack pipe failed";
+ pid = fork();
+ if (pid < 0)
+ return "index-pack fork failed";
+ if (!pid) {
+ dup2(fd[1], 1);
+ close(fd[1]);
+ close(fd[0]);
+ execv_git_cmd(keeper);
+ die("execv of index-pack failed");
+ }
+ close(fd[1]);
+
+ /*
+ * The first thing we expects from index-pack's output
+ * is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
+ * %40s is the newly created pack SHA1 name. In the "keep"
+ * case, we need it to remove the corresponding .keep file
+ * later on. If we don't get that then tough luck with it.
+ */
+ for (len = 0;
+ len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0;
+ len += s);
+ close(fd[0]);
+ if (len == 46 && packname[45] == '\n' &&
+ memcmp(packname, "keep\t", 5) == 0) {
+ char path[PATH_MAX];
+ packname[45] = 0;
+ snprintf(path, sizeof(path), "%s/pack/pack-%s.keep",
+ get_object_directory(), packname + 5);
+ pack_lockfile = xstrdup(path);
+ }
+
+ /* Then wrap our index-pack process. */
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ return "waitpid failed";
+ if (WIFEXITED(status)) {
+ int code = WEXITSTATUS(status);
+ if (code)
+ return "index-pack exited with error code";
+ reprepare_packed_git();
+ return NULL;
+ }
+ return "index-pack abnormal exit";
}
}
const char *unpack_status = unpack();
if (!unpack_status)
execute_commands();
+ if (pack_lockfile)
+ unlink(pack_lockfile);
if (report_status)
report(unpack_status);
}