Package org.apache.hadoop.hdfs

Source Code of org.apache.hadoop.hdfs.BlockReaderFactory

/**
* 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;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.net.Peer;
import org.apache.hadoop.hdfs.protocol.DatanodeID;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
import org.apache.hadoop.hdfs.protocol.datatransfer.Sender;
import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.BlockOpResponseProto;
import org.apache.hadoop.hdfs.protocolPB.PBHelper;
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
import org.apache.hadoop.hdfs.security.token.block.InvalidBlockTokenException;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
import org.apache.hadoop.hdfs.server.datanode.CachingStrategy;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.net.unix.DomainSocket;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.token.SecretManager.InvalidToken;
import org.apache.hadoop.security.token.Token;


/**
* Utility class to create BlockReader implementations.
*/
@InterfaceAudience.Private
public class BlockReaderFactory {
  /**
   * Create a new BlockReader specifically to satisfy a read.
   * This method also sends the OP_READ_BLOCK request.
   *
   * @param conf the DFSClient configuration
   * @param file  File location
   * @param block  The block object
   * @param blockToken  The block token for security
   * @param startOffset  The read offset, relative to block head
   * @param len  The number of bytes to read, or -1 to read as many as
   *             possible.
   * @param bufferSize  The IO buffer size (not the client buffer size)
   *                    Ignored except on the legacy BlockReader.
   * @param verifyChecksum  Whether to verify checksum
   * @param clientName  Client name.  Used for log messages.
   * @param peer  The peer
   * @param datanodeID  The datanode that the Peer is connected to
   * @param domainSocketFactory  The DomainSocketFactory to notify if the Peer
   *                             is a DomainPeer which turns out to be faulty.
   *                             If null, no factory will be notified in this
   *                             case.
   * @param allowShortCircuitLocalReads  True if short-circuit local reads
   *                                     should be allowed.
   * @return New BlockReader instance
   */
  public static BlockReader newBlockReader(DFSClient.Conf conf,
                                     String file,
                                     ExtendedBlock block,
                                     Token<BlockTokenIdentifier> blockToken,
                                     long startOffset, long len,
                                     boolean verifyChecksum,
                                     String clientName,
                                     Peer peer,
                                     DatanodeID datanodeID,
                                     DomainSocketFactory domSockFactory,
                                     PeerCache peerCache,
                                     FileInputStreamCache fisCache,
                                     boolean allowShortCircuitLocalReads,
                                     CachingStrategy cachingStrategy)
  throws IOException {
    peer.setReadTimeout(conf.socketTimeout);
    peer.setWriteTimeout(HdfsServerConstants.WRITE_TIMEOUT);

    if (peer.getDomainSocket() != null) {
      if (allowShortCircuitLocalReads && !conf.useLegacyBlockReaderLocal) {
        // If this is a domain socket, and short-circuit local reads are
        // enabled, try to set up a BlockReaderLocal.
        BlockReader reader = newShortCircuitBlockReader(conf, file,
            block, blockToken, startOffset, len, peer, datanodeID,
            domSockFactory, verifyChecksum, fisCache);
        if (reader != null) {
          // One we've constructed the short-circuit block reader, we don't
          // need the socket any more.  So let's return it to the cache.
          if (peerCache != null) {
            peerCache.put(datanodeID, peer);
          } else {
            IOUtils.cleanup(null, peer);
          }
          return reader;
        }
      }
      // If this is a domain socket and we couldn't (or didn't want to) set
      // up a BlockReaderLocal, check that we are allowed to pass data traffic
      // over the socket before proceeding.
      if (!conf.domainSocketDataTraffic) {
        throw new IOException("Because we can't do short-circuit access, " +
          "and data traffic over domain sockets is disabled, " +
          "we cannot use this socket to talk to " + datanodeID);
      }
    }

    if (conf.useLegacyBlockReader) {
      @SuppressWarnings("deprecation")
      RemoteBlockReader reader = RemoteBlockReader.newBlockReader(file,
          block, blockToken, startOffset, len, conf.ioBufferSize,
          verifyChecksum, clientName, peer, datanodeID, peerCache,
          cachingStrategy);
      return reader;
    } else {
      return RemoteBlockReader2.newBlockReader(
          file, block, blockToken, startOffset, len,
          verifyChecksum, clientName, peer, datanodeID, peerCache,
          cachingStrategy);
    }
  }

