diff --git a/internal/xdscache/v3/snapshot.go b/internal/xdscache/v3/snapshot.go index 7fe84b95..47fb65aa 100644 --- a/internal/xdscache/v3/snapshot.go +++ b/internal/xdscache/v3/snapshot.go @@ -35,7 +35,7 @@ import ( type SnapshotHandler struct { resources map[envoy_resource_v3.Type]xdscache.ResourceCache defaultCache envoy_cache_v3.SnapshotCache - edsCache envoy_cache_v3.SnapshotCache + edsCache *envoy_cache_v3.LinearCache mux *envoy_cache_v3.MuxCache log logrus.FieldLogger } @@ -44,7 +44,7 @@ type SnapshotHandler struct { func NewSnapshotHandler(resources []xdscache.ResourceCache, log logrus.FieldLogger) *SnapshotHandler { var ( defaultCache = envoy_cache_v3.NewSnapshotCache(false, &contour_xds_v3.Hash, log.WithField("context", "defaultCache")) - edsCache = envoy_cache_v3.NewSnapshotCache(false, &contour_xds_v3.Hash, log.WithField("context", "edsCache")) + edsCache = envoy_cache_v3.NewLinearCache(envoy_resource_v3.EndpointType, envoy_cache_v3.WithLogger(log.WithField("context", "edsCache"))) mux = &envoy_cache_v3.MuxCache{ Caches: map[string]envoy_cache_v3.Cache{}, @@ -89,20 +89,36 @@ func (s *SnapshotHandler) GetCache() envoy_cache_v3.Cache { // Refresh is called when the EndpointsTranslator updates values // in its cache. It updates the EDS cache. func (s *SnapshotHandler) Refresh() { - version := uuid.NewString() + resources := asResources(s.resources[envoy_resource_v3.EndpointType].Contents()) + resMap := envoy_cache_v3.IndexRawResourcesByName(resources) + edsResMap := s.edsCache.GetResources() - resources := map[envoy_resource_v3.Type][]envoy_types.Resource{ - envoy_resource_v3.EndpointType: asResources(s.resources[envoy_resource_v3.EndpointType].Contents()), + toDeleteMap := make(map[string]struct{}, len(edsResMap)) + for name := range edsResMap { + toDeleteMap[name] = struct{}{} } - snapshot, err := envoy_cache_v3.NewSnapshot(version, resources) - if err != nil { - s.log.Errorf("failed to generate snapshot version %q: %s", version, err) - return + toUpdateMap := make(map[string]envoy_types.Resource) + for name, res := range resMap { + if edsRes, ok := edsResMap[name]; ok { + if !proto.Equal(edsRes, res) { + toUpdateMap[name] = res + } + delete(toDeleteMap, name) + } else { + toUpdateMap[name] = res + } } - if err := s.edsCache.SetSnapshot(context.Background(), contour_xds_v3.Hash.String(), snapshot); err != nil { - s.log.Errorf("failed to store snapshot version %q: %s", version, err) + toDelete := make([]string, len(toDeleteMap)) + i := 0 + for name := range toDeleteMap { + toDelete[i] = name + i++ + } + + if err := s.edsCache.UpdateResources(toUpdateMap, toDelete); err != nil { + s.log.Errorf("failed to update resources: %s", err) return } }