sha1_object_info_extended: make type calculation optional
authorJeff King <peff@peff.net>
Fri, 12 Jul 2013 06:34:57 +0000 (02:34 -0400)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Jul 2013 17:16:36 +0000 (10:16 -0700)
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>
builtin/cat-file.c
cache.h
sha1_file.c
streaming.c
index fe5c77f54cf556547a3c7d90ebc77ef841ca6593..163ce6c77cea19b8c209e52ea2694f98d6cb0d05 100644 (file)
@@ -150,7 +150,9 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
                if (!data->mark_query)
                        strbuf_addstr(sb, sha1_to_hex(data->sha1));
        } else if (is_atom("objecttype", atom, len)) {
-               if (!data->mark_query)
+               if (data->mark_query)
+                       data->info.typep = &data->type;
+               else
                        strbuf_addstr(sb, typename(data->type));
        } else if (is_atom("objectsize", atom, len)) {
                if (data->mark_query)
@@ -229,8 +231,7 @@ static int batch_one_object(const char *obj_name, struct batch_options *opt,
                return 0;
        }
 
-       data->type = sha1_object_info_extended(data->sha1, &data->info);
-       if (data->type <= 0) {
+       if (sha1_object_info_extended(data->sha1, &data->info) < 0) {
                printf("%s missing\n", obj_name);
                fflush(stdout);
                return 0;
diff --git a/cache.h b/cache.h
index dc99366a2e643a6217d474495611b09cfc6db20f..6882bbe6c3f36f8626ce8b1791d44cc1b99b4e16 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1099,6 +1099,7 @@ extern int unpack_object_header(struct packed_git *, struct pack_window **, off_
 
 struct object_info {
        /* Request */
+       enum object_type *typep;
        unsigned long *sizep;
        unsigned long *disk_sizep;
 
index fa2809884bfc9100bf78bec61e9ee5809a1d2abe..d39127131066c7ae34fc2b7d97f3c5d4f66299c2 100644 (file)
@@ -2433,24 +2433,26 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
 {
        struct cached_object *co;
        struct pack_entry e;
-       int type, rtype;
+       int rtype;
 
        co = find_cached_object(sha1);
        if (co) {
+               if (oi->typep)
+                       *(oi->typep) = co->type;
                if (oi->sizep)
                        *(oi->sizep) = co->size;
                if (oi->disk_sizep)
                        *(oi->disk_sizep) = 0;
                oi->whence = OI_CACHED;
-               return co->type;
+               return 0;
        }
 
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(sha1, &type,
+               if (!sha1_loose_object_info(sha1, oi->typep,
                                            oi->sizep, oi->disk_sizep)) {
                        oi->whence = OI_LOOSE;
-                       return type;
+                       return 0;
                }
 
                /* 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)
                        return -1;
        }
 
-       rtype = packed_object_info(e.p, e.offset, &type, oi->sizep,
+       rtype = packed_object_info(e.p, e.offset, oi->typep, oi->sizep,
                                   oi->disk_sizep);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, sha1);
@@ -2474,15 +2476,19 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
                                         rtype == OBJ_OFS_DELTA);
        }
 
-       return type;
+       return 0;
 }
 
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
+       enum object_type type;
        struct object_info oi = {0};
 
+       oi.typep = &type;
        oi.sizep = sizep;
-       return sha1_object_info_extended(sha1, &oi);
+       if (sha1_object_info_extended(sha1, &oi) < 0)
+               return -1;
+       return type;
 }
 
 static void *read_packed_sha1(const unsigned char *sha1,
index cac282f06b3751d8f316653daa79026c9633629c..870657ab5643baac23bbc4ce2a2a073a14299a5f 100644 (file)
@@ -111,11 +111,11 @@ static enum input_source istream_source(const unsigned char *sha1,
        unsigned long size;
        int status;
 
+       oi->typep = type;
        oi->sizep = &size;
        status = sha1_object_info_extended(sha1, oi);
        if (status < 0)
                return stream_error;
-       *type = status;
 
        switch (oi->whence) {
        case OI_LOOSE: