Skip to content

Commit

Permalink
Introducing BufferRecyclerPool (#1064)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariofusco authored Aug 31, 2023
1 parent 0beb6fd commit a4ca94f
Show file tree
Hide file tree
Showing 14 changed files with 713 additions and 106 deletions.
24 changes: 13 additions & 11 deletions src/main/java/com/fasterxml/jackson/core/JsonFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@
import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.util.BufferRecyclerPool;
import com.fasterxml.jackson.core.util.BufferRecyclers;
import com.fasterxml.jackson.core.util.JacksonFeature;
import com.fasterxml.jackson.core.util.JsonGeneratorDecorator;
import com.fasterxml.jackson.core.util.Separators;
import com.fasterxml.jackson.core.util.*;

/**
* The main factory class of Jackson package, used to configure and
Expand Down Expand Up @@ -115,8 +110,10 @@ public enum Feature
FAIL_ON_SYMBOL_HASH_OVERFLOW(true),

/**
* Feature that determines whether we will use {@link BufferRecycler} with
* {@link ThreadLocal} and {@link SoftReference}, for efficient reuse of
* Feature that determines whether we will use a {@link BufferRecyclerPool}
* for allocating and possibly recycling {@link BufferRecycler} or not.
* The default {@link BufferRecyclerPool} implementation uses
* {@link ThreadLocal} and {@link SoftReference} for efficient reuse of
* underlying input/output buffers.
* This usually makes sense on normal J2SE/J2EE server-side processing;
* but may not make sense on platforms where {@link SoftReference} handling
Expand All @@ -125,6 +122,10 @@ public enum Feature
* <a href="https://github.com/FasterXML/jackson-core/issues/189">jackson-core#189</a>
* for a possible case)
*<p>
* Note that since 2.16 naming here is somewhat misleading as this is used
* to now enable or disable pooling; but the actual pooling implementation
* is configurable and may not be based on {@link ThreadLocal}.
*<p>
* This setting is enabled by default.
*
* @since 2.6
Expand Down Expand Up @@ -370,7 +371,7 @@ public static int collectDefaults() {
public JsonFactory() { this((ObjectCodec) null); }

public JsonFactory(ObjectCodec oc) {
_bufferRecyclerPool = BufferRecyclers.defaultRecyclerPool();
_bufferRecyclerPool = BufferRecyclerPool.defaultPool();
_objectCodec = oc;
_quoteChar = DEFAULT_QUOTE_CHAR;
_streamReadConstraints = StreamReadConstraints.defaults();
Expand Down Expand Up @@ -1873,6 +1874,7 @@ protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOExce
e.addSuppressed(e2);
}
}
ctxt.close();
throw e;
}
}
Expand Down Expand Up @@ -2151,7 +2153,7 @@ protected JsonGenerator _decorate(JsonGenerator g) {
*/
public BufferRecycler _getBufferRecycler()
{
return _getBufferRecyclerPool().acquireBufferRecycler(this);
return _getBufferRecyclerPool().acquireBufferRecycler();
}

/**
Expand All @@ -2165,7 +2167,7 @@ public BufferRecyclerPool _getBufferRecyclerPool() {
// scheme, for cases where it is considered harmful (possibly
// on Android, for example)
if (!Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING.enabledIn(_factoryFeatures)) {
return BufferRecyclers.nopRecyclerPool();
return BufferRecyclerPool.nonRecyclingPool();
}
return _bufferRecyclerPool;
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/fasterxml/jackson/core/TSFBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.json.JsonWriteFeature;
import com.fasterxml.jackson.core.util.BufferRecyclerPool;
import com.fasterxml.jackson.core.util.BufferRecyclers;
import com.fasterxml.jackson.core.util.JsonGeneratorDecorator;

/**
Expand Down Expand Up @@ -142,7 +141,7 @@ protected TSFBuilder(JsonFactory base)
protected TSFBuilder(int factoryFeatures,
int parserFeatures, int generatorFeatures)
{
_bufferRecyclerPool = BufferRecyclers.defaultRecyclerPool();
_bufferRecyclerPool = BufferRecyclerPool.defaultPool();

_factoryFeatures = factoryFeatures;
_streamReadFeatures = parserFeatures;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
// as per [JACKSON-324], do in finally block
// Also, internal buffer(s) can now be released as well
_releaseBuffers();
_ioContext.close();
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/com/fasterxml/jackson/core/io/IOContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*<p>
* NOTE: non-final since 2.4, to allow sub-classing.
*/
public class IOContext
public class IOContext implements AutoCloseable
{
/*
/**********************************************************************
Expand Down Expand Up @@ -119,6 +119,8 @@ public class IOContext
*/
protected char[] _nameCopyBuffer;

private boolean _closed = false;

/*
/**********************************************************************
/* Life-cycle
Expand Down Expand Up @@ -458,4 +460,12 @@ private IllegalArgumentException wrongBuf() {
// sanity check failed; trying to return different, smaller buffer.
return new IllegalArgumentException("Trying to release buffer smaller than original");
}

@Override
public void close() {
if (!_closed) {
_bufferRecycler.release();
_closed = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public void close()
illegalSurrogate(code);
}
}
_context.close();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ public abstract class JsonGeneratorImpl extends GeneratorBase
/**********************************************************
*/

@Override
public void close() throws IOException {
if (!isClosed()) {
super.close();
_ioContext.close();
}
}

@SuppressWarnings("deprecation")
public JsonGeneratorImpl(IOContext ctxt, int features, ObjectCodec codec)
{
Expand Down Expand Up @@ -237,6 +245,23 @@ public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() {
return JSON_WRITE_CAPABILITIES;
}

/*
/**********************************************************
/* Misc other accessors
/**********************************************************
*/

/**
* Accessor for use by {@code jackson-core} itself (tests in particular).
*
* @return {@link IOContext} in use by this generator
*
* @since 2.16
*/
public IOContext ioContext() {
return _ioContext;
}

/*
/**********************************************************
/* Shared helper methods
Expand Down
48 changes: 43 additions & 5 deletions src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
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 used through
* <code>ThreadLocal</code> member of the owning class pointing to
* instance of this class through a <code>SoftReference</code>. The
* end result is a low-overhead GC-cleanable recycling: hopefully
* simple reuse of raw byte/char buffers. It is usually allocated through
* {@link BufferRecyclerPool} (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.
*<p>
* Rewritten in 2.10 to be thread-safe (see [jackson-core#479] for details),
* to not rely on {@code ThreadLocal} access.
* to not rely on {@code ThreadLocal} access.<br />
* Rewritten in 2.16 to work with {@link BufferRecyclerPool} abstraction.
*/
public class BufferRecycler
{
Expand Down Expand Up @@ -82,6 +86,8 @@ public class BufferRecycler
// Note: changed from simple array in 2.10:
protected final AtomicReferenceArray<char[]> _charBuffers;

private BufferRecyclerPool _pool;

/*
/**********************************************************
/* Construction
Expand Down Expand Up @@ -189,4 +195,36 @@ protected int charBufferLength(int ix) {

protected byte[] balloc(int size) { return new byte[size]; }
protected char[] calloc(int size) { return new char[size]; }

/**
* Method called by owner of this recycler instance, to provide reference to
* {@link BufferRecyclerPool} into which instance is to be released (if any)
*
* @since 2.16
*/
BufferRecycler withPool(BufferRecyclerPool pool) {
if (this._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
*/
public void release() {
if (_pool != null) {
BufferRecyclerPool 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.releaseBufferRecycler(this);
}
}
}
Loading

0 comments on commit a4ca94f

Please sign in to comment.