sha1_object_info_extended: make type calculation optional

Each caller of sha1_object_info_extended sets up an object_info struct to tell the function which elements of the object it wants to get. Until now, getting the type of the object has always been required (and it is returned via the return type rather than a pointer in object_info). This can involve actually opening a loose object file to determine its type, or following delta chains to determine a packed file's base type. These effects produce a measurable slow-down when doing a "cat-file --batch-check" that does not include %(objecttype). This patch adds a "typep" query to struct object_info, so that it can be optionally queried just like size and disk_size. As a result, the return type of the function is no longer the object type, but rather 0/-1 for success/error. As there are only three callers total, we just fix up each caller rather than keep a compatibility wrapper: 1. The simpler sha1_object_info wrapper continues to always ask for and return the type field. 2. The istream_source function wants to know the type, and so always asks for it. 3. The cat-file batch code asks for the type only when %(objecttype) is part of the format string. On linux.git, the best-of-five for running: $ git rev-list --objects --all >objects $ time git cat-file --batch-check='%(objectsize:disk)' on a fully packed repository goes from: real 0m8.680s user 0m8.160s sys 0m0.512s to: real 0m7.205s user 0m6.580s sys 0m0.608s Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jul 12, 2013 at 02:34 UTC 5b0864070e1e64683e49464c77a72f3c528c8f71
4 files changed +19 -11
builtin/cat-file.c
+4 -3
@@ -150,7 +150,9 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
150 if (!data->mark_query)
151 strbuf_addstr(sb, sha1_to_hex(data->sha1));
152 } else if (is_atom("objecttype", atom, len)) {
153 - if (!data->mark_query)
153 + if (data->mark_query)
154 + data->info.typep = &data->type;
155 + else
156 strbuf_addstr(sb, typename(data->type));
157 } else if (is_atom("objectsize", atom, len)) {
158 if (data->mark_query)
@@ -229,8 +231,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
231 return 0;
232 }
233
232 - data->type = sha1_object_info_extended(data->sha1, &data->info);
233 - if (data->type <= 0) {
234 + if (sha1_object_info_extended(data->sha1, &data->info) < 0) {
235 printf("%s missing\n", obj_name);
236 fflush(stdout);
237 return 0;
cache.h
+1
@@ -1099,6 +1099,7 @@ extern int unpack_object_header(struct packed_git *, struct pack_window **, off_
1099
1100 struct object_info {
1101 /* Request */
1102 + enum object_type *typep;
1103 unsigned long *sizep;
1104 unsigned long *disk_sizep;
1105
sha1_file.c
+13 -7
@@ -2433,24 +2433,26 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
2433 {
2434 struct cached_object *co;
2435 struct pack_entry e;
2436 - int type, rtype;
2436 + int rtype;
2437
2438 co = find_cached_object(sha1);
2439 if (co) {
2440 + if (oi->typep)
2441 + *(oi->typep) = co->type;
2442 if (oi->sizep)
2443 *(oi->sizep) = co->size;
2444 if (oi->disk_sizep)
2445 *(oi->disk_sizep) = 0;
2446 oi->whence = OI_CACHED;
2445 - return co->type;
2447 + return 0;
2448 }
2449
2450 if (!find_pack_entry(sha1, &e)) {
2451 /* Most likely it's a loose object. */
2450 - if (!sha1_loose_object_info(sha1, &type,
2452 + if (!sha1_loose_object_info(sha1, oi->typep,
2453 oi->sizep, oi->disk_sizep)) {
2454 oi->whence = OI_LOOSE;
2453 - return type;
2455 + return 0;
2456 }
2457
2458 /* Not a loose object; someone else may have just packed it. */
@@ -2459,7 +2461,7 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
2461 return -1;
2462 }
2463
2462 - rtype = packed_object_info(e.p, e.offset, &type, oi->sizep,
2464 + rtype = packed_object_info(e.p, e.offset, oi->typep, oi->sizep,
2465 oi->disk_sizep);
2466 if (rtype < 0) {
2467 mark_bad_packed_object(e.p, sha1);
@@ -2474,15 +2476,19 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
2476 rtype == OBJ_OFS_DELTA);
2477 }
2478
2477 - return type;
2479 + return 0;
2480 }
2481
2482 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
2483 {
2484 + enum object_type type;
2485 struct object_info oi = {0};
2486
2487 + oi.typep = &type;
2488 oi.sizep = sizep;
2485 - return sha1_object_info_extended(sha1, &oi);
2489 + if (sha1_object_info_extended(sha1, &oi) < 0)
2490 + return -1;
2491 + return type;
2492 }
2493
2494 static void *read_packed_sha1(const unsigned char *sha1,
streaming.c
+1 -1
@@ -111,11 +111,11 @@ static enum input_source istream_source(const unsigned char *sha1,
111 unsigned long size;
112 int status;
113
114 + oi->typep = type;
115 oi->sizep = &size;
116 status = sha1_object_info_extended(sha1, oi);
117 if (status < 0)
118 return stream_error;
118 - *type = status;
119
120 switch (oi->whence) {
121 case OI_LOOSE: