nl.topicus.jdbc.shaded.com.google.cloud.spanner.SpannerOptions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spanner-jdbc Show documentation
Show all versions of spanner-jdbc Show documentation
JDBC Driver for Google Cloud Spanner
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in nl.topicus.jdbc.shaded.com.liance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.nl.topicus.jdbc.shaded.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 nl.topicus.jdbc.shaded.com.google.cloud.spanner;
import nl.topicus.jdbc.shaded.com.google.cloud.grpc.GrpcTransportOptions;
import nl.topicus.jdbc.shaded.com.google.cloud.ServiceDefaults;
import nl.topicus.jdbc.shaded.com.google.cloud.ServiceOptions;
import nl.topicus.jdbc.shaded.com.google.cloud.ServiceRpc;
import nl.topicus.jdbc.shaded.com.google.cloud.TransportOptions;
import nl.topicus.jdbc.shaded.com.google.cloud.spanner.spi.v1.GrpcSpannerRpc;
import nl.topicus.jdbc.shaded.com.google.cloud.spanner.spi.v1.SpannerRpc;
import nl.topicus.jdbc.shaded.com.google.cloud.spanner.spi.SpannerRpcFactory;
import nl.topicus.jdbc.shaded.com.google.nl.topicus.jdbc.shaded.com.on.base.MoreObjects;
import nl.topicus.jdbc.shaded.com.google.nl.topicus.jdbc.shaded.com.on.base.Preconditions;
import nl.topicus.jdbc.shaded.com.google.nl.topicus.jdbc.shaded.com.on.collect.ImmutableList;
import nl.topicus.jdbc.shaded.com.google.nl.topicus.jdbc.shaded.com.on.collect.ImmutableSet;
import nl.topicus.jdbc.shaded.io.grpc.ClientInterceptor;
import nl.topicus.jdbc.shaded.io.grpc.ManagedChannel;
import nl.topicus.jdbc.shaded.io.grpc.nl.topicus.jdbc.shaded.net.y.GrpcSslContexts;
import nl.topicus.jdbc.shaded.io.grpc.nl.topicus.jdbc.shaded.net.y.NettyChannelBuilder;
import nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.handler.ssl.SslContext;
import java.nl.topicus.jdbc.shaded.net.MalformedURLException;
import java.nl.topicus.jdbc.shaded.net.URL;
import java.util.List;
import java.util.Set;
import javax.nl.topicus.jdbc.shaded.net.ssl.SSLException;
/** Options for the Cloud Spanner service. */
public class SpannerOptions extends ServiceOptions {
private static final String API_SHORT_NAME = "Spanner";
private static final String DEFAULT_HOST = "https://spanner.googleapis.nl.topicus.jdbc.shaded.com.;
private static final ImmutableSet SCOPES =
ImmutableSet.of(
"https://www.googleapis.nl.topicus.jdbc.shaded.com.auth/spanner.admin",
"https://www.googleapis.nl.topicus.jdbc.shaded.com.auth/spanner.data");
private static final int MAX_CHANNELS = 256;
private static final RpcChannelFactory DEFAULT_RPC_CHANNEL_FACTORY = new NettyRpcChannelFactory();
/** Default implementation of {@code SpannerFactory}. */
private static class DefaultSpannerFactory implements SpannerFactory {
private static final DefaultSpannerFactory INSTANCE = new DefaultSpannerFactory();
@Override
public Spanner create(SpannerOptions serviceOptions) {
return new SpannerImpl(serviceOptions);
}
}
/** Default implementation of {@code SpannerRpcFactory}. */
private static class DefaultSpannerRpcFactory implements SpannerRpcFactory {
private static final DefaultSpannerRpcFactory INSTANCE = new DefaultSpannerRpcFactory();
@Override
public ServiceRpc create(SpannerOptions options) {
return new GrpcSpannerRpc(options);
}
}
private final List rpcChannels;
private final SessionPoolOptions sessionPoolOptions;
private final int prefetchChunks;
private final int numChannels;
private final String userAgent;
private SpannerOptions(Builder builder) {
super(SpannerFactory.class, SpannerRpcFactory.class, builder, new SpannerDefaults());
numChannels = builder.numChannels;
userAgent = builder.userAgentPrefix;
RpcChannelFactory defaultRpcChannelFactory =
userAgent == null
? DEFAULT_RPC_CHANNEL_FACTORY
: new NettyRpcChannelFactory(userAgent);
rpcChannels =
createChannels(
getHost(),
MoreObjects.firstNonNull(builder.rpcChannelFactory, defaultRpcChannelFactory),
numChannels);
sessionPoolOptions =
builder.sessionPoolOptions != null
? builder.sessionPoolOptions
: SessionPoolOptions.newBuilder().build();
prefetchChunks = builder.prefetchChunks;
}
/** Builder for {@link SpannerOptions} instances. */
public static class Builder
extends ServiceOptions.Builder<
Spanner, SpannerOptions, SpannerOptions.Builder> {
private static final int DEFAULT_PREFETCH_CHUNKS = 4;
private RpcChannelFactory rpcChannelFactory;
/** By default, we create 4 channels per {@link SpannerOptions} */
private int numChannels = 4;
private int prefetchChunks = DEFAULT_PREFETCH_CHUNKS;
private SessionPoolOptions sessionPoolOptions;
private String userAgentPrefix;
private Builder() {}
Builder(SpannerOptions options) {
super(options);
this.numChannels = options.numChannels;
this.sessionPoolOptions = options.sessionPoolOptions;
this.prefetchChunks = options.prefetchChunks;
this.userAgentPrefix = options.userAgent;
}
@Override
public Builder setTransportOptions(TransportOptions transportOptions) {
if (!(transportOptions instanceof GrpcTransportOptions)) {
throw new IllegalArgumentException(
"Only grpc transport is allowed for " + API_SHORT_NAME + ".");
}
return super.setTransportOptions(transportOptions);
}
/** Sets the factory for creating gRPC channels. If not set, a default will be used. */
public Builder setRpcChannelFactory(RpcChannelFactory factory) {
this.rpcChannelFactory = factory;
return this;
}
/**
* Sets the number of gRPC channels to use. By default 4 channels are created per {@link
* SpannerOptions}.
*/
public Builder setNumChannels(int numChannels) {
this.numChannels = numChannels;
return this;
}
/**
* Sets the options for managing the session pool. If not specified then the default {@code
* SessionPoolOptions} is used.
*/
public Builder setSessionPoolOption(SessionPoolOptions sessionPoolOptions) {
this.sessionPoolOptions = sessionPoolOptions;
return this;
}
/**
* Specifying this will allow the client to prefetch up to {@code prefetchChunks} {@code
* PartialResultSet} chunks for each read and query. The data size of each chunk depends on the
* server implementation but a good rule of thumb is that each chunk will be up to 1 MiB. Larger
* values reduce the likelihood of blocking while consuming results at the cost of greater
* memory consumption. {@code prefetchChunks} should be greater than 0. To get good performance
* choose a value that is large enough to allow buffering of chunks for an entire row. Apart
* from the buffered chunks, there can be at most one more row buffered in the client. This can
* be overriden on a per read/query basis by {@link Options#prefetchChunks()}. If unspecified,
* we will use a default value (currently 4).
*/
public Builder setPrefetchChunks(int prefetchChunks) {
this.prefetchChunks = prefetchChunks;
return this;
}
/** If specified, this will be prefixed to the default user agent sent in the requests. */
public Builder setUserAgentPrefix(String userAgentPrefix) {
this.userAgentPrefix = userAgentPrefix;
return this;
}
@Override
public SpannerOptions build() {
return new SpannerOptions(this);
}
}
/**
* Interface for gRPC channel creation. Most users won't need to use this, as the default covers
* typical deployment scenarios.
*/
public interface RpcChannelFactory {
ManagedChannel newChannel(String host, int port);
}
/** Returns default instance of {@code SpannerOptions}. */
public static SpannerOptions getDefaultInstance() {
return newBuilder().build();
}
public static Builder newBuilder() {
return new Builder();
}
public List getRpcChannels() {
return rpcChannels;
}
public SessionPoolOptions getSessionPoolOptions() {
return sessionPoolOptions;
}
public int getPrefetchChunks() {
return prefetchChunks;
}
public static GrpcTransportOptions getDefaultGrpcTransportOptions() {
return GrpcTransportOptions.newBuilder().build();
}
/**
* Returns the default RPC channel factory used when none is specified. This may be useful for
* callers that wish to add interceptors to gRPC channels used by the Cloud Spanner client
* library.
*/
public static RpcChannelFactory getDefaultRpcChannelFactory() {
return DEFAULT_RPC_CHANNEL_FACTORY;
}
@Override
protected String getDefaultHost() {
return DEFAULT_HOST;
}
private static List createChannels(
String rootUrl, RpcChannelFactory factory, int numChannels) {
Preconditions.checkArgument(
numChannels >= 1 && numChannels <= MAX_CHANNELS,
"Number of channels must fall in the range [1, %s], found: %s",
MAX_CHANNELS,
numChannels);
ImmutableList.Builder builder = ImmutableList.builder();
for (int i = 0; i < numChannels; i++) {
builder.add(createChannel(rootUrl, factory));
}
return builder.build();
}
private static ManagedChannel createChannel(String rootUrl, RpcChannelFactory factory) {
URL url;
try {
url = new URL(rootUrl);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid host: " + rootUrl, e);
}
ManagedChannel channel =
factory.newChannel(url.getHost(), url.getPort() > 0 ? url.getPort() : url.getDefaultPort());
return channel;
}
static class NettyRpcChannelFactory implements RpcChannelFactory {
private static final int MAX_MESSAGE_SIZE = 100 * 1024 * 1024;
private final String userAgent;
private final List interceptors;
NettyRpcChannelFactory() {
this(null);
}
NettyRpcChannelFactory(String userAgent) {
this(userAgent, ImmutableList.of());
}
NettyRpcChannelFactory(String userAgent, List interceptors) {
this.userAgent = userAgent;
this.interceptors = interceptors;
}
@Override
public ManagedChannel newChannel(String host, int port) {
NettyChannelBuilder builder =
NettyChannelBuilder.forAddress(host, port)
.sslContext(newSslContext())
.intercept(interceptors)
.maxMessageSize(MAX_MESSAGE_SIZE);
if (userAgent != null) {
builder.userAgent(userAgent);
}
return builder.build();
}
private static SslContext newSslContext() {
try {
return GrpcSslContexts.forClient().ciphers(null).build();
} catch (SSLException e) {
throw new RuntimeException("SSL configuration failed: " + e.getMessage(), e);
}
}
}
private static class SpannerDefaults implements
ServiceDefaults {
@Override
public SpannerFactory getDefaultServiceFactory() {
return DefaultSpannerFactory.INSTANCE;
}
@Override
public SpannerRpcFactory getDefaultRpcFactory() {
return DefaultSpannerRpcFactory.INSTANCE;
}
@Override
public TransportOptions getDefaultTransportOptions() {
return getDefaultGrpcTransportOptions();
}
}
@Override
public Set getScopes() {
return SCOPES;
}
protected SpannerRpc getSpannerRpcV1() {
return (SpannerRpc) getRpc();
}
@SuppressWarnings("unchecked")
@Override
public Builder toBuilder() {
return new Builder(this);
}
}