index-pack: kill union delta_base to save memory
Once we know the number of objects in the input pack, we allocate an array of nr_objects of struct delta_entry. On x86-64, this struct is 32 bytes long. The union delta_base, which is part of struct delta_entry, provides enough space to store either ofs-delta (8 bytes) or ref-delta (20 bytes). Because ofs-delta encoding is more efficient space-wise and more performant at runtime than ref-delta encoding, Git packers try to use ofs-delta whenever possible, and it is expected that objects encoded as ref-delta are minority. In the best clone case where no ref-delta object is present, we waste (20-8) * nr_objects bytes because of this union. That's about 38MB out of 100MB for deltas[] with 3.4M objects, or 38%. deltas[] would be around 62MB without the waste. This patch attempts to eliminate that. deltas[] array is split into two: one for ofs-delta and one for ref-delta. Many functions are also duplicated because of this split. With this patch, ofs_deltas[] array takes 51MB. ref_deltas[] should remain unallocated in clone case (0 bytes). This array grows as we see ref-delta. We save about half in this case, or 25% of total bookkeeping. The saving is more than the calculation above because some padding in the old delta_entry struct is removed. ofs_delta_entry is 16 bytes, including the 4 bytes padding. That's 13MB for padding, but packing the struct could break platforms that do not support unaligned access. If someone on 32-bit is really low on memory and only deals with packs smaller than 2G, using 32-bit off_t would eliminate the padding and save 27MB on top. A note about ofs_deltas allocation. We could use ref_deltas memory allocation strategy for ofs_deltas. But that probably just adds more overhead on top. ofs-deltas are generally the majority (1/2 to 2/3) in any pack. Incremental realloc may lead to too many memcpy. And if we preallocate, say 1/2 or 2/3 of nr_objects initially, the growth rate of ALLOC_GROW() could make this array larger than nr_objects, wasting more memory. Brought-up-by: Matthew Sporleder <msporleder@gmail.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
parent
417305764a
commit
c6458e60ed
|
@ -28,11 +28,6 @@ struct object_stat {
|
||||||
int base_object_no;
|
int base_object_no;
|
||||||
};
|
};
|
||||||
|
|
||||||
union delta_base {
|
|
||||||
unsigned char sha1[20];
|
|
||||||
off_t offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct base_data {
|
struct base_data {
|
||||||
struct base_data *base;
|
struct base_data *base;
|
||||||
struct base_data *child;
|
struct base_data *child;
|
||||||
|
@ -52,26 +47,28 @@ struct thread_local {
|
||||||
int pack_fd;
|
int pack_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want
|
|
||||||
* to memcmp() only the first 20 bytes.
|
|
||||||
*/
|
|
||||||
#define UNION_BASE_SZ 20
|
|
||||||
|
|
||||||
#define FLAG_LINK (1u<<20)
|
#define FLAG_LINK (1u<<20)
|
||||||
#define FLAG_CHECKED (1u<<21)
|
#define FLAG_CHECKED (1u<<21)
|
||||||
|
|
||||||
struct delta_entry {
|
struct ofs_delta_entry {
|
||||||
union delta_base base;
|
off_t offset;
|
||||||
|
int obj_no;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ref_delta_entry {
|
||||||
|
unsigned char sha1[20];
|
||||||
int obj_no;
|
int obj_no;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct object_entry *objects;
|
static struct object_entry *objects;
|
||||||
static struct object_stat *obj_stat;
|
static struct object_stat *obj_stat;
|
||||||
static struct delta_entry *deltas;
|
static struct ofs_delta_entry *ofs_deltas;
|
||||||
|
static struct ref_delta_entry *ref_deltas;
|
||||||
static struct thread_local nothread_data;
|
static struct thread_local nothread_data;
|
||||||
static int nr_objects;
|
static int nr_objects;
|
||||||
static int nr_deltas;
|
static int nr_ofs_deltas;
|
||||||
|
static int nr_ref_deltas;
|
||||||
|
static int ref_deltas_alloc;
|
||||||
static int nr_resolved_deltas;
|
static int nr_resolved_deltas;
|
||||||
static int nr_threads;
|
static int nr_threads;
|
||||||
|
|
||||||
|
@ -480,7 +477,8 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *unpack_raw_entry(struct object_entry *obj,
|
static void *unpack_raw_entry(struct object_entry *obj,
|
||||||
union delta_base *delta_base,
|
off_t *ofs_offset,
|
||||||
|
unsigned char *ref_sha1,
|
||||||
unsigned char *sha1)
|
unsigned char *sha1)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
@ -509,11 +507,10 @@ static void *unpack_raw_entry(struct object_entry *obj,
|
||||||
|
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case OBJ_REF_DELTA:
|
case OBJ_REF_DELTA:
|
||||||
hashcpy(delta_base->sha1, fill(20));
|
hashcpy(ref_sha1, fill(20));
|
||||||
use(20);
|
use(20);
|
||||||
break;
|
break;
|
||||||
case OBJ_OFS_DELTA:
|
case OBJ_OFS_DELTA:
|
||||||
memset(delta_base, 0, sizeof(*delta_base));
|
|
||||||
p = fill(1);
|
p = fill(1);
|
||||||
c = *p;
|
c = *p;
|
||||||
use(1);
|
use(1);
|
||||||
|
@ -527,8 +524,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
|
||||||
use(1);
|
use(1);
|
||||||
base_offset = (base_offset << 7) + (c & 127);
|
base_offset = (base_offset << 7) + (c & 127);
|
||||||
}
|
}
|
||||||
delta_base->offset = obj->idx.offset - base_offset;
|
*ofs_offset = obj->idx.offset - base_offset;
|
||||||
if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
|
if (*ofs_offset <= 0 || *ofs_offset >= obj->idx.offset)
|
||||||
bad_object(obj->idx.offset, _("delta base offset is out of bound"));
|
bad_object(obj->idx.offset, _("delta base offset is out of bound"));
|
||||||
break;
|
break;
|
||||||
case OBJ_COMMIT:
|
case OBJ_COMMIT:
|
||||||
|
@ -612,55 +609,108 @@ static void *get_data_from_pack(struct object_entry *obj)
|
||||||
return unpack_data(obj, NULL, NULL);
|
return unpack_data(obj, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_delta_bases(const union delta_base *base1,
|
static int compare_ofs_delta_bases(off_t offset1, off_t offset2,
|
||||||
const union delta_base *base2,
|
enum object_type type1,
|
||||||
enum object_type type1,
|
enum object_type type2)
|
||||||
enum object_type type2)
|
|
||||||
{
|
{
|
||||||
int cmp = type1 - type2;
|
int cmp = type1 - type2;
|
||||||
if (cmp)
|
if (cmp)
|
||||||
return cmp;
|
return cmp;
|
||||||
return memcmp(base1, base2, UNION_BASE_SZ);
|
return offset1 - offset2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_delta(const union delta_base *base, enum object_type type)
|
static int find_ofs_delta(const off_t offset, enum object_type type)
|
||||||
{
|
{
|
||||||
int first = 0, last = nr_deltas;
|
int first = 0, last = nr_ofs_deltas;
|
||||||
|
|
||||||
while (first < last) {
|
while (first < last) {
|
||||||
int next = (first + last) / 2;
|
int next = (first + last) / 2;
|
||||||
struct delta_entry *delta = &deltas[next];
|
struct ofs_delta_entry *delta = &ofs_deltas[next];
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
cmp = compare_delta_bases(base, &delta->base,
|
cmp = compare_ofs_delta_bases(offset, delta->offset,
|
||||||
type, objects[delta->obj_no].type);
|
type, objects[delta->obj_no].type);
|
||||||
if (!cmp)
|
if (!cmp)
|
||||||
return next;
|
return next;
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
last = next;
|
last = next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
first = next+1;
|
first = next+1;
|
||||||
}
|
}
|
||||||
return -first-1;
|
return -first-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_delta_children(const union delta_base *base,
|
static void find_ofs_delta_children(off_t offset,
|
||||||
int *first_index, int *last_index,
|
int *first_index, int *last_index,
|
||||||
enum object_type type)
|
enum object_type type)
|
||||||
{
|
{
|
||||||
int first = find_delta(base, type);
|
int first = find_ofs_delta(offset, type);
|
||||||
int last = first;
|
int last = first;
|
||||||
int end = nr_deltas - 1;
|
int end = nr_ofs_deltas - 1;
|
||||||
|
|
||||||
if (first < 0) {
|
if (first < 0) {
|
||||||
*first_index = 0;
|
*first_index = 0;
|
||||||
*last_index = -1;
|
*last_index = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ))
|
while (first > 0 && ofs_deltas[first - 1].offset == offset)
|
||||||
--first;
|
--first;
|
||||||
while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ))
|
while (last < end && ofs_deltas[last + 1].offset == offset)
|
||||||
|
++last;
|
||||||
|
*first_index = first;
|
||||||
|
*last_index = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_ref_delta_bases(const unsigned char *sha1,
|
||||||
|
const unsigned char *sha2,
|
||||||
|
enum object_type type1,
|
||||||
|
enum object_type type2)
|
||||||
|
{
|
||||||
|
int cmp = type1 - type2;
|
||||||
|
if (cmp)
|
||||||
|
return cmp;
|
||||||
|
return hashcmp(sha1, sha2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_ref_delta(const unsigned char *sha1, enum object_type type)
|
||||||
|
{
|
||||||
|
int first = 0, last = nr_ref_deltas;
|
||||||
|
|
||||||
|
while (first < last) {
|
||||||
|
int next = (first + last) / 2;
|
||||||
|
struct ref_delta_entry *delta = &ref_deltas[next];
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
cmp = compare_ref_delta_bases(sha1, delta->sha1,
|
||||||
|
type, objects[delta->obj_no].type);
|
||||||
|
if (!cmp)
|
||||||
|
return next;
|
||||||
|
if (cmp < 0) {
|
||||||
|
last = next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
first = next+1;
|
||||||
|
}
|
||||||
|
return -first-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_ref_delta_children(const unsigned char *sha1,
|
||||||
|
int *first_index, int *last_index,
|
||||||
|
enum object_type type)
|
||||||
|
{
|
||||||
|
int first = find_ref_delta(sha1, type);
|
||||||
|
int last = first;
|
||||||
|
int end = nr_ref_deltas - 1;
|
||||||
|
|
||||||
|
if (first < 0) {
|
||||||
|
*first_index = 0;
|
||||||
|
*last_index = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (first > 0 && !hashcmp(ref_deltas[first - 1].sha1, sha1))
|
||||||
|
--first;
|
||||||
|
while (last < end && !hashcmp(ref_deltas[last + 1].sha1, sha1))
|
||||||
++last;
|
++last;
|
||||||
*first_index = first;
|
*first_index = first;
|
||||||
*last_index = last;
|
*last_index = last;
|
||||||
|
@ -927,16 +977,13 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
|
||||||
struct base_data *prev_base)
|
struct base_data *prev_base)
|
||||||
{
|
{
|
||||||
if (base->ref_last == -1 && base->ofs_last == -1) {
|
if (base->ref_last == -1 && base->ofs_last == -1) {
|
||||||
union delta_base base_spec;
|
find_ref_delta_children(base->obj->idx.sha1,
|
||||||
|
&base->ref_first, &base->ref_last,
|
||||||
|
OBJ_REF_DELTA);
|
||||||
|
|
||||||
hashcpy(base_spec.sha1, base->obj->idx.sha1);
|
find_ofs_delta_children(base->obj->idx.offset,
|
||||||
find_delta_children(&base_spec,
|
&base->ofs_first, &base->ofs_last,
|
||||||
&base->ref_first, &base->ref_last, OBJ_REF_DELTA);
|
OBJ_OFS_DELTA);
|
||||||
|
|
||||||
memset(&base_spec, 0, sizeof(base_spec));
|
|
||||||
base_spec.offset = base->obj->idx.offset;
|
|
||||||
find_delta_children(&base_spec,
|
|
||||||
&base->ofs_first, &base->ofs_last, OBJ_OFS_DELTA);
|
|
||||||
|
|
||||||
if (base->ref_last == -1 && base->ofs_last == -1) {
|
if (base->ref_last == -1 && base->ofs_last == -1) {
|
||||||
free(base->data);
|
free(base->data);
|
||||||
|
@ -947,7 +994,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base->ref_first <= base->ref_last) {
|
if (base->ref_first <= base->ref_last) {
|
||||||
struct object_entry *child = objects + deltas[base->ref_first].obj_no;
|
struct object_entry *child = objects + ref_deltas[base->ref_first].obj_no;
|
||||||
struct base_data *result = alloc_base_data();
|
struct base_data *result = alloc_base_data();
|
||||||
|
|
||||||
if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
|
if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
|
||||||
|
@ -963,7 +1010,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base->ofs_first <= base->ofs_last) {
|
if (base->ofs_first <= base->ofs_last) {
|
||||||
struct object_entry *child = objects + deltas[base->ofs_first].obj_no;
|
struct object_entry *child = objects + ofs_deltas[base->ofs_first].obj_no;
|
||||||
struct base_data *result = alloc_base_data();
|
struct base_data *result = alloc_base_data();
|
||||||
|
|
||||||
assert(child->real_type == OBJ_OFS_DELTA);
|
assert(child->real_type == OBJ_OFS_DELTA);
|
||||||
|
@ -999,15 +1046,20 @@ static void find_unresolved_deltas(struct base_data *base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_delta_entry(const void *a, const void *b)
|
static int compare_ofs_delta_entry(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const struct delta_entry *delta_a = a;
|
const struct ofs_delta_entry *delta_a = a;
|
||||||
const struct delta_entry *delta_b = b;
|
const struct ofs_delta_entry *delta_b = b;
|
||||||
|
|
||||||
/* group by type (ref vs ofs) and then by value (sha-1 or offset) */
|
return delta_a->offset - delta_b->offset;
|
||||||
return compare_delta_bases(&delta_a->base, &delta_b->base,
|
}
|
||||||
objects[delta_a->obj_no].type,
|
|
||||||
objects[delta_b->obj_no].type);
|
static int compare_ref_delta_entry(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct ref_delta_entry *delta_a = a;
|
||||||
|
const struct ref_delta_entry *delta_b = b;
|
||||||
|
|
||||||
|
return hashcmp(delta_a->sha1, delta_b->sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_base(struct object_entry *obj)
|
static void resolve_base(struct object_entry *obj)
|
||||||
|
@ -1053,7 +1105,8 @@ static void *threaded_second_pass(void *data)
|
||||||
static void parse_pack_objects(unsigned char *sha1)
|
static void parse_pack_objects(unsigned char *sha1)
|
||||||
{
|
{
|
||||||
int i, nr_delays = 0;
|
int i, nr_delays = 0;
|
||||||
struct delta_entry *delta = deltas;
|
struct ofs_delta_entry *ofs_delta = ofs_deltas;
|
||||||
|
unsigned char ref_delta_sha1[20];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
@ -1062,12 +1115,18 @@ static void parse_pack_objects(unsigned char *sha1)
|
||||||
nr_objects);
|
nr_objects);
|
||||||
for (i = 0; i < nr_objects; i++) {
|
for (i = 0; i < nr_objects; i++) {
|
||||||
struct object_entry *obj = &objects[i];
|
struct object_entry *obj = &objects[i];
|
||||||
void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1);
|
void *data = unpack_raw_entry(obj, &ofs_delta->offset,
|
||||||
|
ref_delta_sha1, obj->idx.sha1);
|
||||||
obj->real_type = obj->type;
|
obj->real_type = obj->type;
|
||||||
if (is_delta_type(obj->type)) {
|
if (obj->type == OBJ_OFS_DELTA) {
|
||||||
nr_deltas++;
|
nr_ofs_deltas++;
|
||||||
delta->obj_no = i;
|
ofs_delta->obj_no = i;
|
||||||
delta++;
|
ofs_delta++;
|
||||||
|
} else if (obj->type == OBJ_REF_DELTA) {
|
||||||
|
ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
|
||||||
|
hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
|
||||||
|
ref_deltas[nr_ref_deltas].obj_no = i;
|
||||||
|
nr_ref_deltas++;
|
||||||
} else if (!data) {
|
} else if (!data) {
|
||||||
/* large blobs, check later */
|
/* large blobs, check later */
|
||||||
obj->real_type = OBJ_BAD;
|
obj->real_type = OBJ_BAD;
|
||||||
|
@ -1118,15 +1177,18 @@ static void resolve_deltas(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!nr_deltas)
|
if (!nr_ofs_deltas && !nr_ref_deltas)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Sort deltas by base SHA1/offset for fast searching */
|
/* Sort deltas by base SHA1/offset for fast searching */
|
||||||
qsort(deltas, nr_deltas, sizeof(struct delta_entry),
|
qsort(ofs_deltas, nr_ofs_deltas, sizeof(struct ofs_delta_entry),
|
||||||
compare_delta_entry);
|
compare_ofs_delta_entry);
|
||||||
|
qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry),
|
||||||
|
compare_ref_delta_entry);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
progress = start_progress(_("Resolving deltas"), nr_deltas);
|
progress = start_progress(_("Resolving deltas"),
|
||||||
|
nr_ref_deltas + nr_ofs_deltas);
|
||||||
|
|
||||||
#ifndef NO_PTHREADS
|
#ifndef NO_PTHREADS
|
||||||
nr_dispatched = 0;
|
nr_dispatched = 0;
|
||||||
|
@ -1164,7 +1226,7 @@ static void resolve_deltas(void)
|
||||||
static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved);
|
static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved);
|
||||||
static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
|
static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
|
||||||
{
|
{
|
||||||
if (nr_deltas == nr_resolved_deltas) {
|
if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
|
||||||
stop_progress(&progress);
|
stop_progress(&progress);
|
||||||
/* Flush remaining pack final 20-byte SHA1. */
|
/* Flush remaining pack final 20-byte SHA1. */
|
||||||
flush();
|
flush();
|
||||||
|
@ -1175,7 +1237,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
|
||||||
struct sha1file *f;
|
struct sha1file *f;
|
||||||
unsigned char read_sha1[20], tail_sha1[20];
|
unsigned char read_sha1[20], tail_sha1[20];
|
||||||
struct strbuf msg = STRBUF_INIT;
|
struct strbuf msg = STRBUF_INIT;
|
||||||
int nr_unresolved = nr_deltas - nr_resolved_deltas;
|
int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
|
||||||
int nr_objects_initial = nr_objects;
|
int nr_objects_initial = nr_objects;
|
||||||
if (nr_unresolved <= 0)
|
if (nr_unresolved <= 0)
|
||||||
die(_("confusion beyond insanity"));
|
die(_("confusion beyond insanity"));
|
||||||
|
@ -1197,11 +1259,11 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
|
||||||
die(_("Unexpected tail checksum for %s "
|
die(_("Unexpected tail checksum for %s "
|
||||||
"(disk corruption?)"), curr_pack);
|
"(disk corruption?)"), curr_pack);
|
||||||
}
|
}
|
||||||
if (nr_deltas != nr_resolved_deltas)
|
if (nr_ofs_deltas + nr_ref_deltas != nr_resolved_deltas)
|
||||||
die(Q_("pack has %d unresolved delta",
|
die(Q_("pack has %d unresolved delta",
|
||||||
"pack has %d unresolved deltas",
|
"pack has %d unresolved deltas",
|
||||||
nr_deltas - nr_resolved_deltas),
|
nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas),
|
||||||
nr_deltas - nr_resolved_deltas);
|
nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_compressed(struct sha1file *f, void *in, unsigned int size)
|
static int write_compressed(struct sha1file *f, void *in, unsigned int size)
|
||||||
|
@ -1261,14 +1323,14 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
|
||||||
|
|
||||||
static int delta_pos_compare(const void *_a, const void *_b)
|
static int delta_pos_compare(const void *_a, const void *_b)
|
||||||
{
|
{
|
||||||
struct delta_entry *a = *(struct delta_entry **)_a;
|
struct ref_delta_entry *a = *(struct ref_delta_entry **)_a;
|
||||||
struct delta_entry *b = *(struct delta_entry **)_b;
|
struct ref_delta_entry *b = *(struct ref_delta_entry **)_b;
|
||||||
return a->obj_no - b->obj_no;
|
return a->obj_no - b->obj_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
|
static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
|
||||||
{
|
{
|
||||||
struct delta_entry **sorted_by_pos;
|
struct ref_delta_entry **sorted_by_pos;
|
||||||
int i, n = 0;
|
int i, n = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1282,28 +1344,25 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
|
||||||
* resolving deltas in the same order as their position in the pack.
|
* resolving deltas in the same order as their position in the pack.
|
||||||
*/
|
*/
|
||||||
sorted_by_pos = xmalloc(nr_unresolved * sizeof(*sorted_by_pos));
|
sorted_by_pos = xmalloc(nr_unresolved * sizeof(*sorted_by_pos));
|
||||||
for (i = 0; i < nr_deltas; i++) {
|
for (i = 0; i < nr_ref_deltas; i++)
|
||||||
if (objects[deltas[i].obj_no].real_type != OBJ_REF_DELTA)
|
sorted_by_pos[n++] = &ref_deltas[i];
|
||||||
continue;
|
|
||||||
sorted_by_pos[n++] = &deltas[i];
|
|
||||||
}
|
|
||||||
qsort(sorted_by_pos, n, sizeof(*sorted_by_pos), delta_pos_compare);
|
qsort(sorted_by_pos, n, sizeof(*sorted_by_pos), delta_pos_compare);
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
struct delta_entry *d = sorted_by_pos[i];
|
struct ref_delta_entry *d = sorted_by_pos[i];
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
struct base_data *base_obj = alloc_base_data();
|
struct base_data *base_obj = alloc_base_data();
|
||||||
|
|
||||||
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
|
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
|
||||||
continue;
|
continue;
|
||||||
base_obj->data = read_sha1_file(d->base.sha1, &type, &base_obj->size);
|
base_obj->data = read_sha1_file(d->sha1, &type, &base_obj->size);
|
||||||
if (!base_obj->data)
|
if (!base_obj->data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (check_sha1_signature(d->base.sha1, base_obj->data,
|
if (check_sha1_signature(d->sha1, base_obj->data,
|
||||||
base_obj->size, typename(type)))
|
base_obj->size, typename(type)))
|
||||||
die(_("local object %s is corrupt"), sha1_to_hex(d->base.sha1));
|
die(_("local object %s is corrupt"), sha1_to_hex(d->sha1));
|
||||||
base_obj->obj = append_obj_to_pack(f, d->base.sha1,
|
base_obj->obj = append_obj_to_pack(f, d->sha1,
|
||||||
base_obj->data, base_obj->size, type);
|
base_obj->data, base_obj->size, type);
|
||||||
find_unresolved_deltas(base_obj);
|
find_unresolved_deltas(base_obj);
|
||||||
display_progress(progress, nr_resolved_deltas);
|
display_progress(progress, nr_resolved_deltas);
|
||||||
|
@ -1495,7 +1554,7 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
|
||||||
|
|
||||||
static void show_pack_info(int stat_only)
|
static void show_pack_info(int stat_only)
|
||||||
{
|
{
|
||||||
int i, baseobjects = nr_objects - nr_deltas;
|
int i, baseobjects = nr_objects - nr_ref_deltas - nr_ofs_deltas;
|
||||||
unsigned long *chain_histogram = NULL;
|
unsigned long *chain_histogram = NULL;
|
||||||
|
|
||||||
if (deepest_delta)
|
if (deepest_delta)
|
||||||
|
@ -1680,11 +1739,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
||||||
objects = xcalloc(nr_objects + 1, sizeof(struct object_entry));
|
objects = xcalloc(nr_objects + 1, sizeof(struct object_entry));
|
||||||
if (show_stat)
|
if (show_stat)
|
||||||
obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));
|
obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));
|
||||||
deltas = xcalloc(nr_objects, sizeof(struct delta_entry));
|
ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
|
||||||
parse_pack_objects(pack_sha1);
|
parse_pack_objects(pack_sha1);
|
||||||
resolve_deltas();
|
resolve_deltas();
|
||||||
conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
|
conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
|
||||||
free(deltas);
|
free(ofs_deltas);
|
||||||
|
free(ref_deltas);
|
||||||
if (strict)
|
if (strict)
|
||||||
foreign_nr = check_objects();
|
foreign_nr = check_objects();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue