From a1945571c46a3068bb0caa72970994f77501e286 Mon Sep 17 00:00:00 2001 From: Chris Vest Date: Sat, 6 Jul 2024 21:08:50 -0700 Subject: [PATCH] Separate API and internals and make tests modular --- api-changes.json | 178 ++++++++++++++ pom.xml | 22 +- src/main/java/module-info.java | 2 +- src/main/java/stormpot/Expiration.java | 5 + src/main/java/stormpot/Pool.java | 39 ++- src/main/java/stormpot/PoolBuilder.java | 195 ++------------- src/main/java/stormpot/PoolTap.java | 22 +- src/main/java/stormpot/SlotInfo.java | 4 +- src/main/java/stormpot/Timeout.java | 4 + .../{ => internal}/AllocationController.java | 9 +- .../{ => internal}/AllocationProcess.java | 26 +- .../{ => internal}/AllocationProcessMode.java | 4 +- .../stormpot/{ => internal}/BAllocThread.java | 12 +- .../java/stormpot/{ => internal}/BSlot.java | 25 +- .../stormpot/{ => internal}/BSlotCache.java | 6 +- .../stormpot/{ => internal}/BlazePool.java | 18 +- .../BlazePoolThreadLocalTap.java | 9 +- .../DirectAllocationController.java | 9 +- .../{ => internal}/EveryExpiration.java | 10 +- .../InlineAllocationController.java | 12 +- .../{ => internal}/LatchCompletion.java | 7 +- .../stormpot/{ => internal}/NanoClock.java | 6 +- .../stormpot/{ => internal}/OrExpiration.java | 10 +- .../{ => internal}/PoolBuilderDefaults.java | 19 +- .../stormpot/internal/PoolBuilderImpl.java | 229 ++++++++++++++++++ .../PoolBuilderPermissions.java | 4 +- .../{ => internal}/PreciseLeakDetector.java | 12 +- .../{ => internal}/ReallocatingAdaptor.java | 13 +- .../stormpot/{ => internal}/RefillPile.java | 14 +- .../stormpot/{ => internal}/RefillSlot.java | 6 +- .../{ => internal}/StormpotThreadFactory.java | 6 +- .../{ => internal}/ThreadLocalBSlotCache.java | 6 +- .../ThreadedAllocationController.java | 9 +- .../{ => internal}/TimeExpiration.java | 10 +- .../{ => internal}/TimeSpreadExpiration.java | 10 +- .../TimingReallocatingAdaptor.java | 12 +- .../TimingReallocatorAdaptor.java | 11 +- src/test/java/module-info.java | 27 +++ .../java/stormpot/{ => tests}/BSlotTest.java | 15 +- .../PoolBuilderReallocatingAdaptorTest.java | 32 ++- .../{ => tests}/PreciseLeakDetectorIT.java | 3 +- .../{ => tests}/PreciseLeakDetectorTest.java | 3 +- .../{ => tests}/ReallocatingAdaptorTest.java | 9 +- .../stormpot/{ => tests}/RefillPileTest.java | 7 +- .../{ => tests}/WhiteboxPoolBuilderTest.java | 43 ++-- .../{ => tests}/WhiteboxPoolTest.java | 8 +- .../tests}/blackbox/AbstractPoolTest.java | 4 +- .../blackbox/AllocatorBasedPoolTest.java | 2 +- .../tests}/blackbox/DefaultPoolTest.java | 2 +- .../tests}/blackbox/DirectPoolTest.java | 2 +- .../tests}/blackbox/ExpirationTest.java | 2 +- .../tests}/blackbox/InlinePoolTest.java | 2 +- .../tests}/blackbox/PoolBuilderTest.java | 5 +- .../tests}/blackbox/PooledTest.java | 2 +- .../{ => stormpot/tests}/blackbox/Taps.java | 2 +- .../tests}/blackbox/ThreadBasedPoolTest.java | 2 +- .../tests}/blackbox/ThreadedPoolTest.java | 2 +- .../tests}/blackbox/TimeoutTest.java | 2 +- ...onstantTrafficBackgroundExpirationSim.java | 2 +- .../tests}/blackbox/simulations/README.adoc | 0 .../tests}/blackbox/simulations/Sim.java | 2 +- .../simulations/TimeSpreadExpirationSim.java | 2 +- .../simulations/VariableTrafficSim.java | 2 +- .../tests}/blackbox/slow/DefaultPoolIT.java | 2 +- .../tests}/blackbox/slow/InlinePoolIT.java | 2 +- .../tests}/blackbox/slow/PoolIT.java | 6 +- .../blackbox/slow/ThreadBasedPoolIT.java | 2 +- .../tests}/blackbox/slow/ThreadedPoolIT.java | 2 +- .../tests}/extensions/ExecutorExtension.java | 2 +- .../extensions/FailurePrinterExtension.java | 2 +- src/test/java/testkits/SlotInfoStub.java | 5 + src/test/resources/junit-platform.properties | 3 + 72 files changed, 811 insertions(+), 394 deletions(-) create mode 100644 api-changes.json rename src/main/java/stormpot/{ => internal}/AllocationController.java (88%) rename src/main/java/stormpot/{ => internal}/AllocationProcess.java (80%) rename src/main/java/stormpot/{ => internal}/AllocationProcessMode.java (91%) rename src/main/java/stormpot/{ => internal}/BAllocThread.java (97%) rename src/main/java/stormpot/{ => internal}/BSlot.java (92%) rename src/main/java/stormpot/{ => internal}/BSlotCache.java (85%) rename src/main/java/stormpot/{ => internal}/BlazePool.java (96%) rename src/main/java/stormpot/{ => internal}/BlazePoolThreadLocalTap.java (86%) rename src/main/java/stormpot/{ => internal}/DirectAllocationController.java (94%) rename src/main/java/stormpot/{ => internal}/EveryExpiration.java (81%) rename src/main/java/stormpot/{ => internal}/InlineAllocationController.java (97%) rename src/main/java/stormpot/{ => internal}/LatchCompletion.java (88%) rename src/main/java/stormpot/{ => internal}/NanoClock.java (90%) rename src/main/java/stormpot/{ => internal}/OrExpiration.java (85%) rename src/main/java/stormpot/{ => internal}/PoolBuilderDefaults.java (74%) create mode 100644 src/main/java/stormpot/internal/PoolBuilderImpl.java rename src/main/java/stormpot/{ => internal}/PoolBuilderPermissions.java (92%) rename src/main/java/stormpot/{ => internal}/PreciseLeakDetector.java (95%) rename src/main/java/stormpot/{ => internal}/ReallocatingAdaptor.java (79%) rename src/main/java/stormpot/{ => internal}/RefillPile.java (91%) rename src/main/java/stormpot/{ => internal}/RefillSlot.java (89%) rename src/main/java/stormpot/{ => internal}/StormpotThreadFactory.java (85%) rename src/main/java/stormpot/{ => internal}/ThreadLocalBSlotCache.java (82%) rename src/main/java/stormpot/{ => internal}/ThreadedAllocationController.java (90%) rename src/main/java/stormpot/{ => internal}/TimeExpiration.java (89%) rename src/main/java/stormpot/{ => internal}/TimeSpreadExpiration.java (94%) rename src/main/java/stormpot/{ => internal}/TimingReallocatingAdaptor.java (88%) rename src/main/java/stormpot/{ => internal}/TimingReallocatorAdaptor.java (86%) create mode 100644 src/test/java/module-info.java rename src/test/java/stormpot/{ => tests}/BSlotTest.java (85%) rename src/test/java/stormpot/{ => tests}/PoolBuilderReallocatingAdaptorTest.java (89%) rename src/test/java/stormpot/{ => tests}/PreciseLeakDetectorIT.java (98%) rename src/test/java/stormpot/{ => tests}/PreciseLeakDetectorTest.java (98%) rename src/test/java/stormpot/{ => tests}/ReallocatingAdaptorTest.java (93%) rename src/test/java/stormpot/{ => tests}/RefillPileTest.java (96%) rename src/test/java/stormpot/{ => tests}/WhiteboxPoolBuilderTest.java (72%) rename src/test/java/stormpot/{ => tests}/WhiteboxPoolTest.java (91%) rename src/test/java/{ => stormpot/tests}/blackbox/AbstractPoolTest.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/AllocatorBasedPoolTest.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/DefaultPoolTest.java (96%) rename src/test/java/{ => stormpot/tests}/blackbox/DirectPoolTest.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/ExpirationTest.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/InlinePoolTest.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/PoolBuilderTest.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/PooledTest.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/Taps.java (97%) rename src/test/java/{ => stormpot/tests}/blackbox/ThreadBasedPoolTest.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/ThreadedPoolTest.java (96%) rename src/test/java/{ => stormpot/tests}/blackbox/TimeoutTest.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/simulations/README.adoc (100%) rename src/test/java/{ => stormpot/tests}/blackbox/simulations/Sim.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/simulations/TimeSpreadExpirationSim.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/simulations/VariableTrafficSim.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/slow/DefaultPoolIT.java (96%) rename src/test/java/{ => stormpot/tests}/blackbox/slow/InlinePoolIT.java (96%) rename src/test/java/{ => stormpot/tests}/blackbox/slow/PoolIT.java (98%) rename src/test/java/{ => stormpot/tests}/blackbox/slow/ThreadBasedPoolIT.java (99%) rename src/test/java/{ => stormpot/tests}/blackbox/slow/ThreadedPoolIT.java (96%) rename src/test/java/{ => stormpot/tests}/extensions/ExecutorExtension.java (99%) rename src/test/java/{ => stormpot/tests}/extensions/FailurePrinterExtension.java (99%) create mode 100644 src/test/resources/junit-platform.properties diff --git a/api-changes.json b/api-changes.json new file mode 100644 index 00000000..baa27eb7 --- /dev/null +++ b/api-changes.json @@ -0,0 +1,178 @@ +[ + { + "extension": "revapi.versions", + "configuration": { + "enabled": true, + "semantic0": true, + "strictSemver": true, + "versionIncreaseAllows": { + "major": { + "severity": "BREAKING" + }, + "minor": { + "severity": "NON_BREAKING" + }, + "patch": { + "severity": "EQUIVALENT" + } + } + } + }, + { + "extension": "revapi.differences", + "configuration": { + "ignore": true, + "differences": [ + { + "code": "java.class.noLongerInheritsFromClass", + "old": "class stormpot.Pool", + "new": "interface stormpot.Pool", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.class.kindChanged", + "old": "class stormpot.Pool", + "new": "interface stormpot.Pool", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.Pool stormpot.PoolBuilder::build()", + "new": "method stormpot.Pool stormpot.PoolBuilder::build()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::clone()", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::clone()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.Allocator stormpot.PoolBuilder::getAllocator()", + "new": "method stormpot.Allocator stormpot.PoolBuilder::getAllocator()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method int stormpot.PoolBuilder::getBackgroundExpirationCheckDelay()", + "new": "method int stormpot.PoolBuilder::getBackgroundExpirationCheckDelay()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.Expiration stormpot.PoolBuilder::getExpiration()", + "new": "method stormpot.Expiration stormpot.PoolBuilder::getExpiration()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.MetricsRecorder stormpot.PoolBuilder::getMetricsRecorder()", + "new": "method stormpot.MetricsRecorder stormpot.PoolBuilder::getMetricsRecorder()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.Reallocator stormpot.PoolBuilder::getReallocator()", + "new": "method stormpot.Reallocator stormpot.PoolBuilder::getReallocator()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method int stormpot.PoolBuilder::getSize()", + "new": "method int stormpot.PoolBuilder::getSize()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method java.util.concurrent.ThreadFactory stormpot.PoolBuilder::getThreadFactory()", + "new": "method java.util.concurrent.ThreadFactory stormpot.PoolBuilder::getThreadFactory()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method boolean stormpot.PoolBuilder::isBackgroundExpirationEnabled()", + "new": "method boolean stormpot.PoolBuilder::isBackgroundExpirationEnabled()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method boolean stormpot.PoolBuilder::isPreciseLeakDetectionEnabled()", + "new": "method boolean stormpot.PoolBuilder::isPreciseLeakDetectionEnabled()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setAllocator(stormpot.Allocator)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setAllocator(stormpot.Allocator)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setBackgroundExpirationCheckDelay(int)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setBackgroundExpirationCheckDelay(int)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setBackgroundExpirationEnabled(boolean)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setBackgroundExpirationEnabled(boolean)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setExpiration(stormpot.Expiration)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setExpiration(stormpot.Expiration)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setMetricsRecorder(stormpot.MetricsRecorder)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setMetricsRecorder(stormpot.MetricsRecorder)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setPreciseLeakDetectionEnabled(boolean)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setPreciseLeakDetectionEnabled(boolean)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setSize(int)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setSize(int)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.nowAbstract", + "old": "method stormpot.PoolBuilder stormpot.PoolBuilder::setThreadFactory(java.util.concurrent.ThreadFactory)", + "new": "method stormpot.PoolBuilder stormpot.PoolBuilder::setThreadFactory(java.util.concurrent.ThreadFactory)", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.class.kindChanged", + "old": "class stormpot.PoolBuilder", + "new": "interface stormpot.PoolBuilder", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.class.nowAbstract", + "old": "class stormpot.PoolBuilder", + "new": "interface stormpot.PoolBuilder", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.class.kindChanged", + "old": "class stormpot.PoolTap", + "new": "interface stormpot.PoolTap", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + }, + { + "code": "java.method.addedToInterface", + "new": "method long stormpot.SlotInfo::getCreatedNanoTime()", + "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" + } + ] + } + } +] diff --git a/pom.xml b/pom.xml index 8b8e3c72..58ce5c69 100644 --- a/pom.xml +++ b/pom.xml @@ -117,12 +117,6 @@ false @{argLine} - --add-opens stormpot/stormpot=ALL-UNNAMED - --add-opens stormpot/blackbox=ALL-UNNAMED - --add-opens stormpot/extensions=ALL-UNNAMED - -Djunit.jupiter.execution.parallel.enabled=true - -Djunit.jupiter.execution.parallel.mode.classes.default=concurrent - -Djunit.jupiter.execution.timeout.default=30m -Djdk.attach.allowAttachSelf @@ -135,12 +129,6 @@ false @{argLine} - --add-opens stormpot/stormpot=ALL-UNNAMED - --add-opens stormpot/blackbox=ALL-UNNAMED - --add-opens stormpot/extensions=ALL-UNNAMED - -Djunit.jupiter.execution.parallel.enabled=true - -Djunit.jupiter.execution.parallel.mode.classes.default=concurrent - -Djunit.jupiter.execution.timeout.default=30m -Djdk.attach.allowAttachSelf @@ -312,7 +300,11 @@ - 3.0.1 + + + api-changes.json + + @@ -395,7 +387,7 @@ org.hdrhistogram HdrHistogram - 2.2.1 + 2.2.2 test @@ -420,7 +412,7 @@ --snippet-path - ${build.testSourceDirectory}/examples/ + ${project.build.testSourceDirectory}/examples/ true diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 2a2bee9c..a16699f6 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -29,6 +29,6 @@ */ module stormpot { requires transitive java.management; - requires static java.sql; // For testing only. exports stormpot; + exports stormpot.internal to stormpot.test; } diff --git a/src/main/java/stormpot/Expiration.java b/src/main/java/stormpot/Expiration.java index 9e6d7049..edff0ef4 100644 --- a/src/main/java/stormpot/Expiration.java +++ b/src/main/java/stormpot/Expiration.java @@ -15,6 +15,11 @@ */ package stormpot; +import stormpot.internal.EveryExpiration; +import stormpot.internal.OrExpiration; +import stormpot.internal.TimeExpiration; +import stormpot.internal.TimeSpreadExpiration; + import java.util.concurrent.TimeUnit; /** diff --git a/src/main/java/stormpot/Pool.java b/src/main/java/stormpot/Pool.java index c52c0dbd..30dda9a8 100644 --- a/src/main/java/stormpot/Pool.java +++ b/src/main/java/stormpot/Pool.java @@ -15,9 +15,11 @@ */ package stormpot; -import static stormpot.AllocationProcess.direct; -import static stormpot.AllocationProcess.inline; -import static stormpot.AllocationProcess.threaded; +import stormpot.internal.PoolBuilderImpl; + +import static stormpot.internal.AllocationProcess.direct; +import static stormpot.internal.AllocationProcess.inline; +import static stormpot.internal.AllocationProcess.threaded; /** * A Pool is a self-renewable set of objects from which one can claim exclusive @@ -72,10 +74,7 @@ * by the configured allocator. * @see stormpot.PoolTap */ -public abstract class Pool extends PoolTap { - Pool() { - } - +public interface Pool extends PoolTap { /** * Get a {@link PoolBuilder} based on the given {@link Allocator} or * {@link Reallocator}, which can then in turn be used to @@ -92,7 +91,7 @@ public abstract class Pool extends PoolTap { * before the pool instance is {@linkplain PoolBuilder#build() built}. * @see #fromThreaded(Allocator) */ - public static PoolBuilder from(Allocator allocator) { + static PoolBuilder from(Allocator allocator) { return fromThreaded(allocator); } @@ -120,8 +119,8 @@ public static PoolBuilder from(Allocator allocator) { * @return A {@link PoolBuilder} that admits additional configurations, * before the pool instance is {@linkplain PoolBuilder#build() built}. */ - public static PoolBuilder fromThreaded(Allocator allocator) { - return new PoolBuilder<>(threaded(), allocator); + static PoolBuilder fromThreaded(Allocator allocator) { + return new PoolBuilderImpl<>(threaded(), allocator); } /** @@ -147,8 +146,8 @@ public static PoolBuilder fromThreaded(Allocator allo * @return A {@link PoolBuilder} that admits additional configurations, * before the pool instance is {@linkplain PoolBuilder#build() built}. */ - public static PoolBuilder fromInline(Allocator allocator) { - return new PoolBuilder<>(inline(), allocator); + static PoolBuilder fromInline(Allocator allocator) { + return new PoolBuilderImpl<>(inline(), allocator); } /** @@ -185,7 +184,7 @@ public static PoolBuilder fromInline(Allocator alloca * @return A pool of the given objects. */ @SafeVarargs - public static Pool> of(T... objects) { + static Pool> of(T... objects) { Allocator> allocator = new Allocator<>() { private int index; @Override @@ -197,7 +196,7 @@ public Pooled allocate(Slot slot) { public void deallocate(Pooled poolable) { } }; - PoolBuilder> builder = new PoolBuilder<>(direct(), allocator); + PoolBuilder> builder = new PoolBuilderImpl<>(direct(), allocator); builder.setSize(objects.length); return builder.build(); } @@ -232,7 +231,7 @@ public void deallocate(Pooled poolable) { * @return A {@link Completion} instance that represents the shutdown * process. */ - public abstract Completion shutdown(); + Completion shutdown(); /** * Set the target size for this pool. The pool will strive to keep this many @@ -256,7 +255,7 @@ public void deallocate(Pooled poolable) { * * @param size The new target size of the pool */ - public abstract void setTargetSize(int size); + void setTargetSize(int size); /** * Get the currently configured target size of the pool. Note that this is @@ -265,20 +264,20 @@ public void deallocate(Pooled poolable) { * * @return The current target size of this pool. */ - public abstract int getTargetSize(); + int getTargetSize(); /** * Get the {@link ManagedPool} instance that represents this pool. * @return The {@link ManagedPool} instance for this pool. */ - public abstract ManagedPool getManagedPool(); + ManagedPool getManagedPool(); /** * Get a thread-safe {@link PoolTap} implementation for this pool, which can * be freely shared among multiple threads. * @return A thread-safe {@link PoolTap}. */ - public final PoolTap getThreadSafeTap() { + default PoolTap getThreadSafeTap() { // We use the anonymous inner class to enforce encapsulation, which is // probably the only reason anyone would wan to use this. return new PoolTap<>() { @@ -308,5 +307,5 @@ public T tryClaim() { * * @return A thread-local {@link PoolTap}. */ - public abstract PoolTap getThreadLocalTap(); + PoolTap getThreadLocalTap(); } diff --git a/src/main/java/stormpot/PoolBuilder.java b/src/main/java/stormpot/PoolBuilder.java index 19156c35..ef8668db 100644 --- a/src/main/java/stormpot/PoolBuilder.java +++ b/src/main/java/stormpot/PoolBuilder.java @@ -15,19 +15,11 @@ */ package stormpot; -import java.util.Map; +import stormpot.internal.PoolBuilderImpl; + import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import static java.util.Objects.requireNonNull; -import static java.util.concurrent.TimeUnit.MINUTES; -import static stormpot.AllocationProcessMode.DIRECT; -import static stormpot.AllocationProcessMode.INLINE; -import static stormpot.AllocationProcessMode.THREADED; -import static stormpot.Expiration.after; -import static stormpot.Expiration.never; -import static stormpot.StormpotThreadFactory.INSTANCE; - /** * The {@code PoolBuilder} collects information about how big a pool should be, * and how it should allocate objects, and so on, and finally acts as the @@ -48,47 +40,9 @@ * @param The type of {@link Poolable} objects that a {@link Pool} based * on this {@code PoolBuilder} will produce. */ -public final class PoolBuilder implements Cloneable { - static final Map DEFAULTS = Map.of( - THREADED, new PoolBuilderDefaults(after(8, 10, MINUTES), INSTANCE, true, true, 1000), - INLINE, new PoolBuilderDefaults(after(8, 10, MINUTES), INSTANCE, true, false, 0), - DIRECT, new PoolBuilderDefaults(never(), INSTANCE, false, false, 0) - ); - - static final Map PERMISSIONS = Map.of( - THREADED, new PoolBuilderPermissions(true, true, true, true, true), - INLINE, new PoolBuilderPermissions(true, true, true, false, false), - DIRECT, new PoolBuilderPermissions(false, true, false, false, false) - ); - - private final AllocationProcess allocationProcess; - private final PoolBuilderPermissions permissions; - private Allocator allocator; - private int size = 10; - private Expiration expiration; - private MetricsRecorder metricsRecorder; - private ThreadFactory threadFactory; - private boolean preciseLeakDetectionEnabled; - private boolean backgroundExpirationEnabled; - private int backgroundExpirationCheckDelay; - - /** - * Build a new empty {@code PoolBuilder} object. - */ - PoolBuilder(AllocationProcess allocationProcess, Allocator allocator) { - requireNonNull(allocator, "The Allocator cannot be null."); - requireNonNull(allocationProcess, "The AllocationProcess cannot be null."); - this.allocator = allocator; - this.allocationProcess = allocationProcess; - this.permissions = PERMISSIONS.get(allocationProcess.getMode()); - PoolBuilderDefaults defaults = DEFAULTS.get(allocationProcess.getMode()); - this.expiration = defaults.expiration; - this.threadFactory = defaults.threadFactory; - this.preciseLeakDetectionEnabled = defaults.preciseLeakDetectionEnabled; - this.backgroundExpirationEnabled = defaults.backgroundExpirationEnabled; - this.backgroundExpirationCheckDelay = defaults.backgroundExpirationCheckDelay; - } - +public sealed interface PoolBuilder + extends Cloneable + permits PoolBuilderImpl { /** * Set the size of the pool we are building. *

@@ -108,22 +62,13 @@ DIRECT, new PoolBuilderPermissions(false, true, false, false, false) * @param size The target pool size. Must be at least 0. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setSize(int size) { - checkPermission(permissions.setSize(), "size"); - if (size < 0) { - throw new IllegalArgumentException("Size must be at least 0, but was " + size + "."); - } - this.size = size; - return this; - } + PoolBuilder setSize(int size); /** * Get the currently configured size. The default is 10. * @return The configured pool size. */ - public synchronized int getSize() { - return size; - } + int getSize(); /** * Set the {@link Allocator} or {@link Reallocator} to use for the pools we @@ -140,22 +85,13 @@ public synchronized int getSize() { * @return This {@code PoolBuilder} instance, but with a generic type parameter that * matches that of the allocator. */ - @SuppressWarnings("unchecked") - public synchronized PoolBuilder setAllocator( - Allocator allocator) { - checkPermission(permissions.setAllocator(), "allocator"); - requireNonNull(allocator, "The Allocator cannot be null."); - this.allocator = (Allocator) allocator; - return (PoolBuilder) this; - } + PoolBuilder setAllocator(Allocator allocator); /** * Get the configured {@link Allocator} instance. * @return The configured Allocator instance. */ - public synchronized Allocator getAllocator() { - return allocator; - } + Allocator getAllocator(); /** * Get the configured {@link stormpot.Allocator} instance as a @@ -164,12 +100,7 @@ public synchronized Allocator getAllocator() { * allocator is wrapped in an adaptor. * @return A configured or adapted Reallocator. */ - public synchronized Reallocator getReallocator() { - if (allocator instanceof Reallocator) { - return (Reallocator) allocator; - } - return new ReallocatingAdaptor<>(allocator); - } + Reallocator getReallocator(); /** * Set the {@link Expiration} to use for the pools we want to @@ -183,12 +114,7 @@ public synchronized Reallocator getReallocator() { * @param expiration The expiration we want our pools to use. Not null. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setExpiration(Expiration expiration) { - checkPermission(permissions.setExpiration(), "expiration"); - requireNonNull(expiration, "Expiration cannot be null."); - this.expiration = expiration; - return this; - } + PoolBuilder setExpiration(Expiration expiration); /** * Get the configured {@link Expiration} instance. The default is a @@ -197,9 +123,7 @@ public synchronized PoolBuilder setExpiration(Expiration expiratio * * @return The configured Expiration. */ - public synchronized Expiration getExpiration() { - return expiration; - } + Expiration getExpiration(); /** * Set the {@link MetricsRecorder} to use for the pools we want to configure. @@ -207,19 +131,14 @@ public synchronized Expiration getExpiration() { * want to use any. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setMetricsRecorder(MetricsRecorder metricsRecorder) { - this.metricsRecorder = metricsRecorder; - return this; - } + PoolBuilder setMetricsRecorder(MetricsRecorder metricsRecorder); /** * Get the configured {@link MetricsRecorder} instance, or {@code null} if none has * been configured. * @return The configured MetricsRecorder. */ - public synchronized MetricsRecorder getMetricsRecorder() { - return metricsRecorder; - } + MetricsRecorder getMetricsRecorder(); /** * Get the ThreadFactory that has been configured, and will be used to create @@ -228,9 +147,7 @@ public synchronized MetricsRecorder getMetricsRecorder() { * the string "Stormpot-" is prepended to the thread name. * @return The configured thread factory. */ - public synchronized ThreadFactory getThreadFactory() { - return threadFactory; - } + ThreadFactory getThreadFactory(); /** * Set the ThreadFactory that the pools will use to create its background @@ -240,12 +157,7 @@ public synchronized ThreadFactory getThreadFactory() { * background threads. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { - checkPermission(permissions.setThreadFactory(), "thread factory"); - requireNonNull(factory, "ThreadFactory cannot be null."); - threadFactory = factory; - return this; - } + PoolBuilder setThreadFactory(ThreadFactory factory); /** * Return whether precise object leak detection is enabled, which is @@ -253,9 +165,7 @@ public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { * @return {@code true} if precise object leak detection is enabled. * @see #setPreciseLeakDetectionEnabled(boolean) */ - public synchronized boolean isPreciseLeakDetectionEnabled() { - return preciseLeakDetectionEnabled; - } + boolean isPreciseLeakDetectionEnabled(); /** * Enable or disable precise object leak detection. It is enabled by default. @@ -285,10 +195,7 @@ public synchronized boolean isPreciseLeakDetectionEnabled() { * default) {@code false} to turn it off. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setPreciseLeakDetectionEnabled(boolean enabled) { - this.preciseLeakDetectionEnabled = enabled; - return this; - } + PoolBuilder setPreciseLeakDetectionEnabled(boolean enabled); /** * Return whether background expiration is enabled. @@ -297,9 +204,7 @@ public synchronized PoolBuilder setPreciseLeakDetectionEnabled(boolean enable * @return {@code true} if background expiration is enabled. * @see #setBackgroundExpirationEnabled(boolean) */ - public synchronized boolean isBackgroundExpirationEnabled() { - return backgroundExpirationEnabled; - } + boolean isBackgroundExpirationEnabled(); /** * Enable or disable background object expiration checking. This is enabled @@ -313,11 +218,7 @@ public synchronized boolean isBackgroundExpirationEnabled() { * {@code false} to turn it off. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setBackgroundExpirationEnabled(boolean enabled) { - checkPermission(permissions.setBackgroundExpiration(), "background expiration enabled/disabled"); - backgroundExpirationEnabled = enabled; - return this; - } + PoolBuilder setBackgroundExpirationEnabled(boolean enabled); /** * Return the default approximate delay, in milliseconds, between background @@ -326,9 +227,7 @@ public synchronized PoolBuilder setBackgroundExpirationEnabled(boolean enable * * @return the delay, in milliseconds, between background maintenance tasks. */ - public synchronized int getBackgroundExpirationCheckDelay() { - return backgroundExpirationCheckDelay; - } + int getBackgroundExpirationCheckDelay(); /** * Set the approximate delay, in milliseconds, between background maintenance tasks. @@ -346,64 +245,18 @@ public synchronized int getBackgroundExpirationCheckDelay() { * @param delay the desired delay, in milliseconds, between background maintenance tasks. * @return This {@code PoolBuilder} instance. */ - public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) { - checkPermission(permissions.setBackgroundExpiration(), "background expiration check delay"); - if (delay < 0) { - throw new IllegalArgumentException("Background expiration check delay cannot be negative."); - } - backgroundExpirationCheckDelay = delay; - return this; - } + PoolBuilder setBackgroundExpirationCheckDelay(int delay); /** * Returns a shallow copy of this {@code PoolBuilder} object. * @return A new {@code PoolBuilder} object of the exact same type as this one, with * identical values in all its fields. */ - @SuppressWarnings("unchecked") - @Override - public synchronized PoolBuilder clone() { - try { - return (PoolBuilder) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(e); - } - } + PoolBuilder clone(); /** * Build a {@link Pool} instance based on the collected configuration. * @return A {@link Pool} instance as configured by this builder. */ - public synchronized Pool build() { - return new BlazePool<>(this, allocationProcess); - } - - /** - * Returns a {@link Reallocator}, possibly by adapting the configured - * {@link Allocator} if need be. - * If a {@link MetricsRecorder} has been configured, the return {@link Reallocator} will - * automatically record allocation, reallocation and deallocation latencies. - */ - synchronized Reallocator getAdaptedReallocator() { - if (metricsRecorder == null) { - if (allocator instanceof Reallocator) { - return (Reallocator) allocator; - } - return new ReallocatingAdaptor<>(allocator); - } else { - if (allocator instanceof Reallocator) { - return new TimingReallocatorAdaptor<>( - (Reallocator) allocator, metricsRecorder); - } - return new TimingReallocatingAdaptor<>(allocator, metricsRecorder); - } - } - - private void checkPermission(boolean permission, String fieldDescription) { - if (!permission) { - String message = "The " + allocationProcess.getMode() + " allocation process does " + - "not support configuring the " + fieldDescription + "."; - throw new IllegalStateException(message); - } - } + Pool build(); } diff --git a/src/main/java/stormpot/PoolTap.java b/src/main/java/stormpot/PoolTap.java index f815bdc0..3b780f57 100644 --- a/src/main/java/stormpot/PoolTap.java +++ b/src/main/java/stormpot/PoolTap.java @@ -15,7 +15,6 @@ */ package stormpot; -import java.time.Duration; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; @@ -33,13 +32,7 @@ * {@linkplain Pool#from(Allocator) configured allocator}. * @see stormpot.Pool */ -public abstract class PoolTap { - - private static final Timeout ZERO_TIMEOUT = new Timeout(Duration.ZERO); - - PoolTap() { - } - +public interface PoolTap { /** * Claim the exclusive rights until released, to an object in the pool. * Possibly waiting up to the specified amount of time, as given by the @@ -99,8 +92,7 @@ public abstract class PoolTap { * while waiting. * @throws IllegalArgumentException if the {@code timeout} argument is {@code null}. */ - public abstract T claim(Timeout timeout) - throws PoolException, InterruptedException; + T claim(Timeout timeout) throws PoolException, InterruptedException; /** * Returns an object from the pool if the pool contains at least one valid object, @@ -117,10 +109,9 @@ public abstract T claim(Timeout timeout) * {@code null}, or the * {@link Expiration#hasExpired(SlotInfo) expiration check} threw an exception. */ - public T tryClaim() throws PoolException { + default T tryClaim() throws PoolException { try { - // default implementation - return claim(ZERO_TIMEOUT); + return claim(Timeout.ZERO_TIMEOUT); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; @@ -150,8 +141,7 @@ public T tryClaim() throws PoolException { * @see #claim(Timeout) The {@code claim} method for more details on failure modes * and memory effects. */ - public final Optional apply(Timeout timeout, Function function) - throws InterruptedException { + default Optional apply(Timeout timeout, Function function) throws InterruptedException { Objects.requireNonNull(function, "Function cannot be null."); T obj = claim(timeout); if (obj == null) { @@ -185,7 +175,7 @@ public final Optional apply(Timeout timeout, Function function) * @see #claim(Timeout) The {@code claim} method for more details on failure modes * and memory effects. */ - public final boolean supply(Timeout timeout, Consumer consumer) + default boolean supply(Timeout timeout, Consumer consumer) throws InterruptedException { Objects.requireNonNull(consumer, "Consumer cannot be null."); T obj = claim(timeout); diff --git a/src/main/java/stormpot/SlotInfo.java b/src/main/java/stormpot/SlotInfo.java index 07ab10b7..02403224 100644 --- a/src/main/java/stormpot/SlotInfo.java +++ b/src/main/java/stormpot/SlotInfo.java @@ -36,9 +36,7 @@ public interface SlotInfo { * was allocated. * @return The object allocation {@link System#nanoTime()} timestamp. */ - default long getCreatedNanoTime() { - return 0; - } + long getCreatedNanoTime(); /** * Get the number of times the object has been claimed since it was diff --git a/src/main/java/stormpot/Timeout.java b/src/main/java/stormpot/Timeout.java index a6a8226f..2bcafc75 100644 --- a/src/main/java/stormpot/Timeout.java +++ b/src/main/java/stormpot/Timeout.java @@ -15,6 +15,8 @@ */ package stormpot; +import stormpot.internal.NanoClock; + import java.time.Duration; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -35,6 +37,8 @@ * @author Chris Vest */ public final class Timeout { + static final Timeout ZERO_TIMEOUT = new Timeout(Duration.ZERO); + private final long timeout; private final TimeUnit unit; private final long timeoutBase; diff --git a/src/main/java/stormpot/AllocationController.java b/src/main/java/stormpot/internal/AllocationController.java similarity index 88% rename from src/main/java/stormpot/AllocationController.java rename to src/main/java/stormpot/internal/AllocationController.java index dce477c7..3cbd5406 100644 --- a/src/main/java/stormpot/AllocationController.java +++ b/src/main/java/stormpot/internal/AllocationController.java @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.ManagedPool; +import stormpot.Pool; +import stormpot.Poolable; /** * An AllocationController implements the actual allocation and deallocation of objects @@ -21,7 +26,7 @@ * * @param The type of {@link Poolable poolables} to allocate or deallocate. */ -abstract class AllocationController { +public abstract class AllocationController { abstract void offerDeadSlot(BSlot slot); diff --git a/src/main/java/stormpot/AllocationProcess.java b/src/main/java/stormpot/internal/AllocationProcess.java similarity index 80% rename from src/main/java/stormpot/AllocationProcess.java rename to src/main/java/stormpot/internal/AllocationProcess.java index 0a8d592e..87fef0de 100644 --- a/src/main/java/stormpot/AllocationProcess.java +++ b/src/main/java/stormpot/internal/AllocationProcess.java @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Poolable; import java.util.concurrent.LinkedTransferQueue; -import static stormpot.AllocationProcessMode.DIRECT; -import static stormpot.AllocationProcessMode.INLINE; -import static stormpot.AllocationProcessMode.THREADED; +import static stormpot.internal.AllocationProcessMode.DIRECT; +import static stormpot.internal.AllocationProcessMode.INLINE; +import static stormpot.internal.AllocationProcessMode.THREADED; -abstract class AllocationProcess { +public abstract class AllocationProcess { public static AllocationProcess threaded() { return new AllocationProcess(THREADED) { @Override @@ -29,7 +31,7 @@ AllocationController buildAllocationController( LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { return new ThreadedAllocationController<>( live, disregardPile, newAllocations, builder, poisonPill); @@ -37,14 +39,14 @@ AllocationController buildAllocationController( }; } - static AllocationProcess inline() { + public static AllocationProcess inline() { return new AllocationProcess(INLINE) { @Override AllocationController buildAllocationController( LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { return new InlineAllocationController<>( live, disregardPile, newAllocations, builder, poisonPill); @@ -52,14 +54,14 @@ AllocationController buildAllocationController( }; } - static AllocationProcess direct() { + public static AllocationProcess direct() { return new AllocationProcess(DIRECT) { @Override AllocationController buildAllocationController( LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { return new DirectAllocationController<>( live, disregardPile, builder, poisonPill); @@ -73,7 +75,7 @@ protected AllocationProcess(AllocationProcessMode mode) { this.mode = mode; } - AllocationProcessMode getMode() { + public AllocationProcessMode getMode() { return mode; } @@ -81,6 +83,6 @@ abstract AllocationController buildAllocationController( LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill); } diff --git a/src/main/java/stormpot/AllocationProcessMode.java b/src/main/java/stormpot/internal/AllocationProcessMode.java similarity index 91% rename from src/main/java/stormpot/AllocationProcessMode.java rename to src/main/java/stormpot/internal/AllocationProcessMode.java index 9a7351ec..179f4a96 100644 --- a/src/main/java/stormpot/AllocationProcessMode.java +++ b/src/main/java/stormpot/internal/AllocationProcessMode.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -enum AllocationProcessMode { +public enum AllocationProcessMode { THREADED, INLINE, DIRECT diff --git a/src/main/java/stormpot/BAllocThread.java b/src/main/java/stormpot/internal/BAllocThread.java similarity index 97% rename from src/main/java/stormpot/BAllocThread.java rename to src/main/java/stormpot/internal/BAllocThread.java index 18548721..96e19d36 100644 --- a/src/main/java/stormpot/BAllocThread.java +++ b/src/main/java/stormpot/internal/BAllocThread.java @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.Expiration; +import stormpot.MetricsRecorder; +import stormpot.Poolable; +import stormpot.Reallocator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; @@ -25,7 +31,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; @SuppressWarnings("NonAtomicOperationOnVolatileField") -final class BAllocThread implements Runnable { +public final class BAllocThread implements Runnable { /** * The amount of time, in nanoseconds, to wait for more work when the * shutdown process has deallocated all the dead and live slots it could @@ -63,7 +69,7 @@ final class BAllocThread implements Runnable { LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { this.live = live; this.disregardPile = disregardPile; diff --git a/src/main/java/stormpot/BSlot.java b/src/main/java/stormpot/internal/BSlot.java similarity index 92% rename from src/main/java/stormpot/BSlot.java rename to src/main/java/stormpot/internal/BSlot.java index ca5912dd..19fe40d2 100644 --- a/src/main/java/stormpot/BSlot.java +++ b/src/main/java/stormpot/internal/BSlot.java @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.PoolException; +import stormpot.Poolable; +import stormpot.Slot; +import stormpot.SlotInfo; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -26,14 +31,14 @@ * the effect of even the tiniest changes! * False-sharing can be quite sneaky. */ -final class BSlot +public final class BSlot extends BSlotColdFields { private static final int CLAIMED = 1; private static final int TLR_CLAIMED = 2; private static final int LIVING = 3; private static final int DEAD = 4; - BSlot(BlockingQueue> live, AtomicInteger poisonedSlots) { + public BSlot(BlockingQueue> live, AtomicInteger poisonedSlots) { // Volatile write in the constructor: This object must be safely published, // so that we are sure that the volatile write happens-before other // threads observe the pointer to this object. @@ -74,23 +79,23 @@ void claim2live() { lazySet(LIVING); } - void claimTlr2live() { + public void claimTlr2live() { lazySet(LIVING); } - void dead2live() { + public void dead2live() { lazySet(LIVING); } - void claim2dead() { + public void claim2dead() { lazySet(DEAD); } - boolean live2claim() { + public boolean live2claim() { return compareAndSet(LIVING, CLAIMED); } - boolean live2claimTlr() { + public boolean live2claimTlr() { return compareAndSet(LIVING, TLR_CLAIMED); } @@ -220,8 +225,8 @@ abstract class BSlotColdFields extends Padding2 implements S final AtomicInteger poisonedSlots; long stamp; long createdNanos; - T obj; - Exception poison; + public T obj; + public Exception poison; long claims; BSlotColdFields( diff --git a/src/main/java/stormpot/BSlotCache.java b/src/main/java/stormpot/internal/BSlotCache.java similarity index 85% rename from src/main/java/stormpot/BSlotCache.java rename to src/main/java/stormpot/internal/BSlotCache.java index 377fd3e8..aa48ad2b 100644 --- a/src/main/java/stormpot/BSlotCache.java +++ b/src/main/java/stormpot/internal/BSlotCache.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -final class BSlotCache { +import stormpot.Poolable; + +public final class BSlotCache { BSlot slot; } diff --git a/src/main/java/stormpot/BlazePool.java b/src/main/java/stormpot/internal/BlazePool.java similarity index 96% rename from src/main/java/stormpot/BlazePool.java rename to src/main/java/stormpot/internal/BlazePool.java index 0922e14c..87a40d71 100644 --- a/src/main/java/stormpot/BlazePool.java +++ b/src/main/java/stormpot/internal/BlazePool.java @@ -13,7 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.Expiration; +import stormpot.ManagedPool; +import stormpot.MetricsRecorder; +import stormpot.Pool; +import stormpot.PoolBuilder; +import stormpot.PoolException; +import stormpot.PoolTap; +import stormpot.Poolable; +import stormpot.Timeout; import java.util.Objects; import java.util.concurrent.LinkedTransferQueue; @@ -38,8 +49,7 @@ * @author Chris Vest * @param The type of {@link Poolable} managed by this pool. */ -final class BlazePool - extends Pool implements ManagedPool { +public final class BlazePool implements Pool, ManagedPool { private static final Exception SHUTDOWN_POISON = new Exception("Stormpot Poison: Shutdown"); @@ -65,7 +75,7 @@ final class BlazePool * Construct a new BlazePool instance based on the given {@link PoolBuilder}. * @param builder The pool configuration to use. */ - BlazePool(PoolBuilder builder, AllocationProcess factory) { + public BlazePool(PoolBuilderImpl builder, AllocationProcess factory) { live = new LinkedTransferQueue<>(); disregardPile = new RefillPile<>(live); newAllocations = new RefillPile<>(live); diff --git a/src/main/java/stormpot/BlazePoolThreadLocalTap.java b/src/main/java/stormpot/internal/BlazePoolThreadLocalTap.java similarity index 86% rename from src/main/java/stormpot/BlazePoolThreadLocalTap.java rename to src/main/java/stormpot/internal/BlazePoolThreadLocalTap.java index 954e5eec..0184da43 100644 --- a/src/main/java/stormpot/BlazePoolThreadLocalTap.java +++ b/src/main/java/stormpot/internal/BlazePoolThreadLocalTap.java @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.PoolException; +import stormpot.PoolTap; +import stormpot.Poolable; +import stormpot.Timeout; /** * The claim method in this pool tap follows the same idea as the thread-local @@ -26,7 +31,7 @@ * * @param The poolable type. */ -final class BlazePoolThreadLocalTap extends PoolTap { +public final class BlazePoolThreadLocalTap implements PoolTap { private final BlazePool pool; private final BSlotCache cache = new BSlotCache<>(); diff --git a/src/main/java/stormpot/DirectAllocationController.java b/src/main/java/stormpot/internal/DirectAllocationController.java similarity index 94% rename from src/main/java/stormpot/DirectAllocationController.java rename to src/main/java/stormpot/internal/DirectAllocationController.java index 6c416cc1..fb3bccac 100644 --- a/src/main/java/stormpot/DirectAllocationController.java +++ b/src/main/java/stormpot/internal/DirectAllocationController.java @@ -13,14 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Allocator; +import stormpot.Completion; +import stormpot.PoolBuilder; +import stormpot.Poolable; import java.util.Objects; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -class DirectAllocationController extends AllocationController { +public class DirectAllocationController extends AllocationController { private final LinkedTransferQueue> live; private final RefillPile disregardPile; private final BSlot poisonPill; diff --git a/src/main/java/stormpot/EveryExpiration.java b/src/main/java/stormpot/internal/EveryExpiration.java similarity index 81% rename from src/main/java/stormpot/EveryExpiration.java rename to src/main/java/stormpot/internal/EveryExpiration.java index 908d9ca8..ed3a22a2 100644 --- a/src/main/java/stormpot/EveryExpiration.java +++ b/src/main/java/stormpot/internal/EveryExpiration.java @@ -13,15 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Expiration; +import stormpot.Poolable; +import stormpot.SlotInfo; import java.util.concurrent.TimeUnit; -final class EveryExpiration implements Expiration { +public final class EveryExpiration implements Expiration { private final Expiration innerExpiration; private final TimeSpreadExpiration timeExpiration; - EveryExpiration(Expiration innerExpiration, long fromTime, long toTime, TimeUnit unit) { + public EveryExpiration(Expiration innerExpiration, long fromTime, long toTime, TimeUnit unit) { this.innerExpiration = innerExpiration; timeExpiration = new TimeSpreadExpiration<>(fromTime, toTime, unit); } diff --git a/src/main/java/stormpot/InlineAllocationController.java b/src/main/java/stormpot/internal/InlineAllocationController.java similarity index 97% rename from src/main/java/stormpot/InlineAllocationController.java rename to src/main/java/stormpot/internal/InlineAllocationController.java index af54abe3..d4801769 100644 --- a/src/main/java/stormpot/InlineAllocationController.java +++ b/src/main/java/stormpot/internal/InlineAllocationController.java @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.MetricsRecorder; +import stormpot.Poolable; +import stormpot.Reallocator; +import stormpot.Timeout; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -25,7 +31,7 @@ import static java.util.Objects.requireNonNull; -class InlineAllocationController extends AllocationController { +public class InlineAllocationController extends AllocationController { private static final VarHandle SIZE; private static final VarHandle ALLOC_COUNT; private static final VarHandle FAILED_ALLOC_COUNT; @@ -64,7 +70,7 @@ class InlineAllocationController extends AllocationControlle LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { this.live = live; this.disregardPile = disregardPile; diff --git a/src/main/java/stormpot/LatchCompletion.java b/src/main/java/stormpot/internal/LatchCompletion.java similarity index 88% rename from src/main/java/stormpot/LatchCompletion.java rename to src/main/java/stormpot/internal/LatchCompletion.java index b4cf4941..ec58cad5 100644 --- a/src/main/java/stormpot/LatchCompletion.java +++ b/src/main/java/stormpot/internal/LatchCompletion.java @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.Timeout; import java.util.Objects; import java.util.concurrent.CountDownLatch; -final class LatchCompletion implements Completion { +public final class LatchCompletion implements Completion { private final CountDownLatch completionLatch; LatchCompletion(CountDownLatch completionLatch) { diff --git a/src/main/java/stormpot/NanoClock.java b/src/main/java/stormpot/internal/NanoClock.java similarity index 90% rename from src/main/java/stormpot/NanoClock.java rename to src/main/java/stormpot/internal/NanoClock.java index f3315510..a9e35bd6 100644 --- a/src/main/java/stormpot/NanoClock.java +++ b/src/main/java/stormpot/internal/NanoClock.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -final class NanoClock { +public final class NanoClock { private NanoClock() { } - static long nanoTime() { + public static long nanoTime() { return System.nanoTime(); } diff --git a/src/main/java/stormpot/OrExpiration.java b/src/main/java/stormpot/internal/OrExpiration.java similarity index 85% rename from src/main/java/stormpot/OrExpiration.java rename to src/main/java/stormpot/internal/OrExpiration.java index 9c08f422..f308770d 100644 --- a/src/main/java/stormpot/OrExpiration.java +++ b/src/main/java/stormpot/internal/OrExpiration.java @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Expiration; +import stormpot.Poolable; +import stormpot.SlotInfo; import java.util.concurrent.TimeUnit; @@ -27,11 +31,11 @@ * @author Guillaume Lederrey * @since 2.4 */ -class OrExpiration implements Expiration { +public class OrExpiration implements Expiration { private final Expiration firstExpiration; private final Expiration secondExpiration; - OrExpiration(Expiration firstExpiration, Expiration secondExpiration) { + public OrExpiration(Expiration firstExpiration, Expiration secondExpiration) { this.firstExpiration = firstExpiration; this.secondExpiration = secondExpiration; } diff --git a/src/main/java/stormpot/PoolBuilderDefaults.java b/src/main/java/stormpot/internal/PoolBuilderDefaults.java similarity index 74% rename from src/main/java/stormpot/PoolBuilderDefaults.java rename to src/main/java/stormpot/internal/PoolBuilderDefaults.java index b6e6f7ad..ffdb18b0 100644 --- a/src/main/java/stormpot/PoolBuilderDefaults.java +++ b/src/main/java/stormpot/internal/PoolBuilderDefaults.java @@ -13,18 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Expiration; +import stormpot.Poolable; import java.util.concurrent.ThreadFactory; -class PoolBuilderDefaults { - final Expiration expiration; - final ThreadFactory threadFactory; - final boolean preciseLeakDetectionEnabled; - final boolean backgroundExpirationEnabled; - final int backgroundExpirationCheckDelay; +public class PoolBuilderDefaults { + public final Expiration expiration; + public final ThreadFactory threadFactory; + public final boolean preciseLeakDetectionEnabled; + public final boolean backgroundExpirationEnabled; + public final int backgroundExpirationCheckDelay; - PoolBuilderDefaults( + public PoolBuilderDefaults( Expiration expiration, ThreadFactory threadFactory, boolean preciseLeakDetectionEnabled, diff --git a/src/main/java/stormpot/internal/PoolBuilderImpl.java b/src/main/java/stormpot/internal/PoolBuilderImpl.java new file mode 100644 index 00000000..a7f66b15 --- /dev/null +++ b/src/main/java/stormpot/internal/PoolBuilderImpl.java @@ -0,0 +1,229 @@ +/* + * Copyright © 2011-2024 Chris Vest (mr.chrisvest@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package stormpot.internal; + +import stormpot.Allocator; +import stormpot.Expiration; +import stormpot.MetricsRecorder; +import stormpot.Pool; +import stormpot.PoolBuilder; +import stormpot.Poolable; +import stormpot.Reallocator; + +import java.util.Map; +import java.util.concurrent.ThreadFactory; + +import static java.util.Objects.requireNonNull; +import static java.util.concurrent.TimeUnit.MINUTES; +import static stormpot.Expiration.after; +import static stormpot.Expiration.never; +import static stormpot.internal.AllocationProcessMode.DIRECT; +import static stormpot.internal.AllocationProcessMode.INLINE; +import static stormpot.internal.AllocationProcessMode.THREADED; +import static stormpot.internal.StormpotThreadFactory.INSTANCE; + +public final class PoolBuilderImpl implements PoolBuilder { + public static final Map DEFAULTS = Map.of( + THREADED, new PoolBuilderDefaults(after(8, 10, MINUTES), INSTANCE, true, true, 1000), + INLINE, new PoolBuilderDefaults(after(8, 10, MINUTES), INSTANCE, true, false, 0), + DIRECT, new PoolBuilderDefaults(never(), INSTANCE, false, false, 0) + ); + + public static final Map PERMISSIONS = Map.of( + THREADED, new PoolBuilderPermissions(true, true, true, true, true), + INLINE, new PoolBuilderPermissions(true, true, true, false, false), + DIRECT, new PoolBuilderPermissions(false, true, false, false, false) + ); + + private final AllocationProcess allocationProcess; + private final PoolBuilderPermissions permissions; + private Allocator allocator; + private int size = 10; + private Expiration expiration; + private MetricsRecorder metricsRecorder; + private ThreadFactory threadFactory; + private boolean preciseLeakDetectionEnabled; + private boolean backgroundExpirationEnabled; + private int backgroundExpirationCheckDelay; + + /** + * Build a new empty {@code PoolBuilder} object. + */ + public PoolBuilderImpl(AllocationProcess allocationProcess, Allocator allocator) { + requireNonNull(allocator, "The Allocator cannot be null."); + requireNonNull(allocationProcess, "The AllocationProcess cannot be null."); + this.allocator = allocator; + this.allocationProcess = allocationProcess; + this.permissions = PERMISSIONS.get(allocationProcess.getMode()); + PoolBuilderDefaults defaults = DEFAULTS.get(allocationProcess.getMode()); + this.expiration = defaults.expiration; + this.threadFactory = defaults.threadFactory; + this.preciseLeakDetectionEnabled = defaults.preciseLeakDetectionEnabled; + this.backgroundExpirationEnabled = defaults.backgroundExpirationEnabled; + this.backgroundExpirationCheckDelay = defaults.backgroundExpirationCheckDelay; + } + + @Override + public synchronized PoolBuilder setSize(int size) { + checkPermission(permissions.setSize(), "size"); + if (size < 0) { + throw new IllegalArgumentException("Size must be at least 0, but was " + size + "."); + } + this.size = size; + return this; + } + + @Override + public synchronized int getSize() { + return size; + } + + @SuppressWarnings("unchecked") + @Override + public synchronized PoolBuilder setAllocator( + Allocator allocator) { + checkPermission(permissions.setAllocator(), "allocator"); + requireNonNull(allocator, "The Allocator cannot be null."); + this.allocator = (Allocator) allocator; + return (PoolBuilderImpl) this; + } + + @Override + public synchronized Allocator getAllocator() { + return allocator; + } + + @Override + public synchronized Reallocator getReallocator() { + if (allocator instanceof Reallocator) { + return (Reallocator) allocator; + } + return new ReallocatingAdaptor<>(allocator); + } + + @Override + public synchronized PoolBuilder setExpiration(Expiration expiration) { + checkPermission(permissions.setExpiration(), "expiration"); + requireNonNull(expiration, "Expiration cannot be null."); + this.expiration = expiration; + return this; + } + + @Override + public synchronized Expiration getExpiration() { + return expiration; + } + + @Override + public synchronized PoolBuilder setMetricsRecorder(MetricsRecorder metricsRecorder) { + this.metricsRecorder = metricsRecorder; + return this; + } + + @Override + public synchronized MetricsRecorder getMetricsRecorder() { + return metricsRecorder; + } + + @Override + public synchronized ThreadFactory getThreadFactory() { + return threadFactory; + } + + @Override + public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { + checkPermission(permissions.setThreadFactory(), "thread factory"); + requireNonNull(factory, "ThreadFactory cannot be null."); + threadFactory = factory; + return this; + } + + @Override + public synchronized boolean isPreciseLeakDetectionEnabled() { + return preciseLeakDetectionEnabled; + } + + @Override + public synchronized PoolBuilder setPreciseLeakDetectionEnabled(boolean enabled) { + this.preciseLeakDetectionEnabled = enabled; + return this; + } + + @Override + public synchronized boolean isBackgroundExpirationEnabled() { + return backgroundExpirationEnabled; + } + + @Override + public synchronized PoolBuilder setBackgroundExpirationEnabled(boolean enabled) { + checkPermission(permissions.setBackgroundExpiration(), "background expiration enabled/disabled"); + backgroundExpirationEnabled = enabled; + return this; + } + + @Override + public synchronized int getBackgroundExpirationCheckDelay() { + return backgroundExpirationCheckDelay; + } + + @Override + public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) { + checkPermission(permissions.setBackgroundExpiration(), "background expiration check delay"); + if (delay < 0) { + throw new IllegalArgumentException("Background expiration check delay cannot be negative."); + } + backgroundExpirationCheckDelay = delay; + return this; + } + + @SuppressWarnings("unchecked") + @Override + public synchronized PoolBuilderImpl clone() { + try { + return (PoolBuilderImpl) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } + } + + @Override + public synchronized Pool build() { + return new BlazePool<>(this, allocationProcess); + } + + public synchronized Reallocator getAdaptedReallocator() { + if (metricsRecorder == null) { + if (allocator instanceof Reallocator) { + return (Reallocator) allocator; + } + return new ReallocatingAdaptor<>(allocator); + } else { + if (allocator instanceof Reallocator) { + return new TimingReallocatorAdaptor<>( + (Reallocator) allocator, metricsRecorder); + } + return new TimingReallocatingAdaptor<>(allocator, metricsRecorder); + } + } + + private void checkPermission(boolean permission, String fieldDescription) { + if (!permission) { + String message = "The " + allocationProcess.getMode() + " allocation process does " + + "not support configuring the " + fieldDescription + "."; + throw new IllegalStateException(message); + } + } +} diff --git a/src/main/java/stormpot/PoolBuilderPermissions.java b/src/main/java/stormpot/internal/PoolBuilderPermissions.java similarity index 92% rename from src/main/java/stormpot/PoolBuilderPermissions.java rename to src/main/java/stormpot/internal/PoolBuilderPermissions.java index 2a22aa06..532fd9f4 100644 --- a/src/main/java/stormpot/PoolBuilderPermissions.java +++ b/src/main/java/stormpot/internal/PoolBuilderPermissions.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -record PoolBuilderPermissions( +public record PoolBuilderPermissions( boolean setAllocator, boolean setSize, boolean setExpiration, diff --git a/src/main/java/stormpot/PreciseLeakDetector.java b/src/main/java/stormpot/internal/PreciseLeakDetector.java similarity index 95% rename from src/main/java/stormpot/PreciseLeakDetector.java rename to src/main/java/stormpot/internal/PreciseLeakDetector.java index 22e295ca..6b8d274d 100644 --- a/src/main/java/stormpot/PreciseLeakDetector.java +++ b/src/main/java/stormpot/internal/PreciseLeakDetector.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; import java.lang.ref.WeakReference; -final class PreciseLeakDetector { +public final class PreciseLeakDetector { private static final int branchPower = Integer.getInteger("stormpot.PreciseLeakDetector.branchPower", 5); private static final int branchFactor = 1 << branchPower; @@ -35,7 +35,7 @@ private static class WeakRef extends WeakReference { private final Object[] probes; private int leakedObjectCount; - PreciseLeakDetector() { + public PreciseLeakDetector() { // The probes are basically a two-level Bagwell hash trie with linked list // buckets at the end, to reduce the proliferation of arrays. // Basically, we compute the identity hash code for an object, and the @@ -52,7 +52,7 @@ private static class WeakRef extends WeakReference { probes = new Object[branchFactor]; } - synchronized void register(Object obj) { + public synchronized void register(Object obj) { int hash1 = System.identityHashCode(obj) & branchMask; Object current = probes[hash1]; @@ -113,7 +113,7 @@ private boolean chainShorterThan(int length, Object weakRef) { return true; } - synchronized void unregister(Object obj) { + public synchronized void unregister(Object obj) { int hash0 = System.identityHashCode(obj); int hash1 = hash0 & branchMask; @@ -147,7 +147,7 @@ private WeakRef removeFromChain(WeakRef chain, Object obj) { return newChain; } - synchronized long countLeakedObjects() { + public synchronized long countLeakedObjects() { for (int i = 0; i < probes.length; i++) { Object current = probes[i]; if (current instanceof WeakRef) { diff --git a/src/main/java/stormpot/ReallocatingAdaptor.java b/src/main/java/stormpot/internal/ReallocatingAdaptor.java similarity index 79% rename from src/main/java/stormpot/ReallocatingAdaptor.java rename to src/main/java/stormpot/internal/ReallocatingAdaptor.java index fda6ae1b..94172589 100644 --- a/src/main/java/stormpot/ReallocatingAdaptor.java +++ b/src/main/java/stormpot/internal/ReallocatingAdaptor.java @@ -13,12 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -class ReallocatingAdaptor implements Reallocator { +import stormpot.Allocator; +import stormpot.Poolable; +import stormpot.Reallocator; +import stormpot.Slot; + +public class ReallocatingAdaptor implements Reallocator { final Allocator allocator; - ReallocatingAdaptor(Allocator allocator) { + public ReallocatingAdaptor(Allocator allocator) { this.allocator = allocator; } @@ -42,7 +47,7 @@ public void deallocate(T poolable) throws Exception { allocator.deallocate(poolable); } - Allocator unwrap() { + public Allocator unwrap() { return allocator; } } diff --git a/src/main/java/stormpot/RefillPile.java b/src/main/java/stormpot/internal/RefillPile.java similarity index 91% rename from src/main/java/stormpot/RefillPile.java rename to src/main/java/stormpot/internal/RefillPile.java index bb9da612..9d6c466f 100644 --- a/src/main/java/stormpot/RefillPile.java +++ b/src/main/java/stormpot/internal/RefillPile.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Poolable; import java.io.Serial; import java.util.concurrent.BlockingQueue; @@ -26,7 +28,7 @@ * @param The concrete {@link Poolable} object type. */ @SuppressWarnings("unchecked") -final class RefillPile +public final class RefillPile extends AtomicReference> { @Serial private static final long serialVersionUID = 2374582348576873465L; @@ -35,7 +37,7 @@ final class RefillPile private final BlockingQueue> refillQueue; - RefillPile(BlockingQueue> refillQueue) { + public RefillPile(BlockingQueue> refillQueue) { this.refillQueue = refillQueue; set((RefillSlot) STACK_END); } @@ -44,12 +46,12 @@ final class RefillPile * Push the given slot onto the stack. This method is wait-free. * @param slot The slot instance to be pushed onto the stack. */ - void push(BSlot slot) { + public void push(BSlot slot) { RefillSlot element = new RefillSlot<>(slot); element.next = getAndSet(element); } - BSlot pop() { + public BSlot pop() { RefillSlot element; RefillSlot next; do { @@ -74,7 +76,7 @@ private boolean pause() { * @return {@code true} if any slots has been offered to the queue, or {@code false} if there were no * slots in the pile. */ - boolean refill() { + public boolean refill() { RefillSlot stack = getAndSet((RefillSlot) STACK_END); int count = 0; while (stack != STACK_END) { diff --git a/src/main/java/stormpot/RefillSlot.java b/src/main/java/stormpot/internal/RefillSlot.java similarity index 89% rename from src/main/java/stormpot/RefillSlot.java rename to src/main/java/stormpot/internal/RefillSlot.java index 9c86a0a3..51ac456e 100644 --- a/src/main/java/stormpot/RefillSlot.java +++ b/src/main/java/stormpot/internal/RefillSlot.java @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -class RefillSlot { +import stormpot.Poolable; + +public class RefillSlot { final BSlot slot; volatile RefillSlot next; diff --git a/src/main/java/stormpot/StormpotThreadFactory.java b/src/main/java/stormpot/internal/StormpotThreadFactory.java similarity index 85% rename from src/main/java/stormpot/StormpotThreadFactory.java rename to src/main/java/stormpot/internal/StormpotThreadFactory.java index e0cb9c41..7bf60765 100644 --- a/src/main/java/stormpot/StormpotThreadFactory.java +++ b/src/main/java/stormpot/internal/StormpotThreadFactory.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -final class StormpotThreadFactory implements ThreadFactory { - static final ThreadFactory INSTANCE = new StormpotThreadFactory(); +public final class StormpotThreadFactory implements ThreadFactory { + public static final ThreadFactory INSTANCE = new StormpotThreadFactory(); private static final ThreadFactory delegate = Executors.defaultThreadFactory(); diff --git a/src/main/java/stormpot/ThreadLocalBSlotCache.java b/src/main/java/stormpot/internal/ThreadLocalBSlotCache.java similarity index 82% rename from src/main/java/stormpot/ThreadLocalBSlotCache.java rename to src/main/java/stormpot/internal/ThreadLocalBSlotCache.java index 368e3198..e9c497ab 100644 --- a/src/main/java/stormpot/ThreadLocalBSlotCache.java +++ b/src/main/java/stormpot/internal/ThreadLocalBSlotCache.java @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; -final class ThreadLocalBSlotCache extends ThreadLocal> { +import stormpot.Poolable; + +public final class ThreadLocalBSlotCache extends ThreadLocal> { @Override protected BSlotCache initialValue() { return new BSlotCache<>(); diff --git a/src/main/java/stormpot/ThreadedAllocationController.java b/src/main/java/stormpot/internal/ThreadedAllocationController.java similarity index 90% rename from src/main/java/stormpot/ThreadedAllocationController.java rename to src/main/java/stormpot/internal/ThreadedAllocationController.java index bc668937..4c643f70 100644 --- a/src/main/java/stormpot/ThreadedAllocationController.java +++ b/src/main/java/stormpot/internal/ThreadedAllocationController.java @@ -13,19 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Completion; +import stormpot.Poolable; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.ThreadFactory; -class ThreadedAllocationController extends AllocationController { +public class ThreadedAllocationController extends AllocationController { private final BAllocThread allocator; private final Thread allocatorThread; ThreadedAllocationController( LinkedTransferQueue> live, RefillPile disregardPile, RefillPile newAllocations, - PoolBuilder builder, + PoolBuilderImpl builder, BSlot poisonPill) { allocator = new BAllocThread<>(live, disregardPile, newAllocations, builder, poisonPill); ThreadFactory factory = builder.getThreadFactory(); diff --git a/src/main/java/stormpot/TimeExpiration.java b/src/main/java/stormpot/internal/TimeExpiration.java similarity index 89% rename from src/main/java/stormpot/TimeExpiration.java rename to src/main/java/stormpot/internal/TimeExpiration.java index 741c9faa..cbe974d6 100644 --- a/src/main/java/stormpot/TimeExpiration.java +++ b/src/main/java/stormpot/internal/TimeExpiration.java @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Expiration; +import stormpot.Poolable; +import stormpot.SlotInfo; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -24,7 +28,7 @@ * * @author Chris Vest */ -final class TimeExpiration implements Expiration { +public final class TimeExpiration implements Expiration { private final long maxPermittedAgeMillis; private final TimeUnit unit; @@ -41,7 +45,7 @@ final class TimeExpiration implements Expiration { * @param unit The {@link TimeUnit} of the maximum permitted age. Never * {@code null}. */ - TimeExpiration(long maxPermittedAge, TimeUnit unit) { + public TimeExpiration(long maxPermittedAge, TimeUnit unit) { Objects.requireNonNull(unit, "TimeUnit cannot be null."); if (maxPermittedAge < 1) { throw new IllegalArgumentException( diff --git a/src/main/java/stormpot/TimeSpreadExpiration.java b/src/main/java/stormpot/internal/TimeSpreadExpiration.java similarity index 94% rename from src/main/java/stormpot/TimeSpreadExpiration.java rename to src/main/java/stormpot/internal/TimeSpreadExpiration.java index c47d444c..cd943ea2 100644 --- a/src/main/java/stormpot/TimeSpreadExpiration.java +++ b/src/main/java/stormpot/internal/TimeSpreadExpiration.java @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Expiration; +import stormpot.Poolable; +import stormpot.SlotInfo; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; @@ -26,7 +30,7 @@ * @author Chris Vest * @since 2.2 */ -final class TimeSpreadExpiration implements Expiration { +public final class TimeSpreadExpiration implements Expiration { private final long fromMillis; private final long toMillis; @@ -48,7 +52,7 @@ final class TimeSpreadExpiration implements Expiration { * lowerBound. * @param unit The {@link TimeUnit} of the bounds values. Never {@code null}. */ - TimeSpreadExpiration( + public TimeSpreadExpiration( long lowerBound, long upperBound, TimeUnit unit) { diff --git a/src/main/java/stormpot/TimingReallocatingAdaptor.java b/src/main/java/stormpot/internal/TimingReallocatingAdaptor.java similarity index 88% rename from src/main/java/stormpot/TimingReallocatingAdaptor.java rename to src/main/java/stormpot/internal/TimingReallocatingAdaptor.java index 07a60cfd..a34fac8c 100644 --- a/src/main/java/stormpot/TimingReallocatingAdaptor.java +++ b/src/main/java/stormpot/internal/TimingReallocatingAdaptor.java @@ -13,17 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.Allocator; +import stormpot.MetricsRecorder; +import stormpot.Poolable; +import stormpot.Reallocator; +import stormpot.Slot; import java.util.concurrent.TimeUnit; -class TimingReallocatingAdaptor +public class TimingReallocatingAdaptor extends ReallocatingAdaptor implements Reallocator { final MetricsRecorder metricsRecorder; - TimingReallocatingAdaptor( + public TimingReallocatingAdaptor( Allocator allocator, MetricsRecorder metricsRecorder) { super(allocator); diff --git a/src/main/java/stormpot/TimingReallocatorAdaptor.java b/src/main/java/stormpot/internal/TimingReallocatorAdaptor.java similarity index 86% rename from src/main/java/stormpot/TimingReallocatorAdaptor.java rename to src/main/java/stormpot/internal/TimingReallocatorAdaptor.java index d7e29320..825e00d9 100644 --- a/src/main/java/stormpot/TimingReallocatorAdaptor.java +++ b/src/main/java/stormpot/internal/TimingReallocatorAdaptor.java @@ -13,14 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.internal; + +import stormpot.MetricsRecorder; +import stormpot.Poolable; +import stormpot.Reallocator; +import stormpot.Slot; import java.util.concurrent.TimeUnit; -final class TimingReallocatorAdaptor +public final class TimingReallocatorAdaptor extends TimingReallocatingAdaptor implements Reallocator { - TimingReallocatorAdaptor( + public TimingReallocatorAdaptor( Reallocator allocator, MetricsRecorder metricsRecorder) { super(allocator, metricsRecorder); } diff --git a/src/test/java/module-info.java b/src/test/java/module-info.java new file mode 100644 index 00000000..81985def --- /dev/null +++ b/src/test/java/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2011-2024 Chris Vest (mr.chrisvest@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +open module stormpot.test { + requires stormpot; + requires transitive org.junit.jupiter.api; + requires transitive org.junit.jupiter.params; + requires transitive org.junit.jupiter.engine; + requires org.assertj.core; + requires jol.core; + requires com.codahale.metrics; + requires java.sql; + requires HdrHistogram; + requires micrometer.core; +} diff --git a/src/test/java/stormpot/BSlotTest.java b/src/test/java/stormpot/tests/BSlotTest.java similarity index 85% rename from src/test/java/stormpot/BSlotTest.java rename to src/test/java/stormpot/tests/BSlotTest.java index 8838ffd9..ed701122 100644 --- a/src/test/java/stormpot/BSlotTest.java +++ b/src/test/java/stormpot/tests/BSlotTest.java @@ -13,10 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import org.junit.jupiter.api.Test; import org.openjdk.jol.info.ClassLayout; +import stormpot.Pool; +import stormpot.Pooled; +import stormpot.Slot; +import stormpot.Timeout; +import stormpot.internal.BSlot; +import testkits.AlloKit; +import testkits.GenericPoolable; import java.util.concurrent.TimeUnit; @@ -31,9 +38,9 @@ class BSlotTest { void slotObjectsShouldBeCacheLineAligned() throws Exception { String arch = System.getProperty("os.arch"); if (arch.equals("x86_64") || arch.equals("amd64")) { // Only enable this on 64-bit machines. - Pool> pool = Pool.of("a"); - Pooled object = pool.claim(new Timeout(1, TimeUnit.SECONDS)); - Slot slot = object.slot; + Pool pool = Pool.fromInline(AlloKit.allocator()).setSize(1).build(); + GenericPoolable object = pool.claim(new Timeout(1, TimeUnit.SECONDS)); + Slot slot = object.getSlot(); ClassLayout classLayout = ClassLayout.parseInstance(slot); long size = classLayout.instanceSize(); String description = "BSlot instance size should be an even multiple of 64, " + diff --git a/src/test/java/stormpot/PoolBuilderReallocatingAdaptorTest.java b/src/test/java/stormpot/tests/PoolBuilderReallocatingAdaptorTest.java similarity index 89% rename from src/test/java/stormpot/PoolBuilderReallocatingAdaptorTest.java rename to src/test/java/stormpot/tests/PoolBuilderReallocatingAdaptorTest.java index 56b92e72..cfede397 100644 --- a/src/test/java/stormpot/PoolBuilderReallocatingAdaptorTest.java +++ b/src/test/java/stormpot/tests/PoolBuilderReallocatingAdaptorTest.java @@ -13,10 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import org.assertj.core.api.Condition; import org.junit.jupiter.api.Test; +import stormpot.Allocator; +import stormpot.MetricsRecorder; +import stormpot.Pool; +import stormpot.PoolBuilder; +import stormpot.Reallocator; +import stormpot.Slot; +import stormpot.internal.PoolBuilderImpl; +import stormpot.internal.ReallocatingAdaptor; import testkits.AlloKit; import testkits.GenericPoolable; import testkits.LastSampleMetricsRecorder; @@ -38,6 +46,10 @@ class PoolBuilderReallocatingAdaptorTest { private PoolBuilder builder; + private Reallocator getAdaptedReallocator() { + return ((PoolBuilderImpl) builder).getAdaptedReallocator(); + } + @Test void mustAdaptAllocatorsToReallocators() { Allocator allocator = allocator(); @@ -62,7 +74,7 @@ void getAdaptedReallocatorMustAdaptConfiguredAllocatorIfNoMetricsRecorderConfigu throws Exception { AlloKit.CountingAllocator allocator = allocator(); builder = Pool.from(allocator); - builder.getAdaptedReallocator().allocate(new NullSlot()); + getAdaptedReallocator().allocate(new NullSlot()); assertThat(allocator.countAllocations()).isOne(); } @@ -72,7 +84,7 @@ void getAdaptedReallocatorMustNotAdaptConfiguredReallocatorIfNoMetricsRecorderCo CountingReallocator reallocator = reallocator(); builder = Pool.from(reallocator); Slot slot = new NullSlot(); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); GenericPoolable obj = adaptedReallocator.allocate(slot); adaptedReallocator.reallocate(slot, obj); @@ -87,7 +99,7 @@ void getAdaptedReallocatorMustInstrumentAllocateMethodOnAllocatorIfMetricsRecord CountingAllocator allocator = allocator(alloc($new, $throw(new Exception()))); builder = Pool.from(allocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -105,7 +117,7 @@ void getAdaptedReallocatorMustInstrumentAllocateMethodOnReallocatorIfMetricsReco CountingReallocator reallocator = reallocator(alloc($new, $throw(new Exception()))); builder = Pool.from(reallocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -123,7 +135,7 @@ void getAdaptedReallocatorMustInstrumentDeallocateMethodOnAllocatorIfMetricsReco CountingAllocator allocator = allocator(); builder = Pool.from(allocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); GenericPoolable obj = adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -138,7 +150,7 @@ void getAdaptedReallocatorMustInstrumentThrowingDeallocateMethodOnAllocatorIfMet CountingAllocator allocator = allocator(dealloc($throw(new Exception()))); builder = Pool.from(allocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); GenericPoolable obj = adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -158,7 +170,7 @@ void getAdaptedReallocatorMustInstrumentDeallocateMethodOnReallocatorIfMetricsRe CountingReallocator reallocator = reallocator(); builder = Pool.from(reallocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); GenericPoolable obj = adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -173,7 +185,7 @@ void getAdaptedReallocatorMustInstrumentThrowingDeallocateMethodOnReallocatorIfM CountingReallocator reallocator = reallocator(dealloc($throw(new Exception()))); builder = Pool.from(reallocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); GenericPoolable obj = adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); @@ -193,7 +205,7 @@ void getAdaptedReallocatorMustInstrumentReallocateMethodOnReallocatorIfMetricsRe CountingReallocator reallocator = reallocator(realloc($new, $throw(new Exception()))); builder = Pool.from(reallocator); builder.setMetricsRecorder(r); - Reallocator adaptedReallocator = builder.getAdaptedReallocator(); + Reallocator adaptedReallocator = getAdaptedReallocator(); verifyLatencies(r, isNaN(), isNaN(), isNaN(), isNaN(), isNaN()); GenericPoolable obj = adaptedReallocator.allocate(new NullSlot()); verifyLatencies(r, not(isNaN()), isNaN(), isNaN(), isNaN(), isNaN()); diff --git a/src/test/java/stormpot/PreciseLeakDetectorIT.java b/src/test/java/stormpot/tests/PreciseLeakDetectorIT.java similarity index 98% rename from src/test/java/stormpot/PreciseLeakDetectorIT.java rename to src/test/java/stormpot/tests/PreciseLeakDetectorIT.java index 64cc10cc..9b810fd1 100644 --- a/src/test/java/stormpot/PreciseLeakDetectorIT.java +++ b/src/test/java/stormpot/tests/PreciseLeakDetectorIT.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import org.junit.jupiter.api.Test; +import stormpot.internal.PreciseLeakDetector; import java.lang.management.GarbageCollectorMXBean; import java.util.HashSet; diff --git a/src/test/java/stormpot/PreciseLeakDetectorTest.java b/src/test/java/stormpot/tests/PreciseLeakDetectorTest.java similarity index 98% rename from src/test/java/stormpot/PreciseLeakDetectorTest.java rename to src/test/java/stormpot/tests/PreciseLeakDetectorTest.java index 5e05f06f..fe9eb8d9 100644 --- a/src/test/java/stormpot/PreciseLeakDetectorTest.java +++ b/src/test/java/stormpot/tests/PreciseLeakDetectorTest.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import stormpot.internal.PreciseLeakDetector; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; diff --git a/src/test/java/stormpot/ReallocatingAdaptorTest.java b/src/test/java/stormpot/tests/ReallocatingAdaptorTest.java similarity index 93% rename from src/test/java/stormpot/ReallocatingAdaptorTest.java rename to src/test/java/stormpot/tests/ReallocatingAdaptorTest.java index 643767f0..bf4253e9 100644 --- a/src/test/java/stormpot/ReallocatingAdaptorTest.java +++ b/src/test/java/stormpot/tests/ReallocatingAdaptorTest.java @@ -13,12 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; -import extensions.FailurePrinterExtension; +import stormpot.tests.extensions.FailurePrinterExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import stormpot.Allocator; +import stormpot.Pool; +import stormpot.PoolBuilder; +import stormpot.Slot; +import stormpot.internal.ReallocatingAdaptor; import testkits.GenericPoolable; import testkits.NullSlot; diff --git a/src/test/java/stormpot/RefillPileTest.java b/src/test/java/stormpot/tests/RefillPileTest.java similarity index 96% rename from src/test/java/stormpot/RefillPileTest.java rename to src/test/java/stormpot/tests/RefillPileTest.java index c8fb7c9c..92b4e94a 100644 --- a/src/test/java/stormpot/RefillPileTest.java +++ b/src/test/java/stormpot/tests/RefillPileTest.java @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; -import extensions.ExecutorExtension; +import stormpot.tests.extensions.ExecutorExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import stormpot.Pooled; +import stormpot.internal.BSlot; +import stormpot.internal.RefillPile; import testkits.GenericPoolable; import java.util.HashSet; diff --git a/src/test/java/stormpot/WhiteboxPoolBuilderTest.java b/src/test/java/stormpot/tests/WhiteboxPoolBuilderTest.java similarity index 72% rename from src/test/java/stormpot/WhiteboxPoolBuilderTest.java rename to src/test/java/stormpot/tests/WhiteboxPoolBuilderTest.java index 31cddcde..421c197e 100644 --- a/src/test/java/stormpot/WhiteboxPoolBuilderTest.java +++ b/src/test/java/stormpot/tests/WhiteboxPoolBuilderTest.java @@ -13,11 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import com.codahale.metrics.MetricRegistry; import examples.DropwizardMetricsRecorder; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import stormpot.Allocator; +import stormpot.Expiration; +import stormpot.internal.AllocationProcessMode; +import stormpot.internal.PoolBuilderImpl; import testkits.AlloKit; import testkits.GenericPoolable; @@ -26,8 +31,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static stormpot.AllocationProcess.direct; -import static stormpot.AllocationProcess.threaded; +import static stormpot.internal.AllocationProcess.direct; +import static stormpot.internal.AllocationProcess.threaded; class WhiteboxPoolBuilderTest { private final Allocator allocator = AlloKit.allocator(); @@ -35,47 +40,47 @@ class WhiteboxPoolBuilderTest { @Test void defaultsMapMustMapAllKeys() { for (AllocationProcessMode mode : AllocationProcessMode.values()) { - assertThat(PoolBuilder.DEFAULTS).containsKey(mode); + Assertions.assertThat(PoolBuilderImpl.DEFAULTS).containsKey(mode); } } @Test void permissionsMapMustMapAllKeys() { for (AllocationProcessMode mode : AllocationProcessMode.values()) { - assertThat(PoolBuilder.PERMISSIONS).containsKey(mode); + assertThat(PoolBuilderImpl.PERMISSIONS).containsKey(mode); } } @Test void threadedProcessAllowSettingAllocator() { AlloKit.CountingAllocator alloc = AlloKit.allocator(); - var pb = new PoolBuilder<>(threaded(), allocator).setAllocator(alloc); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setAllocator(alloc); assertThat(pb.getAllocator()).isSameAs(alloc); } @Test void threadedProcessAllowSettingSize() { - var pb = new PoolBuilder<>(threaded(), allocator).setSize(100); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setSize(100); assertThat(pb.getSize()).isEqualTo(100); } @Test void threadedProcessAllowSettingExpiration() { var exp = Expiration.after(2, TimeUnit.SECONDS); - var pb = new PoolBuilder<>(threaded(), allocator).setExpiration(exp); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setExpiration(exp); assertThat(pb.getExpiration()).isSameAs(exp); } @Test void threadedProcessAllowSettingThreadFactory() { ThreadFactory factory = Thread::new; - var pb = new PoolBuilder<>(threaded(), allocator).setThreadFactory(factory); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setThreadFactory(factory); assertThat(pb.getThreadFactory()).isSameAs(factory); } @Test void threadedProcessAllowSettingBackgroundExpiration() { - var pb = new PoolBuilder<>(threaded(), allocator); + var pb = new PoolBuilderImpl<>(threaded(), allocator); boolean enabled = !pb.isBackgroundExpirationEnabled(); pb.setBackgroundExpirationEnabled(enabled); assertThat(pb.isBackgroundExpirationEnabled()).isEqualTo(enabled); @@ -83,58 +88,58 @@ void threadedProcessAllowSettingBackgroundExpiration() { @Test void threadedProcessAllowSettingBackgroundExpirationCheckDelay() { - var pb = new PoolBuilder<>(threaded(), allocator).setBackgroundExpirationCheckDelay(42); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setBackgroundExpirationCheckDelay(42); assertThat(pb.getBackgroundExpirationCheckDelay()).isEqualTo(42); } @Test void threadedProcessAllowSettingMetricsRecorder() { var recorder = new DropwizardMetricsRecorder("base", new MetricRegistry()); - var pb = new PoolBuilder<>(threaded(), allocator).setMetricsRecorder(recorder); + var pb = new PoolBuilderImpl<>(threaded(), allocator).setMetricsRecorder(recorder); assertThat(pb.getMetricsRecorder()).isSameAs(recorder); } @Test void directProcessAllowSettingSize() { - var pb = new PoolBuilder<>(direct(), allocator).setSize(100); + var pb = new PoolBuilderImpl<>(direct(), allocator).setSize(100); assertThat(pb.getSize()).isEqualTo(100); } @Test void directProcessDisallowSettingExpiration() { - var pb = new PoolBuilder<>(direct(), allocator); + var pb = new PoolBuilderImpl<>(direct(), allocator); assertThrows(IllegalStateException.class, () -> pb.setExpiration(Expiration.never())); } @Test void directProcessDisallowSettingAllocator() { - var pb = new PoolBuilder<>(direct(), allocator); + var pb = new PoolBuilderImpl<>(direct(), allocator); assertThrows(IllegalStateException.class, () -> pb.setAllocator(AlloKit.allocator())); } @Test void directProcessDisallowSettingThreadFactory() { - var pb = new PoolBuilder<>(direct(), allocator); + var pb = new PoolBuilderImpl<>(direct(), allocator); assertThrows(IllegalStateException.class, () -> pb.setThreadFactory(r -> null)); } @Test void directProcessDisallowSettingBackgroundExpiration() { - var pb = new PoolBuilder<>(direct(), allocator); + var pb = new PoolBuilderImpl<>(direct(), allocator); assertThrows(IllegalStateException.class, () -> pb.setBackgroundExpirationEnabled(false)); assertThrows(IllegalStateException.class, () -> pb.setBackgroundExpirationEnabled(true)); } @Test void directProcessDisallowSettingBackgroundExpirationCheckDelay() { - var pb = new PoolBuilder<>(direct(), allocator); + var pb = new PoolBuilderImpl<>(direct(), allocator); assertThrows(IllegalStateException.class, () -> pb.setBackgroundExpirationCheckDelay(42)); } @Test void directProcessAllowSettingMetricsRecorder() { var recorder = new DropwizardMetricsRecorder("base", new MetricRegistry()); - var pb = new PoolBuilder<>(direct(), allocator).setMetricsRecorder(recorder); + var pb = new PoolBuilderImpl<>(direct(), allocator).setMetricsRecorder(recorder); assertThat(pb.getMetricsRecorder()).isSameAs(recorder); } } diff --git a/src/test/java/stormpot/WhiteboxPoolTest.java b/src/test/java/stormpot/tests/WhiteboxPoolTest.java similarity index 91% rename from src/test/java/stormpot/WhiteboxPoolTest.java rename to src/test/java/stormpot/tests/WhiteboxPoolTest.java index b722ab38..9cf85d7e 100644 --- a/src/test/java/stormpot/WhiteboxPoolTest.java +++ b/src/test/java/stormpot/tests/WhiteboxPoolTest.java @@ -13,9 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package stormpot; +package stormpot.tests; import org.junit.jupiter.api.Test; +import stormpot.Completion; +import stormpot.ManagedPool; +import stormpot.Pool; +import stormpot.PoolTap; +import stormpot.Poolable; +import stormpot.Timeout; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/src/test/java/blackbox/AbstractPoolTest.java b/src/test/java/stormpot/tests/blackbox/AbstractPoolTest.java similarity index 99% rename from src/test/java/blackbox/AbstractPoolTest.java rename to src/test/java/stormpot/tests/blackbox/AbstractPoolTest.java index 7f3b5033..713f9399 100644 --- a/src/test/java/blackbox/AbstractPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/AbstractPoolTest.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; -import extensions.FailurePrinterExtension; +import stormpot.tests.extensions.FailurePrinterExtension; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/src/test/java/blackbox/AllocatorBasedPoolTest.java b/src/test/java/stormpot/tests/blackbox/AllocatorBasedPoolTest.java similarity index 99% rename from src/test/java/blackbox/AllocatorBasedPoolTest.java rename to src/test/java/stormpot/tests/blackbox/AllocatorBasedPoolTest.java index cd89b58d..dae29339 100644 --- a/src/test/java/blackbox/AllocatorBasedPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/AllocatorBasedPoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.assertj.core.data.Offset; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/blackbox/DefaultPoolTest.java b/src/test/java/stormpot/tests/blackbox/DefaultPoolTest.java similarity index 96% rename from src/test/java/blackbox/DefaultPoolTest.java rename to src/test/java/stormpot/tests/blackbox/DefaultPoolTest.java index a73fff90..79199f91 100644 --- a/src/test/java/blackbox/DefaultPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/DefaultPoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import testkits.AlloKit; import testkits.GenericPoolable; diff --git a/src/test/java/blackbox/DirectPoolTest.java b/src/test/java/stormpot/tests/blackbox/DirectPoolTest.java similarity index 98% rename from src/test/java/blackbox/DirectPoolTest.java rename to src/test/java/stormpot/tests/blackbox/DirectPoolTest.java index 11490761..fa9ce6c2 100644 --- a/src/test/java/blackbox/DirectPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/DirectPoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import stormpot.ManagedPool; diff --git a/src/test/java/blackbox/ExpirationTest.java b/src/test/java/stormpot/tests/blackbox/ExpirationTest.java similarity index 99% rename from src/test/java/blackbox/ExpirationTest.java rename to src/test/java/stormpot/tests/blackbox/ExpirationTest.java index fe2fafc3..deeaa989 100644 --- a/src/test/java/blackbox/ExpirationTest.java +++ b/src/test/java/stormpot/tests/blackbox/ExpirationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import stormpot.Expiration; diff --git a/src/test/java/blackbox/InlinePoolTest.java b/src/test/java/stormpot/tests/blackbox/InlinePoolTest.java similarity index 98% rename from src/test/java/blackbox/InlinePoolTest.java rename to src/test/java/stormpot/tests/blackbox/InlinePoolTest.java index 95f2637f..4c273bed 100644 --- a/src/test/java/blackbox/InlinePoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/InlinePoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import testkits.AlloKit.CountingAllocator; diff --git a/src/test/java/blackbox/PoolBuilderTest.java b/src/test/java/stormpot/tests/blackbox/PoolBuilderTest.java similarity index 98% rename from src/test/java/blackbox/PoolBuilderTest.java rename to src/test/java/stormpot/tests/blackbox/PoolBuilderTest.java index 236813f1..a35e09b9 100644 --- a/src/test/java/blackbox/PoolBuilderTest.java +++ b/src/test/java/stormpot/tests/blackbox/PoolBuilderTest.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import stormpot.internal.PoolBuilderImpl; import testkits.AlloKit; import stormpot.Allocator; import stormpot.Expiration; @@ -170,7 +171,7 @@ void allPublicDeclaredMethodsMustBeSynchronized() { // We don't care about non-overridden public methods of the super-class // (Object) because they don't operate on the state of the PoolBuilder object // anyway. - Method[] methods = PoolBuilder.class.getDeclaredMethods(); + Method[] methods = PoolBuilderImpl.class.getDeclaredMethods(); for (Method method : methods) { int modifiers = method.getModifiers(); int isSynthetic = 0x00001000; diff --git a/src/test/java/blackbox/PooledTest.java b/src/test/java/stormpot/tests/blackbox/PooledTest.java similarity index 98% rename from src/test/java/blackbox/PooledTest.java rename to src/test/java/stormpot/tests/blackbox/PooledTest.java index 2dc830f2..9c423dd8 100644 --- a/src/test/java/blackbox/PooledTest.java +++ b/src/test/java/stormpot/tests/blackbox/PooledTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import stormpot.Poolable; diff --git a/src/test/java/blackbox/Taps.java b/src/test/java/stormpot/tests/blackbox/Taps.java similarity index 97% rename from src/test/java/blackbox/Taps.java rename to src/test/java/stormpot/tests/blackbox/Taps.java index aec12155..ef1a2bef 100644 --- a/src/test/java/blackbox/Taps.java +++ b/src/test/java/stormpot/tests/blackbox/Taps.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import stormpot.PoolTap; import stormpot.Poolable; diff --git a/src/test/java/blackbox/ThreadBasedPoolTest.java b/src/test/java/stormpot/tests/blackbox/ThreadBasedPoolTest.java similarity index 99% rename from src/test/java/blackbox/ThreadBasedPoolTest.java rename to src/test/java/stormpot/tests/blackbox/ThreadBasedPoolTest.java index 409c9911..cddded04 100644 --- a/src/test/java/blackbox/ThreadBasedPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/ThreadBasedPoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; diff --git a/src/test/java/blackbox/ThreadedPoolTest.java b/src/test/java/stormpot/tests/blackbox/ThreadedPoolTest.java similarity index 96% rename from src/test/java/blackbox/ThreadedPoolTest.java rename to src/test/java/stormpot/tests/blackbox/ThreadedPoolTest.java index 451bcdcc..15b70c90 100644 --- a/src/test/java/blackbox/ThreadedPoolTest.java +++ b/src/test/java/stormpot/tests/blackbox/ThreadedPoolTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import testkits.AlloKit; import testkits.GenericPoolable; diff --git a/src/test/java/blackbox/TimeoutTest.java b/src/test/java/stormpot/tests/blackbox/TimeoutTest.java similarity index 99% rename from src/test/java/blackbox/TimeoutTest.java rename to src/test/java/stormpot/tests/blackbox/TimeoutTest.java index 4a5543a7..981fa7b9 100644 --- a/src/test/java/blackbox/TimeoutTest.java +++ b/src/test/java/stormpot/tests/blackbox/TimeoutTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox; +package stormpot.tests.blackbox; import org.junit.jupiter.api.Test; import stormpot.Timeout; diff --git a/src/test/java/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java b/src/test/java/stormpot/tests/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java similarity index 98% rename from src/test/java/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java rename to src/test/java/stormpot/tests/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java index 52fb8174..56d7197f 100644 --- a/src/test/java/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java +++ b/src/test/java/stormpot/tests/blackbox/simulations/ConstantTrafficBackgroundExpirationSim.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.simulations; +package stormpot.tests.blackbox.simulations; import stormpot.Expiration; import stormpot.Pool; diff --git a/src/test/java/blackbox/simulations/README.adoc b/src/test/java/stormpot/tests/blackbox/simulations/README.adoc similarity index 100% rename from src/test/java/blackbox/simulations/README.adoc rename to src/test/java/stormpot/tests/blackbox/simulations/README.adoc diff --git a/src/test/java/blackbox/simulations/Sim.java b/src/test/java/stormpot/tests/blackbox/simulations/Sim.java similarity index 99% rename from src/test/java/blackbox/simulations/Sim.java rename to src/test/java/stormpot/tests/blackbox/simulations/Sim.java index 5c9b5e2f..85a31cea 100644 --- a/src/test/java/blackbox/simulations/Sim.java +++ b/src/test/java/stormpot/tests/blackbox/simulations/Sim.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.simulations; +package stormpot.tests.blackbox.simulations; import org.HdrHistogram.Histogram; import stormpot.Expiration; diff --git a/src/test/java/blackbox/simulations/TimeSpreadExpirationSim.java b/src/test/java/stormpot/tests/blackbox/simulations/TimeSpreadExpirationSim.java similarity index 98% rename from src/test/java/blackbox/simulations/TimeSpreadExpirationSim.java rename to src/test/java/stormpot/tests/blackbox/simulations/TimeSpreadExpirationSim.java index 24f0cba3..a876f50d 100644 --- a/src/test/java/blackbox/simulations/TimeSpreadExpirationSim.java +++ b/src/test/java/stormpot/tests/blackbox/simulations/TimeSpreadExpirationSim.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.simulations; +package stormpot.tests.blackbox.simulations; import stormpot.Expiration; import testkits.GenericPoolable; diff --git a/src/test/java/blackbox/simulations/VariableTrafficSim.java b/src/test/java/stormpot/tests/blackbox/simulations/VariableTrafficSim.java similarity index 99% rename from src/test/java/blackbox/simulations/VariableTrafficSim.java rename to src/test/java/stormpot/tests/blackbox/simulations/VariableTrafficSim.java index 3b4f8691..cffc9854 100644 --- a/src/test/java/blackbox/simulations/VariableTrafficSim.java +++ b/src/test/java/stormpot/tests/blackbox/simulations/VariableTrafficSim.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.simulations; +package stormpot.tests.blackbox.simulations; import stormpot.Expiration; import stormpot.Pool; diff --git a/src/test/java/blackbox/slow/DefaultPoolIT.java b/src/test/java/stormpot/tests/blackbox/slow/DefaultPoolIT.java similarity index 96% rename from src/test/java/blackbox/slow/DefaultPoolIT.java rename to src/test/java/stormpot/tests/blackbox/slow/DefaultPoolIT.java index 40cb6260..7d0b4649 100644 --- a/src/test/java/blackbox/slow/DefaultPoolIT.java +++ b/src/test/java/stormpot/tests/blackbox/slow/DefaultPoolIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.slow; +package stormpot.tests.blackbox.slow; import testkits.AlloKit; import testkits.GenericPoolable; diff --git a/src/test/java/blackbox/slow/InlinePoolIT.java b/src/test/java/stormpot/tests/blackbox/slow/InlinePoolIT.java similarity index 96% rename from src/test/java/blackbox/slow/InlinePoolIT.java rename to src/test/java/stormpot/tests/blackbox/slow/InlinePoolIT.java index de4f1c3d..34fabdc6 100644 --- a/src/test/java/blackbox/slow/InlinePoolIT.java +++ b/src/test/java/stormpot/tests/blackbox/slow/InlinePoolIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.slow; +package stormpot.tests.blackbox.slow; import testkits.AlloKit; import testkits.GenericPoolable; diff --git a/src/test/java/blackbox/slow/PoolIT.java b/src/test/java/stormpot/tests/blackbox/slow/PoolIT.java similarity index 98% rename from src/test/java/blackbox/slow/PoolIT.java rename to src/test/java/stormpot/tests/blackbox/slow/PoolIT.java index c52d6b10..ac57cbc8 100644 --- a/src/test/java/blackbox/slow/PoolIT.java +++ b/src/test/java/stormpot/tests/blackbox/slow/PoolIT.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.slow; +package stormpot.tests.blackbox.slow; -import extensions.ExecutorExtension; -import extensions.FailurePrinterExtension; +import stormpot.tests.extensions.ExecutorExtension; +import stormpot.tests.extensions.FailurePrinterExtension; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/blackbox/slow/ThreadBasedPoolIT.java b/src/test/java/stormpot/tests/blackbox/slow/ThreadBasedPoolIT.java similarity index 99% rename from src/test/java/blackbox/slow/ThreadBasedPoolIT.java rename to src/test/java/stormpot/tests/blackbox/slow/ThreadBasedPoolIT.java index 688c2c8b..a72d32e0 100644 --- a/src/test/java/blackbox/slow/ThreadBasedPoolIT.java +++ b/src/test/java/stormpot/tests/blackbox/slow/ThreadBasedPoolIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.slow; +package stormpot.tests.blackbox.slow; import org.junit.jupiter.api.Test; import testkits.ExpireKit; diff --git a/src/test/java/blackbox/slow/ThreadedPoolIT.java b/src/test/java/stormpot/tests/blackbox/slow/ThreadedPoolIT.java similarity index 96% rename from src/test/java/blackbox/slow/ThreadedPoolIT.java rename to src/test/java/stormpot/tests/blackbox/slow/ThreadedPoolIT.java index 06cb87e6..0b7ac9e8 100644 --- a/src/test/java/blackbox/slow/ThreadedPoolIT.java +++ b/src/test/java/stormpot/tests/blackbox/slow/ThreadedPoolIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package blackbox.slow; +package stormpot.tests.blackbox.slow; import testkits.AlloKit; import testkits.GenericPoolable; diff --git a/src/test/java/extensions/ExecutorExtension.java b/src/test/java/stormpot/tests/extensions/ExecutorExtension.java similarity index 99% rename from src/test/java/extensions/ExecutorExtension.java rename to src/test/java/stormpot/tests/extensions/ExecutorExtension.java index d227f6cf..df62d5eb 100644 --- a/src/test/java/extensions/ExecutorExtension.java +++ b/src/test/java/stormpot/tests/extensions/ExecutorExtension.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package extensions; +package stormpot.tests.extensions; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; diff --git a/src/test/java/extensions/FailurePrinterExtension.java b/src/test/java/stormpot/tests/extensions/FailurePrinterExtension.java similarity index 99% rename from src/test/java/extensions/FailurePrinterExtension.java rename to src/test/java/stormpot/tests/extensions/FailurePrinterExtension.java index 0e7051a8..2cd6e211 100644 --- a/src/test/java/extensions/FailurePrinterExtension.java +++ b/src/test/java/stormpot/tests/extensions/FailurePrinterExtension.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package extensions; +package stormpot.tests.extensions; import org.junit.jupiter.api.extension.AfterEachCallback; diff --git a/src/test/java/testkits/SlotInfoStub.java b/src/test/java/testkits/SlotInfoStub.java index 34be23ae..8f0490e4 100644 --- a/src/test/java/testkits/SlotInfoStub.java +++ b/src/test/java/testkits/SlotInfoStub.java @@ -37,6 +37,11 @@ public void setAgeInMillis(long ageInMillis) { this.ageInMillis = ageInMillis; } + @Override + public long getCreatedNanoTime() { + return 0; + } + @Override public long getClaimCount() { return 0; diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 00000000..9ae35a5b --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1,3 @@ +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.classes.default=concurrent +junit.jupiter.execution.timeout.default=30m