Merge branch 'jt/unify-object-info'

Code clean-ups.

* jt/unify-object-info:
  sha1_file: refactor has_sha1_file_with_flags
  sha1_file: do not access pack if unneeded
  sha1_file: teach sha1_object_info_extended more flags
  sha1_file: refactor read_object
  sha1_file: move delta base cache code up
  sha1_file: rename LOOKUP_REPLACE_OBJECT
  sha1_file: rename LOOKUP_UNKNOWN_OBJECT
  sha1_file: teach packed_object_info about typename
This commit is contained in:
Junio C Hamano
2017-07-05 13:32:57 -07:00
5 changed files with 223 additions and 216 deletions

View File

@ -1964,7 +1964,7 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
* we're obtaining the type using '--allow-unknown-type'
* option.
*/
if ((flags & LOOKUP_UNKNOWN_OBJECT) && (type < 0))
if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
type = 0;
else if (type < 0)
die("invalid object type");
@ -2002,20 +2002,7 @@ int parse_sha1_header(const char *hdr, unsigned long *sizep)
struct object_info oi = OBJECT_INFO_INIT;
oi.sizep = sizep;
return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT);
}
static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
{
int ret;
git_zstream stream;
char hdr[8192];
ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
return NULL;
return unpack_sha1_rest(&stream, hdr, *size, sha1);
return parse_sha1_header_extended(hdr, &oi, 0);
}
unsigned long get_size_from_delta(struct packed_git *p,
@ -2239,107 +2226,6 @@ unwind:
goto out;
}
int packed_object_info(struct packed_git *p, off_t obj_offset,
struct object_info *oi)
{
struct pack_window *w_curs = NULL;
unsigned long size;
off_t curpos = obj_offset;
enum object_type type;
/*
* We always get the representation type, but only convert it to
* a "real" type later if the caller is interested.
*/
type = unpack_object_header(p, &w_curs, &curpos, &size);
if (oi->sizep) {
if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
off_t tmp_pos = curpos;
off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
type, obj_offset);
if (!base_offset) {
type = OBJ_BAD;
goto out;
}
*oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
if (*oi->sizep == 0) {
type = OBJ_BAD;
goto out;
}
} else {
*oi->sizep = size;
}
}
if (oi->disk_sizep) {
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
*oi->disk_sizep = revidx[1].offset - obj_offset;
}
if (oi->typep) {
*oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
if (*oi->typep < 0) {
type = OBJ_BAD;
goto out;
}
}
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;
}
static void *unpack_compressed_entry(struct packed_git *p,
struct pack_window **w_curs,
off_t curpos,
unsigned long size)
{
int st;
git_zstream stream;
unsigned char *buffer, *in;
buffer = xmallocz_gently(size);
if (!buffer)
return NULL;
memset(&stream, 0, sizeof(stream));
stream.next_out = buffer;
stream.avail_out = size + 1;
git_inflate_init(&stream);
do {
in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
st = git_inflate(&stream, Z_FINISH);
if (!stream.avail_out)
break; /* the payload is larger than it should be */
curpos += stream.next_in - in;
} while (st == Z_OK || st == Z_BUF_ERROR);
git_inflate_end(&stream);
if ((st != Z_STREAM_END) || stream.total_out != size) {
free(buffer);
return NULL;
}
return buffer;
}
static struct hashmap delta_base_cache;
static size_t delta_base_cached;
@ -2427,8 +2313,10 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
if (!ent)
return unpack_entry(p, base_offset, type, base_size);
*type = ent->type;
*base_size = ent->size;
if (type)
*type = ent->type;
if (base_size)
*base_size = ent->size;
return xmemdupz(ent->data, ent->size);
}
@ -2477,6 +2365,123 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
hashmap_add(&delta_base_cache, ent);
}
int packed_object_info(struct packed_git *p, off_t obj_offset,
struct object_info *oi)
{
struct pack_window *w_curs = NULL;
unsigned long size;
off_t curpos = obj_offset;
enum object_type type;
/*
* We always get the representation type, but only convert it to
* a "real" type later if the caller is interested.
*/
if (oi->contentp) {
*oi->contentp = cache_or_unpack_entry(p, obj_offset, oi->sizep,
&type);
if (!*oi->contentp)
type = OBJ_BAD;
} else {
type = unpack_object_header(p, &w_curs, &curpos, &size);
}
if (!oi->contentp && oi->sizep) {
if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
off_t tmp_pos = curpos;
off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
type, obj_offset);
if (!base_offset) {
type = OBJ_BAD;
goto out;
}
*oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
if (*oi->sizep == 0) {
type = OBJ_BAD;
goto out;
}
} else {
*oi->sizep = size;
}
}
if (oi->disk_sizep) {
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
*oi->disk_sizep = revidx[1].offset - obj_offset;
}
if (oi->typep || oi->typename) {
enum object_type ptot;
ptot = packed_to_object_type(p, obj_offset, type, &w_curs,
curpos);
if (oi->typep)
*oi->typep = ptot;
if (oi->typename) {
const char *tn = typename(ptot);
if (tn)
strbuf_addstr(oi->typename, tn);
}
if (ptot < 0) {
type = OBJ_BAD;
goto out;
}
}
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;
}
static void *unpack_compressed_entry(struct packed_git *p,
struct pack_window **w_curs,
off_t curpos,
unsigned long size)
{
int st;
git_zstream stream;
unsigned char *buffer, *in;
buffer = xmallocz_gently(size);
if (!buffer)
return NULL;
memset(&stream, 0, sizeof(stream));
stream.next_out = buffer;
stream.avail_out = size + 1;
git_inflate_init(&stream);
do {
in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
st = git_inflate(&stream, Z_FINISH);
if (!stream.avail_out)
break; /* the payload is larger than it should be */
curpos += stream.next_in - in;
} while (st == Z_OK || st == Z_BUF_ERROR);
git_inflate_end(&stream);
if ((st != Z_STREAM_END) || stream.total_out != size) {
free(buffer);
return NULL;
}
return buffer;
}
static void *read_object(const unsigned char *sha1, enum object_type *type,
unsigned long *size);
@ -2670,8 +2675,10 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
free(external_base);
}
*final_type = type;
*final_size = size;
if (final_type)
*final_type = type;
if (final_size)
*final_size = size;
unuse_pack(&w_curs);
@ -2905,6 +2912,7 @@ static int sha1_loose_object_info(const unsigned char *sha1,
git_zstream stream;
char hdr[32];
struct strbuf hdrbuf = STRBUF_INIT;
unsigned long size_scratch;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
@ -2917,7 +2925,7 @@ static int sha1_loose_object_info(const unsigned char *sha1,
* return value implicitly indicates whether the
* object even exists.
*/
if (!oi->typep && !oi->typename && !oi->sizep) {
if (!oi->typep && !oi->typename && !oi->sizep && !oi->contentp) {
const char *path;
struct stat st;
if (stat_sha1_file(sha1, &st, &path) < 0)
@ -2930,9 +2938,13 @@ static int sha1_loose_object_info(const unsigned char *sha1,
map = map_sha1_file(sha1, &mapsize);
if (!map)
return -1;
if (!oi->sizep)
oi->sizep = &size_scratch;
if (oi->disk_sizep)
*oi->disk_sizep = mapsize;
if ((flags & LOOKUP_UNKNOWN_OBJECT)) {
if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
status = error("unable to unpack %s header with --allow-unknown-type",
sha1_to_hex(sha1));
@ -2947,36 +2959,52 @@ static int sha1_loose_object_info(const unsigned char *sha1,
sha1_to_hex(sha1));
} else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
status = error("unable to parse %s header", sha1_to_hex(sha1));
git_inflate_end(&stream);
if (status >= 0 && oi->contentp)
*oi->contentp = unpack_sha1_rest(&stream, hdr,
*oi->sizep, sha1);
else
git_inflate_end(&stream);
munmap(map, mapsize);
if (status && oi->typep)
*oi->typep = status;
if (oi->sizep == &size_scratch)
oi->sizep = NULL;
strbuf_release(&hdrbuf);
return (status < 0) ? status : 0;
}
int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
{
struct cached_object *co;
static struct object_info blank_oi = OBJECT_INFO_INIT;
struct pack_entry e;
int rtype;
enum object_type real_type;
const unsigned char *real = lookup_replace_object_extended(sha1, flags);
const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
lookup_replace_object(sha1) :
sha1;
co = find_cached_object(real);
if (co) {
if (oi->typep)
*(oi->typep) = co->type;
if (oi->sizep)
*(oi->sizep) = co->size;
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
if (oi->typename)
strbuf_addstr(oi->typename, typename(co->type));
oi->whence = OI_CACHED;
return 0;
if (!oi)
oi = &blank_oi;
if (!(flags & OBJECT_INFO_SKIP_CACHED)) {
struct cached_object *co = find_cached_object(real);
if (co) {
if (oi->typep)
*(oi->typep) = co->type;
if (oi->sizep)
*(oi->sizep) = co->size;
if (oi->disk_sizep)
*(oi->disk_sizep) = 0;
if (oi->delta_base_sha1)
hashclr(oi->delta_base_sha1);
if (oi->typename)
strbuf_addstr(oi->typename, typename(co->type));
if (oi->contentp)
*oi->contentp = xmemdupz(co->buf, co->size);
oi->whence = OI_CACHED;
return 0;
}
}
if (!find_pack_entry(real, &e)) {
@ -2987,23 +3015,25 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
}
/* Not a loose object; someone else may have just packed it. */
reprepare_packed_git();
if (!find_pack_entry(real, &e))
if (flags & OBJECT_INFO_QUICK) {
return -1;
} else {
reprepare_packed_git();
if (!find_pack_entry(real, &e))
return -1;
}
}
/*
* packed_object_info() does not follow the delta chain to
* find out the real type, unless it is given oi->typep.
*/
if (oi->typename && !oi->typep)
oi->typep = &real_type;
if (oi == &blank_oi)
/*
* We know that the caller doesn't actually need the
* information below, so return early.
*/
return 0;
rtype = packed_object_info(e.p, e.offset, oi);
if (rtype < 0) {
mark_bad_packed_object(e.p, real);
if (oi->typep == &real_type)
oi->typep = NULL;
return sha1_object_info_extended(real, oi, 0);
} else if (in_delta_base_cache(e.p, e.offset)) {
oi->whence = OI_DBCACHED;
@ -3014,10 +3044,6 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
rtype == OBJ_OFS_DELTA);
}
if (oi->typename)
strbuf_addstr(oi->typename, typename(*oi->typep));
if (oi->typep == &real_type)
oi->typep = NULL;
return 0;
}
@ -3030,7 +3056,8 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
oi.typep = &type;
oi.sizep = sizep;
if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
if (sha1_object_info_extended(sha1, &oi,
OBJECT_INFO_LOOKUP_REPLACE) < 0)
return -1;
return type;
}
@ -3080,28 +3107,15 @@ int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
static void *read_object(const unsigned char *sha1, enum object_type *type,
unsigned long *size)
{
unsigned long mapsize;
void *map, *buf;
struct cached_object *co;
struct object_info oi = OBJECT_INFO_INIT;
void *content;
oi.typep = type;
oi.sizep = size;
oi.contentp = &content;
co = find_cached_object(sha1);
if (co) {
*type = co->type;
*size = co->size;
return xmemdupz(co->buf, co->size);
}
buf = read_packed_sha1(sha1, type, size);
if (buf)
return buf;
map = map_sha1_file(sha1, &mapsize);
if (map) {
buf = unpack_sha1_file(map, mapsize, type, size, sha1);
munmap(map, mapsize);
return buf;
}
reprepare_packed_git();
return read_packed_sha1(sha1, type, size);
if (sha1_object_info_extended(sha1, &oi, 0) < 0)
return NULL;
return content;
}
/*
@ -3112,13 +3126,14 @@ static void *read_object(const unsigned char *sha1, enum object_type *type,
void *read_sha1_file_extended(const unsigned char *sha1,
enum object_type *type,
unsigned long *size,
unsigned flag)
int lookup_replace)
{
void *data;
const struct packed_git *p;
const char *path;
struct stat st;
const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
const unsigned char *repl = lookup_replace ? lookup_replace_object(sha1)
: sha1;
errno = 0;
data = read_object(repl, type, size);
@ -3479,18 +3494,10 @@ int has_sha1_pack(const unsigned char *sha1)
int has_sha1_file_with_flags(const unsigned char *sha1, int flags)
{
struct pack_entry e;
if (!startup_info->have_repository)
return 0;
if (find_pack_entry(sha1, &e))
return 1;
if (has_loose_object(sha1))
return 1;
if (flags & HAS_SHA1_QUICK)
return 0;
reprepare_packed_git();
return find_pack_entry(sha1, &e);
return sha1_object_info_extended(sha1, NULL,
flags | OBJECT_INFO_SKIP_CACHED) >= 0;
}
int has_object_file(const struct object_id *oid)