Skip to content

Commit

Permalink
index-pack: smarter memory usage during delta resolution
Browse files Browse the repository at this point in the history
There is no need to keep the base object data around after its last delta
has been resolved.  This also means that long delta chains with only one
delta per base won't grow the cache size unnecessarily as the base will
be freed before recursing down.

To make it easy, find_delta_children() is modified so the first and last
indices are initialized in all cases.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Nicolas Pitre authored and Junio C Hamano committed Oct 18, 2008
1 parent 9441b61 commit 6a87ed9
Showing 1 changed file with 39 additions and 34 deletions.
73 changes: 39 additions & 34 deletions index-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,17 +221,23 @@ static void bad_object(unsigned long offset, const char *format, ...)
die("pack has bad object at offset %lu: %s", offset, buf);
}

static void free_base_data(struct base_data *c)
{
if (c->data) {
free(c->data);
c->data = NULL;
base_cache_used -= c->size;
}
}

static void prune_base_data(struct base_data *retain)
{
struct base_data *b = base_cache;
for (b = base_cache;
base_cache_used > delta_base_cache_limit && b;
b = b->child) {
if (b->data && b != retain) {
free(b->data);
b->data = NULL;
base_cache_used -= b->size;
}
if (b->data && b != retain)
free_base_data(b);
}
}

Expand All @@ -256,10 +262,7 @@ static void unlink_base_data(struct base_data *c)
base->child = NULL;
else
base_cache = NULL;
if (c->data) {
free(c->data);
base_cache_used -= c->size;
}
free_base_data(c);
}

static void *unpack_entry_data(unsigned long offset, unsigned long size)
Expand Down Expand Up @@ -409,22 +412,24 @@ static int find_delta(const union delta_base *base)
return -first-1;
}

static int find_delta_children(const union delta_base *base,
int *first_index, int *last_index)
static void find_delta_children(const union delta_base *base,
int *first_index, int *last_index)
{
int first = find_delta(base);
int last = first;
int end = nr_deltas - 1;

if (first < 0)
return -1;
if (first < 0) {
*first_index = 0;
*last_index = -1;
return;
}
while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ))
--first;
while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ))
++last;
*first_index = first;
*last_index = last;
return 0;
}

static void sha1_object(const void *data, unsigned long size,
Expand Down Expand Up @@ -529,7 +534,7 @@ static void resolve_delta(struct object_entry *delta_obj,
static void find_unresolved_deltas(struct base_data *base,
struct base_data *prev_base)
{
int i, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
int i, ref_first, ref_last, ofs_first, ofs_last;

/*
* This is a recursive function. Those brackets should help reducing
Expand All @@ -539,37 +544,37 @@ static void find_unresolved_deltas(struct base_data *base,
union delta_base base_spec;

hashcpy(base_spec.sha1, base->obj->idx.sha1);
ref = !find_delta_children(&base_spec, &ref_first, &ref_last);
find_delta_children(&base_spec, &ref_first, &ref_last);

memset(&base_spec, 0, sizeof(base_spec));
base_spec.offset = base->obj->idx.offset;
ofs = !find_delta_children(&base_spec, &ofs_first, &ofs_last);
find_delta_children(&base_spec, &ofs_first, &ofs_last);
}

if (!ref && !ofs)
if (ref_last == -1 && ofs_last == -1)
return;

link_base_data(prev_base, base);

if (ref) {
for (i = ref_first; i <= ref_last; i++) {
struct object_entry *child = objects + deltas[i].obj_no;
if (child->real_type == OBJ_REF_DELTA) {
struct base_data result;
resolve_delta(child, base, &result);
find_unresolved_deltas(&result, base);
}
for (i = ref_first; i <= ref_last; i++) {
struct object_entry *child = objects + deltas[i].obj_no;
if (child->real_type == OBJ_REF_DELTA) {
struct base_data result;
resolve_delta(child, base, &result);
if (i == ref_last && ofs_last == -1)
free_base_data(base);
find_unresolved_deltas(&result, base);
}
}

if (ofs) {
for (i = ofs_first; i <= ofs_last; i++) {
struct object_entry *child = objects + deltas[i].obj_no;
if (child->real_type == OBJ_OFS_DELTA) {
struct base_data result;
resolve_delta(child, base, &result);
find_unresolved_deltas(&result, base);
}
for (i = ofs_first; i <= ofs_last; i++) {
struct object_entry *child = objects + deltas[i].obj_no;
if (child->real_type == OBJ_OFS_DELTA) {
struct base_data result;
resolve_delta(child, base, &result);
if (i == ofs_last)
free_base_data(base);
find_unresolved_deltas(&result, base);
}
}

Expand Down

0 comments on commit 6a87ed9

Please sign in to comment.