diff --git a/cache.h b/cache.h index ce377e1354..67356dbe54 100644 --- a/cache.h +++ b/cache.h @@ -1074,6 +1074,7 @@ struct object_info { enum object_type *typep; unsigned long *sizep; unsigned long *disk_sizep; + unsigned char *delta_base_sha1; /* Response */ enum { diff --git a/sha1_file.c b/sha1_file.c index daacc0cfb0..4e8dd8be6d 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1667,6 +1667,38 @@ static off_t get_delta_base(struct packed_git *p, return base_offset; } +/* + * Like get_delta_base above, but we return the sha1 instead of the pack + * offset. This means it is cheaper for REF deltas (we do not have to do + * the final object lookup), but more expensive for OFS deltas (we + * have to load the revidx to convert the offset back into a sha1). + */ +static const unsigned char *get_delta_base_sha1(struct packed_git *p, + struct pack_window **w_curs, + off_t curpos, + enum object_type type, + off_t delta_obj_offset) +{ + if (type == OBJ_REF_DELTA) { + unsigned char *base = use_pack(p, w_curs, curpos, NULL); + return base; + } else if (type == OBJ_OFS_DELTA) { + struct revindex_entry *revidx; + off_t base_offset = get_delta_base(p, w_curs, &curpos, + type, delta_obj_offset); + + if (!base_offset) + return NULL; + + revidx = find_pack_revindex(p, base_offset); + if (!revidx) + return NULL; + + return nth_packed_object_sha1(p, revidx->nr); + } else + return NULL; +} + int unpack_object_header(struct packed_git *p, struct pack_window **w_curs, off_t *curpos, @@ -1824,6 +1856,22 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset, } } + if (oi->delta_base_sha1) { + if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) { + const unsigned char *base; + + base = get_delta_base_sha1(p, &w_curs, curpos, + type, obj_offset); + if (!base) { + type = OBJ_BAD; + goto out; + } + + hashcpy(oi->delta_base_sha1, base); + } else + hashclr(oi->delta_base_sha1); + } + out: unuse_pack(&w_curs); return type; @@ -2407,6 +2455,9 @@ static int sha1_loose_object_info(const unsigned char *sha1, git_zstream stream; char hdr[32]; + if (oi->delta_base_sha1) + hashclr(oi->delta_base_sha1); + /* * If we don't care about type or size, then we don't * need to look inside the object at all. Note that we @@ -2457,6 +2508,8 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi) *(oi->sizep) = co->size; if (oi->disk_sizep) *(oi->disk_sizep) = 0; + if (oi->delta_base_sha1) + hashclr(oi->delta_base_sha1); oi->whence = OI_CACHED; return 0; }