@Override public void flush(final ChannelHandlerContext ctx) throws Exception { if (buffer != null && buffer.isReadable()) { final ByteBuf buf = allocateBuffer(ctx, Unpooled.EMPTY_BUFFER, isPreferDirect(), false); flushBufferedData(buf); ctx.write(buf); } ctx.flush(); }
/** * Creates a new customizable LZ4 encoder. * * @param factory user customizable {@link LZ4Factory} instance * which may be JNI bindings to the original C implementation, a pure Java implementation * or a Java implementation that uses the {@link sun.misc.Unsafe} * @param highCompressor if {@code true} codec will use compressor which requires more memory * and is slower but compresses more efficiently * @param blockSize the maximum number of bytes to try to compress at once, * must be >= 64 and <= 32 M * @param checksum the {@link Checksum} instance to use to check data for integrity * @param maxEncodeSize the maximum size for an encode (compressed) buffer */ public Lz4FrameEncoder(LZ4Factory factory, boolean highCompressor, int blockSize, Checksum checksum, int maxEncodeSize) { if (factory == null) { throw new NullPointerException("factory"); } if (checksum == null) { throw new NullPointerException("checksum"); } compressor = highCompressor ? factory.highCompressor() : factory.fastCompressor(); this.checksum = ByteBufChecksum.wrapChecksum(checksum); compressionLevel = compressionLevel(blockSize); this.blockSize = blockSize; this.maxEncodeSize = ObjectUtil.checkPositive(maxEncodeSize, "maxEncodeSize"); finished = false; }
/** * Close this {@link Lz4FrameEncoder} and so finish the encoding. * The given {@link ChannelFuture} will be notified once the operation * completes and will also be returned. */ public ChannelFuture close(final ChannelPromise promise) { ChannelHandlerContext ctx = ctx(); EventExecutor executor = ctx.executor(); if (executor.inEventLoop()) { return finishEncode(ctx, promise); } else { executor.execute(new Runnable() { @Override public void run() { ChannelFuture f = finishEncode(ctx(), promise); f.addListener(new ChannelPromiseNotifier(promise)); } }); return promise; } }
/** * {@inheritDoc} * * Encodes the input buffer into {@link #blockSize} chunks in the output buffer. Data is only compressed and * written once we hit the {@link #blockSize}; else, it is copied into the backing {@link #buffer} to await * more data. */ @Override protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { if (finished) { if (!out.isWritable(in.readableBytes())) { // out should be EMPTY_BUFFER because we should have allocated enough space above in allocateBuffer. throw ENCODE_FINSHED_EXCEPTION; } out.writeBytes(in); return; } final ByteBuf buffer = this.buffer; int length; while ((length = in.readableBytes()) > 0) { final int nextChunkSize = Math.min(length, buffer.writableBytes()); in.readBytes(buffer, nextChunkSize); if (!buffer.isWritable()) { flushBufferedData(out); } } }
@Override protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) { return allocateBuffer(ctx, msg, preferDirect, true); }
@Override public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { ChannelFuture f = finishEncode(ctx, ctx.newPromise()); f.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { ctx.close(promise); } }); if (!f.isDone()) { // Ensure the channel is closed even if the write operation completes in time. ctx.executor().schedule(new Runnable() { @Override public void run() { ctx.close(promise); } }, 10, TimeUnit.SECONDS); // FIXME: Magic number } }
/** * Close this {@link Lz4FrameEncoder} and so finish the encoding. * The given {@link ChannelFuture} will be notified once the operation * completes and will also be returned. */ public ChannelFuture close(final ChannelPromise promise) { ChannelHandlerContext ctx = ctx(); EventExecutor executor = ctx.executor(); if (executor.inEventLoop()) { return finishEncode(ctx, promise); } else { executor.execute(new Runnable() { @Override public void run() { ChannelFuture f = finishEncode(ctx(), promise); f.addListener(new ChannelPromiseNotifier(promise)); } }); return promise; } }
/** * {@inheritDoc} * * Encodes the input buffer into {@link #blockSize} chunks in the output buffer. Data is only compressed and * written once we hit the {@link #blockSize}; else, it is copied into the backing {@link #buffer} to await * more data. */ @Override protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { if (finished) { if (!out.isWritable(in.readableBytes())) { // out should be EMPTY_BUFFER because we should have allocated enough space above in allocateBuffer. throw ENCODE_FINSHED_EXCEPTION; } out.writeBytes(in); return; } final ByteBuf buffer = this.buffer; int length; while ((length = in.readableBytes()) > 0) { final int nextChunkSize = Math.min(length, buffer.writableBytes()); in.readBytes(buffer, nextChunkSize); if (!buffer.isWritable()) { flushBufferedData(out); } } }
@Override protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) { return allocateBuffer(ctx, msg, preferDirect, true); }
@Override public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { ChannelFuture f = finishEncode(ctx, ctx.newPromise()); f.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { ctx.close(promise); } }); if (!f.isDone()) { // Ensure the channel is closed even if the write operation completes in time. ctx.executor().schedule(new Runnable() { @Override public void run() { ctx.close(promise); } }, 10, TimeUnit.SECONDS); // FIXME: Magic number } }
@Override public void flush(final ChannelHandlerContext ctx) throws Exception { if (buffer != null && buffer.isReadable()) { final ByteBuf buf = allocateBuffer(ctx, Unpooled.EMPTY_BUFFER, isPreferDirect(), false); flushBufferedData(buf); ctx.write(buf); } ctx.flush(); }
/** * Close this {@link Lz4FrameEncoder} and so finish the encoding. * The given {@link ChannelFuture} will be notified once the operation * completes and will also be returned. */ public ChannelFuture close(final ChannelPromise promise) { ChannelHandlerContext ctx = ctx(); EventExecutor executor = ctx.executor(); if (executor.inEventLoop()) { return finishEncode(ctx, promise); } else { executor.execute(new Runnable() { @Override public void run() { ChannelFuture f = finishEncode(ctx(), promise); f.addListener(new ChannelPromiseNotifier(promise)); } }); return promise; } }
private ChannelFuture finishEncode(final ChannelHandlerContext ctx, ChannelPromise promise) { if (finished) { promise.setSuccess(); return promise; } finished = true; final ByteBuf footer = ctx.alloc().heapBuffer( compressor.maxCompressedLength(buffer.readableBytes()) + HEADER_LENGTH); flushBufferedData(footer); final int idx = footer.writerIndex(); footer.setLong(idx, MAGIC_NUMBER); footer.setByte(idx + TOKEN_OFFSET, (byte) (BLOCK_TYPE_NON_COMPRESSED | compressionLevel)); footer.setInt(idx + COMPRESSED_LENGTH_OFFSET, 0); footer.setInt(idx + DECOMPRESSED_LENGTH_OFFSET, 0); footer.setInt(idx + CHECKSUM_OFFSET, 0); footer.writerIndex(idx + HEADER_LENGTH); return ctx.writeAndFlush(footer, promise); }
@Override protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) { return allocateBuffer(ctx, msg, preferDirect, true); }
@Override public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { ChannelFuture f = finishEncode(ctx, ctx.newPromise()); f.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { ctx.close(promise); } }); if (!f.isDone()) { // Ensure the channel is closed even if the write operation completes in time. ctx.executor().schedule(new Runnable() { @Override public void run() { ctx.close(promise); } }, 10, TimeUnit.SECONDS); // FIXME: Magic number } }
/** * Creates a new customizable LZ4 encoder. * * @param factory user customizable {@link LZ4Factory} instance * which may be JNI bindings to the original C implementation, a pure Java implementation * or a Java implementation that uses the {@link sun.misc.Unsafe} * @param highCompressor if {@code true} codec will use compressor which requires more memory * and is slower but compresses more efficiently * @param blockSize the maximum number of bytes to try to compress at once, * must be >= 64 and <= 32 M * @param checksum the {@link Checksum} instance to use to check data for integrity * @param maxEncodeSize the maximum size for an encode (compressed) buffer */ public Lz4FrameEncoder(LZ4Factory factory, boolean highCompressor, int blockSize, Checksum checksum, int maxEncodeSize) { if (factory == null) { throw new NullPointerException("factory"); } if (checksum == null) { throw new NullPointerException("checksum"); } compressor = highCompressor ? factory.highCompressor() : factory.fastCompressor(); this.checksum = ByteBufChecksum.wrapChecksum(checksum); compressionLevel = compressionLevel(blockSize); this.blockSize = blockSize; this.maxEncodeSize = ObjectUtil.checkPositive(maxEncodeSize, "maxEncodeSize"); finished = false; }
@Override public void flush(final ChannelHandlerContext ctx) throws Exception { if (buffer != null && buffer.isReadable()) { final ByteBuf buf = allocateBuffer(ctx, Unpooled.EMPTY_BUFFER, isPreferDirect(), false); flushBufferedData(buf); ctx.write(buf); } ctx.flush(); }