Permalink
Browse files

chunked-object: fallback checkout codepaths

This prepares the default codepaths based on the traditional "slurping
everything in-core" model around read_sha1_file() API for objects that use
chunked encoding. Needless to say, these codepaths are unsuitable for the
kind of objects that use chunked encoding and are intended to only serve
as the fallback where specialized "large object API" support is still
lacking.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information...
1 parent 21aa04b commit 01f654e8289dcf2e09165d2335d7f094654165cf @gitster gitster committed Dec 1, 2011
Showing with 73 additions and 1 deletion.
  1. +60 −0 sha1_file.c
  2. +13 −1 t/t1050-large.sh
View
@@ -1617,6 +1617,11 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
if (sizep)
*sizep = size;
break;
+ case OBJ_CHUNKED_BLOB:
+ if (sizep)
+ *sizep = size;
+ type = OBJ_DEKNUHC(type);
+ break;
default:
error("unknown object type %i at offset %"PRIuMAX" in %s",
type, (uintmax_t)obj_offset, p->pack_name);
@@ -1658,6 +1663,57 @@ static void *unpack_compressed_entry(struct packed_git *p,
return buffer;
}
+static void *unpack_chunked_entry(struct packed_git *p,
+ struct pack_window **w_curs,
+ off_t curpos,
+ unsigned long size)
+{
+ /*
+ * *NOTE* *NOTE* *NOTE*
+ *
+ * In the longer term, we should aim to exercise this codepath
+ * less and less often, as it defeats the whole purpose of
+ * chuncked object encoding!
+ */
+ unsigned char *buffer;
+ const unsigned char *in, *ptr;
+ unsigned long avail, ofs;
+ int chunk_cnt;
+
+ buffer = xmallocz(size);
+ in = use_pack(p, w_curs, curpos, &avail);
+ ptr = in;
+ chunk_cnt = decode_in_pack_varint(&ptr);
+ curpos += ptr - in;
+ ofs = 0;
+ while (chunk_cnt--) {
+ unsigned long csize;
+ unsigned char *data;
+ enum object_type type;
+
+ in = use_pack(p, w_curs, curpos, &avail);
+ data = read_sha1_file(in, &type, &csize);
+ if (!data)
+ die("malformed chunked object contents ('%s' does not exist)",
+ sha1_to_hex(in));
+ if (type != OBJ_BLOB)
+ die("malformed chunked object contents (not a blob)");
+
+ /*
+ * The sum of the size of component blobs should match
+ * the resulting object, or something is wrong.
+ */
+ if ((chunk_cnt && (size < ofs + csize)) ||
+ (!chunk_cnt && (size != ofs + csize)))
+ die("malformed chunked object contents (sizes do not add up)");
+ memcpy(buffer + ofs, data, csize);
+ ofs += csize;
+ curpos += 20;
+ free(data);
+ }
+ return buffer;
+}
+
#define MAX_DELTA_CACHE (256)
static size_t delta_base_cached;
@@ -1893,6 +1949,10 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
case OBJ_TAG:
data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
break;
+ case OBJ_CHUNKED_BLOB:
+ data = unpack_chunked_entry(p, &w_curs, curpos, *sizep);
+ *type = OBJ_DEKNUHC(*type);
+ break;
default:
data = NULL;
error("unknown object type %i at offset %"PRIuMAX" in %s",
View
@@ -124,8 +124,20 @@ test_expect_success 'split limit' '
# switch to a better chunking heuristics.
echo cruft >head &&
cat split >>head &&
- git add head
+ git add head &&
+ echo blob >expect &&
+ git cat-file -t :split >actual &&
+ test_cmp expect actual &&
+
+ git cat-file -p :split >actual &&
+ # You probably do not want to use test_cmp here...
+ cmp split actual &&
+
+ mv split expect &&
+ git checkout split &&
+ # You probably do not want to use test_cmp here...
+ cmp expect split
)
'

0 comments on commit 01f654e

Please sign in to comment.