k8s.io/kubernetes@v1.29.3/pkg/scheduler/internal/heap/heap.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  // Below is the implementation of the a heap. The logic is pretty much the same
    18  // as cache.heap, however, this heap does not perform synchronization. It leaves
    19  // synchronization to the SchedulingQueue.
    20  
    21  package heap
    22  
    23  import (
    24  	"container/heap"
    25  	"fmt"
    26  
    27  	"k8s.io/client-go/tools/cache"
    28  	"k8s.io/kubernetes/pkg/scheduler/metrics"
    29  )
    30  
    31  // KeyFunc is a function type to get the key from an object.
    32  type KeyFunc func(obj interface{}) (string, error)
    33  
    34  type heapItem struct {
    35  	obj   interface{} // The object which is stored in the heap.
    36  	index int         // The index of the object's key in the Heap.queue.
    37  }
    38  
    39  type itemKeyValue struct {
    40  	key string
    41  	obj interface{}
    42  }
    43  
    44  // data is an internal struct that implements the standard heap interface
    45  // and keeps the data stored in the heap.
    46  type data struct {
    47  	// items is a map from key of the objects to the objects and their index.
    48  	// We depend on the property that items in the map are in the queue and vice versa.
    49  	items map[string]*heapItem
    50  	// queue implements a heap data structure and keeps the order of elements
    51  	// according to the heap invariant. The queue keeps the keys of objects stored
    52  	// in "items".
    53  	queue []string
    54  
    55  	// keyFunc is used to make the key used for queued item insertion and retrieval, and
    56  	// should be deterministic.
    57  	keyFunc KeyFunc
    58  	// lessFunc is used to compare two objects in the heap.
    59  	lessFunc lessFunc
    60  }
    61  
    62  var (
    63  	_ = heap.Interface(&data{}) // heapData is a standard heap
    64  )
    65  
    66  // Less compares two objects and returns true if the first one should go
    67  // in front of the second one in the heap.
    68  func (h *data) Less(i, j int) bool {
    69  	if i > len(h.queue) || j > len(h.queue) {
    70  		return false
    71  	}
    72  	itemi, ok := h.items[h.queue[i]]
    73  	if !ok {
    74  		return false
    75  	}
    76  	itemj, ok := h.items[h.queue[j]]
    77  	if !ok {
    78  		return false
    79  	}
    80  	return h.lessFunc(itemi.obj, itemj.obj)
    81  }
    82  
    83  // Len returns the number of items in the Heap.
    84  func (h *data) Len() int { return len(h.queue) }
    85  
    86  // Swap implements swapping of two elements in the heap. This is a part of standard
    87  // heap interface and should never be called directly.
    88  func (h *data) Swap(i, j int) {
    89  	h.queue[i], h.queue[j] = h.queue[j], h.queue[i]
    90  	item := h.items[h.queue[i]]
    91  	item.index = i
    92  	item = h.items[h.queue[j]]
    93  	item.index = j
    94  }
    95  
    96  // Push is supposed to be called by heap.Push only.
    97  func (h *data) Push(kv interface{}) {
    98  	keyValue := kv.(*itemKeyValue)
    99  	n := len(h.queue)
   100  	h.items[keyValue.key] = &heapItem{keyValue.obj, n}
   101  	h.queue = append(h.queue, keyValue.key)
   102  }
   103  
   104  // Pop is supposed to be called by heap.Pop only.
   105  func (h *data) Pop() interface{} {
   106  	key := h.queue[len(h.queue)-1]
   107  	h.queue = h.queue[0 : len(h.queue)-1]
   108  	item, ok := h.items[key]
   109  	if !ok {
   110  		// This is an error
   111  		return nil
   112  	}
   113  	delete(h.items, key)
   114  	return item.obj
   115  }
   116  
   117  // Peek is supposed to be called by heap.Peek only.
   118  func (h *data) Peek() interface{} {
   119  	if len(h.queue) > 0 {
   120  		return h.items[h.queue[0]].obj
   121  	}
   122  	return nil
   123  }
   124  
   125  // Heap is a producer/consumer queue that implements a heap data structure.
   126  // It can be used to implement priority queues and similar data structures.
   127  type Heap struct {
   128  	// data stores objects and has a queue that keeps their ordering according
   129  	// to the heap invariant.
   130  	data *data
   131  	// metricRecorder updates the counter when elements of a heap get added or
   132  	// removed, and it does nothing if it's nil
   133  	metricRecorder metrics.MetricRecorder
   134  }
   135  
   136  // Add inserts an item, and puts it in the queue. The item is updated if it
   137  // already exists.
   138  func (h *Heap) Add(obj interface{}) error {
   139  	key, err := h.data.keyFunc(obj)
   140  	if err != nil {
   141  		return cache.KeyError{Obj: obj, Err: err}
   142  	}
   143  	if _, exists := h.data.items[key]; exists {
   144  		h.data.items[key].obj = obj
   145  		heap.Fix(h.data, h.data.items[key].index)
   146  	} else {
   147  		heap.Push(h.data, &itemKeyValue{key, obj})
   148  		if h.metricRecorder != nil {
   149  			h.metricRecorder.Inc()
   150  		}
   151  	}
   152  	return nil
   153  }
   154  
   155  // Update is the same as Add in this implementation. When the item does not
   156  // exist, it is added.
   157  func (h *Heap) Update(obj interface{}) error {
   158  	return h.Add(obj)
   159  }
   160  
   161  // Delete removes an item.
   162  func (h *Heap) Delete(obj interface{}) error {
   163  	key, err := h.data.keyFunc(obj)
   164  	if err != nil {
   165  		return cache.KeyError{Obj: obj, Err: err}
   166  	}
   167  	if item, ok := h.data.items[key]; ok {
   168  		heap.Remove(h.data, item.index)
   169  		if h.metricRecorder != nil {
   170  			h.metricRecorder.Dec()
   171  		}
   172  		return nil
   173  	}
   174  	return fmt.Errorf("object not found")
   175  }
   176  
   177  // Peek returns the head of the heap without removing it.
   178  func (h *Heap) Peek() interface{} {
   179  	return h.data.Peek()
   180  }
   181  
   182  // Pop returns the head of the heap and removes it.
   183  func (h *Heap) Pop() (interface{}, error) {
   184  	obj := heap.Pop(h.data)
   185  	if obj != nil {
   186  		if h.metricRecorder != nil {
   187  			h.metricRecorder.Dec()
   188  		}
   189  		return obj, nil
   190  	}
   191  	return nil, fmt.Errorf("object was removed from heap data")
   192  }
   193  
   194  // Get returns the requested item, or sets exists=false.
   195  func (h *Heap) Get(obj interface{}) (interface{}, bool, error) {
   196  	key, err := h.data.keyFunc(obj)
   197  	if err != nil {
   198  		return nil, false, cache.KeyError{Obj: obj, Err: err}
   199  	}
   200  	return h.GetByKey(key)
   201  }
   202  
   203  // GetByKey returns the requested item, or sets exists=false.
   204  func (h *Heap) GetByKey(key string) (interface{}, bool, error) {
   205  	item, exists := h.data.items[key]
   206  	if !exists {
   207  		return nil, false, nil
   208  	}
   209  	return item.obj, true, nil
   210  }
   211  
   212  // List returns a list of all the items.
   213  func (h *Heap) List() []interface{} {
   214  	list := make([]interface{}, 0, len(h.data.items))
   215  	for _, item := range h.data.items {
   216  		list = append(list, item.obj)
   217  	}
   218  	return list
   219  }
   220  
   221  // Len returns the number of items in the heap.
   222  func (h *Heap) Len() int {
   223  	return len(h.data.queue)
   224  }
   225  
   226  // New returns a Heap which can be used to queue up items to process.
   227  func New(keyFn KeyFunc, lessFn lessFunc) *Heap {
   228  	return NewWithRecorder(keyFn, lessFn, nil)
   229  }
   230  
   231  // NewWithRecorder wraps an optional metricRecorder to compose a Heap object.
   232  func NewWithRecorder(keyFn KeyFunc, lessFn lessFunc, metricRecorder metrics.MetricRecorder) *Heap {
   233  	return &Heap{
   234  		data: &data{
   235  			items:    map[string]*heapItem{},
   236  			queue:    []string{},
   237  			keyFunc:  keyFn,
   238  			lessFunc: lessFn,
   239  		},
   240  		metricRecorder: metricRecorder,
   241  	}
   242  }
   243  
   244  // lessFunc is a function that receives two items and returns true if the first
   245  // item should be placed before the second one when the list is sorted.
   246  type lessFunc = func(item1, item2 interface{}) bool