diff --git a/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java index 65bfe489f0..b46d20f767 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledByteBuf.java @@ -153,6 +153,8 @@ abstract class PooledByteBuf extends AbstractReferenceCountedByteBuf { ByteBuffer tmpNioBuf = this.tmpNioBuf; if (tmpNioBuf == null) { this.tmpNioBuf = tmpNioBuf = newInternalNioBuffer(memory); + } else { + tmpNioBuf.clear(); } return tmpNioBuf; } diff --git a/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java index dee7fe6774..3d77ecf195 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java @@ -260,7 +260,7 @@ final class PooledDirectByteBuf extends PooledByteBuf { } index = idx(index); - tmpBuf.clear().position(index).limit(index + length); + tmpBuf.limit(index + length).position(index); tmpBuf.put(src); return this; } @@ -274,7 +274,7 @@ final class PooledDirectByteBuf extends PooledByteBuf { return readBytes; } ByteBuffer tmpBuf = internalNioBuffer(); - tmpBuf.clear().position(idx(index)); + tmpBuf.position(idx(index)); tmpBuf.put(tmp, 0, readBytes); return readBytes; } diff --git a/buffer/src/test/java/io/netty/buffer/PoolArenaTest.java b/buffer/src/test/java/io/netty/buffer/PoolArenaTest.java index 2c1bd12db3..3ad331ddb3 100644 --- a/buffer/src/test/java/io/netty/buffer/PoolArenaTest.java +++ b/buffer/src/test/java/io/netty/buffer/PoolArenaTest.java @@ -20,6 +20,8 @@ import io.netty.util.internal.PlatformDependent; import org.junit.Assert; import org.junit.Test; +import static org.junit.Assume.assumeTrue; + import java.nio.ByteBuffer; public class PoolArenaTest { @@ -46,6 +48,7 @@ public class PoolArenaTest { @Test public void testDirectArenaOffsetCacheLine() throws Exception { + assumeTrue(PlatformDependent.hasUnsafe()); int capacity = 5; int alignment = 128; @@ -64,7 +67,7 @@ public class PoolArenaTest { } @Test - public final void testAllocationCounter() { + public void testAllocationCounter() { final PooledByteBufAllocator allocator = new PooledByteBufAllocator( true, // preferDirect 0, // nHeapArena @@ -107,4 +110,26 @@ public class PoolArenaTest { Assert.assertEquals(1, metric.numNormalDeallocations()); Assert.assertEquals(1, metric.numNormalAllocations()); } + + @Test + public void testDirectArenaMemoryCopy() { + ByteBuf src = PooledByteBufAllocator.DEFAULT.directBuffer(512); + ByteBuf dst = PooledByteBufAllocator.DEFAULT.directBuffer(512); + + PooledByteBuf pooledSrc = unwrapIfNeeded(src); + PooledByteBuf pooledDst = unwrapIfNeeded(dst); + + // This causes the internal reused ByteBuffer duplicate limit to be set to 128 + pooledDst.writeBytes(ByteBuffer.allocate(128)); + // Ensure internal ByteBuffer duplicate limit is properly reset (used in memoryCopy non-Unsafe case) + pooledDst.chunk.arena.memoryCopy(pooledSrc.memory, 0, pooledDst, 512); + + src.release(); + dst.release(); + } + + @SuppressWarnings("unchecked") + private PooledByteBuf unwrapIfNeeded(ByteBuf buf) { + return (PooledByteBuf) (buf instanceof PooledByteBuf ? buf : buf.unwrap()); + } }