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  }