autosharding: implementation of EndpointMap, autosharding client and LB Policy - #13039
shivaspeaks wants to merge 45 commits into
Conversation
…harding-part2-picker
…harding-part3-lazy-endpoints
…harding-part3-lazy-endpoints
sauravzg
left a comment
There was a problem hiding this comment.
Reviewed the sources.
This PR in its current state is very difficult to review. We have classes with a lot of getters, setters, invariants and state manipulation some of which lead to inconsistent state.
We should either couple this PR with the class that uses it so that we can understand the expecations from the class, or meticulously document the expectations as our contract in this class to make the review easier.
Happy to discuss offline if needed.
| static final class EndpointHolder { | ||
| private int index; | ||
| private final LazyLoadBalancer childLb; | ||
| private final AtomicBoolean connectingScheduled = new AtomicBoolean(false); |
There was a problem hiding this comment.
Why AtomicBoolean? Is this class supposed to be threadsafe? Seems counterintuitive if it's supposed to be held in a class that's not threadsafe, unless we expect people to get it from the map which may not be the correct abstraction for EndpointHolder.
There was a problem hiding this comment.
Oh right! This class is indeed @notThreadSafe and confined to the synchronization context. The only entry point from RPC threads is PickerEndpoint.requestConnection, which hops onto the sync context before touching anything.
| private void exitIdle() { | ||
| if (connectingScheduled.compareAndSet(false, true)) { | ||
| helper.getSynchronizationContext().execute(() -> { | ||
| connectingScheduled.set(false); |
There was a problem hiding this comment.
So, we move atomic from false to true, then we execute stuff on synccontext , but then we set it to false again before requesting connection. So, this means while we are requesting connection, other rpcs can again trigger requesting connection?
What are we tryting to achieve here? This seems to be doing nothing. Shouldn't this be set to false only when the connection becomes idle again instead of before we start requesting connection?
There was a problem hiding this comment.
Oh right! This class is indeed @notThreadSafe and confined to the synchronization context. The only entry point from RPC threads is PickerEndpoint.requestConnection, which hops onto the sync context before touching anything.
| childLb.acceptResolvedAddresses(childAddresses); | ||
| } | ||
|
|
||
| void requestConnection() { |
There was a problem hiding this comment.
Why do we need this if we already have exitIdle? This seems like a very unsafe verision which doesn't bother executing on sync context and doesn't check the atomic boolean.
There was a problem hiding this comment.
Fixed with a childShutdown flag on the holder that is checked inside the synchronization context, after the thread hop, so it cannot be stale by the time it is read.
Is our PickerEndpoint truly immutable?
Yes, PickerEndpoint is immutable. It captures the state and picker by value, and its only reference back into this class is the ExitIdler, which does nothing but schedule work on the synchronization context.
|
I've added the LB policy that consumes it ( Note for updates in
|
|
I will re-request for your review after I do my final review. Please wait for the re-request @sauravzg before taking a look. |
This is Part3 of gRFC A119, introducing EndpointMap.
This is responsible for managing individual backend child load balancers lazily, keeping uncontacted endpoints in IDLE until an RPC is assigned to them. We are calling
EndpointStateasEndpointHolderin this implementation to avoid name collision with actual endpointState coming fromcom.google.cloud.autosharding.v1.EndpointState.