001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.hadoop.hdfs.server.namenode.ha;
019
020 import java.io.Closeable;
021 import java.io.IOException;
022 import java.net.InetSocketAddress;
023 import java.net.URI;
024
025 import org.apache.hadoop.conf.Configuration;
026 import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
027 import org.apache.hadoop.hdfs.DFSConfigKeys;
028 import org.apache.hadoop.hdfs.NameNodeProxies;
029 import org.apache.hadoop.hdfs.server.namenode.NameNode;
030 import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols;
031 import org.apache.hadoop.io.retry.FailoverProxyProvider;
032 import org.apache.hadoop.ipc.RPC;
033 import org.apache.hadoop.security.UserGroupInformation;
034
035 import com.google.common.base.Preconditions;
036
037 /**
038 * A NNFailoverProxyProvider implementation which works on IP failover setup.
039 * Only one proxy is used to connect to both servers and switching between
040 * the servers is done by the environment/infrastructure, which guarantees
041 * clients can consistently reach only one node at a time.
042 *
043 * Clients with a live connection will likely get connection reset after an
044 * IP failover. This case will be handled by the
045 * FailoverOnNetworkExceptionRetry retry policy. I.e. if the call is
046 * not idempotent, it won't get retried.
047 *
048 * A connection reset while setting up a connection (i.e. before sending a
049 * request) will be handled in ipc client.
050 *
051 * The namenode URI must contain a resolvable host name.
052 */
053 public class IPFailoverProxyProvider<T> extends
054 AbstractNNFailoverProxyProvider<T> {
055 private final Configuration conf;
056 private final Class<T> xface;
057 private final URI nameNodeUri;
058 private ProxyInfo<T> nnProxyInfo = null;
059
060 public IPFailoverProxyProvider(Configuration conf, URI uri,
061 Class<T> xface) {
062 Preconditions.checkArgument(
063 xface.isAssignableFrom(NamenodeProtocols.class),
064 "Interface class %s is not a valid NameNode protocol!");
065 this.xface = xface;
066 this.nameNodeUri = uri;
067
068 this.conf = new Configuration(conf);
069 int maxRetries = this.conf.getInt(
070 DFSConfigKeys.DFS_CLIENT_FAILOVER_CONNECTION_RETRIES_KEY,
071 DFSConfigKeys.DFS_CLIENT_FAILOVER_CONNECTION_RETRIES_DEFAULT);
072 this.conf.setInt(
073 CommonConfigurationKeysPublic.IPC_CLIENT_CONNECT_MAX_RETRIES_KEY,
074 maxRetries);
075
076 int maxRetriesOnSocketTimeouts = this.conf.getInt(
077 DFSConfigKeys.DFS_CLIENT_FAILOVER_CONNECTION_RETRIES_ON_SOCKET_TIMEOUTS_KEY,
078 DFSConfigKeys.DFS_CLIENT_FAILOVER_CONNECTION_RETRIES_ON_SOCKET_TIMEOUTS_DEFAULT);
079 this.conf.setInt(
080 CommonConfigurationKeysPublic.IPC_CLIENT_CONNECT_MAX_RETRIES_ON_SOCKET_TIMEOUTS_KEY,
081 maxRetriesOnSocketTimeouts);
082 }
083
084 @Override
085 public Class<T> getInterface() {
086 return xface;
087 }
088
089 @Override
090 public synchronized ProxyInfo<T> getProxy() {
091 // Create a non-ha proxy if not already created.
092 if (nnProxyInfo == null) {
093 try {
094 // Create a proxy that is not wrapped in RetryProxy
095 InetSocketAddress nnAddr = NameNode.getAddress(nameNodeUri);
096 nnProxyInfo = new ProxyInfo<T>(NameNodeProxies.createNonHAProxy(
097 conf, nnAddr, xface, UserGroupInformation.getCurrentUser(),
098 false).getProxy(), nnAddr.toString());
099 } catch (IOException ioe) {
100 throw new RuntimeException(ioe);
101 }
102 }
103 return nnProxyInfo;
104 }
105
106 /** Nothing to do for IP failover */
107 @Override
108 public void performFailover(T currentProxy) {
109 }
110
111 /**
112 * Close the proxy,
113 */
114 @Override
115 public synchronized void close() throws IOException {
116 if (nnProxyInfo == null) {
117 return;
118 }
119 if (nnProxyInfo.proxy instanceof Closeable) {
120 ((Closeable)nnProxyInfo.proxy).close();
121 } else {
122 RPC.stopProxy(nnProxyInfo.proxy);
123 }
124 }
125
126 /**
127 * Logical URI is not used for IP failover.
128 */
129 @Override
130 public boolean useLogicalURI() {
131 return false;
132 }
133 }