Skip to content
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

Introduce NameResolver.Args.Extensions #11669

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

jdcormie
Copy link
Member

@jdcormie jdcormie commented Nov 6, 2024

grpc-binder's upcoming IntentNameResolver needs to know the target Android user so it can resolve target URIs in the correct place. Unfortunately, Android's built in intent:// URI scheme has no way to specify a user and in fact the android.os.UserHandle object can't reasonably be encoded as a String at all.

We solve this problem by extending NameResolver.Args to permit externally defined arguments using the same type-safe and domain-specific Key<T> pattern used by CallOptions, Context and CreateSubchannelArgs. New "extension" arguments could apply to all NameResolvers of a certain URI scheme, to all NameResolvers producing a particular type of java.net.SocketAddress, or even to a specific NameResolver subclass.

A follow up PR will move the target UserHandle from being a property of the ManagedChannel to being a property of the SocketAddress.

@jdcormie jdcormie requested a review from ejona86 November 6, 2024 04:52
@jdcormie jdcormie added the kokoro:force-run Add this label to a PR to tell Kokoro to re-run all tests. Not generally necessary label Nov 8, 2024
@grpc-kokoro grpc-kokoro removed the kokoro:force-run Add this label to a PR to tell Kokoro to re-run all tests. Not generally necessary label Nov 8, 2024
@jdcormie
Copy link
Member Author

Friendly 1 week ping. This is the domain-specific Key<>-based approach you requested in our last meeting.

Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how Extensions was implemented to avoid copying the map on build().

api/src/main/java/io/grpc/NameResolver.java Outdated Show resolved Hide resolved
api/src/main/java/io/grpc/NameResolver.java Outdated Show resolved Hide resolved
*
* <p>Optional, {@link Extensions#EMPTY} by default.
*/
public Builder setExtensions(Extensions extensions) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... This makes Extensions public, and you have to set all Extensions for this builder but reading gets only a single one. I see the awkwardness is because we're going through the ManagedChannelBuilder API. I'm tempted to just use a map in the channel builder and copy it to this API later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely removed Extensions from the public API (it's now @internal)

I tried maintaining a map in ManagedChannelImplBuilder but the code to copy entries over was problematic because 1) one more place needing unchecked casts 2) it's doing work that's best encapsulated and unit tested inside Args.Extensions.

I also tried out moving the NameResolver.Args.Builder to ManagedChannelImplBuilder. This worked but only because the current ManagedChannelImpl ctor unconditionally sets every property of Args.Builder. This is fragile - if this code ever changed to conditionally set a property it would silently leak that property across channels when the builder is reused. This seemed too fragile to me.

api/src/main/java/io/grpc/NameResolver.java Outdated Show resolved Hide resolved

private IdentityHashMap<Key<?>, Object> data(int size) {
if (newdata == null) {
newdata = new IdentityHashMap<>(size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be nicer to copy base at this point:

newdata = new IdentityHashMap<>(base.data);

Yes, you're doing the sizing of the map here, but that size is pretty arbitrary. If we care:

newdata = new IdentityHashMap<>(base.data.size() + 1);
newdata.putAll(base.data);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm seems like that could work but for me it really muddies the meaning/invariant of 'base' and 'newdata'. Anyway, I just copy/pasted all this from Attributes. Seems to me like the idea is to do all the copying in one place, in build(). Does that change anything for you? Should we consider your proposed change for Attributes too?

api/src/main/java/io/grpc/NameResolver.java Show resolved Hide resolved
Fully remove Args.Extensions from the public API (@internal)
Make TODO non-javadoc
google-java-format
unused imports
@jdcormie
Copy link
Member Author

I like how Extensions was implemented to avoid copying the map on build().

👍 I can't take credit though, just copy pasted from Attributes. LMK if you think one of the other special-purpose containers would be a better fit.

@jdcormie jdcormie closed this Nov 20, 2024
@jdcormie jdcormie reopened this Nov 20, 2024
Update NameResolverTest.
Include setAll() coverage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants