From 3a0f9e5c384504e0e2ea03b801ba2f964d373a84 Mon Sep 17 00:00:00 2001 From: mariofusco Date: Fri, 28 Jul 2023 09:58:59 +0200 Subject: [PATCH] javadoc + better pool management + pool decorator for debug --- .../jackson/core/util/BufferRecycler.java | 6 +- .../jackson/core/util/BufferRecyclerPool.java | 4 +- .../jackson/core/util/ObjectPool.java | 91 +++++++++++++++---- 3 files changed, 82 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java b/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java index 26516ec233..4c8843610f 100644 --- a/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java +++ b/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java @@ -193,6 +193,9 @@ protected int charBufferLength(int ix) { protected char[] calloc(int size) { return new char[size]; } BufferRecycler withPool(ObjectPool pool) { + if (this._pool != null) { + throw new IllegalStateException(); + } this._pool = pool; return this; } @@ -200,8 +203,9 @@ BufferRecycler withPool(ObjectPool pool) { @Override public void close() { if (_pool != null) { - _pool.release(this); + ObjectPool tempPool = _pool; _pool = null; + tempPool.release(this); } } } diff --git a/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclerPool.java b/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclerPool.java index 47750eb69d..d93b9df61a 100644 --- a/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclerPool.java +++ b/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclerPool.java @@ -2,10 +2,10 @@ public class BufferRecyclerPool { - private static final ObjectPool pool = ObjectPool.newObjectPool(new BufferRecycler()::withPool); + private static final ObjectPool pool = ObjectPool.newObjectPool(BufferRecycler::new); public static BufferRecycler acquireBufferRecycler() { - return pool.acquire(); + return pool.acquire().withPool(pool); } public static void releaseBufferRecycler(BufferRecycler bufferRecycler) { diff --git a/src/main/java/com/fasterxml/jackson/core/util/ObjectPool.java b/src/main/java/com/fasterxml/jackson/core/util/ObjectPool.java index 3b01b63693..c17d78cc2a 100644 --- a/src/main/java/com/fasterxml/jackson/core/util/ObjectPool.java +++ b/src/main/java/com/fasterxml/jackson/core/util/ObjectPool.java @@ -3,9 +3,19 @@ import java.util.Deque; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.LongAdder; import java.util.function.Consumer; import java.util.function.Function; - +import java.util.function.Supplier; + +/** + * This is a utility class, whose main functionality is pooling object + * with a huge memory footprint and that are costly to be recreated at + * every usage like the {@link BufferRecycler}. It is intended for + * internal use only. + * + * @since 2.16 + */ public interface ObjectPool extends AutoCloseable { T acquire(); @@ -21,7 +31,22 @@ default void withPooledObject(Consumer objectConsumer) { } enum Strategy { - CONCURRENT_DEQUEUE, LOCK_FREE + CONCURRENT_DEQUEUE(ConcurrentDequePool::new, false), LOCK_FREE(LockFreePool::new, false), + DEBUG_CONCURRENT_DEQUEUE(ConcurrentDequePool::new, true), DEBUG_LOCK_FREE(LockFreePool::new, true); + + private final Function constructor; + + private final boolean debug; + + Strategy(Function constructor, boolean debug) { + this.constructor = constructor; + this.debug = debug; + } + + ObjectPool newObjectPool(Supplier factory) { + ObjectPool pool = constructor.apply(factory); + return debug ? new DebugPoolDecorator<>(pool) : pool; + } } class StrategyHolder { @@ -32,25 +57,21 @@ public static void setStrategy(String name) { } } - static ObjectPool newObjectPool(Function, T> factory) { - switch (StrategyHolder.strategy) { - case CONCURRENT_DEQUEUE: return new ConcurrentDequePool<>(factory); - case LOCK_FREE: return new LockFreePool<>(factory); - } - throw new UnsupportedOperationException(); + static ObjectPool newObjectPool(Supplier factory) { + return StrategyHolder.strategy.newObjectPool(factory); } class ConcurrentDequePool implements ObjectPool { - private final Function, T> factory; + private final Supplier factory; private final Consumer destroyer; private final Deque pool = new ConcurrentLinkedDeque<>(); - public ConcurrentDequePool(Function, T> factory) { + public ConcurrentDequePool(Supplier factory) { this(factory, null); } - public ConcurrentDequePool(Function, T> factory, Consumer destroyer) { + public ConcurrentDequePool(Supplier factory, Consumer destroyer) { this.factory = factory; this.destroyer = destroyer; } @@ -58,7 +79,7 @@ public ConcurrentDequePool(Function, T> factory, Consumer destr @Override public T acquire() { T t = pool.pollFirst(); - return t != null ? t : factory.apply(this); + return t != null ? t : factory.get(); } @Override @@ -77,9 +98,9 @@ public void close() throws Exception { class LockFreePool implements ObjectPool { private final AtomicReference> head = new AtomicReference<>(); - private final Function, T> factory; + private final Supplier factory; - public LockFreePool(Function, T> factory) { + public LockFreePool(Supplier factory) { this.factory = factory; } @@ -88,14 +109,14 @@ public T acquire() { for (int i = 0; i < 3; i++) { Node currentHead = head.get(); if (currentHead == null) { - return factory.apply(this); + return factory.get(); } if (head.compareAndSet(currentHead, currentHead.next)) { currentHead.next = null; return currentHead.value; } } - return factory.apply(this); + return factory.get(); } @Override @@ -123,4 +144,42 @@ static class Node { } } } + + class DebugPoolDecorator implements ObjectPool { + + private final ObjectPool pool; + + private final LongAdder acquireCounter = new LongAdder(); + private final LongAdder releaseCounter = new LongAdder(); + + public DebugPoolDecorator(ObjectPool pool) { + this.pool = pool; + } + + @Override + public T acquire() { + acquireCounter.increment(); + return pool.acquire(); + } + + @Override + public void release(T t) { + releaseCounter.increment(); + pool.release(t); + } + + @Override + public void close() throws Exception { + System.out.println("Closing " + this); + pool.close(); + } + + @Override + public String toString() { + return "DebugPoolDecorator{" + + "acquires = " + acquireCounter.sum() + + ", releases = " + releaseCounter.sum() + + '}'; + } + } }