@@ -35,7 +35,7 @@ import (
35
35
type SnapshotHandler struct {
36
36
resources map [envoy_resource_v3.Type ]xdscache.ResourceCache
37
37
defaultCache envoy_cache_v3.SnapshotCache
38
- edsCache envoy_cache_v3.SnapshotCache
38
+ edsCache * envoy_cache_v3.LinearCache
39
39
mux * envoy_cache_v3.MuxCache
40
40
log logrus.FieldLogger
41
41
}
@@ -44,7 +44,12 @@ type SnapshotHandler struct {
44
44
func NewSnapshotHandler (resources []xdscache.ResourceCache , log logrus.FieldLogger ) * SnapshotHandler {
45
45
var (
46
46
defaultCache = envoy_cache_v3 .NewSnapshotCache (false , & contour_xds_v3 .Hash , log .WithField ("context" , "defaultCache" ))
47
- edsCache = envoy_cache_v3 .NewSnapshotCache (false , & contour_xds_v3 .Hash , log .WithField ("context" , "edsCache" ))
47
+ // Envoy will open EDS stream per CDS entry.
48
+ // LinearCache mitigates the issue where all EDS streams are notified of any endpoint changes, even if unrelated to the requested resources.
49
+ // With LinearCache, updates are sent only for resources explicitly requested by Envoy.
50
+ edsCache = envoy_cache_v3 .NewLinearCache (envoy_resource_v3 .EndpointType ,
51
+ envoy_cache_v3 .WithVersionPrefix (uuid .NewString ()+ "-" ),
52
+ envoy_cache_v3 .WithLogger (log .WithField ("context" , "edsCache" )))
48
53
49
54
mux = & envoy_cache_v3.MuxCache {
50
55
Caches : map [string ]envoy_cache_v3.Cache {},
@@ -89,21 +94,40 @@ func (s *SnapshotHandler) GetCache() envoy_cache_v3.Cache {
89
94
// Refresh is called when the EndpointSliceTranslator updates values
90
95
// in its cache. It updates the EDS cache.
91
96
func (s * SnapshotHandler ) Refresh () {
92
- version := uuid .NewString ()
97
+ previouslyNotifiedResources := s .edsCache .GetResources ()
98
+ currentResources := envoy_cache_v3 .IndexRawResourcesByName (asResources (s .resources [envoy_resource_v3 .EndpointType ].Contents ()))
99
+
100
+ toUpdate := make (map [string ]envoy_types.Resource , len (currentResources ))
101
+ toDelete := make ([]string , 0 , len (previouslyNotifiedResources ))
102
+
103
+ for resourceName , previousResource := range previouslyNotifiedResources {
104
+ if newResource , ok := currentResources [resourceName ]; ok {
105
+ // Add resources that were updated.
106
+ if ! proto .Equal (newResource , previousResource ) {
107
+ toUpdate [resourceName ] = newResource
108
+ }
109
+ } else {
110
+ // Add resources that were deleted.
111
+ toDelete = append (toDelete , resourceName )
112
+ }
113
+ }
93
114
94
- resources := map [envoy_resource_v3.Type ][]envoy_types.Resource {
95
- envoy_resource_v3 .EndpointType : asResources (s .resources [envoy_resource_v3 .EndpointType ].Contents ()),
115
+ // Add resources that are new.
116
+ for resourceName , newResource := range currentResources {
117
+ if _ , ok := previouslyNotifiedResources [resourceName ]; ! ok {
118
+ toUpdate [resourceName ] = newResource
119
+ }
96
120
}
97
121
98
- snapshot , err := envoy_cache_v3 .NewSnapshot (version , resources )
99
- if err != nil {
100
- s .log .Errorf ("failed to generate snapshot version %q: %s" , version , err )
122
+ if len (toUpdate ) == 0 && len (toDelete ) == 0 {
123
+ s .log .Debug ("no EDS resources to update" )
101
124
return
102
125
}
103
126
104
- if err := s .edsCache .SetSnapshot (context .Background (), contour_xds_v3 .Hash .String (), snapshot ); err != nil {
105
- s .log .Errorf ("failed to store snapshot version %q: %s" , version , err )
106
- return
127
+ s .log .WithField ("toUpdate" , len (toUpdate )).WithField ("toDelete" , len (toDelete )).Debug ("refreshing EDS cache" )
128
+
129
+ if err := s .edsCache .UpdateResources (toUpdate , toDelete ); err != nil {
130
+ s .log .WithError (err ).Error ("failed to update EDS cache" )
107
131
}
108
132
}
109
133
0 commit comments