using set instead of lists for topologyPairsMaps attributes

This commit is contained in:
Ahmad Diaa 2018-08-17 21:30:33 +02:00
parent 0f4c3064fd
commit b4c7d190cd
3 changed files with 52 additions and 88 deletions

View File

@ -51,11 +51,15 @@ type matchingPodAntiAffinityTerm struct {
node *v1.Node node *v1.Node
} }
type podSet map[*v1.Pod]struct{}
type topologyPairSet map[topologyPair]struct{}
// topologyPairsMaps keeps topologyPairToAntiAffinityPods and antiAffinityPodToTopologyPairs in sync // topologyPairsMaps keeps topologyPairToAntiAffinityPods and antiAffinityPodToTopologyPairs in sync
// as they are the inverse of each others. // as they are the inverse of each others.
type topologyPairsMaps struct { type topologyPairsMaps struct {
topologyPairToPods map[topologyPair][]*v1.Pod topologyPairToPods map[topologyPair]podSet
podToTopologyPairs map[string][]topologyPair podToTopologyPairs map[string]topologyPairSet
} }
// NOTE: When new fields are added/removed or logic is changed, please make sure that // NOTE: When new fields are added/removed or logic is changed, please make sure that
@ -151,44 +155,40 @@ func (pfactory *PredicateMetadataFactory) GetMetadata(pod *v1.Pod, nodeNameToInf
return predicateMetadata return predicateMetadata
} }
func (topologyPairsMaps *topologyPairsMaps) AddTopologyPair(pair topologyPair, pod *v1.Pod) { // returns a pointer to a new topologyPairsMaps
found := false func newTopologyPairsMaps() *topologyPairsMaps {
for _, existingPod := range topologyPairsMaps.topologyPairToPods[pair] { return &topologyPairsMaps{topologyPairToPods: make(map[topologyPair]podSet),
if existingPod == pod { podToTopologyPairs: make(map[string]topologyPairSet)}
found = true
break
}
}
if !found {
topologyPairsMaps.topologyPairToPods[pair] = append(topologyPairsMaps.topologyPairToPods[pair], pod)
topologyPairsMaps.podToTopologyPairs[schedutil.GetPodFullName(pod)] = append(topologyPairsMaps.podToTopologyPairs[schedutil.GetPodFullName(pod)], pair)
}
} }
func (topologyPairsMaps *topologyPairsMaps) RemovePod(podName string) { func (topologyPairsMaps *topologyPairsMaps) addTopologyPair(pair topologyPair, pod *v1.Pod) {
for _, pair := range topologyPairsMaps.podToTopologyPairs[podName] { podFullName := schedutil.GetPodFullName(pod)
for index, pod := range topologyPairsMaps.topologyPairToPods[pair] { if topologyPairsMaps.topologyPairToPods[pair] == nil {
if schedutil.GetPodFullName(pod) == podName { topologyPairsMaps.topologyPairToPods[pair] = make(map[*v1.Pod]struct{})
podsList := topologyPairsMaps.topologyPairToPods[pair] }
podsList[index] = podsList[len(podsList)-1] topologyPairsMaps.topologyPairToPods[pair][pod] = struct{}{}
if len(podsList) <= 1 { if topologyPairsMaps.podToTopologyPairs[podFullName] == nil {
delete(topologyPairsMaps.topologyPairToPods, pair) topologyPairsMaps.podToTopologyPairs[podFullName] = make(map[topologyPair]struct{})
} else { }
topologyPairsMaps.topologyPairToPods[pair] = podsList[:len(podsList)-1] topologyPairsMaps.podToTopologyPairs[podFullName][pair] = struct{}{}
} }
break
} func (topologyPairsMaps *topologyPairsMaps) removePod(deletedPod *v1.Pod) {
deletedPodFullName := schedutil.GetPodFullName(deletedPod)
for pair := range topologyPairsMaps.podToTopologyPairs[deletedPodFullName] {
delete(topologyPairsMaps.topologyPairToPods[pair], deletedPod)
if len(topologyPairsMaps.topologyPairToPods[pair]) == 0 {
delete(topologyPairsMaps.topologyPairToPods, pair)
} }
} }
delete(topologyPairsMaps.podToTopologyPairs, podName) delete(topologyPairsMaps.podToTopologyPairs, deletedPodFullName)
} }
func (topologyPairsMaps *topologyPairsMaps) appendMaps(toAppend *topologyPairsMaps) { func (topologyPairsMaps *topologyPairsMaps) appendMaps(toAppend *topologyPairsMaps) {
for pod, pairs := range toAppend.podToTopologyPairs { for pair := range toAppend.topologyPairToPods {
topologyPairsMaps.podToTopologyPairs[pod] = append(topologyPairsMaps.podToTopologyPairs[pod], pairs...) for pod := range toAppend.topologyPairToPods[pair] {
} topologyPairsMaps.addTopologyPair(pair, pod)
for pair, pods := range toAppend.topologyPairToPods { }
topologyPairsMaps.topologyPairToPods[pair] = append(topologyPairsMaps.topologyPairToPods[pair], pods...)
} }
} }
@ -199,7 +199,7 @@ func (meta *predicateMetadata) RemovePod(deletedPod *v1.Pod) error {
if deletedPodFullName == schedutil.GetPodFullName(meta.pod) { if deletedPodFullName == schedutil.GetPodFullName(meta.pod) {
return fmt.Errorf("deletedPod and meta.pod must not be the same") return fmt.Errorf("deletedPod and meta.pod must not be the same")
} }
meta.topologyPairsAntiAffinityPodsMap.RemovePod(deletedPodFullName) meta.topologyPairsAntiAffinityPodsMap.removePod(deletedPod)
// Delete pod from the matching affinity or anti-affinity pods if exists. // Delete pod from the matching affinity or anti-affinity pods if exists.
affinity := meta.pod.Spec.Affinity affinity := meta.pod.Spec.Affinity
podNodeName := deletedPod.Spec.NodeName podNodeName := deletedPod.Spec.NodeName
@ -324,8 +324,7 @@ func (meta *predicateMetadata) ShallowCopy() algorithm.PredicateMetadata {
for k, v := range meta.nodeNameToMatchingAntiAffinityPods { for k, v := range meta.nodeNameToMatchingAntiAffinityPods {
newPredMeta.nodeNameToMatchingAntiAffinityPods[k] = append([]*v1.Pod(nil), v...) newPredMeta.nodeNameToMatchingAntiAffinityPods[k] = append([]*v1.Pod(nil), v...)
} }
newPredMeta.topologyPairsAntiAffinityPodsMap = &topologyPairsMaps{topologyPairToPods: make(map[topologyPair][]*v1.Pod), newPredMeta.topologyPairsAntiAffinityPodsMap = newTopologyPairsMaps()
podToTopologyPairs: make(map[string][]topologyPair)}
newPredMeta.topologyPairsAntiAffinityPodsMap.appendMaps(meta.topologyPairsAntiAffinityPodsMap) newPredMeta.topologyPairsAntiAffinityPodsMap.appendMaps(meta.topologyPairsAntiAffinityPodsMap)
newPredMeta.serviceAffinityMatchingPodServices = append([]*v1.Service(nil), newPredMeta.serviceAffinityMatchingPodServices = append([]*v1.Service(nil),
meta.serviceAffinityMatchingPodServices...) meta.serviceAffinityMatchingPodServices...)

View File

@ -28,33 +28,6 @@ import (
schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing" schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
) )
// sortableTopologyPairs lets us sort topology pairs
type sortableTopologyPairs []topologyPair
// Less establishes some ordering between two topologyPairs for sorting.
func (s sortableTopologyPairs) Less(i, j int) bool {
t1, t2 := s[i], s[j]
return t1.key < t2.key || (t1.key == t2.key && t1.value < t2.value)
}
func (s sortableTopologyPairs) Len() int { return len(s) }
func (s sortableTopologyPairs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
var _ = sort.Interface(sortableTopologyPairs{})
func sortTopologyPairs(pairs map[string][]topologyPair) {
for k, v := range pairs {
sortableTerms := sortableTopologyPairs(v)
sort.Sort(sortableTerms)
pairs[k] = sortableTerms
}
}
func sortTopologyPairPods(np map[topologyPair][]*v1.Pod) {
for _, pl := range np {
sortablePods := sortablePods(pl)
sort.Sort(sortablePods)
}
}
// sortablePods lets us to sort pods. // sortablePods lets us to sort pods.
type sortablePods []*v1.Pod type sortablePods []*v1.Pod
@ -114,17 +87,13 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
if !reflect.DeepEqual(meta1.nodeNameToMatchingAntiAffinityPods, meta2.nodeNameToMatchingAntiAffinityPods) { if !reflect.DeepEqual(meta1.nodeNameToMatchingAntiAffinityPods, meta2.nodeNameToMatchingAntiAffinityPods) {
return fmt.Errorf("nodeNameToMatchingAntiAffinityPods are not euqal") return fmt.Errorf("nodeNameToMatchingAntiAffinityPods are not euqal")
} }
sortTopologyPairs(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs)
sortTopologyPairs(meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs)
if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs, if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs,
meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) { meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) {
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.antiAffinityPodToTopologyPairs are not equal") return fmt.Errorf("topologyPairsAntiAffinityPodsMap.podToTopologyPairs are not equal")
} }
sortTopologyPairPods(meta1.topologyPairsAntiAffinityPodsMap.topologyPairToPods)
sortTopologyPairPods(meta2.topologyPairsAntiAffinityPodsMap.topologyPairToPods)
if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.topologyPairToPods, if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.topologyPairToPods,
meta2.topologyPairsAntiAffinityPodsMap.topologyPairToPods) { meta2.topologyPairsAntiAffinityPodsMap.topologyPairToPods) {
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToAntiAffinityPods are not equal") return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToPods are not equal")
} }
if meta1.serviceAffinityInUse { if meta1.serviceAffinityInUse {
sortablePods1 := sortablePods(meta1.serviceAffinityMatchingPodList) sortablePods1 := sortablePods(meta1.serviceAffinityMatchingPodList)
@ -464,24 +433,24 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
}, },
}, },
topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{ topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{
topologyPairToPods: map[topologyPair][]*v1.Pod{ topologyPairToPods: map[topologyPair]podSet{
{key: "name", value: "machine1"}: { {key: "name", value: "machine1"}: {
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2", Labels: selector1}, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeC"}, Spec: v1.PodSpec{NodeName: "nodeC"},
}, }: struct{}{},
}, },
{key: "name", value: "machine2"}: { {key: "name", value: "machine2"}: {
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1}, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeA"}, Spec: v1.PodSpec{NodeName: "nodeA"},
}, }: struct{}{},
}, },
}, },
podToTopologyPairs: map[string][]topologyPair{ podToTopologyPairs: map[string]topologyPairSet{
"p2": { "p2_": {
topologyPair{key: "name", value: "machine1"}, topologyPair{key: "name", value: "machine1"}: struct{}{},
}, },
"p1": { "p1_": {
topologyPair{key: "name", value: "machine2"}, topologyPair{key: "name", value: "machine2"}: struct{}{},
}, },
}, },
}, },

