Example #1
0
  /**
   * sendBlock() is used to read block and its metadata and stream the data to either a client or to
   * another datanode.
   *
   * @param out stream to which the block is written to
   * @param baseStream optional. if non-null, <code>out</code> is assumed to be a wrapper over this
   *     stream. This enables optimizations for sending the data, e.g. {@link
   *     SocketOutputStream#transferToFully(FileChannel, long, int)}.
   * @param throttler for sending data.
   * @return total bytes reads, including crc.
   */
  long sendBlock(DataOutputStream out, OutputStream baseStream, DataTransferThrottler throttler)
      throws IOException {
    if (out == null) {
      throw new IOException("out stream is null");
    }
    this.throttler = throttler;

    long initialOffset = offset;
    long totalRead = 0;
    OutputStream streamForSendChunks = out;

    final long startTime = ClientTraceLog.isInfoEnabled() ? System.nanoTime() : 0;
    try {
      try {
        checksum.writeHeader(out);
        if (chunkOffsetOK) {
          out.writeLong(offset);
        }
        out.flush();
      } catch (IOException e) { // socket error
        throw ioeToSocketException(e);
      }

      int maxChunksPerPacket;
      int pktSize = PacketHeader.PKT_HEADER_LEN;

      if (transferToAllowed
          && !verifyChecksum
          && baseStream instanceof SocketOutputStream
          && blockIn instanceof FileInputStream) {

        FileChannel fileChannel = ((FileInputStream) blockIn).getChannel();

        // blockInPosition also indicates sendChunks() uses transferTo.
        blockInPosition = fileChannel.position();
        streamForSendChunks = baseStream;

        // assure a mininum buffer size.
        maxChunksPerPacket =
            (Math.max(BUFFER_SIZE, MIN_BUFFER_WITH_TRANSFERTO) + bytesPerChecksum - 1)
                / bytesPerChecksum;

        // allocate smaller buffer while using transferTo().
        pktSize += checksumSize * maxChunksPerPacket;
      } else {
        maxChunksPerPacket = Math.max(1, (BUFFER_SIZE + bytesPerChecksum - 1) / bytesPerChecksum);
        pktSize += (bytesPerChecksum + checksumSize) * maxChunksPerPacket;
      }

      ByteBuffer pktBuf = ByteBuffer.allocate(pktSize);

      while (endOffset > offset) {
        long len = sendChunks(pktBuf, maxChunksPerPacket, streamForSendChunks);
        offset += len;
        totalRead += len + ((len + bytesPerChecksum - 1) / bytesPerChecksum * checksumSize);
        seqno++;
      }
      try {
        // send an empty packet to mark the end of the block
        sendChunks(pktBuf, maxChunksPerPacket, streamForSendChunks);
        out.flush();
      } catch (IOException e) { // socket error
        throw ioeToSocketException(e);
      }

      sentEntireByteRange = true;
    } finally {
      if (clientTraceFmt != null) {
        final long endTime = System.nanoTime();
        ClientTraceLog.info(
            String.format(clientTraceFmt, totalRead, initialOffset, endTime - startTime));
      }
      close();
    }

    blockReadFully = initialOffset == 0 && offset >= replicaVisibleLength;

    return totalRead;
  }