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