mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #59954 from msau42/index-sc
Automatic merge from submit-queue (batch tested with PRs 57700, 59954). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Index PVs by StorageClass in assume cache **What this PR does / why we need it**: Performance optimization for delayed binding in the scheduler to only search for PVs with a matching StorageClass name. This means that if you prebind the PV to a PVC, the PV must have a matching StorageClass name. This behavior is different from when you prebind with immediate binding, which doesn't care about StorageClass. **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes #56102 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```
This commit is contained in:
commit
d594a13d69
@ -43,7 +43,7 @@ type AssumeCache interface {
|
|||||||
Get(objName string) (interface{}, error)
|
Get(objName string) (interface{}, error)
|
||||||
|
|
||||||
// List all the objects in the cache
|
// List all the objects in the cache
|
||||||
List() []interface{}
|
List(indexObj interface{}) []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type errWrongType struct {
|
type errWrongType struct {
|
||||||
@ -89,7 +89,11 @@ type assumeCache struct {
|
|||||||
description string
|
description string
|
||||||
|
|
||||||
// Stores objInfo pointers
|
// Stores objInfo pointers
|
||||||
store cache.Store
|
store cache.Indexer
|
||||||
|
|
||||||
|
// Index function for object
|
||||||
|
indexFunc cache.IndexFunc
|
||||||
|
indexName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type objInfo struct {
|
type objInfo struct {
|
||||||
@ -111,9 +115,21 @@ func objInfoKeyFunc(obj interface{}) (string, error) {
|
|||||||
return objInfo.name, nil
|
return objInfo.name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAssumeCache(informer cache.SharedIndexInformer, description string) *assumeCache {
|
func (c *assumeCache) objInfoIndexFunc(obj interface{}) ([]string, error) {
|
||||||
// TODO: index by storageclass
|
objInfo, ok := obj.(*objInfo)
|
||||||
c := &assumeCache{store: cache.NewStore(objInfoKeyFunc), description: description}
|
if !ok {
|
||||||
|
return []string{""}, &errWrongType{"objInfo", obj}
|
||||||
|
}
|
||||||
|
return c.indexFunc(objInfo.latestObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAssumeCache(informer cache.SharedIndexInformer, description, indexName string, indexFunc cache.IndexFunc) *assumeCache {
|
||||||
|
c := &assumeCache{
|
||||||
|
description: description,
|
||||||
|
indexFunc: indexFunc,
|
||||||
|
indexName: indexName,
|
||||||
|
}
|
||||||
|
c.store = cache.NewIndexer(objInfoKeyFunc, cache.Indexers{indexName: c.objInfoIndexFunc})
|
||||||
|
|
||||||
// Unit tests don't use informers
|
// Unit tests don't use informers
|
||||||
if informer != nil {
|
if informer != nil {
|
||||||
@ -211,12 +227,18 @@ func (c *assumeCache) Get(objName string) (interface{}, error) {
|
|||||||
return objInfo.latestObj, nil
|
return objInfo.latestObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *assumeCache) List() []interface{} {
|
func (c *assumeCache) List(indexObj interface{}) []interface{} {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
allObjs := []interface{}{}
|
allObjs := []interface{}{}
|
||||||
for _, obj := range c.store.List() {
|
objs, err := c.store.Index(c.indexName, &objInfo{latestObj: indexObj})
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("list index error: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, obj := range objs {
|
||||||
objInfo, ok := obj.(*objInfo)
|
objInfo, ok := obj.(*objInfo)
|
||||||
if !ok {
|
if !ok {
|
||||||
glog.Errorf("list error: %v", &errWrongType{"objInfo", obj})
|
glog.Errorf("list error: %v", &errWrongType{"objInfo", obj})
|
||||||
@ -280,15 +302,22 @@ type PVAssumeCache interface {
|
|||||||
AssumeCache
|
AssumeCache
|
||||||
|
|
||||||
GetPV(pvName string) (*v1.PersistentVolume, error)
|
GetPV(pvName string) (*v1.PersistentVolume, error)
|
||||||
ListPVs() []*v1.PersistentVolume
|
ListPVs(storageClassName string) []*v1.PersistentVolume
|
||||||
}
|
}
|
||||||
|
|
||||||
type pvAssumeCache struct {
|
type pvAssumeCache struct {
|
||||||
*assumeCache
|
*assumeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pvStorageClassIndexFunc(obj interface{}) ([]string, error) {
|
||||||
|
if pv, ok := obj.(*v1.PersistentVolume); ok {
|
||||||
|
return []string{pv.Spec.StorageClassName}, nil
|
||||||
|
}
|
||||||
|
return []string{""}, fmt.Errorf("object is not a v1.PersistentVolume: %v", obj)
|
||||||
|
}
|
||||||
|
|
||||||
func NewPVAssumeCache(informer cache.SharedIndexInformer) PVAssumeCache {
|
func NewPVAssumeCache(informer cache.SharedIndexInformer) PVAssumeCache {
|
||||||
return &pvAssumeCache{assumeCache: NewAssumeCache(informer, "v1.PersistentVolume")}
|
return &pvAssumeCache{assumeCache: NewAssumeCache(informer, "v1.PersistentVolume", "storageclass", pvStorageClassIndexFunc)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *pvAssumeCache) GetPV(pvName string) (*v1.PersistentVolume, error) {
|
func (c *pvAssumeCache) GetPV(pvName string) (*v1.PersistentVolume, error) {
|
||||||
@ -304,8 +333,12 @@ func (c *pvAssumeCache) GetPV(pvName string) (*v1.PersistentVolume, error) {
|
|||||||
return pv, nil
|
return pv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *pvAssumeCache) ListPVs() []*v1.PersistentVolume {
|
func (c *pvAssumeCache) ListPVs(storageClassName string) []*v1.PersistentVolume {
|
||||||
objs := c.List()
|
objs := c.List(&v1.PersistentVolume{
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
StorageClassName: storageClassName,
|
||||||
|
},
|
||||||
|
})
|
||||||
pvs := []*v1.PersistentVolume{}
|
pvs := []*v1.PersistentVolume{}
|
||||||
for _, obj := range objs {
|
for _, obj := range objs {
|
||||||
pv, ok := obj.(*v1.PersistentVolume)
|
pv, ok := obj.(*v1.PersistentVolume)
|
||||||
|
@ -24,8 +24,16 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makePV(name, version string) *v1.PersistentVolume {
|
func makePV(name, version, storageClass string) *v1.PersistentVolume {
|
||||||
return &v1.PersistentVolume{ObjectMeta: metav1.ObjectMeta{Name: name, ResourceVersion: version}}
|
return &v1.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
ResourceVersion: version,
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
StorageClassName: storageClass,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAssumePV(t *testing.T) {
|
func TestAssumePV(t *testing.T) {
|
||||||
@ -35,33 +43,38 @@ func TestAssumePV(t *testing.T) {
|
|||||||
shouldSucceed bool
|
shouldSucceed bool
|
||||||
}{
|
}{
|
||||||
"success-same-version": {
|
"success-same-version": {
|
||||||
oldPV: makePV("pv1", "5"),
|
oldPV: makePV("pv1", "5", ""),
|
||||||
newPV: makePV("pv1", "5"),
|
newPV: makePV("pv1", "5", ""),
|
||||||
|
shouldSucceed: true,
|
||||||
|
},
|
||||||
|
"success-storageclass-same-version": {
|
||||||
|
oldPV: makePV("pv1", "5", "class1"),
|
||||||
|
newPV: makePV("pv1", "5", "class1"),
|
||||||
shouldSucceed: true,
|
shouldSucceed: true,
|
||||||
},
|
},
|
||||||
"success-new-higher-version": {
|
"success-new-higher-version": {
|
||||||
oldPV: makePV("pv1", "5"),
|
oldPV: makePV("pv1", "5", ""),
|
||||||
newPV: makePV("pv1", "6"),
|
newPV: makePV("pv1", "6", ""),
|
||||||
shouldSucceed: true,
|
shouldSucceed: true,
|
||||||
},
|
},
|
||||||
"fail-old-not-found": {
|
"fail-old-not-found": {
|
||||||
oldPV: makePV("pv2", "5"),
|
oldPV: makePV("pv2", "5", ""),
|
||||||
newPV: makePV("pv1", "5"),
|
newPV: makePV("pv1", "5", ""),
|
||||||
shouldSucceed: false,
|
shouldSucceed: false,
|
||||||
},
|
},
|
||||||
"fail-new-lower-version": {
|
"fail-new-lower-version": {
|
||||||
oldPV: makePV("pv1", "5"),
|
oldPV: makePV("pv1", "5", ""),
|
||||||
newPV: makePV("pv1", "4"),
|
newPV: makePV("pv1", "4", ""),
|
||||||
shouldSucceed: false,
|
shouldSucceed: false,
|
||||||
},
|
},
|
||||||
"fail-new-bad-version": {
|
"fail-new-bad-version": {
|
||||||
oldPV: makePV("pv1", "5"),
|
oldPV: makePV("pv1", "5", ""),
|
||||||
newPV: makePV("pv1", "a"),
|
newPV: makePV("pv1", "a", ""),
|
||||||
shouldSucceed: false,
|
shouldSucceed: false,
|
||||||
},
|
},
|
||||||
"fail-old-bad-version": {
|
"fail-old-bad-version": {
|
||||||
oldPV: makePV("pv1", "a"),
|
oldPV: makePV("pv1", "a", ""),
|
||||||
newPV: makePV("pv1", "5"),
|
newPV: makePV("pv1", "5", ""),
|
||||||
shouldSucceed: false,
|
shouldSucceed: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -107,8 +120,8 @@ func TestRestorePV(t *testing.T) {
|
|||||||
t.Fatalf("Failed to get internal cache")
|
t.Fatalf("Failed to get internal cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPV := makePV("pv1", "5")
|
oldPV := makePV("pv1", "5", "")
|
||||||
newPV := makePV("pv1", "5")
|
newPV := makePV("pv1", "5", "")
|
||||||
|
|
||||||
// Restore PV that doesn't exist
|
// Restore PV that doesn't exist
|
||||||
cache.Restore("nothing")
|
cache.Restore("nothing")
|
||||||
@ -159,21 +172,21 @@ func TestBasicPVCache(t *testing.T) {
|
|||||||
// Add a bunch of PVs
|
// Add a bunch of PVs
|
||||||
pvs := map[string]*v1.PersistentVolume{}
|
pvs := map[string]*v1.PersistentVolume{}
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
pv := makePV(fmt.Sprintf("test-pv%v", i), "1")
|
pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "")
|
||||||
pvs[pv.Name] = pv
|
pvs[pv.Name] = pv
|
||||||
internal_cache.add(pv)
|
internal_cache.add(pv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List them
|
// List them
|
||||||
verifyListPVs(t, cache, pvs)
|
verifyListPVs(t, cache, pvs, "")
|
||||||
|
|
||||||
// Update a PV
|
// Update a PV
|
||||||
updatedPV := makePV("test-pv3", "2")
|
updatedPV := makePV("test-pv3", "2", "")
|
||||||
pvs[updatedPV.Name] = updatedPV
|
pvs[updatedPV.Name] = updatedPV
|
||||||
internal_cache.update(nil, updatedPV)
|
internal_cache.update(nil, updatedPV)
|
||||||
|
|
||||||
// List them
|
// List them
|
||||||
verifyListPVs(t, cache, pvs)
|
verifyListPVs(t, cache, pvs, "")
|
||||||
|
|
||||||
// Delete a PV
|
// Delete a PV
|
||||||
deletedPV := pvs["test-pv7"]
|
deletedPV := pvs["test-pv7"]
|
||||||
@ -181,11 +194,57 @@ func TestBasicPVCache(t *testing.T) {
|
|||||||
internal_cache.delete(deletedPV)
|
internal_cache.delete(deletedPV)
|
||||||
|
|
||||||
// List them
|
// List them
|
||||||
verifyListPVs(t, cache, pvs)
|
verifyListPVs(t, cache, pvs, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyListPVs(t *testing.T, cache PVAssumeCache, expectedPVs map[string]*v1.PersistentVolume) {
|
func TestPVCacheWithStorageClasses(t *testing.T) {
|
||||||
pvList := cache.ListPVs()
|
cache := NewPVAssumeCache(nil)
|
||||||
|
internal_cache, ok := cache.(*pvAssumeCache)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Failed to get internal cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a bunch of PVs
|
||||||
|
pvs1 := map[string]*v1.PersistentVolume{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "class1")
|
||||||
|
pvs1[pv.Name] = pv
|
||||||
|
internal_cache.add(pv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a bunch of PVs
|
||||||
|
pvs2 := map[string]*v1.PersistentVolume{}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
pv := makePV(fmt.Sprintf("test2-pv%v", i), "1", "class2")
|
||||||
|
pvs2[pv.Name] = pv
|
||||||
|
internal_cache.add(pv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List them
|
||||||
|
verifyListPVs(t, cache, pvs1, "class1")
|
||||||
|
verifyListPVs(t, cache, pvs2, "class2")
|
||||||
|
|
||||||
|
// Update a PV
|
||||||
|
updatedPV := makePV("test-pv3", "2", "class1")
|
||||||
|
pvs1[updatedPV.Name] = updatedPV
|
||||||
|
internal_cache.update(nil, updatedPV)
|
||||||
|
|
||||||
|
// List them
|
||||||
|
verifyListPVs(t, cache, pvs1, "class1")
|
||||||
|
verifyListPVs(t, cache, pvs2, "class2")
|
||||||
|
|
||||||
|
// Delete a PV
|
||||||
|
deletedPV := pvs1["test-pv7"]
|
||||||
|
delete(pvs1, deletedPV.Name)
|
||||||
|
internal_cache.delete(deletedPV)
|
||||||
|
|
||||||
|
// List them
|
||||||
|
verifyListPVs(t, cache, pvs1, "class1")
|
||||||
|
verifyListPVs(t, cache, pvs2, "class2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyListPVs(t *testing.T, cache PVAssumeCache, expectedPVs map[string]*v1.PersistentVolume, storageClassName string) {
|
||||||
|
pvList := cache.ListPVs(storageClassName)
|
||||||
if len(pvList) != len(expectedPVs) {
|
if len(pvList) != len(expectedPVs) {
|
||||||
t.Errorf("ListPVs() returned %v PVs, expected %v", len(pvList), len(expectedPVs))
|
t.Errorf("ListPVs() returned %v PVs, expected %v", len(pvList), len(expectedPVs))
|
||||||
}
|
}
|
||||||
|
@ -350,10 +350,17 @@ func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*bindingI
|
|||||||
// Sort all the claims by increasing size request to get the smallest fits
|
// Sort all the claims by increasing size request to get the smallest fits
|
||||||
sort.Sort(byPVCSize(claimsToBind))
|
sort.Sort(byPVCSize(claimsToBind))
|
||||||
|
|
||||||
allPVs := b.pvCache.ListPVs()
|
|
||||||
chosenPVs := map[string]*v1.PersistentVolume{}
|
chosenPVs := map[string]*v1.PersistentVolume{}
|
||||||
|
|
||||||
for _, bindingInfo := range claimsToBind {
|
for _, bindingInfo := range claimsToBind {
|
||||||
|
// Get storage class name from each PVC
|
||||||
|
storageClassName := ""
|
||||||
|
storageClass := bindingInfo.pvc.Spec.StorageClassName
|
||||||
|
if storageClass != nil {
|
||||||
|
storageClassName = *storageClass
|
||||||
|
}
|
||||||
|
allPVs := b.pvCache.ListPVs(storageClassName)
|
||||||
|
|
||||||
// Find a matching PV
|
// Find a matching PV
|
||||||
bindingInfo.pv, err = findMatchingVolume(bindingInfo.pvc, allPVs, node, chosenPVs, true)
|
bindingInfo.pv, err = findMatchingVolume(bindingInfo.pvc, allPVs, node, chosenPVs, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user