View File

@ -1255,8 +1255,7 @@ func getMatchingTopologyPairs(pod *v1.Pod, nodeInfoMap map[string]*schedulercach
var lock sync.Mutex var lock sync.Mutex
var firstError error var firstError error
topologyMaps := &topologyPairsMaps{topologyPairToPods: make(map[topologyPair][]*v1.Pod), topologyMaps := newTopologyPairsMaps()
podToTopologyPairs: make(map[string][]topologyPair)}
appendTopologyPairsMaps := func(toAppend *topologyPairsMaps) { appendTopologyPairsMaps := func(toAppend *topologyPairsMaps) {
lock.Lock() lock.Lock()
@ -1278,8 +1277,7 @@ func getMatchingTopologyPairs(pod *v1.Pod, nodeInfoMap map[string]*schedulercach
catchError(fmt.Errorf("node not found")) catchError(fmt.Errorf("node not found"))
return return
} }
nodeTopologyMaps := &topologyPairsMaps{topologyPairToPods: make(map[topologyPair][]*v1.Pod), nodeTopologyMaps := newTopologyPairsMaps()
podToTopologyPairs: make(map[string][]topologyPair)}
for _, existingPod := range nodeInfo.PodsWithAffinity() { for _, existingPod := range nodeInfo.PodsWithAffinity() {
affinity := existingPod.Spec.Affinity affinity := existingPod.Spec.Affinity
if affinity == nil { if affinity == nil {
@ -1295,7 +1293,7 @@ func getMatchingTopologyPairs(pod *v1.Pod, nodeInfoMap map[string]*schedulercach
if priorityutil.PodMatchesTermsNamespaceAndSelector(pod, namespaces, selector) { if priorityutil.PodMatchesTermsNamespaceAndSelector(pod, namespaces, selector) {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok { if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue} pair := topologyPair{key: term.TopologyKey, value: topologyValue}
nodeTopologyMaps.AddTopologyPair(pair, existingPod) nodeTopologyMaps.addTopologyPair(pair, existingPod)
} }
} }
} }
@ -1309,8 +1307,7 @@ func getMatchingTopologyPairs(pod *v1.Pod, nodeInfoMap map[string]*schedulercach
} }
func getMatchingTopologyPairsOfExistingPod(newPod *v1.Pod, existingPod *v1.Pod, node *v1.Node) (*topologyPairsMaps, error) { func getMatchingTopologyPairsOfExistingPod(newPod *v1.Pod, existingPod *v1.Pod, node *v1.Node) (*topologyPairsMaps, error) {
topologyMaps := &topologyPairsMaps{topologyPairToPods: make(map[topologyPair][]*v1.Pod), topologyMaps := newTopologyPairsMaps()
podToTopologyPairs: make(map[string][]topologyPair)}
affinity := existingPod.Spec.Affinity affinity := existingPod.Spec.Affinity
if affinity != nil && affinity.PodAntiAffinity != nil { if affinity != nil && affinity.PodAntiAffinity != nil {
for _, term := range GetPodAntiAffinityTerms(affinity.PodAntiAffinity) { for _, term := range GetPodAntiAffinityTerms(affinity.PodAntiAffinity) {
@ -1322,7 +1319,7 @@ func getMatchingTopologyPairsOfExistingPod(newPod *v1.Pod, existingPod *v1.Pod,
if priorityutil.PodMatchesTermsNamespaceAndSelector(newPod, namespaces, selector) { if priorityutil.PodMatchesTermsNamespaceAndSelector(newPod, namespaces, selector) {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok { if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue} pair := topologyPair{key: term.TopologyKey, value: topologyValue}
topologyMaps.AddTopologyPair(pair, existingPod) topologyMaps.addTopologyPair(pair, existingPod)
} }
} }
} }
@ -1330,8 +1327,7 @@ func getMatchingTopologyPairsOfExistingPod(newPod *v1.Pod, existingPod *v1.Pod,
return topologyMaps, nil return topologyMaps, nil
} }
func (c *PodAffinityChecker) getMatchingAntiAffinityTopologyPairs(pod *v1.Pod, allPods []*v1.Pod) (*topologyPairsMaps, error) { func (c *PodAffinityChecker) getMatchingAntiAffinityTopologyPairs(pod *v1.Pod, allPods []*v1.Pod) (*topologyPairsMaps, error) {
topologyMaps := &topologyPairsMaps{topologyPairToPods: make(map[topologyPair][]*v1.Pod), topologyMaps := newTopologyPairsMaps()
podToTopologyPairs: make(map[string][]topologyPair)}
for _, existingPod := range allPods { for _, existingPod := range allPods {
affinity := existingPod.Spec.Affinity affinity := existingPod.Spec.Affinity
@ -1383,7 +1379,7 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
// Iterate over topology pairs to get any of the pods being affected by // Iterate over topology pairs to get any of the pods being affected by
// the scheduled pod anti-affinity rules // the scheduled pod anti-affinity rules
for topologyKey, topologyValue := range node.Labels { for topologyKey, topologyValue := range node.Labels {
if _, ok := topologyMaps.topologyPairToPods[topologyPair{key: topologyKey, value: topologyValue}]; ok { if topologyMaps.topologyPairToPods[topologyPair{key: topologyKey, value: topologyValue}] != nil {
glog.V(10).Infof("Cannot schedule pod %+v onto node %v", podName(pod), node.Name) glog.V(10).Infof("Cannot schedule pod %+v onto node %v", podName(pod), node.Name)
return ErrExistingPodsAntiAffinityRulesNotMatch, nil return ErrExistingPodsAntiAffinityRulesNotMatch, nil
} }