Exemple #1
0
  /**
   * Writes the current checksum to the stream. If <i>reset</i> is true, then resets the checksum.
   *
   * @return number of bytes written. Will be equal to getChecksumSize();
   */
  public int writeValue(DataOutputStream out, boolean reset) throws IOException {
    if (size <= 0) {
      return 0;
    }

    if (type == CHECKSUM_CRC32) {
      out.writeInt((int) summer.getValue());
    } else {
      throw new IOException("Unknown Checksum " + type);
    }

    if (reset) {
      reset();
    }

    return size;
  }
Exemple #2
0
  /**
   * Writes the current checksum to a buffer. If <i>reset</i> is true, then resets the checksum.
   *
   * @return number of bytes written. Will be equal to getChecksumSize();
   */
  public int writeValue(byte[] buf, int offset, boolean reset) throws IOException {
    if (size <= 0) {
      return 0;
    }

    if (type == CHECKSUM_CRC32) {
      int checksum = (int) summer.getValue();
      buf[offset + 0] = (byte) ((checksum >>> 24) & 0xff);
      buf[offset + 1] = (byte) ((checksum >>> 16) & 0xff);
      buf[offset + 2] = (byte) ((checksum >>> 8) & 0xff);
      buf[offset + 3] = (byte) (checksum & 0xff);
    } else {
      throw new IOException("Unknown Checksum " + type);
    }

    if (reset) {
      reset();
    }

    return size;
  }
  /**
   * Sends upto maxChunks chunks of data.
   *
   * <p>When blockInPosition is >= 0, assumes 'out' is a {@link SocketOutputStream} and tries {@link
   * SocketOutputStream#transferToFully(FileChannel, long, int)} to send data (and updates
   * blockInPosition).
   */
  private int sendChunks(ByteBuffer pkt, int maxChunks, OutputStream out) throws IOException {
    // Sends multiple chunks in one packet with a single write().

    int len = (int) Math.min(endOffset - offset, (((long) bytesPerChecksum) * ((long) maxChunks)));
    int numChunks = (len + bytesPerChecksum - 1) / bytesPerChecksum;
    int packetLen = len + numChunks * checksumSize + 4;
    boolean lastDataPacket = offset + len == endOffset && len > 0;
    pkt.clear();

    PacketHeader header = new PacketHeader(packetLen, offset, seqno, (len == 0), len);
    header.putInBuffer(pkt);

    int checksumOff = pkt.position();
    int checksumLen = numChunks * checksumSize;
    byte[] buf = pkt.array();

    if (checksumSize > 0 && checksumIn != null) {
      try {
        checksumIn.readFully(buf, checksumOff, checksumLen);
      } catch (IOException e) {
        LOG.warn(
            " Could not read or failed to veirfy checksum for data"
                + " at offset "
                + offset
                + " for block "
                + block
                + " got : "
                + StringUtils.stringifyException(e));
        IOUtils.closeStream(checksumIn);
        checksumIn = null;
        if (corruptChecksumOk) {
          if (checksumOff < checksumLen) {
            // Just fill the array with zeros.
            Arrays.fill(buf, checksumOff, checksumLen, (byte) 0);
          }
        } else {
          throw e;
        }
      }

      // write in progress that we need to use to get last checksum
      if (lastDataPacket && lastChunkChecksum != null) {
        int start = checksumOff + checksumLen - checksumSize;
        byte[] updatedChecksum = lastChunkChecksum.getChecksum();

        if (updatedChecksum != null) {
          System.arraycopy(updatedChecksum, 0, buf, start, checksumSize);
        }
      }
    }

    int dataOff = checksumOff + checksumLen;

    if (blockInPosition < 0) {
      // normal transfer
      IOUtils.readFully(blockIn, buf, dataOff, len);

      if (verifyChecksum) {
        int dOff = dataOff;
        int cOff = checksumOff;
        int dLeft = len;

        for (int i = 0; i < numChunks; i++) {
          checksum.reset();
          int dLen = Math.min(dLeft, bytesPerChecksum);
          checksum.update(buf, dOff, dLen);
          if (!checksum.compare(buf, cOff)) {
            long failedPos = offset + len - dLeft;
            throw new ChecksumException("Checksum failed at " + failedPos, failedPos);
          }
          dLeft -= dLen;
          dOff += dLen;
          cOff += checksumSize;
        }
      }
      // writing is done below (mainly to handle IOException)
    }

    try {
      if (blockInPosition >= 0) {
        // use transferTo(). Checks on out and blockIn are already done.

        SocketOutputStream sockOut = (SocketOutputStream) out;
        // first write the packet
        sockOut.write(buf, 0, dataOff);
        // no need to flush. since we know out is not a buffered stream.

        sockOut.transferToFully(((FileInputStream) blockIn).getChannel(), blockInPosition, len);

        blockInPosition += len;
      } else {
        // normal transfer
        out.write(buf, 0, dataOff + len);
      }

    } catch (IOException e) {
      /* Exception while writing to the client. Connection closure from
       * the other end is mostly the case and we do not care much about
       * it. But other things can go wrong, especially in transferTo(),
       * which we do not want to ignore.
       *
       * The message parsing below should not be considered as a good
       * coding example. NEVER do it to drive a program logic. NEVER.
       * It was done here because the NIO throws an IOException for EPIPE.
       */
      String ioem = e.getMessage();
      if (!ioem.startsWith("Broken pipe") && !ioem.startsWith("Connection reset")) {
        LOG.error("BlockSender.sendChunks() exception: ", e);
      }
      throw ioeToSocketException(e);
    }

    if (throttler != null) { // rebalancing so throttle
      throttler.throttle(packetLen);
    }

    return len;
  }