From: Junio C Hamano <junkio@cox.net>
Date: Fri, 1 Jul 2005 00:13:07 +0000 (-0700)
Subject: [PATCH] Avoid unnecessarily inflating and interpreting delta
X-Git-Tag: v0.99~103
X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=c62266f37c677c1de7415ac6cf1e2eb6726590e1;p=git.git

[PATCH] Avoid unnecessarily inflating and interpreting delta

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>
---

diff --git a/cat-file.c b/cat-file.c
index 85a5d4cae..fa0bb722a 100644
--- a/cat-file.c
+++ b/cat-file.c
@@ -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);
diff --git a/sha1_file.c b/sha1_file.c
index 63cbdded8..3178fbf83 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -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);