blob: 73486bb0bd9f68482ea715e93f98bb5b104fbfd6 [file] [log] [blame]
/*
* Copyright 2019 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.internal;
import static com.google.common.base.Preconditions.checkState;
import io.grpc.NameResolver.ConfigOrError;
import javax.annotation.Nullable;
/**
* {@link ServiceConfigState} holds the state of the current service config. It must be mutated
* and read from {@link ManagedChannelImpl} constructor or the provided syncContext.
*/
final class ServiceConfigState {
@Nullable private final ConfigOrError defaultServiceConfig;
private final boolean lookUpServiceConfig;
// mutable state
@Nullable private ConfigOrError currentServiceConfigOrError;
// Has there been at least one update?
private boolean updated;
/**
* @param defaultServiceConfig The initial service config, or {@code null} if absent.
* @param lookUpServiceConfig {@code true} if service config updates might occur.
*/
ServiceConfigState(
@Nullable ManagedChannelServiceConfig defaultServiceConfig,
boolean lookUpServiceConfig) {
if (defaultServiceConfig == null) {
this.defaultServiceConfig = null;
} else {
this.defaultServiceConfig = ConfigOrError.fromConfig(defaultServiceConfig);
}
this.lookUpServiceConfig = lookUpServiceConfig;
if (!lookUpServiceConfig) {
this.currentServiceConfigOrError = this.defaultServiceConfig;
}
}
/**
* Returns {@code true} if it RPCs should wait on a service config resolution. This can return
* {@code false} if:
*
* <ul>
* <li>There is a valid service config from the name resolver
* <li>There is a valid default service config and a service config error from the name
* resolver
* <li>No service config from the name resolver, and no intent to lookup a service config.
* </ul>
*
* <p>In the final case, the default service config may be present or absent, and will be the
* current service config.
*/
boolean shouldWaitOnServiceConfig() {
return !(updated || !expectUpdates());
}
/**
* Gets the current service config or error.
*
* @throws IllegalStateException if the service config has not yet been updated.
*/
@Nullable
ConfigOrError getCurrent() {
checkState(!shouldWaitOnServiceConfig(), "still waiting on service config");
return currentServiceConfigOrError;
}
void update(@Nullable ConfigOrError coe) {
checkState(expectUpdates(), "unexpected service config update");
boolean firstUpdate = !updated;
updated = true;
if (firstUpdate) {
if (coe == null) {
currentServiceConfigOrError = defaultServiceConfig;
} else if (coe.getError() != null) {
if (defaultServiceConfig != null) {
currentServiceConfigOrError = defaultServiceConfig;
} else {
currentServiceConfigOrError = coe;
}
} else {
assert coe.getConfig() != null;
currentServiceConfigOrError = coe;
}
} else {
if (coe == null) {
if (defaultServiceConfig != null) {
currentServiceConfigOrError = defaultServiceConfig;
} else {
currentServiceConfigOrError = null;
}
} else if (coe.getError() != null) {
if (currentServiceConfigOrError != null && currentServiceConfigOrError.getError() != null) {
currentServiceConfigOrError = coe;
} else {
// discard
}
} else {
assert coe.getConfig() != null;
currentServiceConfigOrError = coe;
}
}
}
boolean expectUpdates() {
return lookUpServiceConfig;
}
}