@Override public int read() throws IOException { mReadByte++; if (mReadByte > mBlockInfo.length) { doneRecache(); return -1; } if (mCurrentBuffer != null) { if (mCurrentBuffer.remaining() == 0) { mBufferStartPosition = mReadByte - 1; updateCurrentBuffer(); } if (mCurrentBuffer != null) { int ret = mCurrentBuffer.get() & 0xFF; if (mRecache) { mBlockOutStream.write(ret); } return ret; } setupStreamFromUnderFs(mBlockInfo.offset + mReadByte - 1, mUFSConf); } int ret = mCheckpointInputStream.read() & 0xFF; if (mRecache) { mBlockOutStream.write(ret); } return ret; }
@Override public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } long ret = mBlockInfo.length - mReadByte; if (ret < len) { len = (int) ret; } if (ret == 0) { return -1; } if (mCurrentBuffer != null) { if (mCurrentBuffer.remaining() == 0) { mBufferStartPosition = mReadByte; updateCurrentBuffer(); } if (mCurrentBuffer != null) { ret = Math.min(ret, mCurrentBuffer.remaining()); ret = Math.min(ret, len); mCurrentBuffer.get(b, off, (int) ret); mReadByte += ret; if (mRecache) { mBlockOutStream.write(b, off, (int) ret); if (mReadByte == mBlockInfo.length) { doneRecache(); } } return (int) ret; } setupStreamFromUnderFs(mBlockInfo.offset + mReadByte, mUFSConf); } ret = mCheckpointInputStream.read(b, off, len); mReadByte += ret; if (mRecache) { mBlockOutStream.write(b, off, (int) ret); if (mReadByte == mBlockInfo.length) { doneRecache(); } } return (int) ret; }
/** * Cancels the re-caching attempt * * @throws IOException when the underlying stream cannot be canceled */ private void cancelRecache() throws IOException { if (mRecache) { mRecache = false; if (mBlockOutStream != null) { mBlockOutStream.cancel(); } } }
@Override public void close() throws IOException { if (!mClosed) { if (mRecache) { mBlockOutStream.cancel(); } if (mCheckpointInputStream != null) { mCheckpointInputStream.close(); } } mClosed = true; }
@Override public long skip(long n) throws IOException { if (n <= 0) { return 0; } long ret = mBlockInfo.length - mReadByte; if (ret > n) { ret = n; } if (mCurrentBuffer != null) { if (mCurrentBuffer.remaining() < ret) { mBufferStartPosition = mReadByte + ret; updateCurrentBuffer(); } if (mCurrentBuffer != null) { if (ret > 0) { if (mRecache) { mBlockOutStream.cancel(); } mRecache = false; } return (int) ret; } setupStreamFromUnderFs(mBlockInfo.offset + mReadByte, mUFSConf); } long tmp = mCheckpointInputStream.skip(ret); ret = Math.min(ret, tmp); mReadByte += ret; if (ret > 0) { if (mRecache) { mBlockOutStream.cancel(); } mRecache = false; } return ret; }
@Override public void close() throws IOException { if (mClosed) { return; } if (mRecache && mBlockOutStream != null) { // We only finish re-caching if we've gotten to the end of the file if (mBlockPos == mBlockInfo.length) { mBlockOutStream.close(); } else { mBlockOutStream.cancel(); } } if (mCheckpointInputStream != null) { mCheckpointInputStream.close(); } if (mBytesReadRemote > 0) { mTachyonFS.getClientMetrics().incBlocksReadRemote(1); } closeReader(); mClosed = true; }
/** * Re-cache the block into memory * * @param blockIndex The block index of the current file. * @return true if succeed, false otherwise * @throws IOException */ boolean recache(int blockIndex) throws IOException { String path = getUfsPath(); UnderFileSystem underFsClient = UnderFileSystem.get(path, mTachyonConf); InputStream inputStream = null; BlockOutStream bos = null; try { inputStream = underFsClient.open(path); long length = getBlockSizeByte(); long offset = blockIndex * length; inputStream.skip(offset); int bufferBytes = (int) mTachyonConf.getBytes(Constants.USER_FILE_BUFFER_BYTES, Constants.MB); byte[] buffer = new byte[bufferBytes]; bos = BlockOutStream.get(this, WriteType.TRY_CACHE, blockIndex, mTachyonConf); int limit; while (length > 0 && ((limit = inputStream.read(buffer)) >= 0)) { if (limit != 0) { if (length >= limit) { bos.write(buffer, 0, limit); length -= limit; } else { bos.write(buffer, 0, (int) length); length = 0; } } } bos.close(); } catch (IOException e) { LOG.warn(e.getMessage(), e); if (bos != null) { bos.cancel(); } return false; } finally { if (inputStream != null) { inputStream.close(); } } return true; }
private void doneRecache() throws IOException { if (mRecache) { mBlockOutStream.close(); } }
@Override public int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } else if (mBlockPos == mBlockInfo.length) { return -1; } // We read at most len bytes, but if mBlockPos + len exceeds the length of the file, we only // read up to the end of the file len = (int) Math.min(len, mBlockInfo.length - mBlockPos); int bytesLeft = len; // Lazy initialization of the out stream for caching to avoid collisions with other caching // attempts that are invalidated later due to seek/skips if (bytesLeft > 0 && mBlockOutStream == null && mRecache) { try { mBlockOutStream = BlockOutStream.get(mFile, WriteType.TRY_CACHE, mBlockIndex, mTachyonConf); // We should only cache when we are writing to a local worker if (mBlockOutStream instanceof RemoteBlockOutStream) { LOG.info("Cannot find a local worker to write to, recache attempt cancelled."); cancelRecache(); } } catch (IOException ioe) { LOG.warn("Recache attempt failed.", ioe); cancelRecache(); } } // While we still have bytes to read, make sure the buffer is set to read the byte at mBlockPos. // If we fail to set mCurrentBuffer, we stream the rest from the underfs while (bytesLeft > 0 && mAttemptReadFromWorkers && updateCurrentBuffer()) { int bytesToRead = Math.min(bytesLeft, mCurrentBuffer.remaining()); mCurrentBuffer.get(b, off, bytesToRead); if (mRecache) { mBlockOutStream.write(b, off, bytesToRead); } off += bytesToRead; bytesLeft -= bytesToRead; mBlockPos += bytesToRead; } mBytesReadRemote += len - bytesLeft; mTachyonFS.getClientMetrics().incBytesReadRemote(len - bytesLeft); if (bytesLeft > 0) { // Unable to read from worker memory, reading this block from underfs in the future. mAttemptReadFromWorkers = false; // We failed to read everything from mCurrentBuffer, so we need to stream the rest from the // underfs if (!setupStreamFromUnderFs()) { LOG.error( "Failed to read at position " + mBlockPos + " in block " + mBlockInfo.getBlockId() + " from workers or underfs"); // Return the number of bytes we managed to read return len - bytesLeft; } while (bytesLeft > 0) { int readBytes = mCheckpointInputStream.read(b, off, bytesLeft); if (readBytes <= 0) { LOG.error("Checkpoint stream read 0 bytes, which shouldn't ever happen"); return len - bytesLeft; } if (mRecache) { mBlockOutStream.write(b, off, readBytes); } off += readBytes; bytesLeft -= readBytes; mBlockPos += readBytes; mCheckpointPos += readBytes; mTachyonFS.getClientMetrics().incBytesReadUfs(readBytes); } } return len; }