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;
|
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.PlatformDependent;
|
||||||
import io.netty.util.internal.StringUtil;
|
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_INITIAL_CAPACITY = 256;
|
||||||
private static final int DEFAULT_MAX_COMPONENTS = 16;
|
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 boolean directByDefault;
|
||||||
private final ByteBuf emptyBuf;
|
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;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.Recycler;
|
import io.netty.util.Recycler;
|
||||||
import io.netty.util.ResourceLeak;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
||||||
|
|
||||||
private final ResourceLeak leak;
|
|
||||||
private final Recycler.Handle recyclerHandle;
|
private final Recycler.Handle recyclerHandle;
|
||||||
|
|
||||||
protected PoolChunk<T> chunk;
|
protected PoolChunk<T> chunk;
|
||||||
@ -38,7 +36,6 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
protected PooledByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) {
|
protected PooledByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) {
|
||||||
super(maxCapacity);
|
super(maxCapacity);
|
||||||
leak = leakDetector.open(this);
|
|
||||||
this.recyclerHandle = recyclerHandle;
|
this.recyclerHandle = recyclerHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,13 +141,9 @@ abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
|
|||||||
this.handle = -1;
|
this.handle = -1;
|
||||||
memory = null;
|
memory = null;
|
||||||
chunk.arena.free(chunk, handle);
|
chunk.arena.free(chunk, handle);
|
||||||
if (leak != null) {
|
|
||||||
leak.close();
|
|
||||||
} else {
|
|
||||||
recycle();
|
recycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void recycle() {
|
private void recycle() {
|
||||||
|
@ -217,26 +217,34 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
|||||||
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
|
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
|
||||||
PoolThreadCache cache = threadCache.get();
|
PoolThreadCache cache = threadCache.get();
|
||||||
PoolArena<byte[]> heapArena = cache.heapArena;
|
PoolArena<byte[]> heapArena = cache.heapArena;
|
||||||
|
|
||||||
|
ByteBuf buf;
|
||||||
if (heapArena != null) {
|
if (heapArena != null) {
|
||||||
return heapArena.allocate(cache, initialCapacity, maxCapacity);
|
buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
|
||||||
} else {
|
} else {
|
||||||
return new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
buf = new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return toLeakAwareBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
||||||
PoolThreadCache cache = threadCache.get();
|
PoolThreadCache cache = threadCache.get();
|
||||||
PoolArena<ByteBuffer> directArena = cache.directArena;
|
PoolArena<ByteBuffer> directArena = cache.directArena;
|
||||||
|
|
||||||
|
ByteBuf buf;
|
||||||
if (directArena != null) {
|
if (directArena != null) {
|
||||||
return directArena.allocate(cache, initialCapacity, maxCapacity);
|
buf = directArena.allocate(cache, initialCapacity, maxCapacity);
|
||||||
} else {
|
} else {
|
||||||
if (PlatformDependent.hasUnsafe()) {
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
return new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
} else {
|
} else {
|
||||||
return new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return toLeakAwareBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -317,10 +317,14 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf<ByteBuffer> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuf copy(int index, int length) {
|
public ByteBuf copy(int index, int length) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
PooledUnsafeDirectByteBuf copy = (PooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||||
if (length != 0) {
|
if (length != 0) {
|
||||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
if (copy.hasMemoryAddress()) {
|
||||||
|
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||||
copy.setIndex(0, length);
|
copy.setIndex(0, length);
|
||||||
|
} else {
|
||||||
|
copy.writeBytes(this, index, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.ResourceLeak;
|
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -32,7 +31,6 @@ import java.nio.channels.ScatteringByteChannel;
|
|||||||
* Read-only ByteBuf which wraps a read-only ByteBuffer.
|
* Read-only ByteBuf which wraps a read-only ByteBuffer.
|
||||||
*/
|
*/
|
||||||
class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
||||||
private final ResourceLeak leak;
|
|
||||||
|
|
||||||
protected final ByteBuffer buffer;
|
protected final ByteBuffer buffer;
|
||||||
private final ByteBufAllocator allocator;
|
private final ByteBufAllocator allocator;
|
||||||
@ -47,15 +45,10 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.buffer = buffer.slice().order(ByteOrder.BIG_ENDIAN);
|
this.buffer = buffer.slice().order(ByteOrder.BIG_ENDIAN);
|
||||||
writerIndex(this.buffer.limit());
|
writerIndex(this.buffer.limit());
|
||||||
leak = leakDetector.open(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deallocate() {
|
protected void deallocate() { }
|
||||||
if (leak != null) {
|
|
||||||
leak.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(int index) {
|
public byte getByte(int index) {
|
||||||
|
@ -120,10 +120,14 @@ final class ReadOnlyUnsafeDirectByteBuf extends ReadOnlyByteBufferBuf {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuf copy(int index, int length) {
|
public ByteBuf copy(int index, int length) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
UnpooledUnsafeDirectByteBuf copy = (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||||
if (length != 0) {
|
if (length != 0) {
|
||||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
if (copy.hasMemoryAddress()) {
|
||||||
|
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||||
copy.setIndex(0, length);
|
copy.setIndex(0, length);
|
||||||
|
} else {
|
||||||
|
copy.writeBytes(this, index, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return copy;
|
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
|
@Override
|
||||||
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
||||||
|
ByteBuf buf;
|
||||||
if (PlatformDependent.hasUnsafe()) {
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
return new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
} else {
|
} else {
|
||||||
return new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return toLeakAwareBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.ResourceLeak;
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -34,7 +33,6 @@ import java.nio.channels.ScatteringByteChannel;
|
|||||||
*/
|
*/
|
||||||
public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
||||||
|
|
||||||
private final ResourceLeak leak;
|
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
private ByteBuffer buffer;
|
||||||
@ -66,7 +64,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
this.alloc = alloc;
|
this.alloc = alloc;
|
||||||
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
|
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
|
||||||
leak = leakDetector.open(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +96,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
doNotFree = true;
|
doNotFree = true;
|
||||||
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
||||||
writerIndex(initialCapacity);
|
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));
|
throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer dst =
|
return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
|
||||||
src.isDirect()? allocateDirect(length) : ByteBuffer.allocate(length);
|
|
||||||
dst.put(src);
|
|
||||||
dst.order(order());
|
|
||||||
dst.clear();
|
|
||||||
return new UnpooledDirectByteBuf(alloc(), dst, maxCapacity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -604,10 +595,6 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
if (!doNotFree) {
|
if (!doNotFree) {
|
||||||
freeDirect(buffer);
|
freeDirect(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leak != null) {
|
|
||||||
leak.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.ResourceLeak;
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
import java.io.IOException;
|
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 static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||||
|
|
||||||
private final ResourceLeak leak;
|
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
|
|
||||||
private long memoryAddress;
|
private long memoryAddress;
|
||||||
@ -69,7 +67,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
|||||||
|
|
||||||
this.alloc = alloc;
|
this.alloc = alloc;
|
||||||
setByteBuffer(allocateDirect(initialCapacity));
|
setByteBuffer(allocateDirect(initialCapacity));
|
||||||
leak = leakDetector.open(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,7 +99,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
|||||||
doNotFree = true;
|
doNotFree = true;
|
||||||
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
setByteBuffer(initialBuffer.slice().order(ByteOrder.BIG_ENDIAN));
|
||||||
writerIndex(initialCapacity);
|
writerIndex(initialCapacity);
|
||||||
leak = leakDetector.open(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -466,10 +462,14 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuf copy(int index, int length) {
|
public ByteBuf copy(int index, int length) {
|
||||||
checkIndex(index, length);
|
checkIndex(index, length);
|
||||||
UnpooledUnsafeDirectByteBuf copy = (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity());
|
ByteBuf copy = alloc().directBuffer(length, maxCapacity());
|
||||||
if (length != 0) {
|
if (length != 0) {
|
||||||
PlatformDependent.copyMemory(addr(index), copy.addr(0), length);
|
if (copy.hasMemoryAddress()) {
|
||||||
|
PlatformDependent.copyMemory(addr(index), copy.memoryAddress(), length);
|
||||||
copy.setIndex(0, length);
|
copy.setIndex(0, length);
|
||||||
|
} else {
|
||||||
|
copy.writeBytes(this, index, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
@ -504,10 +504,6 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
|
|||||||
if (!doNotFree) {
|
if (!doNotFree) {
|
||||||
freeDirect(buffer);
|
freeDirect(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leak != null) {
|
|
||||||
leak.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,67 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
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.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
|
* A {@link ByteBuf} implementation that wraps another buffer to prevent a user from increasing or decreasing the
|
||||||
* wrapped buffer's reference count.
|
* wrapped buffer's reference count.
|
||||||
*/
|
*/
|
||||||
final class UnreleasableByteBuf extends ByteBuf {
|
final class UnreleasableByteBuf extends WrappedByteBuf {
|
||||||
|
|
||||||
private final ByteBuf buf;
|
|
||||||
private SwappedByteBuf swappedBuf;
|
private SwappedByteBuf swappedBuf;
|
||||||
|
|
||||||
UnreleasableByteBuf(ByteBuf buf) {
|
UnreleasableByteBuf(ByteBuf buf) {
|
||||||
if (buf == null) {
|
super(buf);
|
||||||
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
|
@Override
|
||||||
@ -94,624 +45,11 @@ final class UnreleasableByteBuf extends ByteBuf {
|
|||||||
return swappedBuf;
|
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
|
@Override
|
||||||
public ByteBuf readSlice(int length) {
|
public ByteBuf readSlice(int length) {
|
||||||
return new UnreleasableByteBuf(buf.readSlice(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
|
@Override
|
||||||
public ByteBuf slice() {
|
public ByteBuf slice() {
|
||||||
return new UnreleasableByteBuf(buf.slice());
|
return new UnreleasableByteBuf(buf.slice());
|
||||||
@ -727,81 +65,6 @@ final class UnreleasableByteBuf extends ByteBuf {
|
|||||||
return new UnreleasableByteBuf(buf.duplicate());
|
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
|
@Override
|
||||||
public ByteBuf retain(int increment) {
|
public ByteBuf retain(int increment) {
|
||||||
return this;
|
return this;
|
||||||
@ -812,21 +75,6 @@ final class UnreleasableByteBuf extends ByteBuf {
|
|||||||
return this;
|
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
|
@Override
|
||||||
public boolean release() {
|
public boolean release() {
|
||||||
return false;
|
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;
|
package io.netty.util;
|
||||||
|
|
||||||
public interface ResourceLeak {
|
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.
|
* Close the leak so that {@link ResourceLeakDetector} does not warn about leaked resources.
|
||||||
*
|
*
|
||||||
|
@ -17,42 +17,86 @@
|
|||||||
package io.netty.util;
|
package io.netty.util;
|
||||||
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.StringUtil;
|
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.lang.ref.PhantomReference;
|
import java.lang.ref.PhantomReference;
|
||||||
import java.lang.ref.ReferenceQueue;
|
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.ConcurrentMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static io.netty.util.internal.StringUtil.*;
|
||||||
|
|
||||||
public final class ResourceLeakDetector<T> {
|
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);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final boolean DISABLED = SystemPropertyUtil.getBoolean("io.netty.noResourceLeakDetection", false);
|
String levelStr = SystemPropertyUtil.get(PROP_LEVEL, DEFAULT_LEVEL.name()).trim().toUpperCase();
|
||||||
logger.debug("-Dio.netty.noResourceLeakDetection: {}", DISABLED);
|
Level level = DEFAULT_LEVEL;
|
||||||
disabled = DISABLED;
|
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;
|
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) {
|
public static void setLevel(Level level) {
|
||||||
disabled = !enabled;
|
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() {
|
public static Level getLevel() {
|
||||||
return !disabled;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** the linked list of active resources */
|
/** the linked list of active resources */
|
||||||
@ -60,7 +104,7 @@ public final class ResourceLeakDetector<T> {
|
|||||||
private final DefaultResourceLeak tail = new DefaultResourceLeak(null);
|
private final DefaultResourceLeak tail = new DefaultResourceLeak(null);
|
||||||
|
|
||||||
private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
|
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 String resourceType;
|
||||||
private final int samplingInterval;
|
private final int samplingInterval;
|
||||||
@ -71,7 +115,7 @@ public final class ResourceLeakDetector<T> {
|
|||||||
private long leakCheckCnt;
|
private long leakCheckCnt;
|
||||||
|
|
||||||
public ResourceLeakDetector(Class<?> resourceType) {
|
public ResourceLeakDetector(Class<?> resourceType) {
|
||||||
this(StringUtil.simpleClassName(resourceType));
|
this(simpleClassName(resourceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceLeakDetector(String resourceType) {
|
public ResourceLeakDetector(String resourceType) {
|
||||||
@ -79,7 +123,7 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) {
|
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) {
|
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
|
||||||
@ -108,17 +152,26 @@ public final class ResourceLeakDetector<T> {
|
|||||||
* @return the {@link ResourceLeak} or {@code null}
|
* @return the {@link ResourceLeak} or {@code null}
|
||||||
*/
|
*/
|
||||||
public ResourceLeak open(T obj) {
|
public ResourceLeak open(T obj) {
|
||||||
if (disabled || leakCheckCnt ++ % samplingInterval != 0) {
|
Level level = ResourceLeakDetector.level;
|
||||||
|
if (level == Level.DISABLED) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportLeak();
|
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);
|
return new DefaultResourceLeak(obj);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void reportLeak() {
|
private void reportLeak(Level level) {
|
||||||
if (!logger.isWarnEnabled()) {
|
if (!logger.isErrorEnabled()) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
|
DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
|
||||||
@ -131,9 +184,9 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Report too many instances.
|
// Report too many instances.
|
||||||
|
int samplingInterval = level == Level.PARANOID? 1 : this.samplingInterval;
|
||||||
if (active * samplingInterval > maxActive && loggedTooManyActive.compareAndSet(false, true)) {
|
if (active * samplingInterval > maxActive && loggedTooManyActive.compareAndSet(false, true)) {
|
||||||
logger.warn(
|
logger.error("LEAK: You are creating too many " + resourceType + " instances. " +
|
||||||
"LEAK: You are creating too many " + resourceType + " instances. " +
|
|
||||||
resourceType + " is a shared resource that must be reused across the JVM," +
|
resourceType + " is a shared resource that must be reused across the JVM," +
|
||||||
"so that only a few instances are created.");
|
"so that only a few instances are created.");
|
||||||
}
|
}
|
||||||
@ -152,18 +205,29 @@ public final class ResourceLeakDetector<T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reportedLeaks.putIfAbsent(ref.exception, Boolean.TRUE) == null) {
|
String records = ref.toString();
|
||||||
logger.warn(
|
if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
|
||||||
"LEAK: " + resourceType + " was GC'd before being released correctly. " +
|
if (records.isEmpty()) {
|
||||||
"The following stack trace shows where the leaked object was created, " +
|
logger.error("LEAK: {}.release() was not called before it's garbage-collected. " +
|
||||||
"rather than where you failed to release it.", ref.exception);
|
"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 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 final AtomicBoolean freed;
|
||||||
private DefaultResourceLeak prev;
|
private DefaultResourceLeak prev;
|
||||||
private DefaultResourceLeak next;
|
private DefaultResourceLeak next;
|
||||||
@ -172,8 +236,12 @@ public final class ResourceLeakDetector<T> {
|
|||||||
super(referent, referent != null? refQueue : null);
|
super(referent, referent != null? refQueue : null);
|
||||||
|
|
||||||
if (referent != null) {
|
if (referent != null) {
|
||||||
exception = new ResourceLeakException(
|
Level level = getLevel();
|
||||||
referent.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(referent)));
|
if (level.ordinal() >= Level.ADVANCED.ordinal()) {
|
||||||
|
creationRecord = newRecord();
|
||||||
|
} else {
|
||||||
|
creationRecord = null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Use CAS to update the list.
|
// TODO: Use CAS to update the list.
|
||||||
synchronized (head) {
|
synchronized (head) {
|
||||||
@ -185,11 +253,28 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
freed = new AtomicBoolean();
|
freed = new AtomicBoolean();
|
||||||
} else {
|
} else {
|
||||||
exception = null;
|
creationRecord = null;
|
||||||
freed = new AtomicBoolean(true);
|
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
|
@Override
|
||||||
public boolean close() {
|
public boolean close() {
|
||||||
if (freed.compareAndSet(false, true)) {
|
if (freed.compareAndSet(false, true)) {
|
||||||
@ -204,5 +289,54 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
return false;
|
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>
|
</developer>
|
||||||
</developers>
|
</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>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
Loading…
Reference in New Issue
Block a user