[PATCH] Avoid unnecessarily inflating and interpreting delta
authorJunio C Hamano <junkio@cox.net>
Fri, 1 Jul 2005 00:13:07 +0000 (17:13 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 1 Jul 2005 05:33:47 +0000 (22:33 -0700)
This teaches packed_delta_info() that it only needs to look at
the type of the base object to figure out both type and size of
a deltified object.  This saves quite a many calls to inflate()
when dealing with a deep delta chain.

Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
cat-file.c
sha1_file.c

index 85a5d4c..fa0bb72 100644 (file)
@@ -16,7 +16,8 @@ int main(int argc, char **argv)
                usage("git-cat-file [-t | -s | tagname] <sha1>");
 
        if (!strcmp("-t", argv[1]) || !strcmp("-s", argv[1])) {
-               if (!sha1_object_info(sha1, type, &size)) {
+               if (!sha1_object_info(sha1, type,
+                                     argv[1][1] == 's' ? &size : NULL)) {
                        switch (argv[1][1]) {
                        case 't':
                                printf("%s\n", type);
index 63cbdde..3178fbf 100644 (file)
@@ -624,41 +624,49 @@ static int packed_delta_info(unsigned char *base_sha1,
                             char *type,
                             unsigned long *sizep)
 {
-       const unsigned char *data;
-       unsigned char delta_head[64];
-       unsigned long result_size, base_size, verify_base_size;
-       z_stream stream;
-       int st;
-
        if (left < 20)
                die("truncated pack file");
-       if (sha1_object_info(base_sha1, type, &base_size))
-               die("cannot get info for delta-pack base");
-
-       memset(&stream, 0, sizeof(stream));
 
-       data = stream.next_in = base_sha1 + 20;
-       stream.avail_in = left - 20;
-       stream.next_out = delta_head;
-       stream.avail_out = sizeof(delta_head);
+       /* We choose to only get the type of the base object and
+        * ignore potentially corrupt pack file that expects the delta
+        * based on a base with a wrong size.  This saves tons of
+        * inflate() calls.
+        */
 
-       inflateInit(&stream);
-       st = inflate(&stream, Z_FINISH);
-       inflateEnd(&stream);
-       if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head))
-               die("delta data unpack-initial failed");
+       if (sha1_object_info(base_sha1, type, NULL))
+               die("cannot get info for delta-pack base");
 
-       /* Examine the initial part of the delta to figure out
-        * the result size.  Verify the base size while we are at it.
-        */
-       data = delta_head;
-       verify_base_size = get_delta_hdr_size(&data);
-       if (verify_base_size != base_size)
-               die("delta base size mismatch");
+       if (sizep) {
+               const unsigned char *data;
+               unsigned char delta_head[64];
+               unsigned long result_size;
+               z_stream stream;
+               int st;
+
+               memset(&stream, 0, sizeof(stream));
+
+               data = stream.next_in = base_sha1 + 20;
+               stream.avail_in = left - 20;
+               stream.next_out = delta_head;
+               stream.avail_out = sizeof(delta_head);
+
+               inflateInit(&stream);
+               st = inflate(&stream, Z_FINISH);
+               inflateEnd(&stream);
+               if ((st != Z_STREAM_END) &&
+                   stream.total_out != sizeof(delta_head))
+                       die("delta data unpack-initial failed");
+
+               /* Examine the initial part of the delta to figure out
+                * the result size.
+                */
+               data = delta_head;
+               get_delta_hdr_size(&data); /* ignore base size */
 
-       /* Read the result size */
-       result_size = get_delta_hdr_size(&data);
-       *sizep = result_size;
+               /* Read the result size */
+               result_size = get_delta_hdr_size(&data);
+               *sizep = result_size;
+       }
        return 0;
 }
 
@@ -726,7 +734,8 @@ static int packed_object_info(struct pack_entry *entry,
        default:
                die("corrupted pack file");
        }
-       *sizep = size;
+       if (sizep)
+               *sizep = size;
        unuse_packed_git(p);
        return 0;
 }
@@ -915,12 +924,7 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
 
                if (!find_pack_entry(sha1, &e))
                        return error("unable to find %s", sha1_to_hex(sha1));
-               if (!packed_object_info(&e, type, sizep))
-                       return 0;
-               /* sheesh */
-               map = unpack_entry(&e, type, sizep);
-               free(map);
-               return (map == NULL) ? 0 : -1;
+               return packed_object_info(&e, type, sizep);
        }
        if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
                status = error("unable to unpack %s header",
@@ -929,7 +933,8 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
                status = error("unable to parse %s header", sha1_to_hex(sha1));
        else {
                status = 0;
-               *sizep = size;
+               if (sizep)
+                       *sizep = size;
        }
        inflateEnd(&stream);
        munmap(map, mapsize);