diff --git a/pkg/scheduler/framework/cycle_state.go b/pkg/scheduler/framework/cycle_state.go index 652a257d9a1..4674878377c 100644 --- a/pkg/scheduler/framework/cycle_state.go +++ b/pkg/scheduler/framework/cycle_state.go @@ -41,18 +41,18 @@ type StateKey string // StateData stored by one plugin can be read, altered, or deleted by another plugin. // CycleState does not provide any data protection, as all plugins are assumed to be // trusted. +// Note: CycleState uses a sync.Map to back the storage. It's aimed to optimize for the "write once and read many times" scenarios. +// It is the recommended pattern used in all in-tree plugins - plugin-specific state is written once in PreFilter/PreScore and afterwards read many times in Filter/Score. type CycleState struct { - mx sync.RWMutex - storage map[StateKey]StateData + // storage is keyed with StateKey, and valued with StateData. + storage sync.Map // if recordPluginMetrics is true, PluginExecutionDuration will be recorded for this cycle. recordPluginMetrics bool } // NewCycleState initializes a new CycleState and returns its pointer. func NewCycleState() *CycleState { - return &CycleState{ - storage: make(map[StateKey]StateData), - } + return &CycleState{} } // ShouldRecordPluginMetrics returns whether PluginExecutionDuration metrics should be recorded. @@ -78,36 +78,32 @@ func (c *CycleState) Clone() *CycleState { return nil } copy := NewCycleState() - for k, v := range c.storage { - copy.Write(k, v.Clone()) - } + c.storage.Range(func(k, v interface{}) bool { + copy.storage.Store(k, v.(StateData).Clone()) + return true + }) + return copy } // Read retrieves data with the given "key" from CycleState. If the key is not // present an error is returned. -// This function is thread safe by acquiring an internal lock first. +// This function is thread safe by using sync.Map. func (c *CycleState) Read(key StateKey) (StateData, error) { - c.mx.RLock() - defer c.mx.RUnlock() - if v, ok := c.storage[key]; ok { - return v, nil + if v, ok := c.storage.Load(key); ok { + return v.(StateData), nil } return nil, ErrNotFound } // Write stores the given "val" in CycleState with the given "key". -// This function is thread safe by acquiring an internal lock first. +// This function is thread safe by using sync.Map. func (c *CycleState) Write(key StateKey, val StateData) { - c.mx.Lock() - c.storage[key] = val - c.mx.Unlock() + c.storage.Store(key, val) } // Delete deletes data with the given key from CycleState. -// This function is thread safe by acquiring an internal lock first. +// This function is thread safe by using sync.Map. func (c *CycleState) Delete(key StateKey) { - c.mx.Lock() - delete(c.storage, key) - c.mx.Unlock() + c.storage.Delete(key) }