Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions pkg/scheduler/framework/cyclestate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package framework

import (
"fmt"
"sync"
)

// StateKey is the key for a state value stored in a CycleState.
type StateKey string

// StateValue is the value stored in a CycleState under a specific key.
type StateValue interface{}

// CycleStatePluginReadWriter is an interface through which plugins can store and retrieve data.
type CycleStatePluginReadWriter interface {
Read(key StateKey) (StateValue, error)
Write(key StateKey, val StateValue)
Delete(key StateKey)
}

// CycleState is, similar to its namesake in kube-scheduler, provides a way for plugins to
// store and retrieve arbitrary data during a scheduling cycle. The scheduler also uses
// this struct to keep some global states during a scheduling cycle; note that these
// state are only accessible to the scheduler itself, not to plugins.
//
// It uses a sync.Map for concurrency-safe storage.
type CycleState struct {
// store is a concurrency-safe store (a map).
store sync.Map
}

// Read retrieves a value from CycleState by a key.
func (c *CycleState) Read(key StateKey) (StateValue, error) {
if v, ok := c.store.Load(key); ok {
return v, nil
}
return nil, fmt.Errorf("key %s is not found", key)
}

// Write stores a value in CycleState under a key.
func (c *CycleState) Write(key StateKey, val StateValue) {
c.store.Store(key, val)
}

// Delete deletes a key from CycleState.
func (c *CycleState) Delete(key StateKey) {
c.store.Delete(key)
}

// NewCycleState creates a CycleState.
func NewCycleState() *CycleState {
return &CycleState{}
}
23 changes: 23 additions & 0 deletions pkg/scheduler/framework/cyclestate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package framework

import "testing"

// TestCycleStateBasicOps tests the basic ops (Read, Write, and Delete) of a CycleState.
func TestCycleStateBasicOps(t *testing.T) {
cs := NewCycleState()

k, v := "key", "value"
cs.Write(StateKey(k), StateValue(v))
if out, err := cs.Read("key"); out != "value" || err != nil {
t.Fatalf("Read(%v) = %v, %v, want %v, nil", k, out, err, v)
}
cs.Delete(StateKey(k))
if out, err := cs.Read("key"); out != nil || err == nil {
t.Fatalf("Read(%v) = %v, %v, want nil, not found error", k, out, err)
}
}
65 changes: 65 additions & 0 deletions pkg/scheduler/framework/score.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/

package framework

import (
fleetv1 "go.goms.io/fleet/apis/v1"
)

// ClusterScore is the scores the scheduler assigns to a cluster.
type ClusterScore struct {
// TopologySpreadScore determines how much a binding would satisfy the topology spread
// constraints specified by the user.
TopologySpreadScore int
// AffinityScore determines how much a binding would satisfy the affinity terms
// specified by the user.
AffinityScore int
// PriorityScore determines how much a binding would satisfy the priority terms
// specified by the user.
PriorityScore int
}

// Add adds a ClusterScore to another ClusterScore.
func (s1 *ClusterScore) Add(s2 ClusterScore) {
s1.TopologySpreadScore += s2.TopologySpreadScore
s1.AffinityScore += s2.AffinityScore
s1.PriorityScore += s2.PriorityScore
}

// Less returns true if a ClusterScore is less than another.
func (s1 *ClusterScore) Less(s2 *ClusterScore) bool {
if s1.TopologySpreadScore != s2.TopologySpreadScore {
return s1.TopologySpreadScore < s2.TopologySpreadScore
}

if s1.AffinityScore != s2.AffinityScore {
return s1.AffinityScore < s2.AffinityScore
}

return s1.PriorityScore < s2.PriorityScore
}

// ScoredCluster is a cluster with a score.
type ScoredCluster struct {
Cluster *fleetv1.MemberCluster
Score *ClusterScore
}

// ScoredClusters is a list of ScoredClusters; this type implements the sort.Interface.
type ScoredClusters []*ScoredCluster

// Len returns the length of a ScoredClusters; it implemented sort.Interface.Len().
func (sc ScoredClusters) Len() int { return len(sc) }

// Less returns true if a ScoredCluster is of a lower score than another; it implemented sort.Interface.Less().
func (sc ScoredClusters) Less(i, j int) bool {
return sc[i].Score.Less(sc[j].Score)
}

// Swap swaps two ScoredClusters in the list; it implemented sort.Interface.Swap().
func (sc ScoredClusters) Swap(i, j int) {
sc[i], sc[j] = sc[j], sc[i]
}
Loading