1 /* 2 Copyright 2019 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 framework 18 19 import ( 20 "errors" 21 "sync" 22 23 "k8s.io/apimachinery/pkg/util/sets" 24 ) 25 26 var ( 27 // ErrNotFound is the not found error message. 28 ErrNotFound = errors.New("not found") 29 ) 30 31 // StateData is a generic type for arbitrary data stored in CycleState. 32 type StateData interface { 33 // Clone is an interface to make a copy of StateData. For performance reasons, 34 // clone should make shallow copies for members (e.g., slices or maps) that are not 35 // impacted by PreFilter's optional AddPod/RemovePod methods. 36 Clone() StateData 37 } 38 39 // StateKey is the type of keys stored in CycleState. 40 type StateKey string 41 42 // CycleState provides a mechanism for plugins to store and retrieve arbitrary data. 43 // StateData stored by one plugin can be read, altered, or deleted by another plugin. 44 // CycleState does not provide any data protection, as all plugins are assumed to be 45 // trusted. 46 // Note: CycleState uses a sync.Map to back the storage, because it is thread safe. It's aimed to optimize for the "write once and read many times" scenarios. 47 // It is the recommended pattern used in all in-tree plugins - plugin-specific state is written once in PreFilter/PreScore and afterward read many times in Filter/Score. 48 type CycleState struct { 49 // storage is keyed with StateKey, and valued with StateData. 50 storage sync.Map 51 // if recordPluginMetrics is true, metrics.PluginExecutionDuration will be recorded for this cycle. 52 recordPluginMetrics bool 53 // SkipFilterPlugins are plugins that will be skipped in the Filter extension point. 54 SkipFilterPlugins sets.Set[string] 55 // SkipScorePlugins are plugins that will be skipped in the Score extension point. 56 SkipScorePlugins sets.Set[string] 57 } 58 59 // NewCycleState initializes a new CycleState and returns its pointer. 60 func NewCycleState() *CycleState { 61 return &CycleState{} 62 } 63 64 // ShouldRecordPluginMetrics returns whether metrics.PluginExecutionDuration metrics should be recorded. 65 func (c *CycleState) ShouldRecordPluginMetrics() bool { 66 if c == nil { 67 return false 68 } 69 return c.recordPluginMetrics 70 } 71 72 // SetRecordPluginMetrics sets recordPluginMetrics to the given value. 73 func (c *CycleState) SetRecordPluginMetrics(flag bool) { 74 if c == nil { 75 return 76 } 77 c.recordPluginMetrics = flag 78 } 79 80 // Clone creates a copy of CycleState and returns its pointer. Clone returns 81 // nil if the context being cloned is nil. 82 func (c *CycleState) Clone() *CycleState { 83 if c == nil { 84 return nil 85 } 86 copy := NewCycleState() 87 // Safe copy storage in case of overwriting. 88 c.storage.Range(func(k, v interface{}) bool { 89 copy.storage.Store(k, v.(StateData).Clone()) 90 return true 91 }) 92 // The below are not mutated, so we don't have to safe copy. 93 copy.recordPluginMetrics = c.recordPluginMetrics 94 copy.SkipFilterPlugins = c.SkipFilterPlugins 95 copy.SkipScorePlugins = c.SkipScorePlugins 96 97 return copy 98 } 99 100 // Read retrieves data with the given "key" from CycleState. If the key is not 101 // present, ErrNotFound is returned. 102 // 103 // See CycleState for notes on concurrency. 104 func (c *CycleState) Read(key StateKey) (StateData, error) { 105 if v, ok := c.storage.Load(key); ok { 106 return v.(StateData), nil 107 } 108 return nil, ErrNotFound 109 } 110 111 // Write stores the given "val" in CycleState with the given "key". 112 // 113 // See CycleState for notes on concurrency. 114 func (c *CycleState) Write(key StateKey, val StateData) { 115 c.storage.Store(key, val) 116 } 117 118 // Delete deletes data with the given key from CycleState. 119 // 120 // See CycleState for notes on concurrency. 121 func (c *CycleState) Delete(key StateKey) { 122 c.storage.Delete(key) 123 } 124