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