Better buffer leak reporting
- Remove the reference to ResourceLeak from the buffer implementations and use wrappers instead: - SimpleLeakAwareByteBuf and AdvancedLeakAwareByteBuf - It is now allocator's responsibility to create a leak-aware buffer. - Added AbstractByteBufAllocator.toLeakAwareBuffer() for easier implementation - Add WrappedByteBuf to reduce duplication between *LeakAwareByteBuf and UnreleasableByteBuf - Raise the level of leak reports to ERROR - because it will break the app eventually - Replace enabled/disabled property with the leak detection level - Only print stack trace when level is ADVANCED or above to avoid user confusion - Add the 'leak' build profile, which enables highly detailed leak reporting during the build - Remove ResourceLeakException which is unsed anymore
This commit is contained in:
parent
6bba3c19dd
commit
6431be8954
@ -16,6 +16,8 @@
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
@ -26,6 +28,26 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
|
||||
private static final int DEFAULT_INITIAL_CAPACITY = 256;
|
||||
private static final int DEFAULT_MAX_COMPONENTS = 16;
|
||||
|
||||
protected static ByteBuf toLeakAwareBuffer(ByteBuf buf) {
|
||||
ResourceLeak leak;
|
||||
switch (ResourceLeakDetector.getLevel()) {
|
||||
case SIMPLE:
|
||||
leak = AbstractByteBuf.leakDetector.open(buf);
|
||||
if (leak != null) {
|
||||
buf = new SimpleLeakAwareByteBuf(buf, leak);
|
||||
}
|
||||
break;
|
||||
case ADVANCED:
|
||||
case PARANOID:
|
||||
leak = AbstractByteBuf.leakDetector.open(buf);
|
||||
if (leak != null) {
|
||||
buf = new AdvancedLeakAwareByteBuf(buf, leak);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
private final boolean directByDefault;
|
||||
private final ByteBuf emptyBuf;
|
||||
|
||||
|
@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
final class AdvancedLeakAwareByteBuf extends WrappedByteBuf {
|
||||
|
||||
private final ResourceLeak leak;
|
||||
|
||||
AdvancedLeakAwareByteBuf(ByteBuf buf, ResourceLeak leak) {
|
||||
super(buf);
|
||||
this.leak = leak;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardReadBytes() {
|
||||
leak.record();
|
||||
return super.discardReadBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardSomeReadBytes() {
|
||||
leak.record();
|
||||
return super.discardSomeReadBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf ensureWritable(int minWritableBytes) {
|
||||
leak.record();
|
||||
return super.ensureWritable(minWritableBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ensureWritable(int minWritableBytes, boolean force) {
|
||||
leak.record();
|
||||
return super.ensureWritable(minWritableBytes, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int index) {
|
||||
leak.record();
|
||||
return super.getBoolean(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int index) {
|
||||
leak.record();
|
||||
return super.getByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getUnsignedByte(int index) {
|
||||
leak.record();
|
||||
return super.getUnsignedByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
leak.record();
|
||||
return super.getShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShort(int index) {
|
||||
leak.record();
|
||||
return super.getUnsignedShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMedium(int index) {
|
||||
leak.record();
|
||||
return super.getMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMedium(int index) {
|
||||
leak.record();
|
||||
return super.getUnsignedMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
leak.record();
|
||||
return super.getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedInt(int index) {
|
||||
leak.record();
|
||||
return super.getUnsignedInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
leak.record();
|
||||
return super.getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
leak.record();
|
||||
return super.getChar(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
leak.record();
|
||||
return super.getFloat(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int index) {
|
||||
leak.record();
|
||||
return super.getDouble(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst, dstIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst, dstIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuffer dst) {
|
||||
leak.record();
|
||||
return super.getBytes(index, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.getBytes(index, out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.getBytes(index, out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBoolean(int index, boolean value) {
|
||||
leak.record();
|
||||
return super.setBoolean(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setByte(int index, int value) {
|
||||
leak.record();
|
||||
return super.setByte(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setShort(int index, int value) {
|
||||
leak.record();
|
||||
return super.setShort(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMedium(int index, int value) {
|
||||
leak.record();
|
||||
return super.setMedium(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setInt(int index, int value) {
|
||||
leak.record();
|
||||
return super.setInt(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLong(int index, long value) {
|
||||
leak.record();
|
||||
return super.setLong(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setChar(int index, int value) {
|
||||
leak.record();
|
||||
return super.setChar(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setFloat(int index, float value) {
|
||||
leak.record();
|
||||
return super.setFloat(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setDouble(int index, double value) {
|
||||
leak.record();
|
||||
return super.setDouble(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int length) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src, srcIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src, srcIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuffer src) {
|
||||
leak.record();
|
||||
return super.setBytes(index, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, InputStream in, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setZero(int index, int length) {
|
||||
leak.record();
|
||||
return super.setZero(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
leak.record();
|
||||
return super.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() {
|
||||
leak.record();
|
||||
return super.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readUnsignedByte() {
|
||||
leak.record();
|
||||
return super.readUnsignedByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() {
|
||||
leak.record();
|
||||
return super.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShort() {
|
||||
leak.record();
|
||||
return super.readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMedium() {
|
||||
leak.record();
|
||||
return super.readMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMedium() {
|
||||
leak.record();
|
||||
return super.readUnsignedMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() {
|
||||
leak.record();
|
||||
return super.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
leak.record();
|
||||
return super.readUnsignedInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
leak.record();
|
||||
return super.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
leak.record();
|
||||
return super.readChar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat() {
|
||||
leak.record();
|
||||
return super.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() {
|
||||
leak.record();
|
||||
return super.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(int length) {
|
||||
leak.record();
|
||||
return super.readBytes(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readSlice(int length) {
|
||||
leak.record();
|
||||
return super.readSlice(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst) {
|
||||
leak.record();
|
||||
return super.readBytes(dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int length) {
|
||||
leak.record();
|
||||
return super.readBytes(dst, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
|
||||
leak.record();
|
||||
return super.readBytes(dst, dstIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst) {
|
||||
leak.record();
|
||||
return super.readBytes(dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
|
||||
leak.record();
|
||||
return super.readBytes(dst, dstIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuffer dst) {
|
||||
leak.record();
|
||||
return super.readBytes(dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(OutputStream out, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.readBytes(out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBytes(GatheringByteChannel out, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.readBytes(out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf skipBytes(int length) {
|
||||
leak.record();
|
||||
return super.skipBytes(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBoolean(boolean value) {
|
||||
leak.record();
|
||||
return super.writeBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeByte(int value) {
|
||||
leak.record();
|
||||
return super.writeByte(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeShort(int value) {
|
||||
leak.record();
|
||||
return super.writeShort(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMedium(int value) {
|
||||
leak.record();
|
||||
return super.writeMedium(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeInt(int value) {
|
||||
leak.record();
|
||||
return super.writeInt(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLong(long value) {
|
||||
leak.record();
|
||||
return super.writeLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeChar(int value) {
|
||||
leak.record();
|
||||
return super.writeChar(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeFloat(float value) {
|
||||
leak.record();
|
||||
return super.writeFloat(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeDouble(double value) {
|
||||
leak.record();
|
||||
return super.writeDouble(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src) {
|
||||
leak.record();
|
||||
return super.writeBytes(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int length) {
|
||||
leak.record();
|
||||
return super.writeBytes(src, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
|
||||
leak.record();
|
||||
return super.writeBytes(src, srcIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src) {
|
||||
leak.record();
|
||||
return super.writeBytes(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
|
||||
leak.record();
|
||||
return super.writeBytes(src, srcIndex, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuffer src) {
|
||||
leak.record();
|
||||
return super.writeBytes(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(InputStream in, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
|
||||
leak.record();
|
||||
return super.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeZero(int length) {
|
||||
leak.record();
|
||||
return super.writeZero(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(int fromIndex, int toIndex, byte value) {
|
||||
leak.record();
|
||||
return super.indexOf(fromIndex, toIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(byte value) {
|
||||
leak.record();
|
||||
return super.bytesBefore(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int length, byte value) {
|
||||
leak.record();
|
||||
return super.bytesBefore(length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int index, int length, byte value) {
|
||||
leak.record();
|
||||
return super.bytesBefore(index, length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
leak.record();
|
||||
return super.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy() {
|
||||
leak.record();
|
||||
return super.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
leak.record();
|
||||
return super.copy(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice() {
|
||||
leak.record();
|
||||
return super.slice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice(int index, int length) {
|
||||
leak.record();
|
||||
return super.slice(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf duplicate() {
|
||||
leak.record();
|
||||
return super.duplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nioBufferCount() {
|
||||
leak.record();
|
||||
return super.nioBufferCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
leak.record();
|
||||
return super.nioBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer(int index, int length) {
|
||||
leak.record();
|
||||
return super.nioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers() {
|
||||
leak.record();
|
||||
return super.nioBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers(int index, int length) {
|
||||
leak.record();
|
||||
return super.nioBuffers(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer internalNioBuffer(int index, int length) {
|
||||
leak.record();
|
||||
return super.internalNioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Charset charset) {
|
||||
leak.record();
|
||||
return super.toString(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int index, int length, Charset charset) {
|
||||
leak.record();
|
||||
return super.toString(index, length, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
boolean deallocated = super.release();
|
||||
if (deallocated) {
|
||||
leak.close();
|
||||
}
|
||||
return deallocated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
boolean deallocated = super.release(decrement);
|
||||
if (deallocated) {
|
||||
leak.close();
|
||||
}
|
||||
return deallocated;
|
||||
}
|
||||
}
|
@ -17,14 +17,12 @@
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.Recycler;
|
||||
import io.netty.util.ResourceLeak;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
||||
|
||||
private final ResourceLeak leak;
|
||||
private final Recycler.Handle recyclerHandle;
|
||||
|
||||
protected PoolChunk<T> chunk;
|
||||
@ -38,7 +36,6 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
||||
|
||||
protected PooledByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) {
|
||||
super(maxCapacity);
|
||||
leak = leakDetector.open(this);
|
||||
this.recyclerHandle = recyclerHandle;
|
||||
}
|
||||
|
||||
@ -144,11 +141,7 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
||||
this.handle = -1;
|
||||
memory = null;
|
||||
chunk.arena.free(chunk, handle);
|
||||
if (leak != null) {
|
||||
leak.close();
|
||||
} else {
|
||||
recycle();
|
||||
}
|
||||
recycle();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,26 +217,34 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
||||
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
|
||||
PoolThreadCache cache = threadCache.get();
|
||||
PoolArena<byte[]> heapArena = cache.heapArena;
|
||||
|
||||
ByteBuf buf;
|
||||
if (heapArena != null) {
|
||||
return heapArena.allocate(cache, initialCapacity, maxCapacity);
|
||||
buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
|
||||
} else {
|
||||
return new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
||||
buf = new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
return toLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
||||
PoolThreadCache cache = threadCache.get();
|
||||
PoolArena<ByteBuffer> directArena = cache.directArena;
|
||||
|
||||
ByteBuf buf;
|
||||
if (directArena != null) {
|
||||
return directArena.allocate(cache, initialCapacity, maxCapacity);
|
||||
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
|
||||
} else {
|
||||
if (PlatformDependent.hasUnsafe()) {
|
||||
return new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
} else {
|
||||
return new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
return toLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,10 +317,14 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf<ByteBuffer> {
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
checkIndex(index, length);
|
||||
PooledUnsafeDirectByteBuf copy = (PooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
||||
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||
if (length != 0) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
||||
copy.setIndex(0, length);
|
||||
if (copy.hasMemoryAddress()) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||
copy.setIndex(0, length);
|
||||
} else {
|
||||
copy.writeBytes(this, index, length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -32,7 +31,6 @@ import java.nio.channels.ScatteringByteChannel;
|
||||
* Read-only ByteBuf which wraps a read-only ByteBuffer.
|
||||
*/
|
||||
class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
||||
private final ResourceLeak leak;
|
||||
|
||||
protected final ByteBuffer buffer;
|
||||
private final ByteBufAllocator allocator;
|
||||
@ -47,15 +45,10 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
||||
this.allocator = allocator;
|
||||
this.buffer = buffer.slice().order(ByteOrder.BIG_ENDIAN);
|
||||
writerIndex(this.buffer.limit());
|
||||
leak = leakDetector.open(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deallocate() {
|
||||
if (leak != null) {
|
||||
leak.close();
|
||||
}
|
||||
}
|
||||
protected void deallocate() { }
|
||||
|
||||
@Override
|
||||
public byte getByte(int index) {
|
||||
|
@ -120,10 +120,14 @@ final class ReadOnlyUnsafeDirectByteBuf extends ReadOnlyByteBufferBuf {
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
checkIndex(index, length);
|
||||
UnpooledUnsafeDirectByteBuf copy = (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
||||
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||
if (length != 0) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
||||
copy.setIndex(0, length);
|
||||
if (copy.hasMemoryAddress()) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||
copy.setIndex(0, length);
|
||||
} else {
|
||||
copy.writeBytes(this, index, length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
|
||||
final class SimpleLeakAwareByteBuf extends WrappedByteBuf {
|
||||
|
||||
private final ResourceLeak leak;
|
||||
|
||||
SimpleLeakAwareByteBuf(ByteBuf buf, ResourceLeak leak) {
|
||||
super(buf);
|
||||
this.leak = leak;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
boolean deallocated = super.release();
|
||||
if (deallocated) {
|
||||
leak.close();
|
||||
}
|
||||
return deallocated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
boolean deallocated = super.release(decrement);
|
||||
if (deallocated) {
|
||||
leak.close();
|
||||
}
|
||||
return deallocated;
|
||||
}
|
||||
}
|
@ -45,11 +45,14 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
|
||||
|
||||
@Override
|
||||
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
||||
ByteBuf buf;
|
||||
if (PlatformDependent.hasUnsafe()) {
|
||||
return new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
} else {
|
||||
return new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
return toLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -34,7 +33,6 @@ import java.nio.channels.ScatteringByteChannel;
|
||||
*/
|
||||
public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
|
||||
private final ResourceLeak leak;
|
||||
private final ByteBufAllocator alloc;
|
||||
|
||||
private ByteBuffer buffer;
|
||||
@ -66,7 +64,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
|
||||
this.alloc = alloc;
|
||||
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
|
||||
leak = leakDetector.open(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,7 +96,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
doNotFree = true;
|
||||
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
||||
writerIndex(initialCapacity);
|
||||
leak = leakDetector.open(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -566,12 +562,7 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
|
||||
}
|
||||
|
||||
ByteBuffer dst =
|
||||
src.isDirect()? allocateDirect(length) : ByteBuffer.allocate(length);
|
||||
dst.put(src);
|
||||
dst.order(order());
|
||||
dst.clear();
|
||||
return new UnpooledDirectByteBuf(alloc(), dst, maxCapacity());
|
||||
return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -604,10 +595,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||
if (!doNotFree) {
|
||||
freeDirect(buffer);
|
||||
}
|
||||
|
||||
if (leak != null) {
|
||||
leak.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.ResourceLeak;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -36,7 +35,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
||||
|
||||
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
|
||||
private final ResourceLeak leak;
|
||||
private final ByteBufAllocator alloc;
|
||||
|
||||
private long memoryAddress;
|
||||
@ -69,7 +67,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
||||
|
||||
this.alloc = alloc;
|
||||
setByteBuffer(allocateDirect(initialCapacity));
|
||||
leak = leakDetector.open(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +99,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
||||
doNotFree = true;
|
||||
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
||||
writerIndex(initialCapacity);
|
||||
leak = leakDetector.open(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -466,10 +462,14 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
checkIndex(index, length);
|
||||
UnpooledUnsafeDirectByteBuf copy = (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
||||
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||
if (length != 0) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
||||
copy.setIndex(0, length);
|
||||
if (copy.hasMemoryAddress()) {
|
||||
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||
copy.setIndex(0, length);
|
||||
} else {
|
||||
copy.writeBytes(this, index, length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
@ -504,10 +504,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
||||
if (!doNotFree) {
|
||||
freeDirect(buffer);
|
||||
}
|
||||
|
||||
if (leak != null) {
|
||||
leak.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,67 +15,18 @@
|
||||
*/
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* A {@link ByteBuf} implementation that wraps another buffer to prevent a user from increasing or decreasing the
|
||||
* wrapped buffer's reference count.
|
||||
*/
|
||||
final class UnreleasableByteBuf extends ByteBuf {
|
||||
final class UnreleasableByteBuf extends WrappedByteBuf {
|
||||
|
||||
private final ByteBuf buf;
|
||||
private SwappedByteBuf swappedBuf;
|
||||
|
||||
UnreleasableByteBuf(ByteBuf buf) {
|
||||
if (buf == null) {
|
||||
throw new NullPointerException("buf");
|
||||
}
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMemoryAddress() {
|
||||
return buf.hasMemoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long memoryAddress() {
|
||||
return buf.memoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return buf.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf capacity(int newCapacity) {
|
||||
buf.capacity(newCapacity);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxCapacity() {
|
||||
return buf.maxCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufAllocator alloc() {
|
||||
return buf.alloc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteOrder order() {
|
||||
return buf.order();
|
||||
super(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,624 +45,11 @@ final class UnreleasableByteBuf extends ByteBuf {
|
||||
return swappedBuf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf unwrap() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return buf.isDirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readerIndex() {
|
||||
return buf.readerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readerIndex(int readerIndex) {
|
||||
buf.readerIndex(readerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writerIndex() {
|
||||
return buf.writerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writerIndex(int writerIndex) {
|
||||
buf.writerIndex(writerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setIndex(int readerIndex, int writerIndex) {
|
||||
buf.setIndex(readerIndex, writerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readableBytes() {
|
||||
return buf.readableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writableBytes() {
|
||||
return buf.writableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxWritableBytes() {
|
||||
return buf.maxWritableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
return buf.isReadable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return buf.isWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf clear() {
|
||||
buf.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markReaderIndex() {
|
||||
buf.markReaderIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetReaderIndex() {
|
||||
buf.resetReaderIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markWriterIndex() {
|
||||
buf.markWriterIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetWriterIndex() {
|
||||
buf.resetWriterIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardReadBytes() {
|
||||
buf.discardReadBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardSomeReadBytes() {
|
||||
buf.discardSomeReadBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf ensureWritable(int minWritableBytes) {
|
||||
buf.ensureWritable(minWritableBytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ensureWritable(int minWritableBytes, boolean force) {
|
||||
return buf.ensureWritable(minWritableBytes, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int index) {
|
||||
return buf.getBoolean(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int index) {
|
||||
return buf.getByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getUnsignedByte(int index) {
|
||||
return buf.getUnsignedByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
return buf.getShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShort(int index) {
|
||||
return buf.getUnsignedShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMedium(int index) {
|
||||
return buf.getMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMedium(int index) {
|
||||
return buf.getUnsignedMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
return buf.getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedInt(int index) {
|
||||
return buf.getUnsignedInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
return buf.getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
return buf.getChar(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
return buf.getFloat(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int index) {
|
||||
return buf.getDouble(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
|
||||
buf.getBytes(index, dst, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
|
||||
buf.getBytes(index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
|
||||
buf.getBytes(index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuffer dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
|
||||
buf.getBytes(index, out, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
|
||||
return buf.getBytes(index, out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBoolean(int index, boolean value) {
|
||||
buf.setBoolean(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setByte(int index, int value) {
|
||||
buf.setByte(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setShort(int index, int value) {
|
||||
buf.setShort(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMedium(int index, int value) {
|
||||
buf.setMedium(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setInt(int index, int value) {
|
||||
buf.setInt(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLong(int index, long value) {
|
||||
buf.setLong(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setChar(int index, int value) {
|
||||
buf.setChar(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setFloat(int index, float value) {
|
||||
buf.setFloat(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setDouble(int index, double value) {
|
||||
buf.setDouble(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int length) {
|
||||
buf.setBytes(index, src, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
|
||||
buf.setBytes(index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
|
||||
buf.setBytes(index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuffer src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, InputStream in, int length) throws IOException {
|
||||
return buf.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
|
||||
return buf.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setZero(int index, int length) {
|
||||
buf.setZero(index, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return buf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() {
|
||||
return buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readUnsignedByte() {
|
||||
return buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() {
|
||||
return buf.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShort() {
|
||||
return buf.readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMedium() {
|
||||
return buf.readMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMedium() {
|
||||
return buf.readUnsignedMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() {
|
||||
return buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return buf.readUnsignedInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
return buf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return buf.readChar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat() {
|
||||
return buf.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() {
|
||||
return buf.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(int length) {
|
||||
return buf.readBytes(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readSlice(int length) {
|
||||
return new UnreleasableByteBuf(buf.readSlice(length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int length) {
|
||||
buf.readBytes(dst, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
|
||||
buf.readBytes(dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
|
||||
buf.readBytes(dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuffer dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(OutputStream out, int length) throws IOException {
|
||||
buf.readBytes(out, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBytes(GatheringByteChannel out, int length) throws IOException {
|
||||
return buf.readBytes(out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf skipBytes(int length) {
|
||||
buf.skipBytes(length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBoolean(boolean value) {
|
||||
buf.writeBoolean(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeByte(int value) {
|
||||
buf.writeByte(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeShort(int value) {
|
||||
buf.writeShort(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMedium(int value) {
|
||||
buf.writeMedium(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeInt(int value) {
|
||||
buf.writeInt(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLong(long value) {
|
||||
buf.writeLong(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeChar(int value) {
|
||||
buf.writeChar(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeFloat(float value) {
|
||||
buf.writeFloat(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeDouble(double value) {
|
||||
buf.writeDouble(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int length) {
|
||||
buf.writeBytes(src, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
|
||||
buf.writeBytes(src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
|
||||
buf.writeBytes(src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuffer src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(InputStream in, int length) throws IOException {
|
||||
return buf.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
|
||||
return buf.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeZero(int length) {
|
||||
buf.writeZero(length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(int fromIndex, int toIndex, byte value) {
|
||||
return buf.indexOf(fromIndex, toIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(byte value) {
|
||||
return buf.bytesBefore(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int length, byte value) {
|
||||
return buf.bytesBefore(length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int index, int length, byte value) {
|
||||
return buf.bytesBefore(index, length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
return buf.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
return buf.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
return buf.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
return buf.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy() {
|
||||
return buf.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
return buf.copy(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice() {
|
||||
return new UnreleasableByteBuf(buf.slice());
|
||||
@ -727,81 +65,6 @@ final class UnreleasableByteBuf extends ByteBuf {
|
||||
return new UnreleasableByteBuf(buf.duplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nioBufferCount() {
|
||||
return buf.nioBufferCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
return buf.nioBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer(int index, int length) {
|
||||
return buf.nioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers() {
|
||||
return buf.nioBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers(int index, int length) {
|
||||
return buf.nioBuffers(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer internalNioBuffer(int index, int length) {
|
||||
return buf.internalNioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return buf.hasArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return buf.arrayOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Charset charset) {
|
||||
return buf.toString(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int index, int length, Charset charset) {
|
||||
return buf.toString(index, length, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return buf.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return buf.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ByteBuf buffer) {
|
||||
return buf.compareTo(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtil.simpleClassName(this) + '(' + buf.toString() + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retain(int increment) {
|
||||
return this;
|
||||
@ -812,21 +75,6 @@ final class UnreleasableByteBuf extends ByteBuf {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(int size) {
|
||||
return buf.isReadable(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(int size) {
|
||||
return buf.isWritable(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
return buf.refCnt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return false;
|
||||
|
826
buffer/src/main/java/io/netty/buffer/WrappedByteBuf.java
Normal file
826
buffer/src/main/java/io/netty/buffer/WrappedByteBuf.java
Normal file
@ -0,0 +1,826 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.buffer;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class WrappedByteBuf extends ByteBuf {
|
||||
|
||||
protected final ByteBuf buf;
|
||||
|
||||
protected WrappedByteBuf(ByteBuf buf) {
|
||||
if (buf == null) {
|
||||
throw new NullPointerException("buf");
|
||||
}
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMemoryAddress() {
|
||||
return buf.hasMemoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long memoryAddress() {
|
||||
return buf.memoryAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return buf.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf capacity(int newCapacity) {
|
||||
buf.capacity(newCapacity);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxCapacity() {
|
||||
return buf.maxCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufAllocator alloc() {
|
||||
return buf.alloc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteOrder order() {
|
||||
return buf.order();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf order(ByteOrder endianness) {
|
||||
return buf.order(endianness);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf unwrap() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return buf.isDirect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readerIndex() {
|
||||
return buf.readerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readerIndex(int readerIndex) {
|
||||
buf.readerIndex(readerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writerIndex() {
|
||||
return buf.writerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writerIndex(int writerIndex) {
|
||||
buf.writerIndex(writerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setIndex(int readerIndex, int writerIndex) {
|
||||
buf.setIndex(readerIndex, writerIndex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readableBytes() {
|
||||
return buf.readableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writableBytes() {
|
||||
return buf.writableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxWritableBytes() {
|
||||
return buf.maxWritableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
return buf.isReadable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return buf.isWritable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf clear() {
|
||||
buf.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markReaderIndex() {
|
||||
buf.markReaderIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetReaderIndex() {
|
||||
buf.resetReaderIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf markWriterIndex() {
|
||||
buf.markWriterIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf resetWriterIndex() {
|
||||
buf.resetWriterIndex();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardReadBytes() {
|
||||
buf.discardReadBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf discardSomeReadBytes() {
|
||||
buf.discardSomeReadBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf ensureWritable(int minWritableBytes) {
|
||||
buf.ensureWritable(minWritableBytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int ensureWritable(int minWritableBytes, boolean force) {
|
||||
return buf.ensureWritable(minWritableBytes, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int index) {
|
||||
return buf.getBoolean(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(int index) {
|
||||
return buf.getByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getUnsignedByte(int index) {
|
||||
return buf.getUnsignedByte(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int index) {
|
||||
return buf.getShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShort(int index) {
|
||||
return buf.getUnsignedShort(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMedium(int index) {
|
||||
return buf.getMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMedium(int index) {
|
||||
return buf.getUnsignedMedium(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int index) {
|
||||
return buf.getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedInt(int index) {
|
||||
return buf.getUnsignedInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int index) {
|
||||
return buf.getLong(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int index) {
|
||||
return buf.getChar(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int index) {
|
||||
return buf.getFloat(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int index) {
|
||||
return buf.getDouble(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
|
||||
buf.getBytes(index, dst, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
|
||||
buf.getBytes(index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
|
||||
buf.getBytes(index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, ByteBuffer dst) {
|
||||
buf.getBytes(index, dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
|
||||
buf.getBytes(index, out, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
|
||||
return buf.getBytes(index, out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBoolean(int index, boolean value) {
|
||||
buf.setBoolean(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setByte(int index, int value) {
|
||||
buf.setByte(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setShort(int index, int value) {
|
||||
buf.setShort(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMedium(int index, int value) {
|
||||
buf.setMedium(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setInt(int index, int value) {
|
||||
buf.setInt(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLong(int index, long value) {
|
||||
buf.setLong(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setChar(int index, int value) {
|
||||
buf.setChar(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setFloat(int index, float value) {
|
||||
buf.setFloat(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setDouble(int index, double value) {
|
||||
buf.setDouble(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int length) {
|
||||
buf.setBytes(index, src, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
|
||||
buf.setBytes(index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
|
||||
buf.setBytes(index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBytes(int index, ByteBuffer src) {
|
||||
buf.setBytes(index, src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, InputStream in, int length) throws IOException {
|
||||
return buf.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
|
||||
return buf.setBytes(index, in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setZero(int index, int length) {
|
||||
buf.setZero(index, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return buf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte() {
|
||||
return buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readUnsignedByte() {
|
||||
return buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort() {
|
||||
return buf.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShort() {
|
||||
return buf.readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMedium() {
|
||||
return buf.readMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMedium() {
|
||||
return buf.readUnsignedMedium();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() {
|
||||
return buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return buf.readUnsignedInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
return buf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return buf.readChar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat() {
|
||||
return buf.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble() {
|
||||
return buf.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(int length) {
|
||||
return buf.readBytes(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readSlice(int length) {
|
||||
return buf.readSlice(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int length) {
|
||||
buf.readBytes(dst, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
|
||||
buf.readBytes(dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
|
||||
buf.readBytes(dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuffer dst) {
|
||||
buf.readBytes(dst);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(OutputStream out, int length) throws IOException {
|
||||
buf.readBytes(out, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBytes(GatheringByteChannel out, int length) throws IOException {
|
||||
return buf.readBytes(out, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf skipBytes(int length) {
|
||||
buf.skipBytes(length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBoolean(boolean value) {
|
||||
buf.writeBoolean(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeByte(int value) {
|
||||
buf.writeByte(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeShort(int value) {
|
||||
buf.writeShort(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMedium(int value) {
|
||||
buf.writeMedium(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeInt(int value) {
|
||||
buf.writeInt(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLong(long value) {
|
||||
buf.writeLong(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeChar(int value) {
|
||||
buf.writeChar(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeFloat(float value) {
|
||||
buf.writeFloat(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeDouble(double value) {
|
||||
buf.writeDouble(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int length) {
|
||||
buf.writeBytes(src, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
|
||||
buf.writeBytes(src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
|
||||
buf.writeBytes(src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeBytes(ByteBuffer src) {
|
||||
buf.writeBytes(src);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(InputStream in, int length) throws IOException {
|
||||
return buf.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
|
||||
return buf.writeBytes(in, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeZero(int length) {
|
||||
buf.writeZero(length);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(int fromIndex, int toIndex, byte value) {
|
||||
return buf.indexOf(fromIndex, toIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(byte value) {
|
||||
return buf.bytesBefore(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int length, byte value) {
|
||||
return buf.bytesBefore(length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesBefore(int index, int length, byte value) {
|
||||
return buf.bytesBefore(index, length, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor processor) {
|
||||
return buf.forEachByte(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int index, int length, ByteBufProcessor processor) {
|
||||
return buf.forEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor processor) {
|
||||
return buf.forEachByteDesc(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
|
||||
return buf.forEachByteDesc(index, length, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy() {
|
||||
return buf.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf copy(int index, int length) {
|
||||
return buf.copy(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice() {
|
||||
return buf.slice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice(int index, int length) {
|
||||
return buf.slice(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf duplicate() {
|
||||
return buf.duplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nioBufferCount() {
|
||||
return buf.nioBufferCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer() {
|
||||
return buf.nioBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer nioBuffer(int index, int length) {
|
||||
return buf.nioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers() {
|
||||
return buf.nioBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer[] nioBuffers(int index, int length) {
|
||||
return buf.nioBuffers(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer internalNioBuffer(int index, int length) {
|
||||
return buf.internalNioBuffer(index, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasArray() {
|
||||
return buf.hasArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] array() {
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int arrayOffset() {
|
||||
return buf.arrayOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Charset charset) {
|
||||
return buf.toString(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(int index, int length, Charset charset) {
|
||||
return buf.toString(index, length, charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return buf.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return buf.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ByteBuf buffer) {
|
||||
return buf.compareTo(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtil.simpleClassName(this) + '(' + buf.toString() + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retain(int increment) {
|
||||
buf.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retain() {
|
||||
buf.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(int size) {
|
||||
return buf.isReadable(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable(int size) {
|
||||
return buf.isWritable(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
return buf.refCnt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return buf.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
return buf.release(decrement);
|
||||
}
|
||||
}
|
@ -17,6 +17,12 @@
|
||||
package io.netty.util;
|
||||
|
||||
public interface ResourceLeak {
|
||||
/**
|
||||
* Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked
|
||||
* resource was accessed lastly.
|
||||
*/
|
||||
void record();
|
||||
|
||||
/**
|
||||
* Close the leak so that {@link ResourceLeakDetector} does not warn about leaked resources.
|
||||
*
|
||||
|
@ -17,42 +17,86 @@
|
||||
package io.netty.util;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static io.netty.util.internal.StringUtil.*;
|
||||
|
||||
public final class ResourceLeakDetector<T> {
|
||||
|
||||
private static boolean disabled;
|
||||
private static final String PROP_LEVEL = "io.netty.leakDetectionLevel";
|
||||
private static final Level DEFAULT_LEVEL = Level.SIMPLE;
|
||||
|
||||
/**
|
||||
* Represents the level of resource leak detection.
|
||||
*/
|
||||
public enum Level {
|
||||
/**
|
||||
* Disables resource leak detection.
|
||||
*/
|
||||
DISABLED,
|
||||
/**
|
||||
* Enables simplistic sampling resource leak detection which reports there is a leak or not,
|
||||
* at the cost of small overhead (default).
|
||||
*/
|
||||
SIMPLE,
|
||||
/**
|
||||
* Enables advanced sampling resource leak detection which reports where the leaked object was accessed
|
||||
* recently at the cost of high overhead.
|
||||
*/
|
||||
ADVANCED,
|
||||
/**
|
||||
* Enables paranoid resource leak detection which reports where the leaked object was accessed recently,
|
||||
* at the cost of the highest possible overhead (for testing purposes only).
|
||||
*/
|
||||
PARANOID
|
||||
}
|
||||
|
||||
private static Level level;
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
|
||||
|
||||
static {
|
||||
final boolean DISABLED = SystemPropertyUtil.getBoolean("io.netty.noResourceLeakDetection", false);
|
||||
logger.debug("-Dio.netty.noResourceLeakDetection: {}", DISABLED);
|
||||
disabled = DISABLED;
|
||||
String levelStr = SystemPropertyUtil.get(PROP_LEVEL, DEFAULT_LEVEL.name()).trim().toUpperCase();
|
||||
Level level = DEFAULT_LEVEL;
|
||||
for (Level l: EnumSet.allOf(Level.class)) {
|
||||
if (levelStr.equals(l.name()) || levelStr.equals(String.valueOf(l.ordinal()))) {
|
||||
level = l;
|
||||
}
|
||||
}
|
||||
|
||||
ResourceLeakDetector.level = level;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("-D{}: {}", PROP_LEVEL, level.name().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static final int DEFAULT_SAMPLING_INTERVAL = 113;
|
||||
|
||||
/**
|
||||
* Enables or disabled the resource leak detection.
|
||||
* Sets the resource leak detection level.
|
||||
*/
|
||||
public static void setEnabled(boolean enabled) {
|
||||
disabled = !enabled;
|
||||
public static void setLevel(Level level) {
|
||||
if (level == null) {
|
||||
throw new NullPointerException("level");
|
||||
}
|
||||
ResourceLeakDetector.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if resource leak detection is enabled.
|
||||
* Returns the current resource leak detection level.
|
||||
*/
|
||||
public static boolean isEnabled() {
|
||||
return !disabled;
|
||||
public static Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/** the linked list of active resources */
|
||||
@ -60,7 +104,7 @@ public final class ResourceLeakDetector<T> {
|
||||
private final DefaultResourceLeak tail = new DefaultResourceLeak(null);
|
||||
|
||||
private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
|
||||
private final ConcurrentMap<Exception, Boolean> reportedLeaks = PlatformDependent.newConcurrentHashMap();
|
||||
private final ConcurrentMap<String, Boolean> reportedLeaks = PlatformDependent.newConcurrentHashMap();
|
||||
|
||||
private final String resourceType;
|
||||
private final int samplingInterval;
|
||||
@ -71,7 +115,7 @@ public final class ResourceLeakDetector<T> {
|
||||
private long leakCheckCnt;
|
||||
|
||||
public ResourceLeakDetector(Class<?> resourceType) {
|
||||
this(StringUtil.simpleClassName(resourceType));
|
||||
this(simpleClassName(resourceType));
|
||||
}
|
||||
|
||||
public ResourceLeakDetector(String resourceType) {
|
||||
@ -79,7 +123,7 @@ public final class ResourceLeakDetector<T> {
|
||||
}
|
||||
|
||||
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) {
|
||||
this(StringUtil.simpleClassName(resourceType), samplingInterval, maxActive);
|
||||
this(simpleClassName(resourceType), samplingInterval, maxActive);
|
||||
}
|
||||
|
||||
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
|
||||
@ -108,17 +152,26 @@ public final class ResourceLeakDetector<T> {
|
||||
* @return the {@link ResourceLeak} or {@code null}
|
||||
*/
|
||||
public ResourceLeak open(T obj) {
|
||||
if (disabled || leakCheckCnt ++ % samplingInterval != 0) {
|
||||
Level level = ResourceLeakDetector.level;
|
||||
if (level == Level.DISABLED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
reportLeak();
|
||||
|
||||
return new DefaultResourceLeak(obj);
|
||||
if (level.ordinal() < Level.PARANOID.ordinal()) {
|
||||
if (leakCheckCnt ++ % samplingInterval == 0) {
|
||||
reportLeak(level);
|
||||
return new DefaultResourceLeak(obj);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
reportLeak(level);
|
||||
return new DefaultResourceLeak(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportLeak() {
|
||||
if (!logger.isWarnEnabled()) {
|
||||
private void reportLeak(Level level) {
|
||||
if (!logger.isErrorEnabled()) {
|
||||
for (;;) {
|
||||
@SuppressWarnings("unchecked")
|
||||
DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
|
||||
@ -131,9 +184,9 @@ public final class ResourceLeakDetector<T> {
|
||||
}
|
||||
|
||||
// Report too many instances.
|
||||
int samplingInterval = level == Level.PARANOID? 1 : this.samplingInterval;
|
||||
if (active * samplingInterval > maxActive && loggedTooManyActive.compareAndSet(false, true)) {
|
||||
logger.warn(
|
||||
"LEAK: You are creating too many " + resourceType + " instances. " +
|
||||
logger.error("LEAK: You are creating too many " + resourceType + " instances. " +
|
||||
resourceType + " is a shared resource that must be reused across the JVM," +
|
||||
"so that only a few instances are created.");
|
||||
}
|
||||
@ -152,18 +205,29 @@ public final class ResourceLeakDetector<T> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reportedLeaks.putIfAbsent(ref.exception, Boolean.TRUE) == null) {
|
||||
logger.warn(
|
||||
"LEAK: " + resourceType + " was GC'd before being released correctly. " +
|
||||
"The following stack trace shows where the leaked object was created, " +
|
||||
"rather than where you failed to release it.", ref.exception);
|
||||
String records = ref.toString();
|
||||
if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
|
||||
if (records.isEmpty()) {
|
||||
logger.error("LEAK: {}.release() was not called before it's garbage-collected. " +
|
||||
"Enable advanced leak reporting to find out where the leak occurred. " +
|
||||
"To enable advanced leak reporting, " +
|
||||
"specify the JVM option '-D{}={}' or call {}.setLevel()",
|
||||
resourceType, PROP_LEVEL, Level.ADVANCED.name().toLowerCase(), simpleClassName(this));
|
||||
} else {
|
||||
logger.error(
|
||||
"LEAK: {}.release() was not called before it's garbage-collected.{}",
|
||||
resourceType, records);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class DefaultResourceLeak extends PhantomReference<Object> implements ResourceLeak {
|
||||
|
||||
private final ResourceLeakException exception;
|
||||
private static final int MAX_RECORDS = 4;
|
||||
|
||||
private final String creationRecord;
|
||||
private final Deque<String> lastRecords = new ArrayDeque<String>();
|
||||
private final AtomicBoolean freed;
|
||||
private DefaultResourceLeak prev;
|
||||
private DefaultResourceLeak next;
|
||||
@ -172,8 +236,12 @@ public final class ResourceLeakDetector<T> {
|
||||
super(referent, referent != null? refQueue : null);
|
||||
|
||||
if (referent != null) {
|
||||
exception = new ResourceLeakException(
|
||||
referent.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(referent)));
|
||||
Level level = getLevel();
|
||||
if (level.ordinal() >= Level.ADVANCED.ordinal()) {
|
||||
creationRecord = newRecord();
|
||||
} else {
|
||||
creationRecord = null;
|
||||
}
|
||||
|
||||
// TODO: Use CAS to update the list.
|
||||
synchronized (head) {
|
||||
@ -185,11 +253,28 @@ public final class ResourceLeakDetector<T> {
|
||||
}
|
||||
freed = new AtomicBoolean();
|
||||
} else {
|
||||
exception = null;
|
||||
creationRecord = null;
|
||||
freed = new AtomicBoolean(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record() {
|
||||
if (creationRecord != null) {
|
||||
String value = newRecord();
|
||||
|
||||
synchronized (lastRecords) {
|
||||
int size = lastRecords.size();
|
||||
if (size == 0 || !lastRecords.getLast().equals(value)) {
|
||||
lastRecords.add(value);
|
||||
}
|
||||
if (size > MAX_RECORDS) {
|
||||
lastRecords.removeFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
if (freed.compareAndSet(false, true)) {
|
||||
@ -204,5 +289,54 @@ public final class ResourceLeakDetector<T> {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (creationRecord == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder(16384);
|
||||
int lastRecordCount = lastRecords.size();
|
||||
|
||||
buf.append(NEWLINE);
|
||||
buf.append("Recent access records: ");
|
||||
buf.append(lastRecordCount);
|
||||
buf.append(NEWLINE);
|
||||
|
||||
if (lastRecordCount > 0) {
|
||||
String[] lastRecords = this.lastRecords.toArray(new String[lastRecordCount]);
|
||||
for (int i = lastRecords.length - 1; i >= 0; i --) {
|
||||
buf.append('#');
|
||||
buf.append(i + 1);
|
||||
buf.append(':');
|
||||
buf.append(NEWLINE);
|
||||
buf.append(lastRecords[i]);
|
||||
}
|
||||
}
|
||||
|
||||
buf.append("Created at:");
|
||||
buf.append(NEWLINE);
|
||||
buf.append(creationRecord);
|
||||
buf.setLength(buf.length() - NEWLINE.length());
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static String newRecord() {
|
||||
StringBuilder buf = new StringBuilder(4096);
|
||||
StackTraceElement[] array = new Throwable().getStackTrace();
|
||||
int recordsToSkip = 3;
|
||||
for (StackTraceElement e: array) {
|
||||
if (recordsToSkip > 0) {
|
||||
recordsToSkip --;
|
||||
} else {
|
||||
buf.append('\t');
|
||||
buf.append(e.toString());
|
||||
buf.append(NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.netty.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ResourceLeakException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 7186453858343358280L;
|
||||
|
||||
private final StackTraceElement[] cachedStackTrace;
|
||||
|
||||
public ResourceLeakException() {
|
||||
cachedStackTrace = getStackTrace();
|
||||
}
|
||||
|
||||
public ResourceLeakException(String message) {
|
||||
super(message);
|
||||
cachedStackTrace = getStackTrace();
|
||||
}
|
||||
|
||||
public ResourceLeakException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
cachedStackTrace = getStackTrace();
|
||||
}
|
||||
|
||||
public ResourceLeakException(Throwable cause) {
|
||||
super(cause);
|
||||
cachedStackTrace = getStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
StackTraceElement[] trace = cachedStackTrace;
|
||||
int hashCode = 0;
|
||||
for (StackTraceElement e: trace) {
|
||||
hashCode = hashCode * 31 + e.hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ResourceLeakException)) {
|
||||
return false;
|
||||
}
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Arrays.equals(cachedStackTrace, ((ResourceLeakException) o).cachedStackTrace);
|
||||
}
|
||||
}
|
20
pom.xml
20
pom.xml
@ -67,6 +67,26 @@
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>leak</id>
|
||||
<properties>
|
||||
<test.jvm.argLine>
|
||||
-server
|
||||
-dsa -da -ea:io.netty...
|
||||
-XX:+AggressiveOpts
|
||||
-XX:+TieredCompilation
|
||||
-XX:+UseBiasedLocking
|
||||
-XX:+UseFastAccessorMethods
|
||||
-XX:+UseStringCache
|
||||
-XX:+OptimizeStringConcat
|
||||
-XX:+HeapDumpOnOutOfMemoryError
|
||||
-Dio.netty.leakDetectionLevel=3
|
||||
</test.jvm.argLine>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
|
Loading…
Reference in New Issue
Block a user