提交 e6893da9 编写于 作者: A Arjen Poutsma

Remove use of CompositeByteBuf in NettyDataBuffer

Prior to this commit, NettyDataBuffer had a optimization in
write(ByteBuf...), where it used a CompositeByteBuf to hold the original
and the parameter buffer.
Unfortunately, this procedure has nasty consequences when splicing
buffers (see https://stackoverflow.com/a/48111196/839733).

As of this commit, NettyDataBuffer stopped using CompositeByteBuf, and
 simply does ByteBuf.write().

Issue: SPR-16351
上级 5ed0cf90
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -25,11 +25,8 @@ import java.util.function.IntPredicate; ...@@ -25,11 +25,8 @@ import java.util.function.IntPredicate;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/** /**
* Implementation of the {@code DataBuffer} interface that wraps a Netty * Implementation of the {@code DataBuffer} interface that wraps a Netty
...@@ -42,7 +39,7 @@ public class NettyDataBuffer implements PooledDataBuffer { ...@@ -42,7 +39,7 @@ public class NettyDataBuffer implements PooledDataBuffer {
private final NettyDataBufferFactory dataBufferFactory; private final NettyDataBufferFactory dataBufferFactory;
private ByteBuf byteBuf; private final ByteBuf byteBuf;
/** /**
...@@ -174,8 +171,10 @@ public class NettyDataBuffer implements PooledDataBuffer { ...@@ -174,8 +171,10 @@ public class NettyDataBuffer implements PooledDataBuffer {
@Override @Override
public NettyDataBuffer write(DataBuffer... buffers) { public NettyDataBuffer write(DataBuffer... buffers) {
if (!ObjectUtils.isEmpty(buffers)) { Assert.notNull(buffers, "'buffers' must not be null");
if (buffers[0] instanceof NettyDataBuffer) {
if (buffers.length > 0) {
if (hasNettyDataBuffers(buffers)) {
ByteBuf[] nativeBuffers = Arrays.stream(buffers) ByteBuf[] nativeBuffers = Arrays.stream(buffers)
.map(b -> ((NettyDataBuffer) b).getNativeBuffer()) .map(b -> ((NettyDataBuffer) b).getNativeBuffer())
.toArray(ByteBuf[]::new); .toArray(ByteBuf[]::new);
...@@ -191,12 +190,23 @@ public class NettyDataBuffer implements PooledDataBuffer { ...@@ -191,12 +190,23 @@ public class NettyDataBuffer implements PooledDataBuffer {
return this; return this;
} }
private static boolean hasNettyDataBuffers(DataBuffer[] dataBuffers) {
for (DataBuffer dataBuffer : dataBuffers) {
if (!(dataBuffer instanceof NettyDataBuffer)) {
return false;
}
}
return true;
}
@Override @Override
public NettyDataBuffer write(ByteBuffer... buffers) { public NettyDataBuffer write(ByteBuffer... buffers) {
Assert.notNull(buffers, "'buffers' must not be null"); Assert.notNull(buffers, "'buffers' must not be null");
ByteBuf[] wrappedBuffers = Arrays.stream(buffers).map(Unpooled::wrappedBuffer)
.toArray(ByteBuf[]::new); for (ByteBuffer buffer : buffers) {
return write(wrappedBuffers); this.byteBuf.writeBytes(buffer);
}
return this;
} }
/** /**
...@@ -208,17 +218,8 @@ public class NettyDataBuffer implements PooledDataBuffer { ...@@ -208,17 +218,8 @@ public class NettyDataBuffer implements PooledDataBuffer {
public NettyDataBuffer write(ByteBuf... byteBufs) { public NettyDataBuffer write(ByteBuf... byteBufs) {
Assert.notNull(byteBufs, "'byteBufs' must not be null"); Assert.notNull(byteBufs, "'byteBufs' must not be null");
if (this.byteBuf instanceof CompositeByteBuf) { for (ByteBuf byteBuf : byteBufs) {
CompositeByteBuf composite = (CompositeByteBuf) this.byteBuf; this.byteBuf.writeBytes(byteBuf);
composite.addComponents(true, byteBufs);
}
else {
ByteBuf oldByteBuf = this.byteBuf;
CompositeByteBuf composite = oldByteBuf.alloc().compositeBuffer(byteBufs.length + 1);
composite.addComponent(true, oldByteBuf);
composite.addComponents(true, byteBufs);
this.byteBuf = composite;
} }
return this; return this;
} }
......
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -303,7 +303,7 @@ public class DataBufferTests extends AbstractDataBufferAllocatingTestCase { ...@@ -303,7 +303,7 @@ public class DataBufferTests extends AbstractDataBufferAllocatingTestCase {
assertArrayEquals(new byte[]{'a', 'b', 'c', 'd'}, result); assertArrayEquals(new byte[]{'a', 'b', 'c', 'd'}, result);
release(buffer1); release(buffer1, buffer2, buffer3);
} }
@Test @Test
...@@ -461,5 +461,23 @@ public class DataBufferTests extends AbstractDataBufferAllocatingTestCase { ...@@ -461,5 +461,23 @@ public class DataBufferTests extends AbstractDataBufferAllocatingTestCase {
release(buffer); release(buffer);
} }
@Test
public void spr16351() {
DataBuffer buffer = createDataBuffer(6);
byte[] bytes = {'a', 'b', 'c', 'd', 'e', 'f'};
buffer.write(bytes);
DataBuffer slice = buffer.slice(3, 3);
buffer.writePosition(3);
buffer.write(slice);
assertEquals(6, buffer.readableByteCount());
byte[] result = new byte[6];
buffer.read(result);
assertArrayEquals(bytes, result);
release(buffer);
}
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册