  /**
   * Create a new short-circuit BlockReader.
   *
   * Here, we ask the DataNode to pass us file descriptors over our
   * DomainSocket.  If the DataNode declines to do so, we'll return null here;
   * otherwise, we'll return the BlockReaderLocal.  If the DataNode declines,
   * this function will inform the DomainSocketFactory that short-circuit local
   * reads are disabled for this DataNode, so that we don't ask again.
   *
   * @param conf               the configuration.
   * @param file               the file name. Used in log messages.
   * @param block              The block object.
   * @param blockToken         The block token for security.
   * @param startOffset        The read offset, relative to block head.
   * @param len                The number of bytes to read, or -1 to read
   *                           as many as possible.
   * @param peer               The peer to use.
   * @param datanodeID         The datanode that the Peer is connected to.
   * @param domSockFactory     The DomainSocketFactory to notify if the Peer
   *                           is a DomainPeer which turns out to be faulty.
   *                           If null, no factory will be notified in this
   *                           case.
   * @param verifyChecksum     True if we should verify the checksums.
   *                           Note: even if this is true, when
   *                           DFS_CLIENT_READ_CHECKSUM_SKIP_CHECKSUM_KEY is
   *                           set, we will skip checksums.
   *
   * @return                   The BlockReaderLocal, or null if the
   *                           DataNode declined to provide short-circuit
   *                           access.
   * @throws IOException       If there was a communication error.
   */
  private static BlockReaderLocal newShortCircuitBlockReader(
      DFSClient.Conf conf, String file, ExtendedBlock block,
      Token<BlockTokenIdentifier> blockToken, long startOffset,
      long len, Peer peer, DatanodeID datanodeID,
      DomainSocketFactory domSockFactory, boolean verifyChecksum,
      FileInputStreamCache fisCache) throws IOException {
    final DataOutputStream out =
        new DataOutputStream(new BufferedOutputStream(
          peer.getOutputStream()));
    new Sender(out).requestShortCircuitFds(block, blockToken, 1);
    DataInputStream in =
        new DataInputStream(peer.getInputStream());
    BlockOpResponseProto resp = BlockOpResponseProto.parseFrom(
        PBHelper.vintPrefixed(in));
    DomainSocket sock = peer.getDomainSocket();
    switch (resp.getStatus()) {
    case SUCCESS:
      BlockReaderLocal reader = null;
      byte buf[] = new byte[1];
      FileInputStream fis[] = new FileInputStream[2];
      sock.recvFileInputStreams(fis, buf, 0, buf.length);
      try {
        reader = new BlockReaderLocal(conf, file, block,
            startOffset, len, fis[0], fis[1], datanodeID, verifyChecksum,
            fisCache);
      } finally {
        if (reader == null) {
          IOUtils.cleanup(DFSClient.LOG, fis[0], fis[1]);
        }
      }
      return reader;
    case ERROR_UNSUPPORTED:
      if (!resp.hasShortCircuitAccessVersion()) {
        DFSClient.LOG.warn("short-circuit read access is disabled for " +
            "DataNode " + datanodeID + ".  reason: " + resp.getMessage());
        domSockFactory.disableShortCircuitForPath(sock.getPath());
      } else {
        DFSClient.LOG.warn("short-circuit read access for the file " +
            file + " is disabled for DataNode " + datanodeID +
            ".  reason: " + resp.getMessage());
      }
      return null;
    case ERROR_ACCESS_TOKEN:
      String msg = "access control error while " +
          "attempting to set up short-circuit access to " +
          file + resp.getMessage();
      DFSClient.LOG.debug(msg);
      throw new InvalidBlockTokenException(msg);
    default:
      DFSClient.LOG.warn("error while attempting to set up short-circuit " +
          "access to " + file + ": " + resp.getMessage());
      domSockFactory.disableShortCircuitForPath(sock.getPath());
      return null;
    }
  }

  /**
   * File name to print when accessing a block directly (from servlets)
   * @param s Address of the block location
   * @param poolId Block pool ID of the block
   * @param blockId Block ID of the block
   * @return string that has a file name for debug purposes
   */
  public static String getFileName(final InetSocketAddress s,
      final String poolId, final long blockId) {
    return s.toString() + ":" + poolId + ":" + blockId;
  }

  /**
   * Get {@link BlockReaderLocalLegacy} for short circuited local reads.
   * This block reader implements the path-based style of local reads
   * first introduced in HDFS-2246.
   */
  static BlockReader getLegacyBlockReaderLocal(DFSClient dfsClient,
      String src, ExtendedBlock blk,
      Token<BlockTokenIdentifier> accessToken, DatanodeInfo chosenNode,
      long offsetIntoBlock) throws InvalidToken, IOException {
    try {
      final long length = blk.getNumBytes() - offsetIntoBlock;
      return BlockReaderLocalLegacy.newBlockReader(dfsClient, src, blk,
          accessToken, chosenNode, offsetIntoBlock, length);
    } catch (RemoteException re) {
      throw re.unwrapRemoteException(InvalidToken.class,
          AccessControlException.class);
    }
  }
}
TOP

Related Classes of org.apache.hadoop.hdfs.BlockReaderFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.