Skip to content

Fix #399; support SmileBufferRecycler via new 2.16 pluggable mechanism #402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.fasterxml.jackson.dataformat.smile;

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

import com.fasterxml.jackson.core.util.RecyclerPool;
import com.fasterxml.jackson.core.util.RecyclerPool.WithPool;
import com.fasterxml.jackson.dataformat.smile.SmileGenerator.SharedStringNode;

/**
* Simple helper class used for implementing simple reuse system for Smile-specific
* buffers that are used.
*/
public class SmileBufferRecycler
implements WithPool<SmileBufferRecycler>
{
public final static int DEFAULT_NAME_BUFFER_LENGTH = 64;

Expand All @@ -26,6 +30,7 @@ public class SmileBufferRecycler

protected final AtomicReference<SharedStringNode[]> _seenStringValuesWriteBuffer = new AtomicReference<>();

protected RecyclerPool<SmileBufferRecycler> _pool;

public SmileBufferRecycler() { }

Expand Down Expand Up @@ -64,4 +69,39 @@ public void releaseSeenNamesWriteBuffer(SharedStringNode[] buffer) {
public void releaseSeenStringValuesWriteBuffer(SharedStringNode[] buffer) {
_seenStringValuesWriteBuffer.set(buffer);
}

// // // Pooling life-cycle

/**
* 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 SmileBufferRecycler withPool(RecyclerPool<SmileBufferRecycler> pool) {
if (_pool != null) {
throw new IllegalStateException("SmileBufferRecycler 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) {
RecyclerPool<SmileBufferRecycler> 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.fasterxml.jackson.dataformat.smile;

import java.lang.ref.SoftReference;

import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.util.RecyclerPool;

/**
* Newly (in 2.16) added container class for {@link RecyclerPool}s available
* for recycling Smile {@link SmileBufferRecycler} instances.
*
* @since 2.16
*/
public class SmileBufferRecyclers
{
/**
* @return the default {@link RecyclerPool} implementation
* which is the thread local based one:
* basically alias to {@link #threadLocalPool()}).
*/
public static RecyclerPool<SmileBufferRecycler> defaultPool() {
return threadLocalPool();
}
/**
* Accessor for getting the shared/global {@link ThreadLocalPool} instance
* (due to design only one instance ever needed)
*
* @return Globally shared instance of {@link ThreadLocalPool}
*/
public static RecyclerPool<SmileBufferRecycler> threadLocalPool() {
return ThreadLocalPool.GLOBAL;
}

/*
/**********************************************************************
/* Concrete RecyclerPool implementations for recycling BufferRecyclers
/**********************************************************************
*/

/**
* {@link ThreadLocal}-based {@link RecyclerPool} implementation used for
* recycling {@link BufferRecycler} instances:
* see {@link RecyclerPool.ThreadLocalPoolBase} for full explanation
* of functioning.
*/
public static class ThreadLocalPool
extends RecyclerPool.ThreadLocalPoolBase<SmileBufferRecycler>
{
private static final long serialVersionUID = 1L;

/**
* This <code>ThreadLocal</code> contains a {@link java.lang.ref.SoftReference}
* to a {@link BufferRecycler} used to provide a low-cost
* buffer recycling between reader and writer instances.
*/
protected static final ThreadLocal<SoftReference<SmileBufferRecycler>> _recyclerRef
= new ThreadLocal<>();

protected static final ThreadLocalPool GLOBAL = new ThreadLocalPool();

private ThreadLocalPool() { }

@Override
public SmileBufferRecycler acquirePooled() {
SoftReference<SmileBufferRecycler> ref = _recyclerRef.get();
SmileBufferRecycler br = (ref == null) ? null : ref.get();

if (br == null) {
br = new SmileBufferRecycler();
ref = new SoftReference<>(br);
_recyclerRef.set(ref);
}
return br;
}

// // // JDK serialization support

protected Object readResolve() { return GLOBAL; }
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.fasterxml.jackson.dataformat.smile;

import java.io.*;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.Objects;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.format.InputAccessor;
import com.fasterxml.jackson.core.format.MatchStrength;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
import com.fasterxml.jackson.core.util.RecyclerPool;
import com.fasterxml.jackson.dataformat.smile.async.NonBlockingByteArrayParser;

/**
Expand Down Expand Up @@ -61,6 +62,11 @@ public class SmileFactory extends JsonFactory
/**********************************************************
*/

/**
* @since 2.16
*/
protected RecyclerPool<SmileBufferRecycler> _smileRecyclerPool;

/**
* Whether non-supported methods (ones trying to output using
* char-based targets like {@link java.io.Writer}, for example)
Expand All @@ -73,19 +79,6 @@ public class SmileFactory extends JsonFactory
protected int _smileParserFeatures;
protected int _smileGeneratorFeatures;

/*
/**********************************************************
/* Smile-specific buffer recycling (moved here in 2.16)
/**********************************************************

/**
* This <code>ThreadLocal</code> contains a {@link java.lang.ref.SoftReference}
* to a buffer recycler used to provide a low-cost
* buffer recycling for Smile-specific buffers.
*/
final protected static ThreadLocal<SoftReference<SmileBufferRecycler>> _smileRecyclerRef
= new ThreadLocal<SoftReference<SmileBufferRecycler>>();

/*
/**********************************************************
/* Factory construction, configuration
Expand All @@ -106,6 +99,7 @@ public class SmileFactory extends JsonFactory

public SmileFactory(ObjectCodec oc) {
super(oc);
_smileRecyclerPool = SmileBufferRecyclers.defaultPool();
_smileParserFeatures = DEFAULT_SMILE_PARSER_FEATURE_FLAGS;
_smileGeneratorFeatures = DEFAULT_SMILE_GENERATOR_FEATURE_FLAGS;
}
Expand All @@ -119,6 +113,7 @@ public SmileFactory(ObjectCodec oc) {
public SmileFactory(SmileFactory src, ObjectCodec oc)
{
super(src, oc);
_smileRecyclerPool = src._smileRecyclerPool;
_cfgDelegateToTextual = src._cfgDelegateToTextual;
_smileParserFeatures = src._smileParserFeatures;
_smileGeneratorFeatures = src._smileGeneratorFeatures;
Expand All @@ -129,6 +124,7 @@ public SmileFactory(SmileFactory src, ObjectCodec oc)
*/
protected SmileFactory(SmileFactoryBuilder b) {
super(b, false);
_smileRecyclerPool = b.smileRecyclerPool();
_smileParserFeatures = b.formatParserFeaturesMask();
_smileGeneratorFeatures = b.formatGeneratorFeaturesMask();
}
Expand Down Expand Up @@ -334,6 +330,17 @@ public int getFormatGeneratorFeatures() {
return _smileGeneratorFeatures;
}

/*
/**********************************************************
/* Configuration, other
/**********************************************************
*/

public SmileFactory setSmileRecyclerPool(RecyclerPool<SmileBufferRecycler> p) {
_smileRecyclerPool = Objects.requireNonNull(p);
return this;
}

/*
/**********************************************************
/* Overridden parser factory methods: only override methods
Expand Down Expand Up @@ -547,15 +554,8 @@ protected SmileGenerator _createGenerator(OutputStream out, IOContext ctxt) thro
return gen;
}

protected final static SmileBufferRecycler _smileBufferRecycler()
protected SmileBufferRecycler _smileBufferRecycler()
{
SoftReference<SmileBufferRecycler> ref = _smileRecyclerRef.get();
SmileBufferRecycler br = (ref == null) ? null : ref.get();

if (br == null) {
br = new SmileBufferRecycler();
_smileRecyclerRef.set(new SoftReference<SmileBufferRecycler>(br));
}
return br;
return _smileRecyclerPool.acquireAndLinkPooled();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.fasterxml.jackson.dataformat.smile;

import java.util.Objects;

import com.fasterxml.jackson.core.TSFBuilder;
import com.fasterxml.jackson.core.util.RecyclerPool;

/**
* {@link com.fasterxml.jackson.core.TSFBuilder}
Expand All @@ -17,6 +20,11 @@ public class SmileFactoryBuilder extends TSFBuilder<SmileFactory, SmileFactoryBu
/**********************************************************
*/

/**
* @since 2.16
*/
protected RecyclerPool<SmileBufferRecycler> _smileRecyclerPool;

/**
* Set of {@link SmileParser.Feature}s enabled, as bitmask.
*/
Expand All @@ -34,12 +42,14 @@ public class SmileFactoryBuilder extends TSFBuilder<SmileFactory, SmileFactoryBu
*/

protected SmileFactoryBuilder() {
_smileRecyclerPool = SmileBufferRecyclers.defaultPool();
_formatParserFeatures = SmileFactory.DEFAULT_SMILE_PARSER_FEATURE_FLAGS;
_formatGeneratorFeatures = SmileFactory.DEFAULT_SMILE_GENERATOR_FEATURE_FLAGS;
}

public SmileFactoryBuilder(SmileFactory base) {
super(base);
_smileRecyclerPool = base._smileRecyclerPool;
_formatParserFeatures = base._smileParserFeatures;
_formatGeneratorFeatures = base._smileGeneratorFeatures;
}
Expand Down Expand Up @@ -114,8 +124,27 @@ public SmileFactoryBuilder configure(SmileGenerator.Feature f, boolean state) {
return state ? enable(f) : disable(f);
}

// // // Other configuration

/**
* @param p RecyclerPool to use for buffer allocation
*
* @return this builder (for call chaining)
*
* @since 2.16
*/
public SmileFactoryBuilder smileRcyclerPool(RecyclerPool<SmileBufferRecycler> p) {
_smileRecyclerPool = Objects.requireNonNull(p);
return _this();
}

// // // Accessors

// @since 2.16
public RecyclerPool<SmileBufferRecycler> smileRecyclerPool() {
return _smileRecyclerPool;
}

public int formatParserFeaturesMask() { return _formatParserFeatures; }
public int formatGeneratorFeaturesMask() { return _formatGeneratorFeatures; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public SharedStringNode(String value, int index, SharedStringNode next)
* Helper object used for low-level recycling of Smile-generator
* specific buffers.
*/
protected final SmileBufferRecycler _smileBufferRecycler;
protected SmileBufferRecycler _smileBufferRecycler;

/*
/**********************************************************************
Expand Down Expand Up @@ -2632,7 +2632,8 @@ protected void _releaseBuffers()
/* Ok: since clearing up of larger arrays is much slower,
* let's only recycle default-sized buffers...
*/
{
SmileBufferRecycler br = _smileBufferRecycler;
if (br != null) {
SharedStringNode[] nameBuf = _seenNames;
if (nameBuf != null && nameBuf.length == SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH) {
_seenNames = null;
Expand All @@ -2644,8 +2645,6 @@ protected void _releaseBuffers()
}
_smileBufferRecycler.releaseSeenNamesWriteBuffer(nameBuf);
}
}
{
SharedStringNode[] valueBuf = _seenStringValues;
if (valueBuf != null && valueBuf.length == SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH) {
_seenStringValues = null;
Expand All @@ -2657,6 +2656,8 @@ protected void _releaseBuffers()
}
_smileBufferRecycler.releaseSeenStringValuesWriteBuffer(valueBuf);
}
_smileBufferRecycler = null;
br.release();
}
}

Expand Down
Loading