k8s.io/kubernetes@v1.29.3/pkg/scheduler/internal/cache/debugger/comparer.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package debugger 18 19 import ( 20 "sort" 21 "strings" 22 23 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/labels" 25 corelisters "k8s.io/client-go/listers/core/v1" 26 "k8s.io/klog/v2" 27 "k8s.io/kubernetes/pkg/scheduler/framework" 28 internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" 29 internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" 30 ) 31 32 // CacheComparer is an implementation of the Scheduler's cache comparer. 33 type CacheComparer struct { 34 NodeLister corelisters.NodeLister 35 PodLister corelisters.PodLister 36 Cache internalcache.Cache 37 PodQueue internalqueue.SchedulingQueue 38 } 39 40 // Compare compares the nodes and pods of NodeLister with Cache.Snapshot. 41 func (c *CacheComparer) Compare(logger klog.Logger) error { 42 logger.V(3).Info("Cache comparer started") 43 defer logger.V(3).Info("Cache comparer finished") 44 45 nodes, err := c.NodeLister.List(labels.Everything()) 46 if err != nil { 47 return err 48 } 49 50 pods, err := c.PodLister.List(labels.Everything()) 51 if err != nil { 52 return err 53 } 54 55 dump := c.Cache.Dump() 56 57 pendingPods, _ := c.PodQueue.PendingPods() 58 59 if missed, redundant := c.CompareNodes(nodes, dump.Nodes); len(missed)+len(redundant) != 0 { 60 logger.Info("Cache mismatch", "missedNodes", missed, "redundantNodes", redundant) 61 } 62 63 if missed, redundant := c.ComparePods(pods, pendingPods, dump.Nodes); len(missed)+len(redundant) != 0 { 64 logger.Info("Cache mismatch", "missedPods", missed, "redundantPods", redundant) 65 } 66 67 return nil 68 } 69 70 // CompareNodes compares actual nodes with cached nodes. 71 func (c *CacheComparer) CompareNodes(nodes []*v1.Node, nodeinfos map[string]*framework.NodeInfo) (missed, redundant []string) { 72 actual := []string{} 73 for _, node := range nodes { 74 actual = append(actual, node.Name) 75 } 76 77 cached := []string{} 78 for nodeName := range nodeinfos { 79 cached = append(cached, nodeName) 80 } 81 82 return compareStrings(actual, cached) 83 } 84 85 // ComparePods compares actual pods with cached pods. 86 func (c *CacheComparer) ComparePods(pods, waitingPods []*v1.Pod, nodeinfos map[string]*framework.NodeInfo) (missed, redundant []string) { 87 actual := []string{} 88 for _, pod := range pods { 89 actual = append(actual, string(pod.UID)) 90 } 91 92 cached := []string{} 93 for _, nodeinfo := range nodeinfos { 94 for _, p := range nodeinfo.Pods { 95 cached = append(cached, string(p.Pod.UID)) 96 } 97 } 98 for _, pod := range waitingPods { 99 cached = append(cached, string(pod.UID)) 100 } 101 102 return compareStrings(actual, cached) 103 } 104 105 func compareStrings(actual, cached []string) (missed, redundant []string) { 106 missed, redundant = []string{}, []string{} 107 108 sort.Strings(actual) 109 sort.Strings(cached) 110 111 compare := func(i, j int) int { 112 if i == len(actual) { 113 return 1 114 } else if j == len(cached) { 115 return -1 116 } 117 return strings.Compare(actual[i], cached[j]) 118 } 119 120 for i, j := 0, 0; i < len(actual) || j < len(cached); { 121 switch compare(i, j) { 122 case 0: 123 i++ 124 j++ 125 case -1: 126 missed = append(missed, actual[i]) 127 i++ 128 case 1: 129 redundant = append(redundant, cached[j]) 130 j++ 131 } 132 } 133 134 return 135 }