/** * @param file the file the block belongs to * @param readType the InStream's read type * @param blockIndex the index of the block in the file * @param ufsConf the under file system configuration * @throws IOException */ RemoteBlockInStream(TachyonFile file, ReadType readType, int blockIndex, Object ufsConf) throws IOException { super(file, readType, blockIndex); mBlockInfo = TFS.getClientBlockInfo(FILE.FID, BLOCK_INDEX); mReadByte = 0; mBufferStartPosition = 0; if (!FILE.isComplete()) { throw new IOException("File " + FILE.getPath() + " is not ready to read"); } mRecache = readType.isCache(); if (mRecache) { mBlockOutStream = new BlockOutStream(file, WriteType.TRY_CACHE, blockIndex); } updateCurrentBuffer(); mUFSConf = ufsConf; if (mCurrentBuffer == null) { setupStreamFromUnderFs(mBlockInfo.offset, mUFSConf); if (mCheckpointInputStream == null) { TFS.reportLostFile(FILE.FID); throw new IOException("Can not find the block " + FILE + " " + BLOCK_INDEX); } } }
private synchronized void appendCurrentBuffer(byte[] buf, int offset, int length) throws IOException { if (!TFS.requestSpace(length)) { mCanWrite = false; String msg = "Local tachyon worker does not have enough " + "space (" + length + ") or no worker for " + FILE.FID + " " + BLOCK_ID; if (PIN) { TFS.outOfMemoryForPinFile(FILE.FID); throw new IOException(msg); } throw new IOException(msg); } MappedByteBuffer out = mLocalFileChannel.map(MapMode.READ_WRITE, mInFileBytes, length); out.put(buf, 0, length); mInFileBytes += length; }
private void setupStreamFromUnderFs(long offset, Object conf) throws IOException { String checkpointPath = TFS.getUfsPath(FILE.FID); if (!checkpointPath.equals("")) { LOG.info("May stream from underlayer fs: " + checkpointPath); UnderFileSystem underfsClient = UnderFileSystem.get(checkpointPath, conf); try { mCheckpointInputStream = underfsClient.open(checkpointPath); while (offset > 0) { long skipped = mCheckpointInputStream.skip(offset); offset -= skipped; if (skipped == 0) { throw new IOException( "Failed to find the start position " + offset + " for block " + mBlockInfo); } } } catch (IOException e) { LOG.error( "Failed to read from checkpoint " + checkpointPath + " for File " + FILE.FID + "\n" + e); mCheckpointInputStream = null; } } }
BlockOutStream(TachyonFile file, WriteType opType, int blockIndex) throws IOException { super(file, opType); if (!opType.isCache()) { throw new IOException("BlockOutStream only support WriteType.CACHE"); } BLOCK_INDEX = blockIndex; BLOCK_CAPACITY_BYTE = FILE.getBlockSizeByte(); BLOCK_ID = FILE.getBlockId(BLOCK_INDEX); BLOCK_OFFSET = BLOCK_CAPACITY_BYTE * blockIndex; PIN = FILE.needPin(); mCanWrite = true; if (!TFS.hasLocalWorker()) { mCanWrite = false; String msg = "The machine does not have any local worker."; throw new IOException(msg); } File localFolder = TFS.createAndGetUserTempFolder(); if (localFolder == null) { mCanWrite = false; String msg = "Failed to create temp user folder for tachyon client."; throw new IOException(msg); } mLocalFilePath = CommonUtils.concat(localFolder.getPath(), BLOCK_ID); mLocalFile = new RandomAccessFile(mLocalFilePath, "rw"); mLocalFileChannel = mLocalFile.getChannel(); // change the permission of the temporary file in order that the worker can move it. CommonUtils.changeLocalFileToFullPermission(mLocalFilePath); // use the sticky bit, only the client and the worker can write to the block CommonUtils.setLocalFileStickyBit(mLocalFilePath); LOG.info(mLocalFilePath + " was created!"); mBuffer = ByteBuffer.allocate(USER_CONF.FILE_BUFFER_BYTES + 4); }
@Override public void close() throws IOException { if (!mClosed) { if (!mCancel && mBuffer.position() > 0) { appendCurrentBuffer(mBuffer.array(), 0, mBuffer.position()); } if (mLocalFileChannel != null) { mLocalFileChannel.close(); mLocalFile.close(); } if (mCancel) { TFS.releaseSpace(mWrittenBytes - mBuffer.position()); new File(mLocalFilePath).delete(); LOG.info("Canceled output of block " + BLOCK_ID + ", deleted local file " + mLocalFilePath); } else { TFS.cacheBlock(BLOCK_ID); } } mClosed = true; }
private ByteBuffer readRemoteByteBuffer(ClientBlockInfo blockInfo, long offset, long len) { ByteBuffer buf = null; try { List<NetAddress> blockLocations = blockInfo.getLocations(); LOG.info("Block locations:" + blockLocations); for (int k = 0; k < blockLocations.size(); k++) { String host = blockLocations.get(k).mHost; int port = blockLocations.get(k).mSecondaryPort; // The data is not in remote machine's memory if port == -1. if (port == -1) { continue; } if (host.equals(InetAddress.getLocalHost().getHostName()) || host.equals(InetAddress.getLocalHost().getHostAddress())) { String localFileName = CommonUtils.concat(TFS.getRootFolder(), blockInfo.blockId); LOG.warn("Master thinks the local machine has data " + localFileName + "! But not!"); } LOG.info( host + ":" + port + " current host is " + InetAddress.getLocalHost().getHostName() + " " + InetAddress.getLocalHost().getHostAddress()); try { buf = retrieveByteBufferFromRemoteMachine( new InetSocketAddress(host, port), blockInfo.blockId, offset, len); if (buf != null) { break; } } catch (IOException e) { LOG.error(e.getMessage()); buf = null; } } } catch (IOException e) { LOG.error("Failed to get read data from remote " + e.getMessage()); buf = null; } return buf; }
private void updateCurrentBuffer() throws IOException { long length = BUFFER_SIZE; if (mBufferStartPosition + length > mBlockInfo.length) { length = mBlockInfo.length - mBufferStartPosition; } LOG.info( String.format( "Try to find remote worker and read block %d from %d, with len %d", mBlockInfo.blockId, mBufferStartPosition, length)); mCurrentBuffer = readRemoteByteBuffer(mBlockInfo, mBufferStartPosition, length); if (mCurrentBuffer == null) { mBlockInfo = TFS.getClientBlockInfo(FILE.FID, BLOCK_INDEX); mCurrentBuffer = readRemoteByteBuffer(mBlockInfo, mBufferStartPosition, length); } }