1 package com.fasterxml.jackson.core.util; 2 3 import java.util.concurrent.atomic.AtomicReferenceArray; 4 5 /** 6 * This is a small utility class, whose main functionality is to allow 7 * simple reuse of raw byte/char buffers. It is usually used through 8 * <code>ThreadLocal</code> member of the owning class pointing to 9 * instance of this class through a <code>SoftReference</code>. The 10 * end result is a low-overhead GC-cleanable recycling: hopefully 11 * ideal for use by stream readers. 12 *<p> 13 * Rewritten in 2.10 to be thread-safe (see [jackson-core#479] for details), 14 * to not rely on {@code ThreadLocal} access. 15 */ 16 public class BufferRecycler 17 { 18 /** 19 * Buffer used for reading byte-based input. 20 */ 21 public final static int BYTE_READ_IO_BUFFER = 0; 22 23 /** 24 * Buffer used for temporarily storing encoded content; used 25 * for example by UTF-8 encoding writer 26 */ 27 public final static int BYTE_WRITE_ENCODING_BUFFER = 1; 28 29 /** 30 * Buffer used for temporarily concatenating output; used for 31 * example when requesting output as byte array. 32 */ 33 public final static int BYTE_WRITE_CONCAT_BUFFER = 2; 34 35 /** 36 * Buffer used for concatenating binary data that is either being 37 * encoded as base64 output, or decoded from base64 input. 38 * 39 * @since 2.1 40 */ 41 public final static int BYTE_BASE64_CODEC_BUFFER = 3; 42 43 /** 44 * Buffer used as input buffer for tokenization for character-based parsers. 45 */ 46 public final static int CHAR_TOKEN_BUFFER = 0; 47 48 /** 49 * Buffer used by generators; for byte-backed generators for buffering of 50 * {@link String} values to output (before encoding into UTF-8), 51 * and for char-backed generators as actual concatenation buffer. 52 */ 53 public final static int CHAR_CONCAT_BUFFER = 1; 54 55 /** 56 * Used through {@link TextBuffer}: directly by parsers (to concatenate 57 * String values) 58 * and indirectly via 59 * {@link com.fasterxml.jackson.core.io.SegmentedStringWriter} 60 * when serializing (databind level {@code ObjectMapper} and 61 * {@code ObjectWriter}). In both cases used as segments (and not for whole value), 62 * but may result in retention of larger chunks for big content 63 * (long text values during parsing; bigger output documents for generation). 64 */ 65 public final static int CHAR_TEXT_BUFFER = 2; 66 67 /** 68 * For parsers, temporary buffer into which {@code char[]} for names is copied 69 * when requested as such; for {@code WriterBasedGenerator} used for buffering 70 * during {@code writeString(Reader)} operation (not commonly used). 71 */ 72 public final static int CHAR_NAME_COPY_BUFFER = 3; 73 74 // Buffer lengths 75 76 private final static int[] BYTE_BUFFER_LENGTHS = new int[] { 8000, 8000, 2000, 2000 }; 77 private final static int[] CHAR_BUFFER_LENGTHS = new int[] { 4000, 4000, 200, 200 }; 78 79 // Note: changed from simple array in 2.10: 80 protected final AtomicReferenceArray<byte[]> _byteBuffers; 81 82 // Note: changed from simple array in 2.10: 83 protected final AtomicReferenceArray<char[]> _charBuffers; 84 85 /* 86 /********************************************************** 87 /* Construction 88 /********************************************************** 89 */ 90 91 /** 92 * Default constructor used for creating instances of this default 93 * implementation. 94 */ BufferRecycler()95 public BufferRecycler() { 96 this(4, 4); 97 } 98 99 /** 100 * Alternate constructor to be used by sub-classes, to allow customization 101 * of number of low-level buffers in use. 102 * 103 * @since 2.4 104 */ BufferRecycler(int bbCount, int cbCount)105 protected BufferRecycler(int bbCount, int cbCount) { 106 _byteBuffers = new AtomicReferenceArray<byte[]>(bbCount); 107 _charBuffers = new AtomicReferenceArray<char[]>(cbCount); 108 } 109 110 /* 111 /********************************************************** 112 /* Public API, byte buffers 113 /********************************************************** 114 */ 115 116 /** 117 * @param ix One of <code>READ_IO_BUFFER</code> constants. 118 */ allocByteBuffer(int ix)119 public final byte[] allocByteBuffer(int ix) { 120 return allocByteBuffer(ix, 0); 121 } 122 allocByteBuffer(int ix, int minSize)123 public byte[] allocByteBuffer(int ix, int minSize) { 124 final int DEF_SIZE = byteBufferLength(ix); 125 if (minSize < DEF_SIZE) { 126 minSize = DEF_SIZE; 127 } 128 byte[] buffer = _byteBuffers.getAndSet(ix, null); 129 if (buffer == null || buffer.length < minSize) { 130 buffer = balloc(minSize); 131 } 132 return buffer; 133 } 134 releaseByteBuffer(int ix, byte[] buffer)135 public void releaseByteBuffer(int ix, byte[] buffer) { 136 _byteBuffers.set(ix, buffer); 137 } 138 139 /* 140 /********************************************************** 141 /* Public API, char buffers 142 /********************************************************** 143 */ 144 allocCharBuffer(int ix)145 public final char[] allocCharBuffer(int ix) { 146 return allocCharBuffer(ix, 0); 147 } 148 allocCharBuffer(int ix, int minSize)149 public char[] allocCharBuffer(int ix, int minSize) { 150 final int DEF_SIZE = charBufferLength(ix); 151 if (minSize < DEF_SIZE) { 152 minSize = DEF_SIZE; 153 } 154 char[] buffer = _charBuffers.getAndSet(ix, null); 155 if (buffer == null || buffer.length < minSize) { 156 buffer = calloc(minSize); 157 } 158 return buffer; 159 } 160 releaseCharBuffer(int ix, char[] buffer)161 public void releaseCharBuffer(int ix, char[] buffer) { 162 _charBuffers.set(ix, buffer); 163 } 164 165 /* 166 /********************************************************** 167 /* Overridable helper methods 168 /********************************************************** 169 */ 170 byteBufferLength(int ix)171 protected int byteBufferLength(int ix) { 172 return BYTE_BUFFER_LENGTHS[ix]; 173 } 174 charBufferLength(int ix)175 protected int charBufferLength(int ix) { 176 return CHAR_BUFFER_LENGTHS[ix]; 177 } 178 179 /* 180 /********************************************************** 181 /* Actual allocations separated for easier debugging/profiling 182 /********************************************************** 183 */ 184 balloc(int size)185 protected byte[] balloc(int size) { return new byte[size]; } calloc(int size)186 protected char[] calloc(int size) { return new char[size]; } 187 } 188