Improve docs on framework.CycleState

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Kante Yin <kerthcet@gmail.com>
This commit is contained in:
Adrian Cole 2023-07-14 13:50:10 +08:00
parent 5c72df7281
commit 89ab733760

View File

@ -43,12 +43,12 @@ type StateKey string
// StateData stored by one plugin can be read, altered, or deleted by another plugin. // 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 // CycleState does not provide any data protection, as all plugins are assumed to be
// trusted. // 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. // 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.
// 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. // 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.
type CycleState struct { type CycleState struct {
// storage is keyed with StateKey, and valued with StateData. // storage is keyed with StateKey, and valued with StateData.
storage sync.Map storage sync.Map
// if recordPluginMetrics is true, PluginExecutionDuration will be recorded for this cycle. // if recordPluginMetrics is true, metrics.PluginExecutionDuration will be recorded for this cycle.
recordPluginMetrics bool recordPluginMetrics bool
// SkipFilterPlugins are plugins that will be skipped in the Filter extension point. // SkipFilterPlugins are plugins that will be skipped in the Filter extension point.
SkipFilterPlugins sets.Set[string] SkipFilterPlugins sets.Set[string]
@ -61,7 +61,7 @@ func NewCycleState() *CycleState {
return &CycleState{} return &CycleState{}
} }
// ShouldRecordPluginMetrics returns whether PluginExecutionDuration metrics should be recorded. // ShouldRecordPluginMetrics returns whether metrics.PluginExecutionDuration metrics should be recorded.
func (c *CycleState) ShouldRecordPluginMetrics() bool { func (c *CycleState) ShouldRecordPluginMetrics() bool {
if c == nil { if c == nil {
return false return false
@ -84,10 +84,12 @@ func (c *CycleState) Clone() *CycleState {
return nil return nil
} }
copy := NewCycleState() copy := NewCycleState()
// Safe copy storage in case of overwriting.
c.storage.Range(func(k, v interface{}) bool { c.storage.Range(func(k, v interface{}) bool {
copy.storage.Store(k, v.(StateData).Clone()) copy.storage.Store(k, v.(StateData).Clone())
return true return true
}) })
// The below are not mutated, so we don't have to safe copy.
copy.recordPluginMetrics = c.recordPluginMetrics copy.recordPluginMetrics = c.recordPluginMetrics
copy.SkipFilterPlugins = c.SkipFilterPlugins copy.SkipFilterPlugins = c.SkipFilterPlugins
copy.SkipScorePlugins = c.SkipScorePlugins copy.SkipScorePlugins = c.SkipScorePlugins
@ -96,8 +98,9 @@ func (c *CycleState) Clone() *CycleState {
} }
// Read retrieves data with the given "key" from CycleState. If the key is not // Read retrieves data with the given "key" from CycleState. If the key is not
// present an error is returned. // present, ErrNotFound is returned.
// This function is thread safe by using sync.Map. //
// See CycleState for notes on concurrency.
func (c *CycleState) Read(key StateKey) (StateData, error) { func (c *CycleState) Read(key StateKey) (StateData, error) {
if v, ok := c.storage.Load(key); ok { if v, ok := c.storage.Load(key); ok {
return v.(StateData), nil return v.(StateData), nil
@ -106,13 +109,15 @@ func (c *CycleState) Read(key StateKey) (StateData, error) {
} }
// Write stores the given "val" in CycleState with the given "key". // Write stores the given "val" in CycleState with the given "key".
// This function is thread safe by using sync.Map. //
// See CycleState for notes on concurrency.
func (c *CycleState) Write(key StateKey, val StateData) { func (c *CycleState) Write(key StateKey, val StateData) {
c.storage.Store(key, val) c.storage.Store(key, val)
} }
// Delete deletes data with the given key from CycleState. // Delete deletes data with the given key from CycleState.
// This function is thread safe by using sync.Map. //
// See CycleState for notes on concurrency.
func (c *CycleState) Delete(key StateKey) { func (c *CycleState) Delete(key StateKey) {
c.storage.Delete(key) c.storage.Delete(key)
} }