/** * 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.server.balancer; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FilterFileSystem; import org.apache.hadoop.hdfs.DistributedAvatarFileSystem; import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.FailoverClient; import org.apache.hadoop.hdfs.FailoverClientHandler; import org.apache.hadoop.hdfs.server.FailoverNameNodeProtocol; import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol; import org.apache.hadoop.ipc.VersionedProtocol; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.util.ToolRunner; import org.apache.zookeeper.data.Stat; /** * Extension of the HDFS Balancer utility such that it works correctly with * AvatarNodes and can run during and after an AvatarNode failover. */ public class AvatarBalancer extends Balancer implements FailoverClient { private FailoverNameNodeProtocol failoverNamenode; private FailoverClientHandler failoverHandler; private URI logicalName; public AvatarBalancer() { super(); } public AvatarBalancer(Configuration conf) { super(conf); } public AvatarBalancer(Configuration conf, double threshold) { super(conf, threshold); } static int runBalancer(String[] args) throws Exception { return ToolRunner.run(null, new AvatarBalancer(), args); } @Override public void setConf(Configuration conf) { conf.setClass("dfs.balancer.impl", AvatarBalancer.class, Balancer.class); conf.setClass("fs.hdfs.impl", DistributedAvatarFileSystem.class, FileSystem.class); conf.setBoolean("fs.ha.retrywrites", true); super.setConf(conf); } /** * Run a balancer * * @param args */ public static void main(String[] args) { org.apache.hadoop.hdfs.DnsMonitorSecurityManager.setTheManager(); try { System.exit(runBalancer(args)); } catch (Throwable e) { LOG.error(StringUtils.stringifyException(e)); System.exit(-1); } } @Override protected void initFS() throws IOException { super.initFS(); logicalName = this.fs.getUri(); failoverHandler = new FailoverClientHandler(this.conf, logicalName, this); } @Override protected void initNameNodes() throws IOException { if (this.fs instanceof FilterFileSystem) { this.client = ((DistributedFileSystem) ((FilterFileSystem) this.fs) .getRawFileSystem()).getClient().getNameNodeRPC(); } else { this.client = ((DistributedFileSystem) this.fs).getClient() .getNameNodeRPC(); } initNamenodeProtocol(false); } private void initNamenodeProtocol(boolean failover) throws IOException { boolean firstAttempt = true; Stat stat = new Stat(); while (true) { try { String primaryAddr = failoverHandler.getPrimaryAvatarAddress( logicalName, stat, true, firstAttempt); String parts[] = primaryAddr.split(":"); if (parts.length != 2) { throw new IOException("Invalid address : " + primaryAddr); } InetSocketAddress nnAddr = new InetSocketAddress(parts[0], Integer.parseInt(parts[1])); NamenodeProtocol nn = createNamenode(nnAddr, conf); if (failover) { newNamenode(nn); } else { failoverNamenode = new FailoverNameNodeProtocol(this.namenode, failoverHandler); this.namenode = failoverNamenode; } break; } catch (Exception e) { if (firstAttempt && failoverHandler.isZKCacheEnabled()) { firstAttempt = false; continue; } else { Balancer.LOG.error(e); throw new IOException(e); } } } } @Override public boolean tryFailover() throws IOException { initNamenodeProtocol(true); return true; } @Override public boolean isShuttingdown() { return this.shuttingDown; } @Override public boolean isFailoverInProgress() { return failoverNamenode.getNameNode() == null; } @Override public void nameNodeDown() { failoverNamenode.setNameNode(null); } @Override public void newNamenode(VersionedProtocol namenode) { failoverNamenode.setNameNode((NamenodeProtocol) namenode); } }