Skip to content

Commit f8d0868

Browse files
authored
Revert "core: pass Subchannel state updates to SubchannelStateListener rather than LoadBalancer (grpc#5503)" (grpc#5684)
This reverts commit 62b03fd. Effectively reverts its follow-up commits: dc218b6 405d8c3 44840fe
1 parent 1b6c131 commit f8d0868

21 files changed

Lines changed: 647 additions & 1243 deletions

api/src/main/java/io/grpc/LoadBalancer.java

Lines changed: 3 additions & 310 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616

1717
package io.grpc;
1818

19-
import static com.google.common.base.Preconditions.checkArgument;
2019
import static com.google.common.base.Preconditions.checkNotNull;
2120

2221
import com.google.common.base.MoreObjects;
2322
import com.google.common.base.Objects;
2423
import com.google.common.base.Preconditions;
2524
import java.util.ArrayList;
26-
import java.util.Arrays;
2725
import java.util.Collections;
2826
import java.util.List;
2927
import java.util.Map;
@@ -337,16 +335,9 @@ public boolean equals(Object obj) {
337335
* @param subchannel the involved Subchannel
338336
* @param stateInfo the new state
339337
* @since 1.2.0
340-
* @deprecated This method will be removed. Stop overriding it. Instead, pass {@link
341-
* SubchannelStateListener} to {@link Helper#createSubchannel(CreateSubchannelArgs)}
342-
* to receive Subchannel state updates
343338
*/
344-
@Deprecated
345-
public void handleSubchannelState(
346-
Subchannel subchannel, ConnectivityStateInfo stateInfo) {
347-
// Do nothing. If the implemetation doesn't implement this, it will get subchannel states from
348-
// the new API. We don't throw because there may be forwarding LoadBalancers still plumb this.
349-
}
339+
public abstract void handleSubchannelState(
340+
Subchannel subchannel, ConnectivityStateInfo stateInfo);
350341

351342
/**
352343
* The channel asks the load-balancer to shutdown. No more callbacks will be called after this
@@ -660,243 +651,6 @@ public boolean equals(Object other) {
660651
}
661652
}
662653

663-
/**
664-
* Arguments for {@link Helper#createSubchannel(CreateSubchannelArgs)}.
665-
*
666-
* @since 1.21.0
667-
*/
668-
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
669-
public static final class CreateSubchannelArgs {
670-
private final List<EquivalentAddressGroup> addrs;
671-
private final Attributes attrs;
672-
private final SubchannelStateListener stateListener;
673-
private final Object[][] customOptions;
674-
675-
private CreateSubchannelArgs(
676-
List<EquivalentAddressGroup> addrs, Attributes attrs, Object[][] customOptions,
677-
SubchannelStateListener stateListener) {
678-
this.addrs = checkNotNull(addrs, "addresses are not set");
679-
this.attrs = checkNotNull(attrs, "attrs");
680-
this.customOptions = checkNotNull(customOptions, "customOptions");
681-
this.stateListener = checkNotNull(stateListener, "SubchannelStateListener is not set");
682-
}
683-
684-
/**
685-
* Returns the addresses, which is an unmodifiable list.
686-
*/
687-
public List<EquivalentAddressGroup> getAddresses() {
688-
return addrs;
689-
}
690-
691-
/**
692-
* Returns the attributes.
693-
*/
694-
public Attributes getAttributes() {
695-
return attrs;
696-
}
697-
698-
/**
699-
* Get the value for a custom option or its inherent default.
700-
*
701-
* @param key Key identifying option
702-
*/
703-
@SuppressWarnings("unchecked")
704-
public <T> T getOption(Key<T> key) {
705-
Preconditions.checkNotNull(key, "key");
706-
for (int i = 0; i < customOptions.length; i++) {
707-
if (key.equals(customOptions[i][0])) {
708-
return (T) customOptions[i][1];
709-
}
710-
}
711-
return key.defaultValue;
712-
}
713-
714-
/**
715-
* Returns the state listener.
716-
*/
717-
public SubchannelStateListener getStateListener() {
718-
return stateListener;
719-
}
720-
721-
/**
722-
* Returns a builder with the same initial values as this object.
723-
*/
724-
public Builder toBuilder() {
725-
return newBuilder().setAddresses(addrs).setAttributes(attrs).setStateListener(stateListener)
726-
.copyCustomOptions(customOptions);
727-
}
728-
729-
/**
730-
* Creates a new builder.
731-
*/
732-
public static Builder newBuilder() {
733-
return new Builder();
734-
}
735-
736-
@Override
737-
public String toString() {
738-
return MoreObjects.toStringHelper(this)
739-
.add("addrs", addrs)
740-
.add("attrs", attrs)
741-
.add("listener", stateListener)
742-
.add("customOptions", Arrays.deepToString(customOptions))
743-
.toString();
744-
}
745-
746-
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
747-
public static final class Builder {
748-
749-
private List<EquivalentAddressGroup> addrs;
750-
private Attributes attrs = Attributes.EMPTY;
751-
private SubchannelStateListener stateListener;
752-
private Object[][] customOptions = new Object[0][2];
753-
754-
Builder() {
755-
}
756-
757-
private <T> Builder copyCustomOptions(Object[][] options) {
758-
customOptions = new Object[options.length][2];
759-
System.arraycopy(options, 0, customOptions, 0, options.length);
760-
return this;
761-
}
762-
763-
/**
764-
* Add a custom option. Any existing value for the key is overwritten.
765-
*
766-
* <p>This is an <strong>optional</strong> property.
767-
*
768-
* @param key the option key
769-
* @param value the option value
770-
*/
771-
public <T> Builder addOption(Key<T> key, T value) {
772-
Preconditions.checkNotNull(key, "key");
773-
Preconditions.checkNotNull(value, "value");
774-
775-
int existingIdx = -1;
776-
for (int i = 0; i < customOptions.length; i++) {
777-
if (key.equals(customOptions[i][0])) {
778-
existingIdx = i;
779-
break;
780-
}
781-
}
782-
783-
if (existingIdx == -1) {
784-
Object[][] newCustomOptions = new Object[customOptions.length + 1][2];
785-
System.arraycopy(customOptions, 0, newCustomOptions, 0, customOptions.length);
786-
customOptions = newCustomOptions;
787-
existingIdx = customOptions.length - 1;
788-
}
789-
customOptions[existingIdx] = new Object[]{key, value};
790-
return this;
791-
}
792-
793-
/**
794-
* The addresses to connect to. All addresses are considered equivalent and will be tried
795-
* in the order they are provided.
796-
*/
797-
public Builder setAddresses(EquivalentAddressGroup addrs) {
798-
this.addrs = Collections.singletonList(addrs);
799-
return this;
800-
}
801-
802-
/**
803-
* The addresses to connect to. All addresses are considered equivalent and will
804-
* be tried in the order they are provided.
805-
*
806-
* <p>This is a <strong>required</strong> property.
807-
*
808-
* @throws IllegalArgumentException if {@code addrs} is empty
809-
*/
810-
public Builder setAddresses(List<EquivalentAddressGroup> addrs) {
811-
checkArgument(!addrs.isEmpty(), "addrs is empty");
812-
this.addrs = Collections.unmodifiableList(new ArrayList<>(addrs));
813-
return this;
814-
}
815-
816-
/**
817-
* Attributes provided here will be included in {@link Subchannel#getAttributes}.
818-
*
819-
* <p>This is an <strong>optional</strong> property. Default is empty if not set.
820-
*/
821-
public Builder setAttributes(Attributes attrs) {
822-
this.attrs = checkNotNull(attrs, "attrs");
823-
return this;
824-
}
825-
826-
/**
827-
* Receives state changes of the created Subchannel. The listener is called from
828-
* the {@link Helper#getSynchronizationContext Synchronization Context}. It's safe to share
829-
* the listener among multiple Subchannels.
830-
*
831-
* <p>This is a <strong>required</strong> property.
832-
*/
833-
public Builder setStateListener(SubchannelStateListener listener) {
834-
this.stateListener = checkNotNull(listener, "listener");
835-
return this;
836-
}
837-
838-
/**
839-
* Creates a new args object.
840-
*/
841-
public CreateSubchannelArgs build() {
842-
return new CreateSubchannelArgs(addrs, attrs, customOptions, stateListener);
843-
}
844-
}
845-
846-
/**
847-
* Key for a key-value pair. Uses reference equality.
848-
*/
849-
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
850-
public static final class Key<T> {
851-
852-
private final String debugString;
853-
private final T defaultValue;
854-
855-
private Key(String debugString, T defaultValue) {
856-
this.debugString = debugString;
857-
this.defaultValue = defaultValue;
858-
}
859-
860-
/**
861-
* Factory method for creating instances of {@link Key}. The default value of the key is
862-
* {@code null}.
863-
*
864-
* @param debugString a debug string that describes this key.
865-
* @param <T> Key type
866-
* @return Key object
867-
*/
868-
public static <T> Key<T> create(String debugString) {
869-
Preconditions.checkNotNull(debugString, "debugString");
870-
return new Key<>(debugString, /*defaultValue=*/ null);
871-
}
872-
873-
/**
874-
* Factory method for creating instances of {@link Key}.
875-
*
876-
* @param debugString a debug string that describes this key.
877-
* @param defaultValue default value to return when value for key not set
878-
* @param <T> Key type
879-
* @return Key object
880-
*/
881-
public static <T> Key<T> createWithDefault(String debugString, T defaultValue) {
882-
Preconditions.checkNotNull(debugString, "debugString");
883-
return new Key<>(debugString, defaultValue);
884-
}
885-
886-
/**
887-
* Returns the user supplied default value for this key.
888-
*/
889-
public T getDefault() {
890-
return defaultValue;
891-
}
892-
893-
@Override
894-
public String toString() {
895-
return debugString;
896-
}
897-
}
898-
}
899-
900654
/**
901655
* Provides essentials for LoadBalancer implementations.
902656
*
@@ -910,11 +664,7 @@ public abstract static class Helper {
910664
* EquivalentAddressGroup}.
911665
*
912666
* @since 1.2.0
913-
* @deprecated Use {@link #createSubchannel(CreateSubchannelArgs)} instead. Note the new API
914-
* must be called from {@link #getSynchronizationContext the Synchronization
915-
* Context}.
916667
*/
917-
@Deprecated
918668
public final Subchannel createSubchannel(EquivalentAddressGroup addrs, Attributes attrs) {
919669
checkNotNull(addrs, "addrs");
920670
return createSubchannel(Collections.singletonList(addrs), attrs);
@@ -935,35 +685,11 @@ public final Subchannel createSubchannel(EquivalentAddressGroup addrs, Attribute
935685
*
936686
* @throws IllegalArgumentException if {@code addrs} is empty
937687
* @since 1.14.0
938-
* @deprecated Use {@link #createSubchannel(CreateSubchannelArgs)} instead. Note the new API
939-
* must be called from {@link #getSynchronizationContext the Synchronization
940-
* Context}.
941688
*/
942-
@Deprecated
943689
public Subchannel createSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) {
944690
throw new UnsupportedOperationException();
945691
}
946692

947-
/**
948-
* Creates a Subchannel, which is a logical connection to the given group of addresses which are
949-
* considered equivalent. The {@code attrs} are custom attributes associated with this
950-
* Subchannel, and can be accessed later through {@link Subchannel#getAttributes
951-
* Subchannel.getAttributes()}.
952-
*
953-
* <p>This method <strong>must be called from the {@link #getSynchronizationContext
954-
* Synchronization Context}</strong>, otherwise it may throw. This is to avoid the race between
955-
* the caller and {@link SubchannelStateListener#onSubchannelState}. See <a
956-
* href="https://github.com/grpc/grpc-java/issues/5015">#5015</a> for more discussions.
957-
*
958-
* <p>The LoadBalancer is responsible for closing unused Subchannels, and closing all
959-
* Subchannels within {@link #shutdown}.
960-
*
961-
* @since 1.21.0
962-
*/
963-
public Subchannel createSubchannel(CreateSubchannelArgs args) {
964-
throw new UnsupportedOperationException();
965-
}
966-
967693
/**
968694
* Equivalent to {@link #updateSubchannelAddresses(io.grpc.LoadBalancer.Subchannel, List)} with
969695
* the given single {@code EquivalentAddressGroup}.
@@ -1180,7 +906,7 @@ public abstract static class Subchannel {
1180906
*/
1181907
public final EquivalentAddressGroup getAddresses() {
1182908
List<EquivalentAddressGroup> groups = getAllAddresses();
1183-
Preconditions.checkState(groups.size() == 1, "%s does not have exactly one group", groups);
909+
Preconditions.checkState(groups.size() == 1, "Does not have exactly one group");
1184910
return groups.get(0);
1185911
}
1186912

@@ -1241,39 +967,6 @@ public ChannelLogger getChannelLogger() {
1241967
}
1242968
}
1243969

1244-
/**
1245-
* Receives state changes for one or more {@link Subchannel}s. All methods are run under {@link
1246-
* Helper#getSynchronizationContext}.
1247-
*
1248-
* @since 1.21.0
1249-
*/
1250-
public interface SubchannelStateListener {
1251-
1252-
/**
1253-
* Handles a state change on a Subchannel.
1254-
*
1255-
* <p>The initial state of a Subchannel is IDLE. You won't get a notification for the initial
1256-
* IDLE state.
1257-
*
1258-
* <p>If the new state is not SHUTDOWN, this method should create a new picker and call {@link
1259-
* Helper#updateBalancingState Helper.updateBalancingState()}. Failing to do so may result in
1260-
* unnecessary delays of RPCs. Please refer to {@link PickResult#withSubchannel
1261-
* PickResult.withSubchannel()}'s javadoc for more information.
1262-
*
1263-
* <p>SHUTDOWN can only happen in two cases. One is that LoadBalancer called {@link
1264-
* Subchannel#shutdown} earlier, thus it should have already discarded this Subchannel. The
1265-
* other is that Channel is doing a {@link ManagedChannel#shutdownNow forced shutdown} or has
1266-
* already terminated, thus there won't be further requests to LoadBalancer. Therefore,
1267-
* SHUTDOWN can be safely ignored.
1268-
*
1269-
* @param subchannel the involved Subchannel
1270-
* @param newState the new state
1271-
*
1272-
* @since 1.21.0
1273-
*/
1274-
void onSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState);
1275-
}
1276-
1277970
/**
1278971
* Factory to create {@link LoadBalancer} instance.
1279972
*

0 commit comments

Comments
 (0)