blob: f82c9b8e0fd73babdf099f2a0794d36862db0460 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.accumulo.core.client.impl;
import static com.google.common.base.Preconditions.checkArgument;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.client.AccumuloClient;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.BatchWriterConfig;
import org.apache.accumulo.core.client.ClientInfo;
import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.core.metadata.RootTable;
import org.apache.accumulo.core.rpc.SaslConnectionParams;
import org.apache.accumulo.core.rpc.SslConnectionParams;
import org.apache.accumulo.core.security.thrift.TCredentials;
import org.apache.accumulo.core.util.OpTimer;
import org.apache.accumulo.fate.zookeeper.ZooCache;
import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
import org.apache.accumulo.fate.zookeeper.ZooUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Suppliers;
/**
* This class represents any essential configuration and credentials needed to initiate RPC
* operations throughout the code. It is intended to represent a shared object that contains these
* things from when the client was first constructed. It is not public API, and is only an internal
* representation of the context in which a client is executing RPCs. If additional parameters are
* added to the public API that need to be used in the internals of Accumulo, they should be added
* to this object for later retrieval, rather than as a separate parameter. Any state in this object
* should be available at the time of its construction.
*/
public class ClientContext {
private static final Logger log = LoggerFactory.getLogger(ClientContext.class);
private ClientInfo info;
private String instanceId = null;
private final ZooCache zooCache;
private Credentials creds;
private BatchWriterConfig batchWriterConfig;
private AccumuloConfiguration serverConf;
protected AccumuloClient client;
// These fields are very frequently accessed (each time a connection is created) and expensive to
// compute, so cache them.
private Supplier<Long> timeoutSupplier;
private Supplier<SaslConnectionParams> saslSupplier;
private Supplier<SslConnectionParams> sslSupplier;
private TCredentials rpcCreds;
private static <T> Supplier<T> memoizeWithExpiration(Supplier<T> s) {
// This insanity exists to make modernizer plugin happy. We are living in the future now.
return () -> Suppliers.memoizeWithExpiration(s::get, 100, TimeUnit.MILLISECONDS).get();
}
public ClientContext(ClientInfo info) {
this(info, ClientConfConverter.toAccumuloConf(info.getProperties()));
}
public ClientContext(ClientInfo info, AccumuloConfiguration serverConf) {
this.info = info;
zooCache = new ZooCacheFactory().getZooCache(info.getZooKeepers(),
info.getZooKeepersSessionTimeOut());
this.serverConf = serverConf;
timeoutSupplier = memoizeWithExpiration(
() -> getConfiguration().getTimeInMillis(Property.GENERAL_RPC_TIMEOUT));
sslSupplier = memoizeWithExpiration(() -> SslConnectionParams.forClient(getConfiguration()));
saslSupplier = memoizeWithExpiration(
() -> SaslConnectionParams.from(getConfiguration(), getCredentials().getToken()));
}
/**
* Retrieve the instance used to construct this context
*
* @deprecated since 2.0.0
*/
@Deprecated
public org.apache.accumulo.core.client.Instance getDeprecatedInstance() {
final ClientContext context = this;
return new org.apache.accumulo.core.client.Instance() {
@Override
public String getRootTabletLocation() {
return context.getRootTabletLocation();
}
@Override
public List<String> getMasterLocations() {
return context.getMasterLocations();
}
@Override
public String getInstanceID() {
return context.getInstanceID();
}
@Override
public String getInstanceName() {
return context.getInstanceName();
}
@Override
public String getZooKeepers() {
return context.getZooKeepers();
}
@Override
public int getZooKeepersSessionTimeOut() {
return context.getZooKeepersSessionTimeOut();
}
@Override
public org.apache.accumulo.core.client.Connector getConnector(String principal,
AuthenticationToken token) throws AccumuloException, AccumuloSecurityException {
return org.apache.accumulo.core.client.Connector
.from(context.getClient().changeUser(principal, token));
}
};
}
public ClientInfo getClientInfo() {
return info;
}
/**
* Retrieve the credentials used to construct this context
*/
public synchronized Credentials getCredentials() {
if (creds == null) {
creds = new Credentials(info.getPrincipal(), info.getAuthenticationToken());
}
return creds;
}
public String getPrincipal() {
return getCredentials().getPrincipal();
}
public AuthenticationToken getAuthenticationToken() {
return getCredentials().getToken();
}
public Properties getProperties() {
return info.getProperties();
}
/**
* Update the credentials in the current context after changing the current user's password or
* other auth token
*/
public synchronized void setCredentials(Credentials newCredentials) {
checkArgument(newCredentials != null, "newCredentials is null");
creds = newCredentials;
rpcCreds = null;
}
/**
* Retrieve the configuration used to construct this context
*/
public AccumuloConfiguration getConfiguration() {
return serverConf;
}
/**
* Retrieve the universal RPC client timeout from the configuration
*/
public long getClientTimeoutInMillis() {
return timeoutSupplier.get();
}
/**
* Retrieve SSL/TLS configuration to initiate an RPC connection to a server
*/
public SslConnectionParams getClientSslParams() {
return sslSupplier.get();
}
/**
* Retrieve SASL configuration to initiate an RPC connection to a server
*/
public SaslConnectionParams getSaslParams() {
return saslSupplier.get();
}
/**
* Retrieve an Accumulo client
*/
public synchronized AccumuloClient getClient()
throws AccumuloException, AccumuloSecurityException {
if (client == null) {
client = new AccumuloClientImpl(this);
}
return client;
}
public BatchWriterConfig getBatchWriterConfig() {
if (batchWriterConfig == null) {
batchWriterConfig = ClientInfoFactory.getBatchWriterConfig(getClientInfo());
}
return batchWriterConfig;
}
/**
* Serialize the credentials just before initiating the RPC call
*/
public synchronized TCredentials rpcCreds() {
if (getCredentials().getToken().isDestroyed()) {
rpcCreds = null;
}
if (rpcCreds == null) {
rpcCreds = getCredentials().toThrift(getInstanceID());
}
return rpcCreds;
}
/**
* Returns the location of the tablet server that is serving the root tablet.
*
* @return location in "hostname:port" form
*/
public String getRootTabletLocation() {
String zRootLocPath = getZooKeeperRoot() + RootTable.ZROOT_TABLET_LOCATION;
OpTimer timer = null;
if (log.isTraceEnabled()) {
log.trace("tid={} Looking up root tablet location in zookeeper.",
Thread.currentThread().getId());
timer = new OpTimer().start();
}
byte[] loc = zooCache.get(zRootLocPath);
if (timer != null) {
timer.stop();
log.trace("tid={} Found root tablet at {} in {}", Thread.currentThread().getId(),
(loc == null ? "null" : new String(loc, UTF_8)),
String.format("%.3f secs", timer.scale(TimeUnit.SECONDS)));
}
if (loc == null) {
return null;
}
return new String(loc, UTF_8).split("\\|")[0];
}
/**
* Returns the location(s) of the accumulo master and any redundant servers.
*
* @return a list of locations in "hostname:port" form
*/
public List<String> getMasterLocations() {
String masterLocPath = getZooKeeperRoot() + Constants.ZMASTER_LOCK;
OpTimer timer = null;
if (log.isTraceEnabled()) {
log.trace("tid={} Looking up master location in zookeeper.", Thread.currentThread().getId());
timer = new OpTimer().start();
}
byte[] loc = ZooUtil.getLockData(zooCache, masterLocPath);
if (timer != null) {
timer.stop();
log.trace("tid={} Found master at {} in {}", Thread.currentThread().getId(),
(loc == null ? "null" : new String(loc, UTF_8)),
String.format("%.3f secs", timer.scale(TimeUnit.SECONDS)));
}
if (loc == null) {
return Collections.emptyList();
}
return Collections.singletonList(new String(loc, UTF_8));
}
/**
* Returns a unique string that identifies this instance of accumulo.
*
* @return a UUID
*/
public String getInstanceID() {
final String instanceName = info.getInstanceName();
if (instanceId == null) {
// want the instance id to be stable for the life of this instance object,
// so only get it once
String instanceNamePath = Constants.ZROOT + Constants.ZINSTANCES + "/" + instanceName;
byte[] iidb = zooCache.get(instanceNamePath);
if (iidb == null) {
throw new RuntimeException(
"Instance name " + instanceName + " does not exist in zookeeper. "
+ "Run \"accumulo org.apache.accumulo.server.util.ListInstances\" to see a list.");
}
instanceId = new String(iidb, UTF_8);
}
if (zooCache.get(Constants.ZROOT + "/" + instanceId) == null) {
if (instanceName == null)
throw new RuntimeException("Instance id " + instanceId + " does not exist in zookeeper");
throw new RuntimeException("Instance id " + instanceId + " pointed to by the name "
+ instanceName + " does not exist in zookeeper");
}
return instanceId;
}
public String getZooKeeperRoot() {
return ZooUtil.getRoot(getInstanceID());
}
/**
* Returns the instance name given at system initialization time.
*
* @return current instance name
*/
public String getInstanceName() {
return info.getInstanceName();
}
/**
* Returns a comma-separated list of zookeeper servers the instance is using.
*
* @return the zookeeper servers this instance is using in "hostname:port" form
*/
public String getZooKeepers() {
return info.getZooKeepers();
}
/**
* Returns the zookeeper connection timeout.
*
* @return the configured timeout to connect to zookeeper
*/
public int getZooKeepersSessionTimeOut() {
return info.getZooKeepersSessionTimeOut();
}
public ZooCache getZooCache() {
return zooCache;
}
}