Merge branch 'maint'
[gitweb.git] / builtin / index-pack.c
index 0216af76af3dd263182d85333de456a3e2667013..0945adbb3bb188b612341c31c8986fabb491928d 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "delta.h"
 #include "pack.h"
 #include "csum-file.h"
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
 
-struct object_entry
-{
+struct object_entry {
        struct pack_idx_entry idx;
        unsigned long size;
        unsigned int hdr_size;
        enum object_type type;
        enum object_type real_type;
+       unsigned delta_depth;
+       int base_object_no;
 };
 
 union delta_base {
@@ -44,8 +45,7 @@ struct base_data {
 #define FLAG_LINK (1u<<20)
 #define FLAG_CHECKED (1u<<21)
 
-struct delta_entry
-{
+struct delta_entry {
        union delta_base base;
        int obj_no;
 };
@@ -68,6 +68,7 @@ static struct progress *progress;
 static unsigned char input_buffer[4096];
 static unsigned int input_offset, input_len;
 static off_t consumed_bytes;
+static unsigned deepest_delta;
 static git_SHA_CTX input_ctx;
 static uint32_t input_crc32;
 static int input_fd, output_fd, pack_fd;
@@ -209,7 +210,7 @@ static void parse_pack_header(void)
 static NORETURN void bad_object(unsigned long offset, const char *format,
                       ...) __attribute__((format (printf, 2, 3)));
 
-static void bad_object(unsigned long offset, const char *format, ...)
+static NORETURN void bad_object(unsigned long offset, const char *format, ...)
 {
        va_list params;
        char buf[1024];
@@ -267,7 +268,7 @@ static void unlink_base_data(struct base_data *c)
 static void *unpack_entry_data(unsigned long offset, unsigned long size)
 {
        int status;
-       z_stream stream;
+       git_zstream stream;
        void *buf = xmalloc(size);
 
        memset(&stream, 0, sizeof(stream));
@@ -296,7 +297,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
        void *data;
 
        obj->idx.offset = consumed_bytes;
-       input_crc32 = crc32(0, Z_NULL, 0);
+       input_crc32 = crc32(0, NULL, 0);
 
        p = fill(1);
        c = *p;
@@ -357,7 +358,7 @@ static void *get_data_from_pack(struct object_entry *obj)
        off_t from = obj[0].idx.offset + obj[0].hdr_size;
        unsigned long len = obj[1].idx.offset - from;
        unsigned char *data, *inbuf;
-       z_stream stream;
+       git_zstream stream;
        int status;
 
        data = xmalloc(obj->size);
@@ -535,6 +536,10 @@ static void resolve_delta(struct object_entry *delta_obj,
        void *base_data, *delta_data;
 
        delta_obj->real_type = base->obj->real_type;
+       delta_obj->delta_depth = base->obj->delta_depth + 1;
+       if (deepest_delta < delta_obj->delta_depth)
+               deepest_delta = delta_obj->delta_depth;
+       delta_obj->base_object_no = base->obj - objects;
        delta_data = get_data_from_pack(delta_obj);
        base_data = get_base_data(base);
        result->obj = delta_obj;
@@ -692,26 +697,26 @@ static void parse_pack_objects(unsigned char *sha1)
 
 static int write_compressed(struct sha1file *f, void *in, unsigned int size)
 {
-       z_stream stream;
+       git_zstream stream;
        int status;
        unsigned char outbuf[4096];
 
        memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, zlib_compression_level);
+       git_deflate_init(&stream, zlib_compression_level);
        stream.next_in = in;
        stream.avail_in = size;
 
        do {
                stream.next_out = outbuf;
                stream.avail_out = sizeof(outbuf);
-               status = deflate(&stream, Z_FINISH);
+               status = git_deflate(&stream, Z_FINISH);
                sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
        } while (status == Z_OK);
 
        if (status != Z_STREAM_END)
                die("unable to deflate appended object (%d)", status);
        size = stream.total_out;
-       deflateEnd(&stream);
+       git_deflate_end(&stream);
        return size;
 }
 
@@ -967,9 +972,49 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
        free(p);
 }
 
+static void show_pack_info(int stat_only)
+{
+       int i, baseobjects = nr_objects - nr_deltas;
+       unsigned long *chain_histogram = NULL;
+
+       if (deepest_delta)
+               chain_histogram = xcalloc(deepest_delta, sizeof(unsigned long));
+
+       for (i = 0; i < nr_objects; i++) {
+               struct object_entry *obj = &objects[i];
+
+               if (is_delta_type(obj->type))
+                       chain_histogram[obj->delta_depth - 1]++;
+               if (stat_only)
+                       continue;
+               printf("%s %-6s %lu %lu %"PRIuMAX,
+                      sha1_to_hex(obj->idx.sha1),
+                      typename(obj->real_type), obj->size,
+                      (unsigned long)(obj[1].idx.offset - obj->idx.offset),
+                      (uintmax_t)obj->idx.offset);
+               if (is_delta_type(obj->type)) {
+                       struct object_entry *bobj = &objects[obj->base_object_no];
+                       printf(" %u %s", obj->delta_depth, sha1_to_hex(bobj->idx.sha1));
+               }
+               putchar('\n');
+       }
+
+       if (baseobjects)
+               printf("non delta: %d object%s\n",
+                      baseobjects, baseobjects > 1 ? "s" : "");
+       for (i = 0; i < deepest_delta; i++) {
+               if (!chain_histogram[i])
+                       continue;
+               printf("chain length = %d: %lu object%s\n",
+                      i + 1,
+                      chain_histogram[i],
+                      chain_histogram[i] > 1 ? "s" : "");
+       }
+}
+
 int cmd_index_pack(int argc, const char **argv, const char *prefix)
 {
-       int i, fix_thin_pack = 0, verify = 0;
+       int i, fix_thin_pack = 0, verify = 0, stat_only = 0, stat = 0;
        const char *curr_pack, *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
        const char *keep_name = NULL, *keep_msg = NULL;
@@ -1000,6 +1045,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                strict = 1;
                        } else if (!strcmp(arg, "--verify")) {
                                verify = 1;
+                       } else if (!strcmp(arg, "--verify-stat")) {
+                               verify = 1;
+                               stat = 1;
+                       } else if (!strcmp(arg, "--verify-stat-only")) {
+                               verify = 1;
+                               stat = 1;
+                               stat_only = 1;
                        } else if (!strcmp(arg, "--keep")) {
                                keep_msg = "";
                        } else if (!prefixcmp(arg, "--keep=")) {
@@ -1075,8 +1127,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
 
        curr_pack = open_pack_file(pack_name);
        parse_pack_header();
-       objects = xmalloc((nr_objects + 1) * sizeof(struct object_entry));
-       deltas = xmalloc(nr_objects * sizeof(struct delta_entry));
+       objects = xcalloc(nr_objects + 1, sizeof(struct object_entry));
+       deltas = xcalloc(nr_objects, sizeof(struct delta_entry));
        parse_pack_objects(pack_sha1);
        if (nr_deltas == nr_resolved_deltas) {
                stop_progress(&progress);
@@ -1116,6 +1168,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (strict)
                check_objects();
 
+       if (stat)
+               show_pack_info(stat_only);
+
        idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;