-
Notifications
You must be signed in to change notification settings - Fork 4.6k
xds: refactor xdsresource.Endpoint to embed resolver.Endpoint (gRFC A81) #8750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8750 +/- ##
==========================================
- Coverage 83.28% 83.22% -0.07%
==========================================
Files 418 418
Lines 32367 32396 +29
==========================================
+ Hits 26958 26961 +3
- Misses 4034 4052 +18
- Partials 1375 1383 +8
🚀 New features to boost your workflow:
|
| // TestConcurrentChannels verifies that we can create multiple gRPC channels | ||
| // concurrently with a shared XDSClient, each of which will create a new LRS | ||
| // stream without any race. | ||
| func (s) TestConcurrentChannels(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't remove the (s) receiver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| EndpointHealthStatusDegraded | ||
| ) | ||
|
|
||
| // Endpoint contains information of an endpoint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you are here, could you also please file an issue and add a TODO here to capture the fact that we could completely get rid of this struct, and encode all the information associated with the endpoint in the resolver.Endpoint struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| type hostnameType string | ||
|
|
||
| // hostnameKey is the key to store the hostname key attribute in | ||
| // a resolver.Endpoint attribute. | ||
| const hostnameKey = hostnameType("grpc.resolver.xdsresource.hostname") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of a type and a const, this could be simplified as:
type hostnameKeyType struct{}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| // a resolver.Endpoint attribute. | ||
| const hostnameKey = hostnameType("grpc.resolver.xdsresource.hostname") | ||
|
|
||
| // SetHostname sets the hostname key for this resolver.Endpoint attribute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
// SetHostname returns a copy of the given endpoint with hostname added as an attribute.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| if hostname == "" { | ||
| return endpoint | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would someone call this function with an empty hostname? And why is it important to not include the empty hostname in the attributes. If there are valid reasons for doing this, it should be mentioned in the docstring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hostname should be non-empty for :authority rewriting.
Added a comment.
| endpoint := resolver.Endpoint{ | ||
| Addresses: address, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Literal structs with a single field could be initialized on a single line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| resolverEndpoint := resolver.Endpoint{ | ||
| Addresses: address, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Literal structs with a single field could be initialized on a single line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| "google.golang.org/protobuf/types/known/wrapperspb" | ||
| ) | ||
|
|
||
| func getResolverEndpoint(addr []string, hostname string) resolver.Endpoint { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get prefix here makes it look like this is a getter. Please rename it to buildResolverEndpoint or makeResolverEndpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| ResolverEndpoint: resolver.Endpoint{ | ||
| Addresses: []resolver.Address{{Addr: "addr-1-1"}}, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere in this test file, you could make such lines be one a one-liner since only a single field is being set in the resolver.Endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
| newEP := e | ||
| newEP.Addresses = make([]resolver.Address, len(e.Addresses)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this newEndpoints and newEP local variables. Can we make the modifications to the individual endpoints in the endpoints slice, because that is what was happening earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the previous implementation, xdsresource.Endpoint stored raw address strings, so we were forced to construct a brand new resolver.Endpoint instance in configbuilder.priorityLocalitiesToClusterImpl().
With this refactor, the endpoints slice contains resolver.Endpoint objects that come directly from the xdsClient's cache. If we modify endpoints or its Addresses slice directly in clusterresolver, we are modifying the shared underlying memory which causes a race.
I confirmed this behavior during testing—without the explicit copy, TestConcurrentChannels fails with a data race. The newEndpoints/newEP variables ensure we are modifying a private copy.
But I have again changed the implementation. Instead of creating newEndpoints/newEP variables in clusterresolver, I'm creating a new resovler.Endpoint in configbuilder.priorityLocalitiesToClusterImpl().
This PR updates the internal
xdsresource.Endpointstruct to contain aresolver.Endpointinstead of a[]stringto store the list of addresses associated with the endpoint gRFC A81. This change standardizes how backend information is stored and ensures that attributes (such as Hostname) are correctly associated with the endpoint hierarchy.Key Changes:
Struct Update:
xdsresource.Endpointnow includes aResolverEndpointfield (of typeresolver.Endpoint) to store addresses and attributes. Remove the existingAddressfield (of type[]string) and store address as aresolver.Endpointfield.Attribute Handling:
SetHostnameandGetHostnamehelpers to manage hostname metadata withinresolver.Endpoint.Attributes.Parsing Logic:
parseEndpointsinunmarshal_eds.goto correctly populate theresolver.Endpointobject.RELEASE NOTES: N/A