diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/StringCodecBase.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/StringCodecBase.java index f64f19318311..2ff7fe250859 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/StringCodecBase.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/StringCodecBase.java @@ -42,6 +42,9 @@ abstract class StringCodecBase implements Codec { private final Charset charset; private final boolean fixedLength; private final int maxBytesPerChar; + // CharsetEncoder/CharsetDecoder are stateful and not thread-safe: reuse one per thread. + private final ThreadLocal threadLocalEncoder = ThreadLocal.withInitial(this::newEncoder); + private final ThreadLocal threadLocalDecoder = ThreadLocal.withInitial(this::newDecoder); StringCodecBase(Charset charset) { this.charset = charset; @@ -97,7 +100,7 @@ private int getSerializedSizeUpperBound(String s) { private PutToByteBuffer encode( String string, Integer serializedSize, Function newE) { return buffer -> { - final CoderResult result = newEncoder().encode( + final CoderResult result = threadLocalEncoder.get().reset().encode( CharBuffer.wrap(string), buffer, true); if (result.isError()) { throw newE.apply("Failed to encode with " + charset + ": " + result @@ -114,7 +117,7 @@ private PutToByteBuffer encode( String decodeNoFallback(ByteBuffer buffer) throws CodecException { try { - return newDecoder().decode(buffer.asReadOnlyBuffer()).toString(); + return threadLocalDecoder.get().decode(buffer.asReadOnlyBuffer()).toString(); } catch (Exception e) { throw new CodecException("Failed to decode " + buffer, e); } @@ -123,7 +126,7 @@ String decodeNoFallback(ByteBuffer buffer) throws CodecException { String decodeWithFallback(ByteBuffer buffer) { Runnable error = null; try { - return newDecoder().decode(buffer.asReadOnlyBuffer()).toString(); + return threadLocalDecoder.get().decode(buffer.asReadOnlyBuffer()).toString(); } catch (Exception e) { error = () -> LOG.warn("Failed to decode buffer with {}, buffer = (hex) {}", charset, StringUtils.bytes2Hex(buffer, 20), e);