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