/** * 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.datanode; import org.apache.hadoop.hdfs.protocol.FSConstants; import org.apache.hadoop.hdfs.server.common.HdfsConstants; import org.apache.hadoop.hdfs.server.common.UpgradeObject; import org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol; import org.apache.hadoop.hdfs.server.protocol.NamespaceInfo; import org.apache.hadoop.hdfs.server.protocol.UpgradeCommand; import org.apache.hadoop.util.StringUtils; import java.io.IOException; import java.net.SocketTimeoutException; /** * Base class for data-node upgrade objects. * Data-node upgrades are run in separate threads. */ public abstract class UpgradeObjectDatanode extends UpgradeObject implements Runnable { private DataNode dataNode = null; public HdfsConstants.NodeType getType() { return HdfsConstants.NodeType.DATA_NODE; } protected DataNode getDatanode() { return dataNode; } void setDatanode(DataNode dataNode) { this.dataNode = dataNode; } /** * Specifies how the upgrade is performed. * @throws IOException */ public abstract void doUpgrade() throws IOException; /** * Specifies what to do before the upgrade is started. * * The default implementation checks whether the data-node missed the upgrade * and throws an exception if it did. This leads to the data-node shutdown. * * Data-nodes usually start distributed upgrade when the name-node replies * to its heartbeat with a start upgrade command. * Sometimes though, e.g. when a data-node missed the upgrade and wants to * catchup with the rest of the cluster, it is necessary to initiate the * upgrade directly on the data-node, since the name-node might not ever * start it. An override of this method should then return true. * And the upgrade will start after data-ndoe registration but before sending * its first heartbeat. * * @param nsInfo name-node versions, verify that the upgrade * object can talk to this name-node version if necessary. * * @throws IOException * @return true if data-node itself should start the upgrade or * false if it should wait until the name-node starts the upgrade. */ boolean preUpgradeAction(NamespaceInfo nsInfo) throws IOException { int nsUpgradeVersion = nsInfo.getDistributedUpgradeVersion(); if(nsUpgradeVersion >= getVersion()) return false; // name-node will perform the upgrade // Missed the upgrade. Report problem to the name-node and throw exception String errorMsg = "\n Data-node missed a distributed upgrade and will shutdown." + "\n " + getDescription() + "." + " Name-node version = " + nsInfo.getLayoutVersion() + "."; DataNode.LOG.fatal( errorMsg ); try { dataNode.namenode.errorReport(dataNode.dnRegistration, DatanodeProtocol.NOTIFY, errorMsg); } catch(SocketTimeoutException e) { // namenode is busy DataNode.LOG.info("Problem connecting to server: " + dataNode.getNameNodeAddr()); } throw new IOException(errorMsg); } public void run() { assert dataNode != null : "UpgradeObjectDatanode.dataNode is null"; while(dataNode.shouldRun) { try { doUpgrade(); } catch(Exception e) { DataNode.LOG.error(StringUtils.stringifyException(e)); } break; } // report results if(getUpgradeStatus() < 100) { DataNode.LOG.info("\n Distributed upgrade for DataNode version " + getVersion() + " to current LV " + FSConstants.LAYOUT_VERSION + " cannot be completed"); } // Complete the upgrade by calling the manager method try { dataNode.upgradeManager.completeUpgrade(); } catch(IOException e) { DataNode.LOG.error(StringUtils.stringifyException(e)); } } /** * Complete upgrade and return a status complete command for broadcasting. * * Data-nodes finish upgrade at different times. * The data-node needs to re-confirm with the name-node that the upgrade * is complete while other nodes are still upgrading. */ public UpgradeCommand completeUpgrade() throws IOException { return new UpgradeCommand(UpgradeCommand.UC_ACTION_REPORT_STATUS, getVersion(), (short)100); } }