/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.client.block.stream; import alluxio.client.BoundedStream; import alluxio.client.Cancelable; import alluxio.client.block.BlockWorkerClient; import alluxio.client.file.FileSystemContext; import alluxio.client.file.options.OutStreamOptions; import alluxio.proto.dataserver.Protocol; import alluxio.util.CommonUtils; import alluxio.wire.WorkerNetAddress; import com.google.common.io.Closer; import java.io.FilterOutputStream; import java.io.IOException; import javax.annotation.concurrent.NotThreadSafe; /** * Provides a stream API to write a block to Alluxio. An instance of this class can be obtained by * calling * {@link alluxio.client.block.AlluxioBlockStore#getOutStream(long, long, OutStreamOptions)}. */ @NotThreadSafe public class BlockOutStream extends FilterOutputStream implements BoundedStream, Cancelable { private final long mBlockId; private final long mBlockSize; private final Closer mCloser; private final BlockWorkerClient mBlockWorkerClient; private final PacketOutStream mOutStream; private boolean mClosed; /** * Creates a new block output stream that writes to local file directly. * * @param blockId the block id * @param blockSize the block size * @param workerNetAddress the worker network address * @param context the file system context * @param options the options * @return the {@link BlockOutStream} instance created */ public static BlockOutStream createShortCircuitBlockOutStream(long blockId, long blockSize, WorkerNetAddress workerNetAddress, FileSystemContext context, OutStreamOptions options) throws IOException { Closer closer = Closer.create(); try { BlockWorkerClient client = closer.register(context.createBlockWorkerClient(workerNetAddress)); PacketOutStream outStream = PacketOutStream .createLocalPacketOutStream(client, blockId, blockSize, options); closer.register(outStream); return new BlockOutStream(outStream, blockId, blockSize, client, options); } catch (Throwable t) { throw CommonUtils.closeAndRethrow(closer, t); } } /** * Creates a new netty block output stream. * * @param blockId the block id * @param blockSize the block size * @param workerNetAddress the worker network address * @param context the file system context * @param options the options * @return the {@link BlockOutStream} instance created */ public static BlockOutStream createNettyBlockOutStream(long blockId, long blockSize, WorkerNetAddress workerNetAddress, FileSystemContext context, OutStreamOptions options) throws IOException { Closer closer = Closer.create(); try { BlockWorkerClient client = closer.register(context.createBlockWorkerClient(workerNetAddress)); PacketOutStream outStream = PacketOutStream .createNettyPacketOutStream(context, workerNetAddress, client.getSessionId(), blockId, blockSize, Protocol.RequestType.ALLUXIO_BLOCK, options); closer.register(outStream); return new BlockOutStream(outStream, blockId, blockSize, client, options); } catch (Throwable t) { throw CommonUtils.closeAndRethrow(closer, t); } } // Explicitly overriding some write methods which are not efficiently implemented in // FilterOutStream. @Override public void write(byte[] b) throws IOException { mOutStream.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { mOutStream.write(b, off, len); } @Override public long remaining() { return mOutStream.remaining(); } @Override public void cancel() throws IOException { if (mClosed) { return; } IOException exception = null; try { mOutStream.cancel(); } catch (IOException e) { exception = e; } try { mBlockWorkerClient.cancelBlock(mBlockId); } catch (IOException e) { exception = e; } if (exception == null) { mClosed = true; return; } mClosed = true; throw CommonUtils.closeAndRethrow(mCloser, exception); } @Override public void close() throws IOException { if (mClosed) { return; } try { mOutStream.close(); if (remaining() < mBlockSize) { mBlockWorkerClient.cacheBlock(mBlockId); } } catch (Throwable t) { mCloser.rethrow(t); } finally { mCloser.close(); mClosed = true; } } /** * Creates a new block output stream. * * @param outStream the {@link PacketOutStream} associated with this {@link BlockOutStream} * @param blockId the block id * @param blockSize the block size * @param blockWorkerClient the block worker client * @param options the options */ protected BlockOutStream(PacketOutStream outStream, long blockId, long blockSize, BlockWorkerClient blockWorkerClient, OutStreamOptions options) { super(outStream); mOutStream = outStream; mBlockId = blockId; mBlockSize = blockSize; mCloser = Closer.create(); mBlockWorkerClient = mCloser.register(blockWorkerClient); mClosed = false; } }