index-pack: eliminate unlimited recursion in get_base_data()
Revese the order of delta applying so that by the time a delta is applied, its base is either non-delta or already inflated. get_base_data() is still recursive, but because base's data is always ready, the inner get_base_data() call never has any chance to call itself again. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Jan 14, 2012 at 19:19 UTC
20e95d0a8475ce467903e1aaad5c2fd47777fcc8
1 file changed
+44
-9
builtin/index-pack.c
+44
-9
@@ -515,14 +515,52 @@ static int is_delta_type(enum object_type type)
515
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
516
}
517
518
+/*
519
+ * This function is part of find_unresolved_deltas(). There are two
520
+ * walkers going in the opposite ways.
521
+ *
522
+ * The first one in find_unresolved_deltas() traverses down from
523
+ * parent node to children, deflating nodes along the way. However,
524
+ * memory for deflated nodes is limited by delta_base_cache_limit, so
525
+ * at some point parent node's deflated content may be freed.
526
+ *
527
+ * The second walker is this function, which goes from current node up
528
+ * to top parent if necessary to deflate the node. In normal
529
+ * situation, its parent node would be already deflated, so it just
530
+ * needs to apply delta.
531
+ *
532
+ * In the worst case scenario, parent node is no longer deflated because
533
+ * we're running out of delta_base_cache_limit; we need to re-deflate
534
+ * parents, possibly up to the top base.
535
+ *
536
+ * All deflated objects here are subject to be freed if we exceed
537
+ * delta_base_cache_limit, just like in find_unresolved_deltas(), we
538
+ * just need to make sure the last node is not freed.
539
+ */
540
static void *get_base_data(struct base_data *c)
541
{
542
if (!c->data) {
543
struct object_entry *obj = c->obj;
544
+ struct base_data **delta = NULL;
545
+ int delta_nr = 0, delta_alloc = 0;
546
523
- if (is_delta_type(obj->type)) {
524
- void *base = get_base_data(c->base);
525
- void *raw = get_data_from_pack(obj);
547
+ while (is_delta_type(c->obj->type) && !c->data) {
548
+ ALLOC_GROW(delta, delta_nr + 1, delta_alloc);
549
+ delta[delta_nr++] = c;
550
+ c = c->base;
551
+ }
552
+ if (!delta_nr) {
553
+ c->data = get_data_from_pack(obj);
554
+ c->size = obj->size;
555
+ base_cache_used += c->size;
556
+ prune_base_data(c);
557
+ }
558
+ for (; delta_nr > 0; delta_nr--) {
559
+ void *base, *raw;
560
+ c = delta[delta_nr - 1];
561
+ obj = c->obj;
562
+ base = get_base_data(c->base);
563
+ raw = get_data_from_pack(obj);
564
c->data = patch_delta(
565
base, c->base->size,
566
raw, obj->size,
@@ -530,13 +568,10 @@ static void *get_base_data(struct base_data *c)
568
free(raw);
569
if (!c->data)
570
bad_object(obj->idx.offset, "failed to apply delta");
533
- } else {
534
- c->data = get_data_from_pack(obj);
535
- c->size = obj->size;
571
+ base_cache_used += c->size;
572
+ prune_base_data(c);
573
}
537
-
538
- base_cache_used += c->size;
539
- prune_base_data(c);
574
+ free(delta);
575
}
576
return c->data;
577
}