summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2013-09-08 14:22:38 +0700
committerNicolas Pitre <nico@fluxnic.net>2013-09-13 21:00:28 -0400
commit8ba6d1fc9fdc7fa8072b6385fe87916398f4b769 (patch)
treecdd29e9be05a62fa6cbe7c680a1bebfe56dccdda
parentf8f5b1697a0b612e64b6f18c84bb6b829e8dd3d7 (diff)
downloadgit-8ba6d1fc9fdc7fa8072b6385fe87916398f4b769.tar.gz
index-pack: record all delta bases in v4 (tree and ref-delta)
Signed-off-by: Nicolas Pitre <nico@fluxnic.net>
-rw-r--r--builtin/index-pack.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 18f64fa6eb..5f04809de4 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -24,6 +24,7 @@ struct object_entry {
enum object_type real_type; /* type after delta resolving */
unsigned delta_depth;
int base_object_no;
+ int nr_bases; /* only valid for v4 trees */
};
union delta_base {
@@ -482,6 +483,11 @@ static int is_delta_type(enum object_type type)
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
}
+static int is_delta_tree(const struct object_entry *obj)
+{
+ return obj->type == OBJ_PV4_TREE && obj->nr_bases > 0;
+}
+
static void read_and_inflate(unsigned long offset,
void *buf, unsigned long size,
unsigned long wraparound,
@@ -587,6 +593,20 @@ static void add_ofs_delta(struct object_entry *obj,
nr_deltas++;
}
+static void add_tree_delta_base(struct object_entry *obj,
+ const unsigned char *base,
+ int delta_start)
+{
+ int i;
+
+ for (i = delta_start; i < nr_deltas; i++)
+ if (!hashcmp(base, deltas[i].base.sha1))
+ return;
+
+ add_sha1_delta(obj, base);
+ obj->nr_bases++;
+}
+
/*
* v4 trees are actually kind of deltas and we don't do delta in the
* first pass. This function only walks through a tree object to find
@@ -601,12 +621,14 @@ static void *unpack_tree_v4(struct object_entry *obj,
unsigned int nr = read_varint();
const unsigned char *last_base = NULL;
struct strbuf sb = STRBUF_INIT;
+ int delta_start = nr_deltas;
while (nr) {
unsigned int copy_start_or_path = read_varint();
if (copy_start_or_path & 1) { /* copy_start */
unsigned int copy_count = read_varint();
if (copy_count & 1) { /* first delta */
last_base = read_sha1table_ref();
+ add_tree_delta_base(obj, last_base, delta_start);
} else if (!last_base)
bad_object(offset,
_("missing delta base unpack_tree_v4"));
@@ -740,9 +762,15 @@ static void *unpack_raw_entry(struct object_entry *obj,
switch (obj->type) {
case OBJ_REF_DELTA:
- add_sha1_delta(obj, fill_and_use(20));
+ if (packv4)
+ add_sha1_delta(obj, read_sha1table_ref());
+ else
+ add_sha1_delta(obj, fill_and_use(20));
break;
case OBJ_OFS_DELTA:
+ if (packv4)
+ die(_("pack version 4 does not support ofs-delta type (offset %lu)"),
+ (unsigned long)obj->idx.offset);
offset = obj->idx.offset - read_varint();
if (offset <= 0 || offset >= obj->idx.offset)
bad_object(obj->idx.offset,
@@ -1310,8 +1338,7 @@ static void parse_pack_objects(unsigned char *sha1)
for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
void *data = unpack_raw_entry(obj, obj->idx.sha1);
- if (is_delta_type(obj->type) ||
- (!data && obj->type == OBJ_PV4_TREE)) {
+ if (is_delta_type(obj->type) || is_delta_tree(obj)) {
/* delay sha1_object() until second pass */
} else if (!data) {
/* large blobs, check later */