Skip to content

Commit 1daf69e

Browse files
committed
javadoc + better pool management + pool decorator for debug
1 parent 0712bc0 commit 1daf69e

File tree

3 files changed

+82
-19
lines changed

3 files changed

+82
-19
lines changed

src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,19 @@ protected int charBufferLength(int ix) {
193193
protected char[] calloc(int size) { return new char[size]; }
194194

195195
BufferRecycler withPool(ObjectPool<BufferRecycler> pool) {
196+
if (this._pool != null) {
197+
throw new IllegalStateException();
198+
}
196199
this._pool = pool;
197200
return this;
198201
}
199202

200203
@Override
201204
public void close() {
202205
if (_pool != null) {
203-
_pool.release(this);
206+
ObjectPool<BufferRecycler> tempPool = _pool;
204207
_pool = null;
208+
tempPool.release(this);
205209
}
206210
}
207211
}

src/main/java/com/fasterxml/jackson/core/util/BufferRecyclerPool.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
public class BufferRecyclerPool {
44

5-
private static final ObjectPool<BufferRecycler> pool = ObjectPool.newObjectPool(new BufferRecycler()::withPool);
5+
private static final ObjectPool<BufferRecycler> pool = ObjectPool.newObjectPool(BufferRecycler::new);
66

77
public static BufferRecycler acquireBufferRecycler() {
8-
return pool.acquire();
8+
return pool.acquire().withPool(pool);
99
}
1010

1111
public static void releaseBufferRecycler(BufferRecycler bufferRecycler) {

src/main/java/com/fasterxml/jackson/core/util/ObjectPool.java

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,19 @@
33
import java.util.Deque;
44
import java.util.concurrent.ConcurrentLinkedDeque;
55
import java.util.concurrent.atomic.AtomicReference;
6+
import java.util.concurrent.atomic.LongAdder;
67
import java.util.function.Consumer;
78
import java.util.function.Function;
8-
9+
import java.util.function.Supplier;
10+
11+
/**
12+
* This is a utility class, whose main functionality is pooling object
13+
* with a huge memory footprint and that are costly to be recreated at
14+
* every usage like the {@link BufferRecycler}. It is intended for
15+
* internal use only.
16+
*
17+
* @since 2.16
18+
*/
919
public interface ObjectPool<T> extends AutoCloseable {
1020

1121
T acquire();
@@ -21,7 +31,22 @@ default void withPooledObject(Consumer<T> objectConsumer) {
2131
}
2232

2333
enum Strategy {
24-
CONCURRENT_DEQUEUE, LOCK_FREE
34+
CONCURRENT_DEQUEUE(ConcurrentDequePool::new, false), LOCK_FREE(LockFreePool::new, false),
35+
DEBUG_CONCURRENT_DEQUEUE(ConcurrentDequePool::new, true), DEBUG_LOCK_FREE(LockFreePool::new, true);
36+
37+
private final Function<Supplier, ObjectPool> constructor;
38+
39+
private final boolean debug;
40+
41+
Strategy(Function<Supplier, ObjectPool> constructor, boolean debug) {
42+
this.constructor = constructor;
43+
this.debug = debug;
44+
}
45+
46+
<T> ObjectPool<T> newObjectPool(Supplier<T> factory) {
47+
ObjectPool<T> pool = constructor.apply(factory);
48+
return debug ? new DebugPoolDecorator<>(pool) : pool;
49+
}
2550
}
2651

2752
class StrategyHolder {
@@ -32,33 +57,29 @@ public static void setStrategy(String name) {
3257
}
3358
}
3459

35-
static <T> ObjectPool<T> newObjectPool(Function<ObjectPool<T>, T> factory) {
36-
switch (StrategyHolder.strategy) {
37-
case CONCURRENT_DEQUEUE: return new ConcurrentDequePool<>(factory);
38-
case LOCK_FREE: return new LockFreePool<>(factory);
39-
}
40-
throw new UnsupportedOperationException();
60+
static <T> ObjectPool<T> newObjectPool(Supplier<T> factory) {
61+
return StrategyHolder.strategy.newObjectPool(factory);
4162
}
4263

4364
class ConcurrentDequePool<T> implements ObjectPool<T> {
44-
private final Function<ObjectPool<T>, T> factory;
65+
private final Supplier<T> factory;
4566
private final Consumer<T> destroyer;
4667

4768
private final Deque<T> pool = new ConcurrentLinkedDeque<>();
4869

49-
public ConcurrentDequePool(Function<ObjectPool<T>, T> factory) {
70+
public ConcurrentDequePool(Supplier<T> factory) {
5071
this(factory, null);
5172
}
5273

53-
public ConcurrentDequePool(Function<ObjectPool<T>, T> factory, Consumer<T> destroyer) {
74+
public ConcurrentDequePool(Supplier<T> factory, Consumer<T> destroyer) {
5475
this.factory = factory;
5576
this.destroyer = destroyer;
5677
}
5778

5879
@Override
5980
public T acquire() {
6081
T t = pool.pollFirst();
61-
return t != null ? t : factory.apply(this);
82+
return t != null ? t : factory.get();
6283
}
6384

6485
@Override
@@ -77,9 +98,9 @@ public void close() throws Exception {
7798
class LockFreePool<T> implements ObjectPool<T> {
7899
private final AtomicReference<Node<T>> head = new AtomicReference<>();
79100

80-
private final Function<ObjectPool<T>, T> factory;
101+
private final Supplier<T> factory;
81102

82-
public LockFreePool(Function<ObjectPool<T>, T> factory) {
103+
public LockFreePool(Supplier<T> factory) {
83104
this.factory = factory;
84105
}
85106

@@ -88,14 +109,14 @@ public T acquire() {
88109
for (int i = 0; i < 3; i++) {
89110
Node<T> currentHead = head.get();
90111
if (currentHead == null) {
91-
return factory.apply(this);
112+
return factory.get();
92113
}
93114
if (head.compareAndSet(currentHead, currentHead.next)) {
94115
currentHead.next = null;
95116
return currentHead.value;
96117
}
97118
}
98-
return factory.apply(this);
119+
return factory.get();
99120
}
100121

101122
@Override
@@ -123,4 +144,42 @@ static class Node<T> {
123144
}
124145
}
125146
}
147+
148+
class DebugPoolDecorator<T> implements ObjectPool<T> {
149+
150+
private final ObjectPool<T> pool;
151+
152+
private final LongAdder acquireCounter = new LongAdder();
153+
private final LongAdder releaseCounter = new LongAdder();
154+
155+
public DebugPoolDecorator(ObjectPool<T> pool) {
156+
this.pool = pool;
157+
}
158+
159+
@Override
160+
public T acquire() {
161+
acquireCounter.increment();
162+
return pool.acquire();
163+
}
164+
165+
@Override
166+
public void release(T t) {
167+
releaseCounter.increment();
168+
pool.release(t);
169+
}
170+
171+
@Override
172+
public void close() throws Exception {
173+
System.out.println("Closing " + this);
174+
pool.close();
175+
}
176+
177+
@Override
178+
public String toString() {
179+
return "DebugPoolDecorator{" +
180+
"acquires = " + acquireCounter.sum() +
181+
", releases = " + releaseCounter.sum() +
182+
'}';
183+
}
184+
}
126185
}

0 commit comments

Comments
 (0)