Skip to content

Commit

Permalink
sql, distsql: planning for interleave joins between ancestor and
Browse files Browse the repository at this point in the history
descendant
  • Loading branch information
richardwu committed Nov 8, 2017
1 parent e6c0211 commit 23588ec
Show file tree
Hide file tree
Showing 18 changed files with 1,543 additions and 269 deletions.
65 changes: 65 additions & 0 deletions pkg/roachpb/merge_spans.go → pkg/roachpb/combine_spans.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func (s sortedSpans) Len() int {

// MergeSpans sorts the incoming spans and merges overlapping spans. Returns
// true iff all of the spans are distinct.
// The input spans is not safe for re-use.
func MergeSpans(spans []Span) ([]Span, bool) {
if len(spans) == 0 {
return spans, true
Expand Down Expand Up @@ -100,3 +101,67 @@ func MergeSpans(spans []Span) ([]Span, bool) {
}
return r, distinct
}

// IntersectSpans returns the logical intersection of all spans represented as
// a slice of one Span.
// The input spans is not safe for re-use.
func IntersectSpans(spans []Span) []Span {
if len(spans) == 0 {
return spans
}

sort.Sort(sortedSpans(spans))

// We build up the final one-element slice of spans using the same
// backing slice. This is safe since we are never expanding the final
// slice into the backing slice, thus yet-to-be-processed spans are
// never overwritten.
r := spans[:1]
// The previous element(s) is always folded into the first span.
prev := &r[0]

for _, cur := range spans[1:] {
if len(cur.EndKey) == 0 && len(prev.EndKey) == 0 {
if cur.Key.Compare(prev.Key) != 0 {
// [a, nil] intersect [b, nil]
return nil
}
// [a, nil] intersect [a, nil]
continue
}

if len(prev.EndKey) == 0 {
if prev.Key.Compare(cur.Key) < 0 {
// [a, nil] intersect [b, c]
return nil
}
// [a, nil] intersect [a, b]
// [b, nil] intersect [a, c]
continue
}

if c := prev.EndKey.Compare(cur.Key); c > 0 {
if cur.EndKey != nil {
if prev.EndKey.Compare(cur.EndKey) <= 0 {
// [a, c] intersect [b, d]
// [a, c] intersect [b, c]
prev.Key = cur.Key
} else {
// [a, d] intersect [b, c]
prev.Key = cur.Key
prev.EndKey = cur.EndKey
}
} else {
// [a, c] intersect [b, nil]
prev.Key = cur.Key
prev.EndKey = cur.EndKey
}
continue
}
// [a, b] intersect [b, X]
// [a, b] intersect [c, X]
return nil
}

return r
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@ import (
"testing"
)

func TestMergeSpans(t *testing.T) {
makeSpan := func(s string) Span {
parts := strings.Split(s, "-")
if len(parts) == 2 {
return Span{Key: Key(parts[0]), EndKey: Key(parts[1])}
}
return Span{Key: Key(s)}
func makeSpan(s string) Span {
parts := strings.Split(s, "-")
if len(parts) == 2 {
return Span{Key: Key(parts[0]), EndKey: Key(parts[1])}
}
makeSpans := func(s string) []Span {
var spans []Span
if len(s) > 0 {
for _, p := range strings.Split(s, ",") {
spans = append(spans, makeSpan(p))
}
return Span{Key: Key(s)}
}

func makeSpans(s string) []Span {
var spans []Span
if len(s) > 0 {
for _, p := range strings.Split(s, ",") {
spans = append(spans, makeSpan(p))
}
return spans
}
return spans
}

func TestMergeSpans(t *testing.T) {
testCases := []struct {
spans string
expected string
Expand Down Expand Up @@ -69,3 +70,35 @@ func TestMergeSpans(t *testing.T) {
}
}
}

func TestIntersectSpans(t *testing.T) {
testCases := []struct {
spans string
expected string
}{
{"", ""},
{"a", "a"},
{"a,b", ""},
{"b,a", ""},
{"a,a", "a"},
{"a-b", "a-b"},
{"a-b,b-c", ""},
{"a-c,a-b", "a-b"},
{"a,b-c", ""},
{"a,a-c", "a"},
{"a-c,b", "b"},
{"a-c,c", ""},
{"a-c,b-bb", "b-bb"},
{"b-bb,a-c", "b-bb"},
{"a-c,b-c", "b-c"},
{"a-b,c-d", ""},
{"a-b,a-b,a-b,b", ""},
}
for i, c := range testCases {
spans := IntersectSpans(makeSpans(c.spans))
expected := makeSpans(c.expected)
if !reflect.DeepEqual(expected, spans) {
t.Fatalf("%d: expected\n%s\n, but found:\n%s", i, expected, spans)
}
}
}
Loading

0 comments on commit 23588ec

Please sign in to comment.