/**
* 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.hadoop.hdfs.conf;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.DFSUtil;
import org.apache.hadoop.hdfs.protocol.AvatarConstants.InstanceId;
import org.apache.hadoop.hdfs.protocol.FSConstants;
import org.apache.hadoop.hdfs.server.namenode.NameNode;
import org.apache.hadoop.net.NetUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.data.Stat;
public class FallbackNameSpaceAddressManager extends NameSpaceAddressManager {
private String serviceName;
private static final Log LOG = LogFactory
.getLog(NameSpaceAddressManager.class
.getName());
private final AddressHolder<String> clientProtocolZnodeAddress;
private final AddressHolder<String> datanodeProtocolZnodeAddress;
private final AddressHolder<String> httpZnodeAddress;
private class ConfGetter extends AddressHolder<String> {
private String key;
public ConfGetter(Configurable theParent, String configKey) {
super(theParent);
key = configKey;
}
@Override
public String getAddress() throws UnknownHostException {
return getConf().get(getKey());
}
@Override
public String getKey() {
return key + "." + serviceName;
}
}
public FallbackNameSpaceAddressManager(Configurable parent, String serviceName) {
super(parent);
clientProtocolZnodeAddress = new ConfGetter(parent,
NameNode.DFS_NAMENODE_RPC_ADDRESS_KEY);
datanodeProtocolZnodeAddress = new ConfGetter(parent,
NameNode.DATANODE_PROTOCOL_ADDRESS);
httpZnodeAddress = new ConfGetter(parent,
FSConstants.DFS_NAMENODE_HTTP_ADDRESS_KEY);
this.serviceName = serviceName;
}
@Override
public void refreshZookeeperInfo() throws IOException, KeeperException,
InterruptedException {
NameNodeAddress zero = getNodeZero();
NameNodeAddress one = getNodeOne();
// Using RPC Address to determine which node is primary and using the rest
// of them as a sanity check
String zNodeClientProtocol = clientProtocolZnodeAddress.getAddress();
String primaryClientProtocol = zkClient.getPrimaryAvatarAddress(
zNodeClientProtocol, new Stat(), false, false);
InstanceId instanceIdfromZookeeper = null;
if (primaryClientProtocol == null) {
// Fail-over in progress.
instanceIdfromZookeeper = null;
} else {
InetSocketAddress clientProtAddress = NetUtils
.createSocketAddr(primaryClientProtocol);
if (clientProtAddress.equals(zero.clientProtocol.getAddress())) {
instanceIdfromZookeeper = InstanceId.NODEZERO;
} else if (clientProtAddress.equals(one.clientProtocol.getAddress())) {
instanceIdfromZookeeper = InstanceId.NODEONE;
} else {
throw new IllegalArgumentException(
"Zookeeper client protocol address isn't valid: "
+ primaryClientProtocol);
}
}
String zNodeHttpKey = httpZnodeAddress.getAddress();
verifyAddress(
zkClient.getPrimaryAvatarAddress(zNodeHttpKey, new Stat(), false),
instanceIdfromZookeeper, zero.httpProtocol.getAddress(),
one.httpProtocol.getAddress());
String zNodeKeyForDnAddress = datanodeProtocolZnodeAddress.getAddress();
verifyAddress(zkClient.getPrimaryAvatarAddress(zNodeKeyForDnAddress,
new Stat(), false), instanceIdfromZookeeper,
zero.datanodeProtocol.getAddress(), one.datanodeProtocol.getAddress());
super.setPrimary(instanceIdfromZookeeper);
}
private static void verifyAddress(String address, InstanceId fromZk,
InetSocketAddress zeroAddr, InetSocketAddress oneAddr) {
InstanceId afterMatchingWithConfig = null;
if (address == null) {
afterMatchingWithConfig = null;
} else {
InetSocketAddress addressInIp = NetUtils.createSocketAddr(address);
if (zeroAddr.equals(addressInIp)) {
afterMatchingWithConfig = InstanceId.NODEZERO;
} else if (oneAddr.equals(addressInIp)) {
afterMatchingWithConfig = InstanceId.NODEONE;
} else {
DFSUtil
.throwAndLogIllegalState(
"Address doesn't match any of the possible candidates from the config file",
LOG);
}
}
if (afterMatchingWithConfig != fromZk) {
DFSUtil
.throwAndLogIllegalState(
"One of the addresses of Zookeeper isn't in sync with other addresses.",
LOG);
}
}
@Override
public void validateConfigFile(Configuration conf) {
String[] keysOfInterest = new String[] {
FSConstants.DFS_NAMENODE_HTTP_ADDRESS_KEY,
NameNode.DATANODE_PROTOCOL_ADDRESS,
FSConstants.DFS_NAMENODE_RPC_ADDRESS_KEY };
boolean toThrowTheException = false;
for (String key : keysOfInterest) {
if (conf.get(key) == null) {
LOG.error("Key not found: " + key);
toThrowTheException = true;
}
}
for (String key : keysOfInterest) {
for (InstanceId id : InstanceId.values()) {
String keyWeExpect = key + id.getZookeeeperValue() + "." + serviceName;
if (conf.get(keyWeExpect) == null) {
LOG.error("Key not found: " + keyWeExpect);
toThrowTheException = true;
}
}
}
if (toThrowTheException) {
throw new IllegalArgumentException(
"Essential keys are missing from configuration.");
}
}
@Override
public String getTxidPath() throws UnknownHostException {
return clientProtocolZnodeAddress.getAddress();
}
@Override
public String getSsidPath() throws UnknownHostException {
return getTxidPath();
}
public void setPrimary(InstanceId id) throws IOException {
if (id == null) {
zkClient.clearPrimary(clientProtocolZnodeAddress.getAddress());
zkClient.clearPrimary(datanodeProtocolZnodeAddress.getAddress());
zkClient.clearPrimary(httpZnodeAddress.getAddress());
} else {
NameNodeAddress addressesToWrite = null;
switch (id) {
case NODEZERO:
addressesToWrite = getNodeZero();
case NODEONE:
addressesToWrite = getNodeOne();
}
final boolean toOverWrite = true;
zkClient.registerPrimary(clientProtocolZnodeAddress.getAddress(),
NameNode.getHostPortString(addressesToWrite.clientProtocol
.getAddress()), toOverWrite);
zkClient.registerPrimary(datanodeProtocolZnodeAddress.getAddress(),
NameNode.getHostPortString(addressesToWrite.datanodeProtocol
.getAddress()), toOverWrite);
zkClient
.registerPrimary(httpZnodeAddress.getAddress(), NameNode
.getHostPortString(addressesToWrite.httpProtocol.getAddress()),
toOverWrite);
}
super.setPrimary(id);
}
}