mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 22:46:12 +00:00
Restructure caching logic
This commit is contained in:
parent
7cb18e84f1
commit
9b9925f56d
@ -1,7 +1,8 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -19,56 +20,80 @@ type UnstructuredExtractor interface {
|
|||||||
ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error)
|
ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectTypeCache caches the GVKParser in order to prevent from having to repeatedly
|
// gvkParserCache caches the GVKParser in order to prevent from having to repeatedly
|
||||||
// parse the models from the open API schema when the schema itself changes infrequently.
|
// parse the models from the open API schema when the schema itself changes infrequently.
|
||||||
type objectTypeCache struct {
|
type gvkParserCache struct {
|
||||||
// TODO: lock this?
|
// discoveryClient is the client for retrieving the openAPI document and checking
|
||||||
|
// whether the document has changed recently
|
||||||
discoveryClient discovery.DiscoveryInterface
|
discoveryClient discovery.DiscoveryInterface
|
||||||
|
// ttl is how long the openAPI schema should be considered valid
|
||||||
|
ttl time.Duration
|
||||||
|
// mu protects the gvkParser
|
||||||
|
mu sync.Mutex
|
||||||
|
// gvkParser retrieves the objectType for a given gvk
|
||||||
gvkParser *fieldmanager.GvkParser
|
gvkParser *fieldmanager.GvkParser
|
||||||
|
// lastChecked is the last time we checked if the openAPI doc has changed.
|
||||||
|
lastChecked time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectTypeForGVK retrieves the typed.ParseableType for a given gvk from the cache
|
// regenerateGVKParser builds the parser from the raw OpenAPI schema.
|
||||||
func (c *objectTypeCache) objectTypeForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) {
|
func (c *gvkParserCache) regenerateGVKParser() error {
|
||||||
if !c.discoveryClient.HasOpenAPISchemaChanged() && c.gvkParser != nil {
|
|
||||||
// cache hit
|
|
||||||
fmt.Println("cache hit")
|
|
||||||
fmt.Printf("gvk = %+v\n", gvk)
|
|
||||||
return c.gvkParser.Type(gvk), nil
|
|
||||||
} else {
|
|
||||||
// cache miss
|
|
||||||
fmt.Println("cache miss")
|
|
||||||
fmt.Printf("gvk = %+v\n", gvk)
|
|
||||||
doc, err := c.discoveryClient.OpenAPISchema()
|
doc, err := c.discoveryClient.OpenAPISchema()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
c.lastChecked = time.Now()
|
||||||
models, err := proto.NewOpenAPIData(doc)
|
models, err := proto.NewOpenAPIData(doc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gvkParser, err := fieldmanager.NewGVKParser(models, false)
|
gvkParser, err := fieldmanager.NewGVKParser(models, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.gvkParser = gvkParser
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectTypeForGVK retrieves the typed.ParseableType for a given gvk from the cache
|
||||||
|
func (c *gvkParserCache) objectTypeForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.gvkParser != nil {
|
||||||
|
// if the ttl on the parser cache has expired,
|
||||||
|
// recheck the discovery client to see if the Open API schema has changed
|
||||||
|
if time.Now().After(c.lastChecked.Add(c.ttl)) {
|
||||||
|
c.lastChecked = time.Now()
|
||||||
|
if c.discoveryClient.HasOpenAPISchemaChanged() {
|
||||||
|
// the schema has changed, regenerate the parser
|
||||||
|
if err := c.regenerateGVKParser(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objType := gvkParser.Type(gvk)
|
|
||||||
c.gvkParser = gvkParser
|
|
||||||
|
|
||||||
return objType, nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := c.regenerateGVKParser(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.gvkParser.Type(gvk), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type extractor struct {
|
type extractor struct {
|
||||||
cache *objectTypeCache
|
cache *gvkParserCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnstructuredExtractor creates the extractor with which you can extract the applied configuration
|
// NewUnstructuredExtractor creates the extractor with which you can extract the applied configuration
|
||||||
// for a given manager from an unstructured object.
|
// for a given manager from an unstructured object.
|
||||||
func NewUnstructuredExtractor(dc discovery.DiscoveryInterface) UnstructuredExtractor {
|
func NewUnstructuredExtractor(dc discovery.DiscoveryInterface) UnstructuredExtractor {
|
||||||
|
// TODO: expose ttl as an argument if we want to.
|
||||||
|
defaultTTL := time.Minute
|
||||||
return &extractor{
|
return &extractor{
|
||||||
cache: &objectTypeCache{
|
cache: &gvkParserCache{
|
||||||
discoveryClient: dc,
|
discoveryClient: dc,
|
||||||
|
ttl: defaultTTL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user