ByteBufUtil.isText method should be safe to be called concurrently
Motivation: ByteBufUtil.isText(...) may produce unexpected results if called concurrently on the same ByteBuffer. Modifications: - Don't use internalNioBuffer where it is not safe. - Add unit test. Result: ByteBufUtil.isText is thread-safe.
This commit is contained in:
parent
e72c197aa3
commit
d2bd36fc4c
@ -1151,7 +1151,7 @@ public final class ByteBufUtil {
|
|||||||
CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
|
CharsetDecoder decoder = CharsetUtil.decoder(charset, CodingErrorAction.REPORT, CodingErrorAction.REPORT);
|
||||||
try {
|
try {
|
||||||
if (buf.nioBufferCount() == 1) {
|
if (buf.nioBufferCount() == 1) {
|
||||||
decoder.decode(buf.internalNioBuffer(index, length));
|
decoder.decode(buf.nioBuffer(index, length));
|
||||||
} else {
|
} else {
|
||||||
ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
|
ByteBuf heapBuffer = buf.alloc().heapBuffer(length);
|
||||||
try {
|
try {
|
||||||
|
@ -19,10 +19,15 @@ import io.netty.util.AsciiString;
|
|||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.Buffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static io.netty.buffer.Unpooled.unreleasableBuffer;
|
import static io.netty.buffer.Unpooled.unreleasableBuffer;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
@ -551,4 +556,44 @@ public class ByteBufUtilTest {
|
|||||||
buffer.release();
|
buffer.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsTextMultiThreaded() throws Throwable {
|
||||||
|
final ByteBuf buffer = Unpooled.copiedBuffer("Hello, World!", CharsetUtil.ISO_8859_1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final AtomicInteger counter = new AtomicInteger(60000);
|
||||||
|
final AtomicReference<Throwable> errorRef = new AtomicReference<Throwable>();
|
||||||
|
List<Thread> threads = new ArrayList<Thread>();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Thread thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while (errorRef.get() == null && counter.decrementAndGet() > 0) {
|
||||||
|
assertTrue(ByteBufUtil.isText(buffer, CharsetUtil.ISO_8859_1));
|
||||||
|
}
|
||||||
|
} catch (Throwable cause) {
|
||||||
|
errorRef.compareAndSet(null, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
threads.add(thread);
|
||||||
|
}
|
||||||
|
for (Thread thread : threads) {
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Thread thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
Throwable error = errorRef.get();
|
||||||
|
if (error != null) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
buffer.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user