Skip to content

Commit

Permalink
planner: add a util function of finding common equivs between mutli f…
Browse files Browse the repository at this point in the history
  • Loading branch information
AilinKid authored Feb 11, 2025
1 parent 01a52cb commit 4233e51
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/planner/funcdep/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ go_test(
],
embed = [":funcdep"],
flaky = True,
shard_count = 10,
shard_count = 11,
deps = [
"//pkg/domain",
"//pkg/infoschema",
Expand Down
49 changes: 49 additions & 0 deletions pkg/planner/funcdep/fd_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -1224,3 +1224,52 @@ func (s *FDSet) IsHashCodeRegistered(hashCode string) (int, bool) {
}
return -1, false
}

// FindCommonEquivClasses find the common equivalences between multi fds.
func FindCommonEquivClasses(fdSets []*FDSet) []intset.FastIntSet {
if len(fdSets) == 0 {
return nil
}
var result []intset.FastIntSet
for _, edge := range fdSets[0].fdEdges {
if edge.equiv {
// clone one for later mutable intersection.
set := intset.NewFastIntSet()
set.CopyFrom(edge.from)
result = append(result, set)
}
}
// iterate intersection with later all fdSets.
for i := 1; i < len(fdSets); i++ {
newResult := make([]intset.FastIntSet, 0, len(result))
currFDSet := fdSets[i]
// iterate all equivalence classes in the current fdSet.
for _, equivClass := range result {
// iterate all equivalence FDs in the current fdSet.
for _, edge := range currFDSet.fdEdges {
if !edge.equiv {
continue
}
// find the intersection between the current equivalence class and the current equivalence FD.
intersection := intset.NewFastIntSet()
intersection.CopyFrom(equivClass)
intersection.IntersectionWith(edge.from)
// * if the intersection has changed and not empty. (become a subset)
// * if the intersection is still the same (it means two equivalence classes are the same)
// * intersection with the single point is meaningless in bi-relation of equivalence.
if intersection.Len() > 1 {
// put the intersection one as the new result into the newResult.
newResult = append(newResult, intersection)
continue
}
}
}
// update the result with the newResult.
result = newResult
// if the result is empty, no need to continue. (intersection with empty set continuously is meaningless)
if len(result) == 0 {
return nil
}
}
return result
}
34 changes: 34 additions & 0 deletions pkg/planner/funcdep/fd_graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,37 @@ func TestFDSet_AddEquivalence(t *testing.T) {
require.Equal(t, "(1-4)", fd.EquivalenceCols()[0].String())
require.Equal(t, "(1-6)", fd.ConstantCols().String())
}

func TestFindCommonEquivClasses(t *testing.T) {
fd1 := &FDSet{}
// fd1 is with equivalence classes for {1,2} and {3,4}
fd1.addEquivalence(intset.NewFastIntSet(1, 2))
fd1.addEquivalence(intset.NewFastIntSet(3, 4))

fd2 := &FDSet{}
// fd2 is with equivalence classes for {1,3} and {2,4}
fd2.addEquivalence(intset.NewFastIntSet(1, 3))
fd2.addEquivalence(intset.NewFastIntSet(2, 4))

fd3 := &FDSet{}
// fd3 is with equivalence classes for {1} and {3,4}
fd3.addEquivalence(intset.NewFastIntSet(1))
fd3.addEquivalence(intset.NewFastIntSet(3, 4))

// find common equivalence classes between fd1 and fd2.
res := FindCommonEquivClasses([]*FDSet{fd1, fd2})
require.Equal(t, 0, len(res))

// find common equivalence classes between fd2 and fd3.
res = FindCommonEquivClasses([]*FDSet{fd2, fd3})
require.Equal(t, 0, len(res))

// find common equivalence classes between fd1 and fd3.
res = FindCommonEquivClasses([]*FDSet{fd1, fd3})
require.Equal(t, 1, len(res))
require.Equal(t, "(3,4)", res[0].String())

// find common equivalence classes between fd1, fd2 and fd3.
res = FindCommonEquivClasses([]*FDSet{fd1, fd2, fd3})
require.Equal(t, 0, len(res))
}

0 comments on commit 4233e51

Please sign in to comment.