diff --git a/internal/mesh/internal/controllers/xds/controller.go b/internal/mesh/internal/controllers/xds/controller.go index 604181a49e..25bc98378a 100644 --- a/internal/mesh/internal/controllers/xds/controller.go +++ b/internal/mesh/internal/controllers/xds/controller.go @@ -397,18 +397,13 @@ func (r *xdsReconciler) cancelWatches(leafResourceRefs []*pbresource.Reference) // prevWatchesToCancel computes if there are any items in prevWatchedLeafs that are not in currentLeafs, and returns a list of those items. func prevWatchesToCancel(prevWatchedLeafs []*pbresource.Reference, currentLeafs []resource.ReferenceOrID) []*pbresource.Reference { - var prevWatchedLeafsToCancel []*pbresource.Reference + prevWatchedLeafsToCancel := make([]*pbresource.Reference, 0, len(prevWatchedLeafs)) + newLeafs := make(map[string]struct{}) + for _, newLeaf := range currentLeafs { + newLeafs[keyFromReference(newLeaf)] = struct{}{} + } for _, prevLeaf := range prevWatchedLeafs { - prevKey := keyFromReference(prevLeaf) - found := false - for _, newLeaf := range currentLeafs { - newKey := keyFromReference(newLeaf) - if prevKey == newKey { - found = true - break - } - } - if !found { + if _, ok := newLeafs[keyFromReference(prevLeaf)]; !ok { prevWatchedLeafsToCancel = append(prevWatchedLeafsToCancel, prevLeaf) } } diff --git a/internal/mesh/internal/controllers/xds/controller_test.go b/internal/mesh/internal/controllers/xds/controller_test.go index 1394eb8d6f..556ce97d5e 100644 --- a/internal/mesh/internal/controllers/xds/controller_test.go +++ b/internal/mesh/internal/controllers/xds/controller_test.go @@ -930,6 +930,68 @@ func (suite *xdsControllerTestSuite) setupFooBarProxyStateTemplateAndEndpoints() suite.expectedBarProxyStateEndpoints = expectedBarProxyStateEndpoints } +func (suite *xdsControllerTestSuite) TestReconcile_prevWatchesToCancel() { + makeRef := func(names ...string) []*pbresource.Reference { + out := make([]*pbresource.Reference, len(names)) + for i, name := range names { + out[i] = &pbresource.Reference{ + Name: name, + Type: &pbresource.Type{ + Group: "g", + GroupVersion: "v", + Kind: "k", + }, + Tenancy: &pbresource.Tenancy{}, + } + } + return out + } + convert := func(input []*pbresource.Reference) []resource.ReferenceOrID { + asInterface := make([]resource.ReferenceOrID, len(input)) + for i := range input { + asInterface[i] = input[i] + } + return asInterface + } + + cases := []struct { + old []*pbresource.Reference + new []*pbresource.Reference + expect []*pbresource.Reference + }{ + { + old: makeRef("a", "b", "c"), + new: makeRef("a", "c"), + expect: makeRef("b"), + }, + { + old: makeRef("a", "b", "c"), + new: makeRef("a", "b", "c"), + expect: makeRef(), + }, + { + old: makeRef(), + new: makeRef("a", "b"), + expect: makeRef(), + }, + { + old: makeRef("a", "b"), + new: makeRef(), + expect: makeRef("a", "b"), + }, + { + old: makeRef(), + new: makeRef(), + expect: makeRef(), + }, + } + + for _, tc := range cases { + toCancel := prevWatchesToCancel(tc.old, convert(tc.new)) + require.ElementsMatch(suite.T(), toCancel, tc.expect) + } +} + func TestXdsController(t *testing.T) { suite.Run(t, new(xdsControllerTestSuite)) }