From 752661636262ef92f1d69ccd36fd651599805fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 14 Mar 2012 21:40:55 +0700 Subject: {fetch,receive}-pack: skip sha-1 integrity test on objects from new pack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we fetch or push, usually "git rev-list --verify-objects --not --all --stdin" is used to make sure that all objects between existing refs and new refs are good. This means no gaps in between, all objects are well-formed, object content agrees with its sha-1 signature. For the last one, --verify-objects calls check_sha1_signature() via parse_object(). check_sha1_signature() is an expensive operation, especially when new refs are far away from existing ones because all objects in between are re-hashed. Because objects coming from the new pack are already hashed by index-pack, we can trust their integrity. The only objects left to check are existing ones in repo but has no connection to any current refs. Pass the new pack id down to--verify-objects and skip check_sha1_signature() on objects from that pack. As an (extreme) example, a repository is created with only one commit: e83c516 (Initial revision of "git", the information manager from hell - 2005-04-07). The rest of git.git is fetched on top. Without the patch: $ time git fetch file:///home/pclouds/w/git/.git remote: Counting objects: 125656, done. remote: Compressing objects: 100% (33280/33280), done. remote: Total 125656 (delta 92585), reused 123464 (delta 90682) Receiving objects: 100% (125656/125656), 34.60 MiB | 8.47 MiB/s, done. Resolving deltas: 100% (92585/92585), done. >From file:///home/pclouds/t/test/ * branch HEAD -> FETCH_HEAD real 1m30.437s user 1m31.338s sys 0m1.687s With the patch: $ time git fetch file:///home/pclouds/w/git/.git remote: Counting objects: 125656, done. remote: Compressing objects: 100% (33280/33280), done. remote: Total 125656 (delta 92585), reused 123464 (delta 90682) Receiving objects: 100% (125656/125656), 34.60 MiB | 7.86 MiB/s, done. Resolving deltas: 100% (92585/92585), done. >From file:///home/pclouds/t/test/ * branch HEAD -> FETCH_HEAD real 0m52.182s user 0m53.151s sys 0m1.465s Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- connected.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'connected.c') diff --git a/connected.c b/connected.c index d7624230d4..af81049e7e 100644 --- a/connected.c +++ b/connected.c @@ -14,28 +14,43 @@ * * Returns 0 if everything is connected, non-zero otherwise. */ -int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data) +int check_everything_connected(sha1_iterate_fn fn, unsigned int flags, + const char *pack_lockfile, void *cb_data) { struct child_process rev_list; - const char *argv[] = {"rev-list", "--verify-objects", - "--stdin", "--not", "--all", NULL, NULL}; + const char *argv[] = {"rev-list", "--verify-objects", "--stdin", + "--not", "--all", NULL, NULL, NULL, NULL }; char commit[41]; unsigned char sha1[20]; - int err = 0; + int err = 0, ac = 5; + struct strbuf packfile = STRBUF_INIT; if (fn(cb_data, sha1)) return err; - if (quiet) - argv[5] = "--quiet"; + if (flags & CHECK_CONNECT_QUIET) + argv[ac++] = "--quiet"; + if (pack_lockfile) { + strbuf_addstr(&packfile, pack_lockfile); + /* xxx/pack-%40s.keep */ + assert(strcmp(packfile.buf + packfile.len - 5, ".keep") == 0); + assert(strncmp(packfile.buf + packfile.len - 51, "/pack-", 6) == 0); + strbuf_setlen(&packfile, packfile.len - 5); + strbuf_remove(&packfile, 0, packfile.len - 40); + argv[ac++] = "--safe-pack"; + argv[ac++] = packfile.buf; + } + assert(ac < ARRAY_SIZE(argv) && argv[ac] == NULL); memset(&rev_list, 0, sizeof(rev_list)); rev_list.argv = argv; rev_list.git_cmd = 1; rev_list.in = -1; rev_list.no_stdout = 1; - rev_list.no_stderr = quiet; - if (start_command(&rev_list)) + rev_list.no_stderr = flags & CHECK_CONNECT_QUIET; + err = start_command(&rev_list); + strbuf_release(&packfile); + if (err) return error(_("Could not run 'git rev-list'")); sigchain_push(SIGPIPE, SIG_IGN); -- cgit v1.2.1