All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.core.util.BufferRecycler Maven / Gradle / Ivy

The newest version!
package com.fasterxml.jackson.core.util;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicReferenceArray;

/**
 * This is a small utility class, whose main functionality is to allow
 * simple reuse of raw byte/char buffers. It is usually allocated through
 * {@link RecyclerPool} (starting with 2.16): multiple pool
 * implementations exists.
 * The default pool implementation uses
 * {@code ThreadLocal} combined with {@code SoftReference}.
 * The end result is a low-overhead GC-cleanable recycling: hopefully
 * ideal for use by stream readers.
 *

* Rewritten in 2.10 to be thread-safe (see [jackson-core#479] for details), * to not rely on {@code ThreadLocal} access.
* Rewritten in 2.16 to work with {@link RecyclerPool} abstraction. */ public class BufferRecycler implements RecyclerPool.WithPool { /** * Tag-on interface to allow various other types to expose {@link BufferRecycler} * they are constructed with. * * @since 2.17 */ public interface Gettable { /** * @return Buffer recycler instance object is configured with, if any; * whether this can be {@code null} depends on type of object */ public BufferRecycler bufferRecycler(); } /** * Buffer used for reading byte-based input. */ public final static int BYTE_READ_IO_BUFFER = 0; /** * Buffer used for temporarily storing encoded content; used * for example by UTF-8 encoding writer */ public final static int BYTE_WRITE_ENCODING_BUFFER = 1; /** * Buffer used for temporarily concatenating output; used for * example when requesting output as byte array. */ public final static int BYTE_WRITE_CONCAT_BUFFER = 2; /** * Buffer used for concatenating binary data that is either being * encoded as base64 output, or decoded from base64 input. * * @since 2.1 */ public final static int BYTE_BASE64_CODEC_BUFFER = 3; /** * Buffer used as input buffer for tokenization for character-based parsers. */ public final static int CHAR_TOKEN_BUFFER = 0; /** * Buffer used by generators; for byte-backed generators for buffering of * {@link String} values to output (before encoding into UTF-8), * and for char-backed generators as actual concatenation buffer. */ public final static int CHAR_CONCAT_BUFFER = 1; /** * Used through {@link TextBuffer}: directly by parsers (to concatenate * String values) * and indirectly via * {@link com.fasterxml.jackson.core.io.SegmentedStringWriter} * when serializing (databind level {@code ObjectMapper} and * {@code ObjectWriter}). In both cases used as segments (and not for whole value), * but may result in retention of larger chunks for big content * (long text values during parsing; bigger output documents for generation). */ public final static int CHAR_TEXT_BUFFER = 2; /** * For parsers, temporary buffer into which {@code char[]} for names is copied * when requested as such; for {@code WriterBasedGenerator} used for buffering * during {@code writeString(Reader)} operation (not commonly used). */ public final static int CHAR_NAME_COPY_BUFFER = 3; // Buffer lengths private final static int[] BYTE_BUFFER_LENGTHS = new int[] { 8000, 8000, 2000, 2000 }; private final static int[] CHAR_BUFFER_LENGTHS = new int[] { 4000, 4000, 200, 200 }; // Note: changed from simple array in 2.10: protected final AtomicReferenceArray _byteBuffers; // Note: changed from simple array in 2.10: protected final AtomicReferenceArray _charBuffers; private RecyclerPool _pool; /* /********************************************************** /* Life-cycle /********************************************************** */ /** * Default constructor used for creating instances of this default * implementation. */ public BufferRecycler() { this(4, 4); } /** * Alternate constructor to be used by sub-classes, to allow customization * of number of low-level buffers in use. * * @param bbCount Number of {@code byte[]} buffers to allocate * @param cbCount Number of {@code char[]} buffers to allocate * * @since 2.4 */ protected BufferRecycler(int bbCount, int cbCount) { _byteBuffers = new AtomicReferenceArray<>(bbCount); _charBuffers = new AtomicReferenceArray<>(cbCount); } /** * @return True if this recycler is linked to pool and may be released * with {@link #releaseToPool()}; false if no linkage exists. * * @since 2.17 */ public boolean isLinkedWithPool() { return _pool != null; } /* /********************************************************** /* Public API, byte buffers /********************************************************** */ /** * @param ix One of READ_IO_BUFFER constants. * * @return Buffer allocated (possibly recycled) */ public final byte[] allocByteBuffer(int ix) { return allocByteBuffer(ix, 0); } public byte[] allocByteBuffer(int ix, int minSize) { final int DEF_SIZE = byteBufferLength(ix); if (minSize < DEF_SIZE) { minSize = DEF_SIZE; } byte[] buffer = _byteBuffers.getAndSet(ix, null); if (buffer == null || buffer.length < minSize) { buffer = balloc(minSize); } return buffer; } public void releaseByteBuffer(int ix, byte[] buffer) { // 13-Jan-2024, tatu: [core#1186] Replace only if beneficial: byte[] oldBuffer = _byteBuffers.get(ix); if ((oldBuffer == null) || buffer.length > oldBuffer.length) { // Could use CAS, but should not really matter _byteBuffers.set(ix, buffer); } } /* /********************************************************** /* Public API, char buffers /********************************************************** */ public final char[] allocCharBuffer(int ix) { return allocCharBuffer(ix, 0); } public char[] allocCharBuffer(int ix, int minSize) { final int DEF_SIZE = charBufferLength(ix); if (minSize < DEF_SIZE) { minSize = DEF_SIZE; } char[] buffer = _charBuffers.getAndSet(ix, null); if (buffer == null || buffer.length < minSize) { buffer = calloc(minSize); } return buffer; } public void releaseCharBuffer(int ix, char[] buffer) { // 13-Jan-2024, tatu: [core#1186] Replace only if beneficial: char[] oldBuffer = _charBuffers.get(ix); if ((oldBuffer == null) || buffer.length > oldBuffer.length) { // Could use CAS, but should not really matter _charBuffers.set(ix, buffer); } } /* /********************************************************** /* Overridable helper methods /********************************************************** */ protected int byteBufferLength(int ix) { return BYTE_BUFFER_LENGTHS[ix]; } protected int charBufferLength(int ix) { return CHAR_BUFFER_LENGTHS[ix]; } /* /********************************************************** /* Actual allocations separated for easier debugging/profiling /********************************************************** */ protected byte[] balloc(int size) { return new byte[size]; } protected char[] calloc(int size) { return new char[size]; } /* /********************************************************** /* WithPool implementation /********************************************************** */ /** * Method called by owner of this recycler instance, to provide reference to * {@link RecyclerPool} into which instance is to be released (if any) * * @since 2.16 */ @Override public BufferRecycler withPool(RecyclerPool pool) { if (_pool != null) { throw new IllegalStateException("BufferRecycler already linked to pool: "+pool); } // assign to pool to which this BufferRecycler belongs in order to release it // to the same pool when the work will be completed _pool = Objects.requireNonNull(pool); return this; } /** * Method called when owner of this recycler no longer wishes use it; this should * return it to pool passed via {@code withPool()} (if any). * * @since 2.16 */ @Override public void releaseToPool() { if (_pool != null) { RecyclerPool tmpPool = _pool; // nullify the reference to the pool in order to avoid the risk of releasing // the same BufferRecycler more than once, thus compromising the pool integrity _pool = null; tmpPool.releasePooled(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy