istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/xds_cache.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package model
    16  
    17  import (
    18  	"time"
    19  
    20  	discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
    21  
    22  	"istio.io/istio/pilot/pkg/features"
    23  	"istio.io/istio/pkg/config/schema/kind"
    24  	"istio.io/istio/pkg/util/sets"
    25  )
    26  
    27  type XdsCacheImpl struct {
    28  	cds typedXdsCache[uint64]
    29  	eds typedXdsCache[uint64]
    30  	rds typedXdsCache[uint64]
    31  	sds typedXdsCache[string]
    32  }
    33  
    34  // XdsCache interface defines a store for caching XDS responses.
    35  // All operations are thread safe.
    36  type XdsCache interface {
    37  	// Run starts a background thread to flush evicted indexes periodically.
    38  	Run(stop <-chan struct{})
    39  	// Add adds the given XdsCacheEntry with the value for the given pushContext to the cache.
    40  	// If the cache has been updated to a newer push context, the write will be dropped silently.
    41  	// This ensures stale data does not overwrite fresh data when dealing with concurrent
    42  	// writers.
    43  	Add(entry XdsCacheEntry, pushRequest *PushRequest, value *discovery.Resource)
    44  	// Get retrieves the cached value if it exists.
    45  	Get(entry XdsCacheEntry) *discovery.Resource
    46  	// Clear removes the cache entries that are dependent on the configs passed.
    47  	Clear(sets.Set[ConfigKey])
    48  	// ClearAll clears the entire cache.
    49  	ClearAll()
    50  	// Keys returns all currently configured keys for the type. This is for testing/debug only
    51  	Keys(t string) []any
    52  	// Snapshot returns a snapshot of all values. This is for testing/debug only
    53  	Snapshot() []*discovery.Resource
    54  }
    55  
    56  // XdsCacheEntry interface defines functions that should be implemented by
    57  // resources that can be cached.
    58  type XdsCacheEntry interface {
    59  	// Type indicates the type of Xds resource being cached like CDS.
    60  	Type() string
    61  	// Key is the key to be used in cache.
    62  	Key() any
    63  	// DependentConfigs is config items that this cache key is dependent on.
    64  	// Whenever these configs change, we should invalidate this cache entry.
    65  	DependentConfigs() []ConfigHash
    66  	// Cacheable indicates whether this entry is valid for cache. For example
    67  	// for EDS to be cacheable, the Endpoint should have corresponding service.
    68  	Cacheable() bool
    69  }
    70  
    71  const (
    72  	CDSType = "cds"
    73  	EDSType = "eds"
    74  	RDSType = "rds"
    75  	SDSType = "sds"
    76  )
    77  
    78  // NewXdsCache returns an instance of a cache.
    79  func NewXdsCache() XdsCache {
    80  	cache := XdsCacheImpl{
    81  		eds: newTypedXdsCache[uint64](),
    82  	}
    83  	if features.EnableCDSCaching {
    84  		cache.cds = newTypedXdsCache[uint64]()
    85  	} else {
    86  		cache.cds = disabledCache[uint64]{}
    87  	}
    88  	if features.EnableRDSCaching {
    89  		cache.rds = newTypedXdsCache[uint64]()
    90  	} else {
    91  		cache.rds = disabledCache[uint64]{}
    92  	}
    93  
    94  	cache.sds = newTypedXdsCache[string]()
    95  
    96  	return cache
    97  }
    98  
    99  func (x XdsCacheImpl) Run(stop <-chan struct{}) {
   100  	interval := features.XDSCacheIndexClearInterval
   101  	go func() {
   102  		ticker := time.NewTicker(interval)
   103  		defer ticker.Stop()
   104  		for {
   105  			select {
   106  			case <-ticker.C:
   107  				x.cds.Flush()
   108  				x.eds.Flush()
   109  				x.rds.Flush()
   110  				x.sds.Flush()
   111  			case <-stop:
   112  				return
   113  			}
   114  		}
   115  	}()
   116  }
   117  
   118  func (x XdsCacheImpl) Add(entry XdsCacheEntry, pushRequest *PushRequest, value *discovery.Resource) {
   119  	if !entry.Cacheable() {
   120  		return
   121  	}
   122  	k := entry.Key()
   123  	switch entry.Type() {
   124  	case CDSType:
   125  		key := k.(uint64)
   126  		x.cds.Add(key, entry, pushRequest, value)
   127  	case EDSType:
   128  		key := k.(uint64)
   129  		x.eds.Add(key, entry, pushRequest, value)
   130  	case SDSType:
   131  		key := k.(string)
   132  		x.sds.Add(key, entry, pushRequest, value)
   133  	case RDSType:
   134  		key := k.(uint64)
   135  		x.rds.Add(key, entry, pushRequest, value)
   136  	default:
   137  		log.Errorf("unknown type %s", entry.Type())
   138  	}
   139  }
   140  
   141  func (x XdsCacheImpl) Get(entry XdsCacheEntry) *discovery.Resource {
   142  	if !entry.Cacheable() {
   143  		return nil
   144  	}
   145  
   146  	k := entry.Key()
   147  	switch entry.Type() {
   148  	case CDSType:
   149  		key := k.(uint64)
   150  		return x.cds.Get(key)
   151  	case EDSType:
   152  		key := k.(uint64)
   153  		return x.eds.Get(key)
   154  	case SDSType:
   155  		key := k.(string)
   156  		return x.sds.Get(key)
   157  	case RDSType:
   158  		key := k.(uint64)
   159  		return x.rds.Get(key)
   160  	default:
   161  		log.Errorf("unknown type %s", entry.Type())
   162  		return nil
   163  	}
   164  }
   165  
   166  func (x XdsCacheImpl) Clear(s sets.Set[ConfigKey]) {
   167  	x.cds.Clear(s)
   168  	// clear all EDS cache for PA change
   169  	if HasConfigsOfKind(s, kind.PeerAuthentication) {
   170  		x.eds.ClearAll()
   171  	} else {
   172  		x.eds.Clear(s)
   173  	}
   174  	x.rds.Clear(s)
   175  	x.sds.Clear(s)
   176  }
   177  
   178  func (x XdsCacheImpl) ClearAll() {
   179  	x.cds.ClearAll()
   180  	x.eds.ClearAll()
   181  	x.rds.ClearAll()
   182  	x.sds.ClearAll()
   183  }
   184  
   185  func (x XdsCacheImpl) Keys(t string) []any {
   186  	switch t {
   187  	case CDSType:
   188  		keys := x.cds.Keys()
   189  		return convertToAnySlices(keys)
   190  	case EDSType:
   191  		keys := x.eds.Keys()
   192  		return convertToAnySlices(keys)
   193  	case SDSType:
   194  		keys := x.sds.Keys()
   195  		return convertToAnySlices(keys)
   196  	case RDSType:
   197  		keys := x.rds.Keys()
   198  		return convertToAnySlices(keys)
   199  	default:
   200  		return nil
   201  	}
   202  }
   203  
   204  func convertToAnySlices[K comparable](in []K) []any {
   205  	out := make([]any, len(in))
   206  	for i, k := range in {
   207  		out[i] = k
   208  	}
   209  	return out
   210  }
   211  
   212  func (x XdsCacheImpl) Snapshot() []*discovery.Resource {
   213  	var out []*discovery.Resource
   214  	out = append(out, x.cds.Snapshot()...)
   215  	out = append(out, x.eds.Snapshot()...)
   216  	out = append(out, x.rds.Snapshot()...)
   217  	out = append(out, x.sds.Snapshot()...)
   218  	return out
   219  }
   220  
   221  // DisabledCache is a cache that is always empty
   222  type DisabledCache struct{}
   223  
   224  func (d DisabledCache) Run(stop <-chan struct{}) {
   225  }
   226  
   227  func (d DisabledCache) Add(entry XdsCacheEntry, pushRequest *PushRequest, value *discovery.Resource) {
   228  }
   229  
   230  func (d DisabledCache) Get(entry XdsCacheEntry) *discovery.Resource {
   231  	return nil
   232  }
   233  
   234  func (d DisabledCache) Clear(s sets.Set[ConfigKey]) {
   235  }
   236  
   237  func (d DisabledCache) ClearAll() {
   238  }
   239  
   240  func (d DisabledCache) Keys(t string) []any {
   241  	return nil
   242  }
   243  
   244  func (d DisabledCache) Snapshot() []*discovery.Resource {
   245  	return nil
   246  }
   247  
   248  var _ XdsCache = &DisabledCache{}