From 46f04b3c156b29eb9550b2aadd0424ce426a1976 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Tue, 30 Jul 2019 15:07:11 -0700 Subject: [PATCH] pkg/adt: add "IntervalTree.Delete" failure case Described in https://github.com/etcd-io/etcd/issues/10877. "black-height" property: Every path from a node to any descendant leaf node must have the same number of black nodes. Expected After deleting 11 (requires rebalancing): [510,511] / \ ---------- -------------------------- / \ [383,384] [830,831] / \ / \ / \ / \ [261,262](red) [410,411] [647,648] [899,900](red) / \ \ / \ / \ \ / \ [82,83] [292,293] [815,816](red) [888,889] [972,973] \ / \ / [238,239](red) [953,954](red) Got After deleting 11 (requires rebalancing): [510,511] / \ ---------- -------------------------- / \ [82,83] [830,831] \ / \ \ / \ [383,384] [647,648] [899,900] / \ \ / \ / \ \ / \ [261,262] [410,411] [815,816] [888,889] [972,973] / \ / / \ / [238,239] [292,293] [953,954] This violates "black-height" property. Signed-off-by: Gyuho Lee --- pkg/adt/interval_tree_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pkg/adt/interval_tree_test.go b/pkg/adt/interval_tree_test.go index 4819f3455f8..608841f92f3 100644 --- a/pkg/adt/interval_tree_test.go +++ b/pkg/adt/interval_tree_test.go @@ -257,6 +257,31 @@ func TestIntervalTreeDelete(t *testing.T) { if deleted := tr.Delete(NewInt64Interval(11, 12)); !deleted { t.Fatalf("range %v not deleted", range11) } + + expectedAfterDelete11 := []visitedInterval{ + {root: NewInt64Interval(510, 511), color: black, left: NewInt64Interval(383, 384), right: NewInt64Interval(830, 831), depth: 0}, + + {root: NewInt64Interval(383, 384), color: black, left: NewInt64Interval(261, 262), right: NewInt64Interval(410, 411), depth: 1}, + {root: NewInt64Interval(830, 831), color: black, left: NewInt64Interval(647, 648), right: NewInt64Interval(899, 900), depth: 1}, + + {root: NewInt64Interval(261, 262), color: red, left: NewInt64Interval(82, 83), right: NewInt64Interval(292, 293), depth: 2}, + {root: NewInt64Interval(410, 411), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2}, + {root: NewInt64Interval(647, 648), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(815, 816), depth: 2}, + {root: NewInt64Interval(899, 900), color: red, left: NewInt64Interval(888, 889), right: NewInt64Interval(972, 973), depth: 2}, + + {root: NewInt64Interval(82, 83), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(238, 239), depth: 3}, + {root: NewInt64Interval(292, 293), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3}, + {root: NewInt64Interval(815, 816), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3}, + {root: NewInt64Interval(888, 889), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3}, + {root: NewInt64Interval(972, 973), color: black, left: NewInt64Interval(953, 954), right: newInt64EmptyInterval(), depth: 3}, + + {root: NewInt64Interval(238, 239), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4}, + {root: NewInt64Interval(953, 954), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4}, + } + visitsAfterDelete11 := tr.visitLevel() + if !reflect.DeepEqual(expectedAfterDelete11, visitsAfterDelete11) { + t.Fatalf("level order after deleting '11' expected %v, got %v", expectedAfterDelete11, visitsAfterDelete11) + } } func TestIntervalTreeIntersects(t *testing.T) {