diff --git a/.github/workflows/codeql-legacy.yml b/.github/workflows/codeql-legacy.yml new file mode 100644 index 00000000..16fa2642 --- /dev/null +++ b/.github/workflows/codeql-legacy.yml @@ -0,0 +1,39 @@ +name: "CodeQL Legacy" + +on: + push: + branches: [ "1.0", "2.0", "2.1", "2.2", "2.3", "2.4", "2.4.1", "2.4.2", "3.0", "3.0.1", "3.1" ] + schedule: + - cron: "42 11 * * 6" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ java ] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a49d0f43..d5c87fb8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,7 +2,7 @@ name: "CodeQL" on: push: - branches: [ "main", "1.0", "2.0", "2.1", "2.2", "2.3", "2.4", "2.4.1", "2.4.2", "3.0", "3.0.1", "3.1" ] + branches: [ "main" ] pull_request: branches: [ "main" ] schedule: @@ -25,17 +25,23 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + - uses: actions/checkout@v4.1.6 + - name: Set up Java + uses: actions/setup-java@v4.2.1 + with: + java-version: '21' + distribution: 'zulu' - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index f9ca2842..f69a52d8 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - java-version: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22] + java-version: [21, 22] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4.1.6 @@ -32,7 +32,7 @@ jobs: - name: Set up Java uses: actions/setup-java@v4.2.1 with: - java-version: '11' + java-version: '21' distribution: 'zulu' - name: Build with Maven run: ./mvnw verify package site -B diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b1809ad6..e8053a13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/setup-java@v4.2.1 with: distribution: 'zulu' - java-version: '11' + java-version: '21' server-id: 'ossrh' server-username: SONATYPE_USERNAME server-password: SONATYPE_TOKEN diff --git a/README.adoc b/README.adoc index fcdcf912..323ad1fb 100644 --- a/README.adoc +++ b/README.adoc @@ -68,7 +68,7 @@ We recommend https://github.com/ben-manes/caffeine[Caffeine] for object caching. === Installing -Stormpot 3.1 only depends on Java 11 or newer. +Stormpot 3.2 only depends on Java 11 or newer. Add it as a Maven dependency to your projects: [source,xml] @@ -81,6 +81,7 @@ Add it as a Maven dependency to your projects: ---- You can also build the latest snapshot from source with `mvn clean install`. +Note that Stormpot 4 require Java 21 or newer. === Getting Started diff --git a/build/asciidoclet-2.0.0-shaded.jar b/build/asciidoclet-2.0.0-shaded.jar deleted file mode 100644 index c48435fa..00000000 Binary files a/build/asciidoclet-2.0.0-shaded.jar and /dev/null differ diff --git a/pom.xml b/pom.xml index ef8eeb35..8b8e3c72 100644 --- a/pom.xml +++ b/pom.xml @@ -38,9 +38,8 @@ - UTF-8 UTF-8 - 11 + 21 0.8.12 3.7.0 2.0.0 @@ -105,8 +104,7 @@ maven-compiler-plugin 3.13.0 - ${java.version} - ${java.version} + ${java.version} -Xlint:all true @@ -240,15 +238,11 @@ - - -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED - -Xdoclint:all,-html,-accessibility - --base-dir - ${project.basedir} - - org.asciidoctor.asciidoclet.Asciidoclet + + --snippet-path + ${build.testSourceDirectory}/examples/ + true - ${project.basedir}/build/asciidoclet-2.0.0-shaded.jar @@ -424,15 +418,11 @@ maven-javadoc-plugin ${javadoc.version} - - -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED - -Xdoclint:all,-html,-accessibility - --base-dir - ${project.basedir} - - org.asciidoctor.asciidoclet.Asciidoclet + + --snippet-path + ${build.testSourceDirectory}/examples/ + true - ${project.basedir}/build/asciidoclet-2.0.0-shaded.jar diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 884f59b0..2a2bee9c 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -13,6 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/** + *

Stormpot

+ * Stormpot is a generic, thread-safe and fast object pooling library. + *

+ * The object pools themselves implement the {@link stormpot.Pool} interface. + * The things you actually want to pool must all implement the + * {@link stormpot.Poolable} interface, and you must also provide an + * implementation of the {@link stormpot.Allocator} interface as a factory to + * create your pooled objects. + *

+ * See the online + * Usage Guide + * for a tutorial. + */ module stormpot { requires transitive java.management; requires static java.sql; // For testing only. diff --git a/src/main/java/stormpot/Allocator.java b/src/main/java/stormpot/Allocator.java index 6d4ad130..785db9ec 100644 --- a/src/main/java/stormpot/Allocator.java +++ b/src/main/java/stormpot/Allocator.java @@ -18,10 +18,10 @@ /** * An Allocator is responsible for the creation and destruction of * {@link Poolable} objects. - * + *

* This is where the objects in the Pool comes from. Clients of the Stormpot * library needs to provide their own Allocator implementations. - * + *

* Implementations of this interface must be thread-safe, because there is no * knowing whether pools will try to access it concurrently or not. The easiest * way to achieve this is to just make the @@ -32,16 +32,16 @@ * very slow allocations by allocating in more than one thread, but * synchronizing the {@link #allocate(Slot)} method will render that strategy * ineffective. - * + *

* A better approach to thread-safety is to not have any shared mutable state * in the allocator, if at all possible. - * + *

* Implementations must also be interruption-safe. * When a pool is {@linkplain Pool#shutdown() shut down}, its background * allocation thread may be interrupted, and this thread may be interacting * with the allocator instance when this happens. * - * @author Chris Vest + * @author Chris Vest * @see stormpot.Reallocator * @param any type that implements Poolable. */ @@ -49,22 +49,23 @@ public interface Allocator { /** * Create a fresh new instance of T for the given slot. - * + *

* The returned {@link Poolable} must obey the contract that, when * {@link Poolable#release()} is called on it, it must delegate * the call onto the {@link Slot#release(Poolable)} method of the here * given slot object. - * + *

* Exceptions thrown by this method may propagate out through the * {@link Pool#claim(Timeout) claim} method of a pool, in the form of being * wrapped inside a {@link PoolException}. Pools must be able to handle these * exceptions in a sane manner, and are guaranteed to return to a working * state if an Allocator stops throwing exceptions from its allocate method. + * * @param slot The slot the pool wish to allocate an object for. * Implementers do not need to concern themselves with the details of a * pools slot objects. They just have to call release on them as the * protocol demands. - * @return A newly created instance of T. Never `null`. + * @return A newly created instance of T. Never {@code null}. * @throws Exception If the allocation fails. */ T allocate(Slot slot) throws Exception; @@ -72,35 +73,36 @@ public interface Allocator { /** * Deallocate, if applicable, the given Poolable and free any resources * associated with it. - * + *

* This is an opportunity to close any connections or files, flush buffers, * empty caches or what ever might need to be done to completely free any * resources represented by this Poolable. - * + *

* Note that a Poolable must never touch its slot object after it has been * deallocated. - * + *

* Pools, on the other hand, will guarantee that the same object is never * deallocated more than once. - * + *

* Note that pools will always silently swallow exceptions thrown by the * deallocate method. They do this because there is no knowing whether the * deallocation of an object will be done synchronously by a thread calling * {@link Poolable#release() release} on a Poolable, or asynchronously by * a clean-up thread inside the pool. - * + *

* Deallocation from the release of an expired object, and deallocation from - * the shut down procedure of a {@link Pool} behave the same way in this + * the shutdown procedure of a {@link Pool} behave the same way in this * regard. They will both silently swallow any exception thrown. - * + *

* On the other hand, pools are guaranteed to otherwise correctly deal with - * any exception that might be thrown. The shut down procedure will still + * any exception that might be thrown. The shutdown procedure will still * complete, and release will still maintain the internal data structures of * the pool to make the slot available for new allocations. - * + *

* If you need to somehow specially deal with the exceptions thrown by the * deallocation of objects, then you should do this in the allocator itself, * or in a wrapper around your allocator. + * * @param poolable The non-null Poolable instance to be deallocated. * @throws Exception if the deallocation encounters an error. */ diff --git a/src/main/java/stormpot/BasePoolable.java b/src/main/java/stormpot/BasePoolable.java index eca17b0b..720db7c0 100644 --- a/src/main/java/stormpot/BasePoolable.java +++ b/src/main/java/stormpot/BasePoolable.java @@ -19,7 +19,7 @@ /** * A basic implementation of the {@link Poolable} interface, which can be extended directly. - * + *

* It is not strictly necessary to extend this class in order to implement the {@link Poolable} * interface, but doing so may make your code simpler. */ @@ -32,7 +32,8 @@ public class BasePoolable implements Poolable { protected final Slot slot; /** - * Build a `BasePoolable` for the given slot. + * Build a {@link BasePoolable} for the given slot. + * * @param slot The {@link Slot} that represents this objects place in the pool. */ public BasePoolable(Slot slot) { diff --git a/src/main/java/stormpot/BlazePool.java b/src/main/java/stormpot/BlazePool.java index 477fa42a..0922e14c 100644 --- a/src/main/java/stormpot/BlazePool.java +++ b/src/main/java/stormpot/BlazePool.java @@ -23,19 +23,19 @@ * BlazePool is a highly optimised {@link Pool} implementation that consists of * a queues of Poolable instances, the access to which is made faster with * clever use of ThreadLocals. - * + *

* Object allocation always happens in a dedicated thread, off-loading the * cost of allocating the pooled objects. This leads to reduced deviation * in the times it takes claim method to complete, provided the pool is not * depleted. - * + *

* BlazePool optimises for the case where the same threads need to claim and * release objects over and over again. On the other hand, if the releasing * thread tends to differ from the claiming thread, then the major optimisation * in BlazePool is defeated, and performance regresses to a slow-path that is * limited by contention on a blocking queue. * - * @author Chris Vest + * @author Chris Vest * @param The type of {@link Poolable} managed by this pool. */ final class BlazePool diff --git a/src/main/java/stormpot/BlazePoolThreadLocalTap.java b/src/main/java/stormpot/BlazePoolThreadLocalTap.java index 9a9734db..954e5eec 100644 --- a/src/main/java/stormpot/BlazePoolThreadLocalTap.java +++ b/src/main/java/stormpot/BlazePoolThreadLocalTap.java @@ -20,7 +20,7 @@ * caching and TLR-claiming in the pool itself. However, instead of relying on * a thread-local for the object caching, we instead directly use a field of * the pool tap instance. - * + *

* This has two advantages: 1) a field load is faster than a thread-local * lookup, and 2) there is no thread-local "leaking" or contamination. * diff --git a/src/main/java/stormpot/Completion.java b/src/main/java/stormpot/Completion.java index d58fc243..32937c7e 100644 --- a/src/main/java/stormpot/Completion.java +++ b/src/main/java/stormpot/Completion.java @@ -22,7 +22,8 @@ * cancellation or returning a result. Indeed, you cannot even precisely tell * if the task has already completed, but the await methods will return * immediately if that is the case. - * @author Chris Vest + * + * @author Chris Vest * @see Pool#shutdown() */ public interface Completion { @@ -31,28 +32,28 @@ public interface Completion { * Causes the current thread to wait until the completion is finished, * or the thread is {@link Thread#interrupt() interrupted}, or the specified * waiting time elapses. - * + *

* If the task represented by this completion has already completed, - * the method immediately returns `true`. - * + * the method immediately returns {@code true}. + *

* If the current thread already has its interrupted status set upon entry * to this method, or the thread is interrupted while waiting, then an * {@link InterruptedException} is thrown and the current threads interrupted * status is cleared. - * - * If the specified waiting time elapses, then the method returns `false`. + *

+ * If the specified waiting time elapses, then the method returns {@code false}. * * @param timeout The timeout delimiting the maximum time to wait for the * task to complete. Timeouts with zero or negative values will cause the * method to return immediately. - * @return `true` if the task represented by this completion + * @return {@code true} if the task represented by this completion * completed within the specified waiting time, or was already complete upon - * entry to this method; or `false` if the specified Timeout - * elapsed before the task could finished. + * entry to this method; or {@code false} if the specified Timeout + * elapsed before the task could finish. * @throws InterruptedException if the current thread is interrupted while * waiting. - * @throws IllegalArgumentException if the provided `timeout` parameter is - * `null`. + * @throws IllegalArgumentException if the provided {@code timeout} parameter is + * {@code null}. */ boolean await(Timeout timeout) throws InterruptedException; } diff --git a/src/main/java/stormpot/Expiration.java b/src/main/java/stormpot/Expiration.java index 034cd6f2..9e6d7049 100644 --- a/src/main/java/stormpot/Expiration.java +++ b/src/main/java/stormpot/Expiration.java @@ -20,62 +20,67 @@ /** * The expiration is used to determine if a given slot has expired, or * otherwise become invalid. - * + *

* Note that Expiration instances must be thread-safe, as they may be * accessed concurrently by multiple threads. However, for a given * {@link SlotInfo} and {@link Poolable} instance, only a single thread will * invoke the expiration at a time. This means that there is no need to * synchronise on the SlotInfo or Poolable objects. - * + *

* The easiest way to ensure that an Expiration implementation is thread-safe, * is to make sure that they never mutate any state. If they do, however, * then they must do so in a thread-safe manner, unless the mutable state is * contained within the SlotInfo or Poolable objects – in this case, the * mutable state will be thread-local. Be aware that making the - * {@link #hasExpired(SlotInfo) hasExpired} method `synchronized` will + * {@link #hasExpired(SlotInfo) hasExpired} method {@code synchronized} will * most likely severely reduce the performance and scalability of the pool. - * + *

* The Expiration can be invoked several times during a * {@link Pool#claim(Timeout) claim} call, so it is important that the * Expiration is fast. It can easily be the dominating factor in the * performance of the pool. - * - * [TIP] - * -- + * + * + * + * + * + * + *
Tip
TIP * If the expiration is too slow, you can use * {@link #every(long, TimeUnit)} or {@link #every(long, long, TimeUnit)} to * make an expiration that only performs the slow expiration check every few * seconds, for instance. - * + *

* You can alternatively use a time-based expiration, such as * {@link #after(long, TimeUnit)}, that has been configured with a very low * expiration time, like a few seconds. Then you can configure the pool to use * a {@link stormpot.Reallocator}, where you do the expensive expiration check * in the {@link stormpot.Reallocator#reallocate(Slot, Poolable) reallocate} * method, returning the same Poolable back if it hasn't expired. - * + *

* Be aware, though, that such a scheme has to be tuned to the load of the * application, such that the objects in the pool don't all expire at the same * time, leaving the pool empty. - * -- + *

* - * @author Chris Vest + * @param The type of Poolable to be checked. + * @author Chris Vest */ public interface Expiration { /** * Construct a new Expiration that will invalidate objects that are older * than the exact provided span of time in the given unit. - * + *

* This expiration does not make use of the * {@linkplain SlotInfo#getStamp() slot info stamp}. - * - * If the `time` is less than one, or the `unit` is `null`, then - * an {@link IllegalArgumentException} will be thrown. + *

+ * If the {@code time} is less than one, or the {@code unit} is {@code null}, + * then an {@link IllegalArgumentException} will be thrown. * * @param time Poolables older than this, in the given unit, will * be considered expired. This value must be at least 1. * @param unit The {@link TimeUnit} of the maximum permitted age. - * Never `null`. + * Never {@code null}. * @param The type of {@link Poolable} to check. * @return The specified time-based expiration policy. */ @@ -87,16 +92,16 @@ static Expiration after(long time, TimeUnit unit) { * Construct a new Expiration that will invalidate objects that are older * than the given lower bound, before they get older than the upper bound, * in the given time unit. - * + *

* The actual expiration time is chosen uniformly randomly within the * given brackets, for each allocated object. - * + *

* This expiration make use of the * {@linkplain SlotInfo#getStamp() slot info stamp} for storing the target * expiration timestamp. - * - * If the `fromTime` is less than 1, the `toTime` is less than the - * `fromTime`, or the `unit` is `null`, then an + *

+ * If the {@code fromTime} is less than 1, the {@code toTime} is less than the + * {@code fromTime}, or the {@code unit} is {@code null}, then an * {@link java.lang.IllegalArgumentException} will be thrown. * * @param fromTime Poolables younger than this, in the given unit, are not @@ -104,7 +109,7 @@ static Expiration after(long time, TimeUnit unit) { * @param toTime Poolables older than this, in the given unit, are always * considered expired. This value must be greater than or equal * to the lowerBound. - * @param unit The {@link TimeUnit} of the bounds values. Never `null`. + * @param unit The {@link TimeUnit} of the bounds values. Never {@code null}. * @param The type of {@link Poolable} to check. * @return The specified time-based expiration policy. */ @@ -115,7 +120,7 @@ static Expiration after( /** * Construct a new Expiration that never invalidates any objects. - * + *

* This is useful for effectively disabling object expiration, * for cases where that makes sense. * @@ -129,10 +134,10 @@ static Expiration never() { /** * Construct a new Expiration that will invalidate objects if either this, or * the given expiration, considers an object expired. - * + *

* This is a short-circuiting combinator, such that if this expiration * invalidates the object, then the other expiration will not be checked. - * + *

* This makes it easy to have an expiration that expires both on time, and * some other criteria. * @@ -147,7 +152,7 @@ default Expiration or(Expiration other) { * Construct a new Expiration that is composed of a time-based expiration and * this one, such that this expiration is only consulted at most once within * the given time period. - * + *

* For instance, if an expiration is expensive, you can use this to only * check it, say, every 5 seconds. * @@ -162,8 +167,8 @@ default Expiration every(long time, TimeUnit unit) { /** * Construct a new Expiration that is composed of a time-based expiration and * this one, such that this expiration is only consulted at most once within - * a time period based on the given `fromTime` and `toTime` brackets. - * + * a time period based on the given {@code fromTime} and {@code toTime} brackets. + *

* For instance, if an expiration is expensive, you can use this to only * check it, say, every 5 to 10 seconds. * @@ -180,26 +185,26 @@ default Expiration every(long fromTime, long toTime, TimeUnit unit) { * Test whether the Slot and Poolable object, represented by the given * {@link SlotInfo} object, is still valid, or if the pool should * deallocate it and allocate a replacement. - * + *

* If the method throws an exception, then that is taken to mean that the * slot is invalid. The exception will bubble out of the * {@link Pool#claim(Timeout) claim} method, but the mechanism is * implementation specific. For this reason, it is generally advised that * Expirations do not throw exceptions. - * + *

* Note that this method can be called as often as several times per * {@link Pool#claim(Timeout) claim}. The performance of this method therefor * has a big influence on the perceived performance of the pool. - * + *

* If this implementation ends up being expensive, then the * {@link #every(long, long, TimeUnit) every-combinator} can be used to * construct a new expiration object that only performs the expensive check * every so often. * * @param info An informative representative of the slot being tested. - * Never `null`. - * @return `true` if the Slot and Poolable in question should be - * deallocated, `false` if it is valid and eligible for claiming. + * Never {@code null}. + * @return {@code true} if the Slot and Poolable in question should be + * deallocated, {@code false} if it is valid and eligible for claiming. * @throws Exception If checking the validity of the Slot or Poolable somehow * went wrong. In this case, the Poolable will be assumed to be expired. */ diff --git a/src/main/java/stormpot/ManagedPool.java b/src/main/java/stormpot/ManagedPool.java index 266f8b04..6d67e5c8 100644 --- a/src/main/java/stormpot/ManagedPool.java +++ b/src/main/java/stormpot/ManagedPool.java @@ -20,19 +20,14 @@ /** * This is the JMX management interface for Stormpot object pools. - * + *

* Using this interface, pools can be exposed to external management as an - * MXBean. Since its an MXBean, and not just an MBean, it imposes no + * MXBean. Since it is an MXBean, and not just an MBean, it imposes no * special requirements on 3rd party JMX integrators. - * + *

* Once you have created your pool, it is easy to expose it through the platform * MBeanServer, or any MBeanServer you like: - * - * [source,java,indent=0] - * ---- - * include::src/test/java/examples/Examples.java[tag=managedPoolExample] - * ---- - * + * {@snippet class=Examples region=managedPoolExample } * Using the platform MBeanServer will make the pool visible to tools like * JConsole and VisualVM. * @since 2.3 @@ -61,7 +56,7 @@ public interface ManagedPool { * return the number of object leaks that have been detected, and prevented, * since the pool was created. If the pool does not support precise object * leak detection, then this method returns -1. - * + *

* There are two kinds of leaks: One where the application forgets to release * an object back to the pool, but keeps a strong reference to the object, * and another where the application not only forgets to release the object, @@ -92,10 +87,11 @@ public interface ManagedPool { int getTargetSize(); /** - * Returns 'true' if the shut down process has been started on this pool, - * 'false' otherwise. This method does not reveal whether or not the shut - * down process has completed. - * @return 'true' if {@link Pool#shutdown()} has been called on this pool. + * Returns {@code true} if the shutdown process has been started on this pool, + * {@code false} otherwise. This method does not reveal whether the shutdown + * process has completed. + * + * @return {@code true} if {@link Pool#shutdown()} has been called on this pool. */ boolean isShutDown(); @@ -185,11 +181,11 @@ public interface ManagedPool { /** * Get the approximate number of currently allocated objects. - * + *

* This operation has time complexity O(poolSize) to count the number of slots. - * + *

* The default implementation of this interface methods returns {@code -1}. - * + *

* Unlike {@link #getAllocationCount()}, this returns only the number of objects currently in the pool, * which typically would be the same as {@link #getTargetSize()}. * @@ -201,12 +197,12 @@ default int getCurrentAllocatedCount() { /** * Get the approximate number of objects currently in use. - * + *

* This operation has time complexity O(poolSize) to check each slot. - * + *

* The counting operation is "weakly consistent", * in a similar sense to {@link ConcurrentLinkedQueue#iterator()}. - * + *

* The default implementation of this interface methods returns {@code -1}. * * @return number of objects currently in use diff --git a/src/main/java/stormpot/MetricsRecorder.java b/src/main/java/stormpot/MetricsRecorder.java index 91c39f45..09515a1f 100644 --- a/src/main/java/stormpot/MetricsRecorder.java +++ b/src/main/java/stormpot/MetricsRecorder.java @@ -22,16 +22,12 @@ * configured for the given pool. Stormpot provides no default implementation * of this interface, so by default many of the metrics reporting methods of * the ManagedPool interfaces will return Double.NaN. - * - * NOTE: that implementations of this class must be thread-safe! - * + *

+ * Note: implementations of this interface must be thread-safe! + *

* Here's an example implementation based on the - * https://metrics.dropwizard.io/[Dropwizard Metrics library]: - * - * [source,java] - * ---- - * include::src/test/java/examples/DropwizardMetricsRecorder.java[lines=16..-1] - * ---- + * Dropwizard Metrics library: + * {@snippet class=DropwizardMetricsRecorder region=example} * * @since 2.3 */ @@ -40,7 +36,8 @@ public interface MetricsRecorder { /** * Record a latency sample of a successful allocation, in milliseconds. * This is the time it took for a call to {@link Allocator#allocate(Slot)} - * to return a useable object. + * to return a usable object. + * * @param milliseconds How many milliseconds it took to successfully * allocate an object. */ @@ -49,7 +46,8 @@ public interface MetricsRecorder { /** * Record a latency sample of a failed allocation, in milliseconds. This is * the time it took for a call to {@link Allocator#allocate(Slot)} to throw - * an exception or return `null`. + * an exception or return {@code null}. + * * @param milliseconds How many milliseconds transpired before the allocation * failed. */ @@ -58,6 +56,7 @@ public interface MetricsRecorder { /** * Record a latency sample of a deallocation, in milliseconds. This is the * time it took to complete a call to {@link Allocator#deallocate(Poolable)}. + * * @param milliseconds How many milliseconds to took to deallocate an object. */ void recordDeallocationLatencySampleMillis(long milliseconds); @@ -65,7 +64,8 @@ public interface MetricsRecorder { /** * Record a latency sample of a successful reallocation, in milliseconds. * This is the time it took for a call to - * {@link Reallocator#reallocate(Slot, Poolable)} to return a useable object. + * {@link Reallocator#reallocate(Slot, Poolable)} to return a usable object. + * * @param milliseconds How many milliseconds it took to successfully * reallocate an object. */ @@ -75,7 +75,8 @@ public interface MetricsRecorder { * Record a latency sample of a failed reallocation, in milliseconds. This is * the time it took for a call to * {@link Reallocator#reallocate(Slot, Poolable)} to throw an exception or - * return `null`. + * return {@code null}. + * * @param milliseconds How many milliseconds transpired before the * reallocation failed. */ @@ -86,6 +87,7 @@ public interface MetricsRecorder { * transpired from an object was allocated with * {@link Allocator#allocate(Slot)}, till it was deallocated with * {@link Allocator#deallocate(Poolable)}. + * * @param milliseconds How many milliseconds a Poolable object was in * circulation; from it was created, till it was * deallocated. @@ -96,17 +98,18 @@ public interface MetricsRecorder { * Get the approximate Poolable object allocation latency value, in * milliseconds, of the given percentile/quantile of the values recorded so * far. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. @@ -117,17 +120,18 @@ public interface MetricsRecorder { * Get the approximate latency value, in milliseconds, for failed allocation * latencies within the given percentile/quantile of what has been recorded * so far. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. @@ -138,17 +142,18 @@ public interface MetricsRecorder { * Get the approximate latency value, in milliseconds, for deallocation * latencies within the given percentile/quantile of what has been recorded * so far. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. @@ -159,17 +164,18 @@ public interface MetricsRecorder { * Get the approximate latency value, in milliseconds, for reallocation * latencies within the given percentile/quantile of what has been recorded * so far. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. @@ -180,17 +186,18 @@ public interface MetricsRecorder { * Get the approximate latency value, in milliseconds, for failed * reallocation latencies within the given percentile/quantile of what has * been recorded so far. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. @@ -200,17 +207,18 @@ public interface MetricsRecorder { /** * Get the approximate object lifetime, in milliseconds, for the given * percentile/quantile. - * + *

* A percentile, or quantile, is a value between 0.0 and 1.0, both inclusive, * which represents a percentage of the recorded samples. In other words, * given a percentile, the returned value will be the latency in * milliseconds, that the given percent of samples is less than or equal to. * For instance, if given the percentile 0.9 returns 120, then 90% of all * recorded latency samples will be less than or equal to 120 milliseconds. - * - * Note: Implementers should strive to return `Double.NaN` as a sentinel + *

+ * Note: Implementers should strive to return {@code Double.NaN} as a sentinel * value, if they do not support recording of the allocation latencies and/or * returning a specific percentile of such recordings. + * * @param percentile The percentile/quantile to get a value for. * @return The latency value in milliseconds for the given * percentile/quantile. diff --git a/src/main/java/stormpot/OrExpiration.java b/src/main/java/stormpot/OrExpiration.java index c41586e4..9c08f422 100644 --- a/src/main/java/stormpot/OrExpiration.java +++ b/src/main/java/stormpot/OrExpiration.java @@ -19,12 +19,12 @@ /** * Provides a way to compose {@link Expiration}s. - * + *

* Given two {@link Expiration}s, this class considers that a slot is expired if any of the - * {@link Expiration} returns `true`. This makes it easy to have an {@link Expiration} that + * {@link Expiration} returns {@code true}. This makes it easy to have an {@link Expiration} that * expires both on time ({@link Expiration#after(long, TimeUnit)}) and some other criteria. * - * @author Guillaume Lederrey + * @author Guillaume Lederrey * @since 2.4 */ class OrExpiration implements Expiration { @@ -37,7 +37,7 @@ class OrExpiration implements Expiration { } /** - * Returns `true` if any of the given {@link Expiration} has expired. + * Returns {@code true} if any of the given {@link Expiration} has expired. */ @Override public boolean hasExpired(SlotInfo info) throws Exception { diff --git a/src/main/java/stormpot/Pool.java b/src/main/java/stormpot/Pool.java index e2faf4b4..c52c0dbd 100644 --- a/src/main/java/stormpot/Pool.java +++ b/src/main/java/stormpot/Pool.java @@ -22,52 +22,52 @@ /** * A Pool is a self-renewable set of objects from which one can claim exclusive * access to elements, until they are released back into the pool. - * + *

* Pools are thread-safe, and their {@link #claim(Timeout)} methods can be * called concurrently from multiple threads. * This is a strictly stronger guarantee than {@link PoolTap} provides. - * + *

* Pools extend the {@link PoolTap} class, which provides the API for accessing * the objects contained in the pool. - * + *

* Pools contain {@link Poolable} objects. When you claim an object in a pool, * you also take upon yourself the responsibility of eventually * {@link Poolable#release() releasing} that object again. By far the most - * common idiom to achieve this is with a `try-finally` clause: - * - * [source,java,indent=0] - * ---- - * include::src/test/java/examples/Examples.java[tag=poolClaimExample] - * ---- - * + * common idiom to achieve this is with a {@code try-finally} clause: + * {@snippet class=Examples region=poolClaimExample } + *

* The pools are resizable, and can have their capacity changed at any time * after they have been created. - * + *

* All pools are configured with a certain size, the number of objects that the * pool will have allocated at any one time, and they can change this number on * the fly using the {@link #setTargetSize(int)} method. The change does not * take effect immediately, but instead moves the "goal post" and leaves the * pool to move towards it at its own pace. - * + *

* No guarantees can be made about when the pool will actually reach the target * size, because it might depend on how long it takes for a certain number of * objects to be released back into the pool. * - * [NOTE] - * -- - * Pools created with {@link Pool#of(Object[])} are _not_ resizable, and calling + * + * + * + * + * + * + *
Note
NOTE + * Pools created with {@link Pool#of(Object[])} are not resizable, and calling * {@link Pool#setTargetSize(int)} or {@link ManagedPool#setTargetSize(int)} will * cause an {@link UnsupportedOperationException} to be thrown. - * -- + *
* * Pools are themselves life-cycled, and should be {@link #shutdown() shut down} * when they are no longer needed. + *

+ * Note that Pools don't override the deprecated {@code Object.finalize()} method. + * Pools are expected to rely on explicit clean-up for releasing their resources. * - * Note that Pools are not guaranteed to have overwritten the - * `Object#finalize()` method. Pools are expected to rely on explicit - * clean-up for releasing their resources. - * - * @author Chris Vest + * @author Chris Vest * @param the type of {@link Poolable} contained in the pool, as determined * by the configured allocator. * @see stormpot.PoolTap @@ -81,11 +81,11 @@ public abstract class Pool extends PoolTap { * {@link Reallocator}, which can then in turn be used to * {@linkplain PoolBuilder#build build} a {@link Pool} instance with the * desired configuration. - * + *

* This method is synonymous for {@link #fromThreaded(Allocator)}. * * @param allocator The allocator we want our pools to use. This cannot be - * `null`. + * {@code null}. * @param The type of {@link Poolable} that is created by the allocator, * and the type of objects that the configured pools will contain. * @return A {@link PoolBuilder} that admits additional configurations, @@ -101,20 +101,20 @@ public static PoolBuilder from(Allocator allocator) { * {@link Reallocator}, which can then in turn be used to * {@linkplain PoolBuilder#build build} a threaded {@link Pool} instance with the * desired configuration. - * + *

* The returned {@link PoolBuilder} will build pools that allocate and deallocate * objects in a background thread. - * Hence the "threaded" in the name; the objects are created and destroyed + * Hence, the "threaded" in the name; the objects are created and destroyed * by the background thread, out of band with the threads that call into the pool to * claim objects. - * + *

* By moving the allocation of objects to a background thread, it can be guaranteed * that the timeouts given to {@link #claim(Timeout) claim} will always be honoured. * In other words, a slow allocation cannot block a {@link #claim(Timeout) claim} * call beyond its intended timeout. * * @param allocator The allocator we want our pools to use. This cannot be - * `null`. + * {@code null}. * @param The type of {@link Poolable} that is created by the allocator, * and the type of objects that the configured pools will contain. * @return A {@link PoolBuilder} that admits additional configurations, @@ -129,11 +129,11 @@ public static PoolBuilder fromThreaded(Allocator allo * {@link Reallocator}, which can then in turn be used to * {@linkplain PoolBuilder#build() build} a {@link Pool} operating in the * inline mode, with the desired configuration. - * + *

* The returned {@link PoolBuilder} will build pools that allocate and deallocate * objects in-line with, and as part of, the {@linkplain #claim(Timeout) claim} calls. - * Hence the "inline" in the name. - * + * Hence, the "inline" in the name. + *

* This way, pools operating in the inline mode do not need a background thread. * This means that it is harder for {@linkplain #claim(Timeout) claim} to honour the * given {@link Timeout}. @@ -141,7 +141,7 @@ public static PoolBuilder fromThreaded(Allocator allo * and automatically replacing failed allocations, are not available. * On the other hand, inline pool consumes fewer memory and CPU resources. * - * @param allocator The allcoator we want our pools to use. This cannot be `null`. + * @param allocator The allcoator we want our pools to use. This cannot be {@code null}. * @param The type of {@link Poolable} that is created by the allocator, * and the type of objects that the configured pools will contain. * @return A {@link PoolBuilder} that admits additional configurations, @@ -153,27 +153,32 @@ public static PoolBuilder fromInline(Allocator alloca /** * Build a {@link Pool} instance that pools the given set of objects. - * + *

* The objects in the pool are never expired, and never deallocated. * Explicitly expired objects simply return to the pool. - * + *

* This means that the returned pool has no background allocation thread, * and has no expiration checking overhead when claiming objects. - * + *

* The given objects are wrapped in {@link Pooled} objects, which * implement the {@link Poolable} interface. - * + *

* Shutting down the returned pool will not cause the given objects * to be deallocated. - * The shut down process will complete as soon as the last claimed + * The shutdown process will complete as soon as the last claimed * object is released back to the pool. * - * [NOTE] - * -- + * + * + * + * + * + * + *
Note
NOTE * Passing duplicate objects to this method is not supported. * The behaviour of the pool is unspecified if there are duplicates among * the objects passed as arguments to this method. - * -- + *
* * @param objects The objects the pool should contain. * @param The type of objects being pooled. @@ -198,33 +203,33 @@ public void deallocate(Pooled poolable) { } /** - * Initiate the shut down process on this pool, and return a - * {@link Completion} instance representing the shut down procedure. - * - * The shut down process is asynchronous, and the shutdown method is + * Initiate the shutdown process on this pool, and return a + * {@link Completion} instance representing the shutdown procedure. + *

+ * The shutdown process is asynchronous, and the shutdown method is * guaranteed to not wait for any claimed {@link Poolable Poolables} to * be released. - * - * The shut down process cannot complete before all Poolables are released + *

+ * The shutdown process cannot complete before all Poolables are released * back into the pool and {@link Allocator#deallocate(Poolable) deallocated}, * and all internal resources (such as threads, for instance) have been * released as well. Only when all of these things have been taken care of, * does the await methods of the Completion return. - * - * Once the shut down process has been initiated, that is, as soon as this + *

+ * Once the shutdown process has been initiated, that is, as soon as this * method is called, the pool can no longer be used and all calls to * {@link #claim(Timeout)} will throw an {@link IllegalStateException}. * Threads that are already waiting for objects in the claim method, will * also wake up and receive an {@link IllegalStateException}. - * + *

* All objects that are already claimed when this method is called, * will continue to function until they are * {@link Poolable#release() released}. - * - * The shut down process is guaranteed to never deallocate objects that are + *

+ * The shutdown process is guaranteed to never deallocate objects that are * currently claimed. Their deallocation will wait until they are released. * - * @return A {@link Completion} instance that represents the shut down + * @return A {@link Completion} instance that represents the shutdown * process. */ public abstract Completion shutdown(); @@ -232,20 +237,20 @@ public void deallocate(Pooled poolable) { /** * Set the target size for this pool. The pool will strive to keep this many * objects allocated at any one time. - * + *

* If the new target size is greater than the old one, the pool will allocate * more objects until it reaches the target size. If, on the other hand, the * new target size is less than the old one, the pool will deallocate more * and allocate less, until the new target size is reached. - * + *

* No guarantees are made about when the pool actually reaches the target * size. In fact, it may never happen as the target size can be changed as * often as one sees fit. - * + *

* Pools that do not support a size less than 0 (which would deviate from the * standard configuration space) will throw an * {@link IllegalArgumentException} if passed -1 or less. - * + *

* Pools that do not support online resizing will throw an * {@link UnsupportedOperationException}. * @@ -255,7 +260,7 @@ public void deallocate(Pooled poolable) { /** * Get the currently configured target size of the pool. Note that this is - * _not_ the number of objects currently allocated by the pool - only + * not the number of objects currently allocated by the pool - only * the number of allocations the pool strives to keep alive. * * @return The current target size of this pool. @@ -293,10 +298,10 @@ public T tryClaim() { * Get a {@link PoolTap} that only support access by one thread at a time. * In other words, where {@link #claim(Timeout)} cannot be called * concurrently in multiple threads *on the same tap*. - * + *

* The pool itself will still be thread-safe, but each thread that wishes to * access the pool via a thread-local tap, must have their own tap instance. - * + *

* It is a use error to access these pool taps concurrently from multiple * threads, or to transfer them from one thread to another without safe * publication. diff --git a/src/main/java/stormpot/PoolBuilder.java b/src/main/java/stormpot/PoolBuilder.java index c22bf0bb..3cc212cb 100644 --- a/src/main/java/stormpot/PoolBuilder.java +++ b/src/main/java/stormpot/PoolBuilder.java @@ -29,24 +29,24 @@ import static stormpot.StormpotThreadFactory.INSTANCE; /** - * The `PoolBuilder` collects information about how big a pool should be, - * and how it should allocate objects, an so on, and finally acts as the + * 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 * factory for building the pool instances themselves, with the * {@link #build()} method. - * - * Pool builder instances are obtained by calling one of the `from*` + *

+ * Pool builder instances are obtained by calling one of the {@code from*} * methods on {@link Pool}, such as {@link Pool#fromThreaded(Allocator)}. - * + *

* This class is made thread-safe by having the fields be protected by the - * intrinsic object lock on the `PoolBuilder` object itself. This way, pools - * can `synchronize` on the builder object to read the values out atomically. - * - * The various set* methods are made to return the `PoolBuilder` instance + * intrinsic object lock on the {@code PoolBuilder} object itself. This way, pools + * can {@code synchronize} on the builder object to read the values out atomically. + *

+ * The various {@code set*} methods are made to return the {@code PoolBuilder} instance * itself, so that the method calls may be chained if so desired. * - * @author Chris Vest + * @author Chris Vest * @param The type of {@link Poolable} objects that a {@link Pool} based - * on this `PoolBuilder` will produce. + * on this {@code PoolBuilder} will produce. */ public final class PoolBuilder implements Cloneable { static final Map DEFAULTS = Map.of( @@ -73,7 +73,7 @@ DIRECT, new PoolBuilderPermissions(false, true, false, false, false) private int backgroundExpirationCheckDelay; /** - * Build a new empty `PoolBuilder` object. + * Build a new empty {@code PoolBuilder} object. */ PoolBuilder(AllocationProcess allocationProcess, Allocator allocator) { requireNonNull(allocator, "The Allocator cannot be null."); @@ -91,22 +91,22 @@ DIRECT, new PoolBuilderPermissions(false, true, false, false, false) /** * Set the size of the pool we are building. - * + *

* Pools are required to control the allocations and deallocations, such that * no more than this number of objects are allocated at any time. - * + *

* This means that a pool of size 1, whose single object have expired, will * deallocate that one object before allocating a replacement. - * + *

* The size must be at least one, or an {@link IllegalArgumentException} will * be thrown when building the pool. - * + *

* Note that the pool size can be modified after the pool has been built, by * calling the {@link Pool#setTargetSize(int)} or * {@link ManagedPool#setTargetSize(int)} methods. * * @param size The target pool size. Must be at least 0. - * @return This `PoolBuilder` instance. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setSize(int size) { checkPermission(permissions.setSize, "size"); @@ -127,17 +127,17 @@ public synchronized int getSize() { /** * Set the {@link Allocator} or {@link Reallocator} to use for the pools we - * want to configure. This will change the type-parameter of the `PoolBuilder` + * want to configure. This will change the type-parameter of the {@code PoolBuilder} * object to match that of the new Allocator. - * + *

* The allocator is initially specified by the {@link Pool#from(Allocator)} * method, so there is usually no need to set it later. * * @param allocator The allocator we want our pools to use. - * This cannot be `null`. + * This cannot be {@code null}. * @param The type of {@link Poolable} that is created by the allocator, * and the type of objects that the configured pools will contain. - * @return This `PoolBuilder` instance, but with a generic type parameter that + * @return This {@code PoolBuilder} instance, but with a generic type parameter that * matches that of the allocator. */ @SuppressWarnings("unchecked") @@ -175,13 +175,13 @@ public synchronized Reallocator getReallocator() { * Set the {@link Expiration} to use for the pools we want to * configure. The Expiration determines when a pooled object is valid * for claiming, or when the objects are invalid and should be deallocated. - * + *

* The default Expiration is an * {@link Expiration#after(long, long, TimeUnit)} that invalidates the - * objects after they have been active for somewhere between 8 to 10 minutes. + * objects after they have been active for somewhere from 8 to 10 minutes. * * @param expiration The expiration we want our pools to use. Not null. - * @return This `PoolBuilder` instance. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setExpiration(Expiration expiration) { checkPermission(permissions.setExpiration, "expiration"); @@ -193,7 +193,7 @@ public synchronized PoolBuilder setExpiration(Expiration expiratio /** * Get the configured {@link Expiration} instance. The default is a * {@link Expiration#after(long, long, TimeUnit)} that expires objects after - * somewhere between 8 to 10 minutes. + * somewhere from 8 to 10 minutes. * * @return The configured Expiration. */ @@ -205,7 +205,7 @@ public synchronized Expiration getExpiration() { * Set the {@link MetricsRecorder} to use for the pools we want to configure. * @param metricsRecorder The MetricsRecorder to use, or null if we don't * want to use any. - * @return This `PoolBuilder` instance. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setMetricsRecorder(MetricsRecorder metricsRecorder) { this.metricsRecorder = metricsRecorder; @@ -213,7 +213,7 @@ public synchronized PoolBuilder setMetricsRecorder(MetricsRecorder metricsRec } /** - * Get the configured {@link MetricsRecorder} instance, or null if none has + * Get the configured {@link MetricsRecorder} instance, or {@code null} if none has * been configured. * @return The configured MetricsRecorder. */ @@ -238,7 +238,7 @@ public synchronized ThreadFactory getThreadFactory() { * a pool with a null ThreadFactory will throw an IllegalArgumentException. * @param factory The ThreadFactory the pool should use to create their * background threads. - * @return This `PoolBuilder` instance. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { checkPermission(permissions.setThreadFactory, "thread factory"); @@ -248,9 +248,9 @@ public synchronized PoolBuilder setThreadFactory(ThreadFactory factory) { } /** - * Return whether or not precise object leak detection is enabled, which is + * Return whether precise object leak detection is enabled, which is * the case by default. - * @return `true` if precise object leak detection is enabled. + * @return {@code true} if precise object leak detection is enabled. * @see #setPreciseLeakDetectionEnabled(boolean) */ public synchronized boolean isPreciseLeakDetectionEnabled() { @@ -265,20 +265,25 @@ public synchronized boolean isPreciseLeakDetectionEnabled() { * means that no false positives (counting objects as leaked, even though * they are not) are ever reported. * - * [NOTE] - * -- + * + * + * + * + * + * + *
Note
NOTE * While the pool is able to detect object leaks, it cannot prevent * them. All leaks are a sign that there is a bug in the system; most likely * a bug in your code, or in the way the pool is used. - * -- + *
* * Precise object leak detection incurs virtually no overhead, and is safe to * leave enabled at all times – even in the most demanding production * environments. * - * @param enabled `true` to turn on precise object leak detection (the - * default) `false` to turn it off. - * @return This `PoolBuilder` instance. + * @param enabled {@code true} to turn on precise object leak detection (the + * default) {@code false} to turn it off. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setPreciseLeakDetectionEnabled(boolean enabled) { this.preciseLeakDetectionEnabled = enabled; @@ -286,10 +291,10 @@ public synchronized PoolBuilder setPreciseLeakDetectionEnabled(boolean enable } /** - * Return whether or not background expiration is enabled. + * Return whether background expiration is enabled. * By default, background expiration is enabled. * - * @return `true` if background expiration is enabled. + * @return {@code true} if background expiration is enabled. * @see #setBackgroundExpirationEnabled(boolean) */ public synchronized boolean isBackgroundExpirationEnabled() { @@ -304,9 +309,9 @@ public synchronized boolean isBackgroundExpirationEnabled() { * demand for allocations and deallocations, even though these tasks always * take priority over any expiration checking. * - * @param enabled `true` (the default) to turn background expiration checking on, - * `false` to turn it off. - * @return This `PoolBuilder` instance. + * @param enabled {@code true} (the default) to turn background expiration checking on, + * {@code false} to turn it off. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setBackgroundExpirationEnabled(boolean enabled) { checkPermission(permissions.setBackgroundExpiration, "background expiration enabled/disabled"); @@ -328,18 +333,18 @@ public synchronized int getBackgroundExpirationCheckDelay() { /** * Set the approximate delay, in milliseconds, between background maintenance tasks. * These tasks include the background expiration checks, and retrying failed allocations. - * + *

* The default delay is 1.000 milliseconds (1 second). Lowering this value will * improve the pools responsiveness to repairing failed allocations, and also increase * the frequency of the background expiration checks. This comes at the cost of higher * idle CPU usage. - * + *

* It is not recommended to set this value lower than 100 milliseconds. Values lower * than this tend to have increased CPU and power usage, for very little gain in * responsiveness for the background tasks. * * @param delay the desired delay, in milliseconds, between background maintenance tasks. - * @return This `PoolBuilder` instance. + * @return This {@code PoolBuilder} instance. */ public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) { checkPermission(permissions.setBackgroundExpiration, "background expiration check delay"); @@ -351,8 +356,8 @@ public synchronized PoolBuilder setBackgroundExpirationCheckDelay(int delay) } /** - * Returns a shallow copy of this `PoolBuilder` object. - * @return A new `PoolBuilder` object of the exact same type as this one, with + * 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") @@ -374,9 +379,9 @@ public synchronized Pool build() { } /** - * Returns a `Reallocator`, possibly by adapting the configured - * `Allocator` if need be. - * If a `MetricsRecorder` has been configured, the return `Reallocator` will + * 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() { diff --git a/src/main/java/stormpot/PoolException.java b/src/main/java/stormpot/PoolException.java index f5d96e2d..8b0f6691 100644 --- a/src/main/java/stormpot/PoolException.java +++ b/src/main/java/stormpot/PoolException.java @@ -18,18 +18,18 @@ /** * The PoolException may be thrown by a pool implementation in a number of * circumstances: + *

    + *
  • If claim is called and the pool needs to {@link Allocator#allocate(Slot) allocate} + * a new object, but the allocation fails by returning {@code null} or throwing an exception.
  • + *
  • Likewise if the {@link Reallocator#reallocate(Slot, Poolable)} method + * return {@code null} or throw an exception.
  • + *
  • If the {@link Slot#release(Poolable)} method is misused, and the pool is + * able to detect this.
  • + *
  • If the {@link Expiration#hasExpired(SlotInfo) expiration check} throws an + * exception.
  • + *
* - * * If claim is called and the pool needs to - * {@link Allocator#allocate(Slot) allocate} a new object, but the allocation - * fails by returning `null` or throwing an exception. - * * Likewise if the {@link Reallocator#reallocate(Slot, Poolable)} method - * return `null` or throw an exception. - * * If the {@link Slot#release(Poolable)} method is misused, and the pool is - * able to detect this. - * * If the {@link Expiration#hasExpired(SlotInfo) expiration check} throws an - * exception. - * - * @author Chris Vest + * @author Chris Vest */ public class PoolException extends RuntimeException { private static final long serialVersionUID = -1908093409167496640L; @@ -46,6 +46,7 @@ public PoolException(String message) { /** * Construct a new PoolException with the given message and cause. + * * @param message A description for the exception to be returned form * {@link #getMessage()}. * @param cause The underlying cause of this exception, as to be shown in the diff --git a/src/main/java/stormpot/PoolTap.java b/src/main/java/stormpot/PoolTap.java index 946d5814..f815bdc0 100644 --- a/src/main/java/stormpot/PoolTap.java +++ b/src/main/java/stormpot/PoolTap.java @@ -23,11 +23,11 @@ /** * A PoolTap provides the API for accessing objects in a {@link Pool}. - * + *

* PoolTaps are not necessarily thread-safe, but pools, which extend PoolTap, * are always thread-safe. * - * @author Chris Vest + * @author Chris Vest * @param the type of {@link Poolable} contained in the pool, and made * available via this pool tap, as determined by the * {@linkplain Pool#from(Allocator) configured allocator}. @@ -45,78 +45,76 @@ public abstract class PoolTap { * Possibly waiting up to the specified amount of time, as given by the * provided {@link Timeout} instance, for one to become available if the * pool has been depleted. If the timeout elapses before an object can be - * claimed, then `null` is returned instead. The timeout will be + * claimed, then {@code null} is returned instead. The timeout will be * honoured even if the Allocators {@link Allocator#allocate(Slot) allocate} * methods blocks forever. If the given timeout has a zero or negative value, * then the method will not wait. - * + *

* If the current thread has already one or more objects currently claimed, * then a distinct object will be returned, if one is or becomes available. * This means that it is possible for a single thread to deplete the pool, if * it so desires. However, doing so is inherently deadlock prone, so avoid * claiming more than one object at a time per thread, if at all possible. - * + *

* This method may throw a PoolException if the pool have trouble allocating * objects. That is, if its assigned Allocator throws exceptions from its - * allocate method, or returns `null`. - * + * allocate method, or returns {@code null}. + *

* An {@link InterruptedException} will be thrown if the thread has its * interrupted flag set upon entry to this method, or is interrupted while * waiting. The interrupted flag on the thread will be cleared after * this, as per the general contract of interruptible methods. - * + *

* If the pool has been shut down, then an {@link IllegalStateException} will - * be thrown when this method is called. Likewise if we are waiting for an + * be thrown when this method is called. Likewise, if we are waiting for an * object to become available, and someone shuts the pool down. - * + *

* Here's an example code snippet, where an object is claimed, printed to - * `System.out`, and then released back to the pool: + * {@code System.out}, and then released back to the pool: + * {@snippet class=Examples region=poolClaimPrintExample} * - * [source,java,indent=0] - * ---- - * include::src/test/java/examples/Examples.java[tag=poolClaimPrintExample] - * ---- - * - * Memory effects: - * - * * The {@link Poolable#release() release} of an object happens-before + *

Memory effects:

+ *
    + *
  • The {@link Poolable#release() release} of an object happens-before * any subsequent claim or {@link Allocator#deallocate(Poolable) - * deallocation} of that object, and, - * * The {@link Allocator#allocate(Slot) allocation} of an object - * happens-before any claim of that object. + * deallocation} of that object, and,
  • + *
  • The {@link Allocator#allocate(Slot) allocation} of an object + * happens-before any claim of that object.
  • + *
* * @param timeout The timeout of the maximum permitted time-slice to wait for - * an object to become available. A timeout with a value of zero or less + * an object to become available. A timeout with a value of zero or less, * means that the call will do no waiting, preferring instead to return early * if no objects are available. * @return An object of the Poolable subtype T to which the exclusive rights - * have been claimed, or `null` if the timeout period elapsed + * have been claimed, or {@code null} if the timeout period elapsed * before an object became available. * @throws PoolException If an object allocation failed because the Allocator * threw an exception from its allocate method, or returned - * `null`, or the + * {@code null}, or the * {@link Expiration#hasExpired(SlotInfo) expiration check} threw an * exception. * @throws InterruptedException if the current thread is * {@link Thread#interrupt() interrupted} upon entry, or becomes interrupted * while waiting. - * @throws IllegalArgumentException if the `timeout` argument is `null`. + * @throws IllegalArgumentException if the {@code timeout} argument is {@code null}. */ public abstract T claim(Timeout timeout) throws PoolException, InterruptedException; /** * Returns an object from the pool if the pool contains at least one valid object, - * otherwise returns `null`. + * otherwise returns {@code null}. * This method will first try to return cached object if available. - * If no locally cached object is found, it will go though objects in the pool and + * If no locally cached object is found, it will go through objects in the pool and * return the first ready to claim object. - * If all the objects in the pool is drained, then `null` will be returned. + * If all the objects in the pool is drained, then {@code null} will be returned. + * * @return an object from the pool if the pool contains at least one valid object, - * otherwise returns `null`. + * otherwise returns {@code null}. * @throws PoolException If an object allocation failed because the Allocator * threw an exception from its allocate method, or returned - * `null`, or the + * {@code null}, or the * {@link Expiration#hasExpired(SlotInfo) expiration check} threw an exception. */ public T tryClaim() throws PoolException { @@ -132,13 +130,13 @@ public T tryClaim() throws PoolException { /** * Claim an object from the pool and apply the given function to it, returning * the result and releasing the object back to the pool. - * + *

* If an object cannot be claimed within the given timeout, then - * {@link Optional#empty()} is returned instead. The `empty()` value is also - * returned if the function returns `null`. + * {@link Optional#empty()} is returned instead. The {@code empty()} value is also + * returned if the function returns {@code null}. * * @param timeout The timeout of the maximum permitted amount of time to wait - * for an object to become available. A timeout with a value of zero or less + * for an object to become available. A timeout with a value of zero or less, * means that the call will do no waiting, preferring instead to return early * if no objects are available. * @param function The function to apply to the claimed object, if any. The @@ -147,9 +145,9 @@ public T tryClaim() throws PoolException { * @param The return type of the given function. * @return an {@link Optional} of either the return value of applying the * given function to a claimed object, or empty if the timeout elapsed or - * the function returned `null`. + * the function returned {@code null}. * @throws InterruptedException if the thread was interrupted. - * @see #claim(Timeout) The `claim` method for more details on failure modes + * @see #claim(Timeout) The {@code claim} method for more details on failure modes * and memory effects. */ public final Optional apply(Timeout timeout, Function function) @@ -169,21 +167,22 @@ public final Optional apply(Timeout timeout, Function function) /** * Claim an object from the pool and supply it to the given consumer, and then * release it back to the pool. - * + *

* If an object cannot be claimed within the given timeout, then this method - * returns `false`. Otherwise, if an object was claimed and supplied to the - * consumer, the method returns `true`. + * returns {@code false}. Otherwise, if an object was claimed and supplied to the + * consumer, the method returns {@code true}. + * * @param timeout The timeout of the maximum permitted amount of time to wait - * for an object to become available. A timeout with a value of zero or less + * for an object to become available. A timeout with a value of zero or less, * means that the call will do no waiting, preferring instead to return early * if no objects are available. * @param consumer The consumer to pass the claimed object to, if any. The * consumer should avoid further claims, since having more than one object * claimed at a time per thread is inherently deadlock prone. - * @return `true` if an object could be claimed within the given timeout and - * passed to the given consumer, or `false` otherwise. + * @return {@code true} if an object could be claimed within the given timeout and + * passed to the given consumer, or {@code false} otherwise. * @throws InterruptedException if the thread was interrupted. - * @see #claim(Timeout) The `claim` method for more details on failure modes + * @see #claim(Timeout) The {@code claim} method for more details on failure modes * and memory effects. */ public final boolean supply(Timeout timeout, Consumer consumer) diff --git a/src/main/java/stormpot/Poolable.java b/src/main/java/stormpot/Poolable.java index fd14eb54..33c7b547 100644 --- a/src/main/java/stormpot/Poolable.java +++ b/src/main/java/stormpot/Poolable.java @@ -18,39 +18,31 @@ /** * Objects contained in a {@link Pool} must implement the Poolable interface * and adhere to its contract. - * + *

* Pools call {@link Allocator#allocate(Slot) allocate} on Allocators with the * specific {@link Slot} that they want a Poolable allocated for. The Slot * represents a location in the pool, that can fit an object and make it * available for others to claim. - * + *

* The contract of the Poolable interface is, that when {@link #release()} is * called on the Poolable, it must in turn call {@link Slot#release(Poolable)} * on the specific Slot object that it was allocated with, giving itself as the * Poolable parameter. - * + *

* A simple correct implementation of the Poolable interface looks like this: - * - * [source,java,indent=0] - * ---- - * include::src/test/java/examples/Examples.java[tag=poolableGenericExample] - * ---- + * {@snippet class=Examples region=poolableGenericExample} * * This can be shortened further by extending the {@link BasePoolable} class: - * - * [source,java,indent=0] - * ---- - * include::src/test/java/examples/Examples.java[tag=poolableBaseExample] - * ---- + * {@snippet class=Examples region=poolableBaseExample} * * It is also possible to directly use the {@link Pooled} implementation, which - * implements both `Poolable` and {@link AutoCloseable}, and holds a + * implements both {@code Poolable} and {@link AutoCloseable}, and holds a * reference to the actual object being pooled. - * + *

* Memory effects: The release of an object happens-before it is claimed * by another thread, or deallocated. * - * @author Chris Vest + * @author Chris Vest * @see BasePoolable * @see Pooled */ @@ -59,18 +51,18 @@ public interface Poolable { * Release this Poolable object back into the pool from where it came, * so that others can claim it, or the pool deallocate it if it has * expired. - * + *

* A call to this method MUST delegate to a call to * {@link Slot#release(Poolable)} on the Slot object for which this * Poolable was allocated, giving itself as the Poolable parameter. - * + *

* A Poolable can be released by a thread other than the one that claimed it. * It can not, however, be released more than once per claim. The feature of * permitting releases from threads other than the claiming thread might be * useful in message-passing architectures and the like, but it is not * generally recommendable because it makes it more complicated to keep track * of object life-cycles. - * + *

* Great care must be taken, to ensure that Poolables are not used after they * are released! */ diff --git a/src/main/java/stormpot/Pooled.java b/src/main/java/stormpot/Pooled.java index 07fd472e..53ce776d 100644 --- a/src/main/java/stormpot/Pooled.java +++ b/src/main/java/stormpot/Pooled.java @@ -17,6 +17,8 @@ /** * A reference to a pooled object. + * + * @param The type of object referenced by the {@link Pooled}. */ public class Pooled extends BasePoolable implements Poolable, AutoCloseable { /** @@ -36,7 +38,7 @@ public Pooled(Slot slot, T object) { } /** - * `Pooled` implements {@link AutoCloseable} as a convenient way to release + * {@link Pooled} implements {@link AutoCloseable} as a convenient way to release * claimed objects back to the pool, using the try-with-resources syntax. */ @Override diff --git a/src/main/java/stormpot/Reallocator.java b/src/main/java/stormpot/Reallocator.java index df4452d3..87d9af56 100644 --- a/src/main/java/stormpot/Reallocator.java +++ b/src/main/java/stormpot/Reallocator.java @@ -20,17 +20,17 @@ * {@link Poolable}s that have expired. This is useful since the {@link Pool} * will typically keep the Poolables around for a relatively long time, with * respect to garbage collection. Because of this, there is a high chance that - * the Poolables tenure to the old generation during their life time. This + * the Poolables tenure to the old generation during their life-time. This * way, pools often cause a slow, but steady accretion of old generation * garbage, ultimately helping to increase the frequency of expensive full * collections. - * + *

* The accretion of old generation garbage is inevitable, but the rate can be * slowed by reusing as much as possible of the Poolable instances, when they * are to be reallocated. This interface is only here to enable this * optimisation, and implementing it is completely optional. * - * @author Chris Vest + * @author Chris Vest * * @param any type that implements Poolable. * @since 2.2 @@ -40,38 +40,35 @@ public interface Reallocator extends Allocator { * Possibly reallocate the given instance of T for the given slot, and * return it if the reallocation was successful, or a fresh replacement if * the instance could not be reallocated. - * + *

* This method is effectively equivalent to the following: - * - * [source,java,indent=0] - * -- - * include::src/test/java/examples/Examples.java[tag=reallocatorExample] - * -- + * {@snippet class=Examples region=reallocatorExample} * * With the only difference that it may, if possible, reuse the given * expired Poolable, either wholly or in part. - * + *

* The state stored in the {@link stormpot.SlotInfo} for the object is reset * upon reallocation, just like it would be in the case of a normal * deallocation-allocation cycle. - * + *

* Exceptions thrown by this method may propagate out through the * {@link Pool#claim(Timeout) claim} method of a pool, in the form of being * wrapped inside a {@link PoolException}. Pools must be able to handle these * exceptions in a sane manner, and are guaranteed to return to a working * state if a Reallocator stops throwing exceptions from its reallocate * method. - * + *

* Be aware that if the reallocation of an object fails with an exception, * then no attempts will be made to explicitly deallocate that object. This * way, a failed reallocation is implicitly understood to effectively be a * successful deallocation. + * * @param slot The slot the pool wish to allocate an object for. * Implementers do not need to concern themselves with the details of a * pools slot objects. They just have to call release on them as the * protocol demands. * @param poolable The non-null Poolable instance to be reallocated. - * @return A fresh or rejuvenated instance of T. Never `null`. + * @return A fresh or rejuvenated instance of T. Never {@code null}. * @throws Exception If the allocation fails. * @see #allocate(Slot) * @see #deallocate(Poolable) diff --git a/src/main/java/stormpot/RefillPile.java b/src/main/java/stormpot/RefillPile.java index 47f52b0a..bb9da612 100644 --- a/src/main/java/stormpot/RefillPile.java +++ b/src/main/java/stormpot/RefillPile.java @@ -15,16 +15,20 @@ */ package stormpot; +import java.io.Serial; import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicReference; /** - * A `RefillPile` can collect objects, in a concurrent and wait-free manner, + * A {@code RefillPile} can collect objects, in a concurrent and wait-free manner, * before releasing them all to a queue. + * + * @param The concrete {@link Poolable} object type. */ @SuppressWarnings("unchecked") final class RefillPile extends AtomicReference> { + @Serial private static final long serialVersionUID = 2374582348576873465L; private static final RefillSlot STACK_END = new RefillSlot<>(null); @@ -67,7 +71,7 @@ private boolean pause() { * Refill the target queue with all the slots that have been pushed onto this stack. * This method atomically pops all elements from the stack at once, and then pushed onto the * queue one by one. - * @return `true` if any slots has been offered to the queue, or `false` if there were no + * @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() { diff --git a/src/main/java/stormpot/Slot.java b/src/main/java/stormpot/Slot.java index e986adb5..882b5031 100644 --- a/src/main/java/stormpot/Slot.java +++ b/src/main/java/stormpot/Slot.java @@ -19,42 +19,42 @@ * A Slot represents a location in a Pool where objects can be allocated into, * so that they can be claimed and released. The Slot is used by the allocated * Poolables as a call-back, to tell the pool when an object is released. - * + *

* The individual pool implementations provide their own Slot implementations. - * + *

* Slots contain mutable state within them. If objects are claimed, released * and otherwise worked on from different threads, then the hand-over must * happen through a safe publication mechanism. - * + *

* See Java Concurrency in Practice by Brian Goetz for more information on safe * publication. - * + *

* Slots also expects single-threaded access, so they cannot be used * concurrently by multiple threads. Only one thread at a time can use a Slot * instance. * - * @author Chris Vest + * @author Chris Vest * @see Poolable */ public interface Slot { /** * Signal to the pool that the currently claimed object in this slot has been * released. - * + *

* It is a user error to release a slot that is not currently claimed. It is * likewise a user error to release a Slot while inside the Allocators * {@link Allocator#allocate(Slot) allocate} method, or the Expirations * {@link Expiration#hasExpired(SlotInfo) hasExpired} method. - * - * On the other hand, it is _not_ an error to release a Poolable + *

+ * On the other hand, it is not an error to release a Poolable * from a thread other than the one that claimed it. - * + *

* Pools are free to throw a PoolException if they detect any of these * wrong uses, but it is not guaranteed and the exact behaviour is not - * specified. "Unspecified behaviour" means that dead-locks and infinite + * specified. "Unspecified behaviour" means that deadlocks and infinite * loops are fair responses as well. Therefore, heed the advice and don't * misuse release! - * + *

* Pools must, however, guarantee that an object is never * {@link Allocator#deallocate(Poolable) deallocated} more than once. * This guarantee must hold even if release is misused. @@ -72,11 +72,11 @@ public interface Slot { * explicitly expired using this method. Objects can only be explicitly * expired while they are claimed, and such expired objects will not be * deallocated until they are released back to the pool. - * + *

* It is a user error to expire objects that are not currently claimed. It is * likewise a user error to expire a Slot while inside the Allocators * {@link Allocator#allocate(Slot) allocate} method. - * + *

* The expiration only takes effect after the object has been released, so * calling this method from within the Expirations * {@link Expiration#hasExpired(SlotInfo) hasExpired} method will not prevent @@ -84,12 +84,12 @@ public interface Slot { * again after it's been released back to the pool. An Expiration policy that * expires all objects with this method, is effectively allowing objects to * only be claimed once. - * + *

* Pools are free to throw a PoolException if they detect any wrong uses, * but it is not guaranteed and the exact behaviour is not specified. - * "Unspecified behaviour" means that dead-locks and infinite loops are fair + * "Unspecified behaviour" means that deadlocks and infinite loops are fair * responses as well. Therefore, heed the advice and don't misuse expire! - * + *

* Pools must, however, guarantee that an object is never * {@link Allocator#deallocate(Poolable) deallocated} more than once. * This guarantee must hold even if expire is misused. diff --git a/src/main/java/stormpot/SlotInfo.java b/src/main/java/stormpot/SlotInfo.java index 000de1aa..13099031 100644 --- a/src/main/java/stormpot/SlotInfo.java +++ b/src/main/java/stormpot/SlotInfo.java @@ -19,7 +19,7 @@ * An informative interface, used by {@link Expiration} instances to * determine if a slot has expired or is still invalid for claiming. * - * @author Chris Vest + * @author Chris Vest * @param The type of Poolables that this Expiration is able to examine. */ public interface SlotInfo { @@ -40,14 +40,14 @@ public interface SlotInfo { /** * Get the Poolable object represented by this SlotInfo instance. - * + *

* WARNING: Do not {@link Poolable#release() release()} * Poolables from within an {@link Expiration} — doing so is a user * error, and the behaviour of the pool in such a situation is unspecified - * and implementation specific. This means that dead-locks and infinite + * and implementation specific. This means that deadlocks and infinite * loops are possible outcomes as well. - * - * WARNING: Also note that accessing the Poolable through + *

+ * WARNING: Also note that accessing the Poolable through * this method, from your {@link Expiration} implementation, is a * potentially concurrent access. This means that you need to take * thread-safety issues into consideration - especially if you intend on @@ -56,14 +56,14 @@ public interface SlotInfo { * might even have claimed the Poolable and put it to use, by the time it * is returned from this method. * - * @return The Poolable being examined for validity. Never `null`. + * @return The Poolable being examined for validity. Never {@code null}. */ T getPoolable(); /** * Get the stamp value that has been set on this SlotInfo, or 0 if none has * been set since the Poolable was allocated. - * + *

* Apart from the zero-value, the actual meaning of this value is completely * up to the {@link Expiration} that sets it. * @return The current stamp value. @@ -72,10 +72,10 @@ public interface SlotInfo { /** * Set the stamp value on this SlotInfo. - * + *

* This method is only thread-safe to call from within the scope of the * {@link Expiration#hasExpired(SlotInfo)} method. - * + *

* The stamp value is 0 by default, if it has not been set after the Poolable * has been allocated. Its meaning is otherwise up to the particular * Expiration that might use it. diff --git a/src/main/java/stormpot/TimeExpiration.java b/src/main/java/stormpot/TimeExpiration.java index d0e7bd9e..741c9faa 100644 --- a/src/main/java/stormpot/TimeExpiration.java +++ b/src/main/java/stormpot/TimeExpiration.java @@ -22,7 +22,7 @@ * This is a time based {@link Expiration}. It will invalidate * objects based on how long ago they were allocated. * - * @author Chris Vest + * @author Chris Vest */ final class TimeExpiration implements Expiration { @@ -32,14 +32,14 @@ final class TimeExpiration implements Expiration { /** * Construct a new Expiration that will invalidate objects that are older * than the provided span of time in the given unit. - * - * If the `maxPermittedAge` is less than one, or the `unit` is `null`, then + *

+ * If the {@code maxPermittedAge} is less than one, or the {@code unit} is {@code null}, then * an {@link IllegalArgumentException} will be thrown. * * @param maxPermittedAge Poolables older than this, in the given unit, will * be considered expired. This value must be at least 1. * @param unit The {@link TimeUnit} of the maximum permitted age. Never - * `null`. + * {@code null}. */ TimeExpiration(long maxPermittedAge, TimeUnit unit) { Objects.requireNonNull(unit, "TimeUnit cannot be null."); @@ -52,7 +52,7 @@ final class TimeExpiration implements Expiration { } /** - * Returns `true` if the {@link Poolable} represented by the given + * Returns {@code true} if the {@link Poolable} represented by the given * {@link SlotInfo} is older than the maximum age permitted by this * TimeExpiration. */ diff --git a/src/main/java/stormpot/TimeSpreadExpiration.java b/src/main/java/stormpot/TimeSpreadExpiration.java index 3c628789..c47d444c 100644 --- a/src/main/java/stormpot/TimeSpreadExpiration.java +++ b/src/main/java/stormpot/TimeSpreadExpiration.java @@ -23,7 +23,7 @@ * This is the standard time based {@link Expiration}. It will invalidate * objects based on about how long ago they were allocated. * - * @author Chris Vest + * @author Chris Vest * @since 2.2 */ final class TimeSpreadExpiration implements Expiration { @@ -36,9 +36,9 @@ final class TimeSpreadExpiration implements Expiration { * Construct a new Expiration that will invalidate objects that are older * than the given lower bound, before they get older than the upper bound, * in the given time unit. - * - * If the `lowerBound` is less than 1, the `upperBound` is less than the - * `lowerBound`, or the `unit` is `null`, then an + *

+ * If the {@code lowerBound} is less than 1, the {@code upperBound} is less than the + * {@code lowerBound}, or the {@code unit} is {@code null}, then an * {@link java.lang.IllegalArgumentException} will be thrown. * * @param lowerBound Poolables younger than this, in the given unit, are not @@ -46,7 +46,7 @@ final class TimeSpreadExpiration implements Expiration { * @param upperBound Poolables older than this, in the given unit, are always * considered expired. This value must be greater than the * lowerBound. - * @param unit The {@link TimeUnit} of the bounds values. Never `null`. + * @param unit The {@link TimeUnit} of the bounds values. Never {@code null}. */ TimeSpreadExpiration( long lowerBound, @@ -67,12 +67,12 @@ final class TimeSpreadExpiration implements Expiration { } /** - * Returns `true`, with uniformly increasing probability, if the + * Returns {@code true}, with uniformly increasing probability, if the * {@link stormpot.Poolable} represented by the given {@link SlotInfo} is - * older than the lower bound, eventually returning `true` with + * older than the lower bound, eventually returning {@code true} with * 100% certainty when the age of the Poolable is equal to or greater than * the upper bound. - * + *

* The uniformity of the random expiration holds regardless of how often a * Poolable is checked. That is to say, checking a Poolable more times within * an interval of time, does _not_ increase its chances of being diff --git a/src/main/java/stormpot/Timeout.java b/src/main/java/stormpot/Timeout.java index 84c4fcde..361d0da0 100644 --- a/src/main/java/stormpot/Timeout.java +++ b/src/main/java/stormpot/Timeout.java @@ -22,17 +22,17 @@ /** * A Timeout represents the maximum amount of time a caller is willing to wait * for a blocking operation to complete. - * + *

* Timeouts are independent of their units, so two timeouts of equivalent * duration but constructed in different units, will be equal to each other and * work exactly the same. - * + *

* Timeouts are also independent of "calendar time" in the sense that they * represent and work as a duration of absolute time. In other words, timeouts * do not grow or shrink with passing leap seconds or daylight savings time * adjustments. * - * @author Chris Vest + * @author Chris Vest */ public final class Timeout { private final long timeout; @@ -41,12 +41,12 @@ public final class Timeout { /** * Construct a new timeout with the given value and unit. The unit cannot be - * `null`, but the timeout value is unrestricted. The meaning of a + * {@code null}, but the timeout value is unrestricted. The meaning of a * negative timeout value is specific to the implementation of the use site, * but typically means that no amount of blocking or waiting is tolerated. * @param timeout A numerical value for the timeout. Can be zero or negative, * though the meaning is implementation specific. - * @param unit The unit of the timeout value. Never `null`. + * @param unit The unit of the timeout value. Never {@code null}. */ public Timeout(long timeout, TimeUnit unit) { Objects.requireNonNull(unit, "The TimeUnit cannot be null."); @@ -58,7 +58,7 @@ public Timeout(long timeout, TimeUnit unit) { /** * Construct a new timeout with the given duration. * An exception will be thrown if the duration cannot be converted to a nanosecond quantity. - * The duration also cannot be `null`. + * The duration also cannot be {@code null}. * Apart from these two, there are no restrictions on the duration. * @param duration A duration to use for the timeout. */ @@ -79,7 +79,7 @@ public long getTimeout() { /** * Get the unit for the {@link #getTimeout() timeout value}. - * @return The {@link TimeUnit} of the timeout value. Never `null`. + * @return The {@link TimeUnit} of the timeout value. Never {@code null}. */ public TimeUnit getUnit() { return unit; @@ -90,8 +90,8 @@ public TimeUnit getUnit() { * {@link #getBaseUnit() base unit}. Once you have a deadline, you can ask * how much time is left until it transpires, with the * {@link #getTimeLeft(long)} method, giving the deadline as an argument. - * - * If the {@link #getTimeout() timeout value} is really small, zero or + *

+ * If the {@link #getTimeout() timeout value} is very small, zero or * negative, then the deadline might be an instant in the past. * @return A numerical value that represents the deadline from "now" until * this timeout has passed. @@ -148,8 +148,8 @@ public int hashCode() { /** * Timeouts of equivalent duration are equal, even if they were constructed * with different units. - * @return `true` if this Timeout value is equal to the given - * Timeout value, `false` otherwise. + * @return {@code true} if this Timeout value is equal to the given + * Timeout value, {@code false} otherwise. */ @Override public boolean equals(Object obj) { diff --git a/src/main/java/stormpot/package-info.java b/src/main/java/stormpot/package-info.java index 5b2cb2ca..d8bcf092 100644 --- a/src/main/java/stormpot/package-info.java +++ b/src/main/java/stormpot/package-info.java @@ -14,17 +14,17 @@ * limitations under the License. */ /** - * == Stormpot - * + *

Stormpot

* Stormpot is a generic, thread-safe and fast object pooling library. - * + *

* The object pools themselves implement the {@link stormpot.Pool} interface. * The things you actually want to pool must all implement the * {@link stormpot.Poolable} interface, and you must also provide an * implementation of the {@link stormpot.Allocator} interface as a factory to * create your pooled objects. - * - * include::docs/usage.adoc[] - * + *

+ * See the online + * Usage Guide + * for a tutorial. */ package stormpot; diff --git a/src/test/java/blackbox/AllocatorBasedPoolTest.java b/src/test/java/blackbox/AllocatorBasedPoolTest.java index 16977772..bc38b862 100644 --- a/src/test/java/blackbox/AllocatorBasedPoolTest.java +++ b/src/test/java/blackbox/AllocatorBasedPoolTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import stormpot.AlloKit; import stormpot.Allocator; import stormpot.Completion; import stormpot.Expiration; @@ -824,9 +825,10 @@ void mustStillBeUsableAfterExceptionInAllocate(Taps taps) throws Exception { @ParameterizedTest @EnumSource(Taps.class) void mustStillBeUsableAfterExceptionInReallocate(Taps taps) throws Exception { - builder.setAllocator(reallocator( - alloc($new), - realloc($throw(new RuntimeException("boo from realloc"))))); + AlloKit.CountingReallocator alloc = reallocator( + alloc($new), + realloc($throw(new RuntimeException("boo from realloc")))); + builder.setAllocator(alloc); builder.setExpiration(Expiration.never()); noBackgroundExpirationChecking(); createPool(); @@ -838,7 +840,7 @@ void mustStillBeUsableAfterExceptionInReallocate(Taps taps) throws Exception { tap.claim(longTimeout).release(); // if "claim" doesn't throw, then the background thread might have cleaned up the poisoned // slot before we could get to it. In that case, the allocation count should be 2. - assertThat(pool.getManagedPool().getAllocationCount()).isEqualTo(2); + assertThat(alloc.countAllocations()).isEqualTo(2); } catch (PoolException ignore) {} GenericPoolable claim = tap.claim(longTimeout); assertThat(claim).isNotNull(); diff --git a/src/test/java/examples/DropwizardMetricsRecorder.java b/src/test/java/examples/DropwizardMetricsRecorder.java index 399f005d..fe6a24c8 100644 --- a/src/test/java/examples/DropwizardMetricsRecorder.java +++ b/src/test/java/examples/DropwizardMetricsRecorder.java @@ -19,6 +19,7 @@ import com.codahale.metrics.MetricRegistry; import stormpot.MetricsRecorder; +// @start region=example public class DropwizardMetricsRecorder implements MetricsRecorder { private final Histogram allocationLatency; private final Histogram allocationFailureLatency; @@ -96,3 +97,4 @@ public double getObjectLifetimePercentile(double percentile) { return objectLifetime.getSnapshot().getValue(percentile); } } +// @end diff --git a/src/test/java/examples/Examples.java b/src/test/java/examples/Examples.java index 95199a23..93603e56 100644 --- a/src/test/java/examples/Examples.java +++ b/src/test/java/examples/Examples.java @@ -56,19 +56,19 @@ public void deallocate(MyPoolable poolable) { @Test void managedPoolExample() throws Exception { - // tag::managedPoolExample[] + // @start region=managedPoolExample Pool pool = Pool.from(new MyAllocator()).build(); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("com.myapp:objectpool=stormpot"); server.registerMBean(pool.getManagedPool(), name); - // end::managedPoolExample[] + // @end } @SuppressWarnings("EmptyTryBlock") @Test void poolClaimExample() throws Exception { Pool pool = Pool.from(new MyAllocator()).build(); - // tag::poolClaimExample[] + // @start region=poolClaimExample Timeout timeout = new Timeout(1, SECONDS); MyPoolable obj = pool.claim(timeout); try { @@ -79,14 +79,14 @@ void poolClaimExample() throws Exception { obj.release(); } } - // end::poolClaimExample[] + // @end } @Test void poolClaimPrintExample() throws Exception { Pool pool = Pool.from(new MyAllocator()).build(); - // tag::poolClaimPrintExample[] + // @start region=poolClaimPrintExample Poolable obj = pool.claim(TIMEOUT); if (obj != null) { try { @@ -95,12 +95,12 @@ void poolClaimPrintExample() throws Exception { obj.release(); } } - // end::poolClaimPrintExample[] + // @end } @Test void directPoolExample() throws Exception { - // tag::directPoolExample[] + // @start region=directPoolExample Object a = new Object(); Object b = new Object(); Object c = new Object(); @@ -110,24 +110,24 @@ void directPoolExample() throws Exception { System.out.println(claim.object); } } - // end::directPoolExample[] + // @end } @Test void inlinePoolExample() throws Exception { MyAllocator allocator = new MyAllocator(); - // tag::inlinePoolExample[] + // @start region=inlinePoolExample Pool pool = Pool.fromInline(allocator).build(); MyPoolable obj = pool.claim(TIMEOUT); if (obj != null) { System.out.println(obj); obj.release(); } - // end::inlinePoolExample[] + // @end } @SuppressWarnings("InnerClassMayBeStatic") - // tag::poolableGenericExample[] + // @start region=poolableGenericExample public class GenericPoolable implements Poolable { private final Slot slot; public GenericPoolable(Slot slot) { @@ -139,26 +139,26 @@ public void release() { slot.release(this); } } - // end::poolableGenericExample[] + // @end @SuppressWarnings({"InnerClassMayBeStatic", "unused"}) - // tag::poolableBaseExample[] + // @start region=poolableBaseExample public class CustomPoolable extends BasePoolable { public CustomPoolable(Slot slot) { super(slot); } } - // end::poolableBaseExample[] + // @end @SuppressWarnings("unused") static class ReallocatorExample implements Reallocator { @Override public T reallocate(Slot slot, T poolable) { - // tag::reallocatorExample[] + // @start region=reallocatorExample deallocate(poolable); return allocate(slot); - // end::reallocatorExample[] + // @end } @Override @@ -195,13 +195,13 @@ public void deallocate(PooledConnection poolable) { } }; - // tag::expensiveExpirationWithEveryExample[] + // @start region=expensiveExpirationWithEveryExample Expiration checkConnection = new CheckConnectionExpiration() .every(10, SECONDS); // <1> Pool connectionPool = Pool.from(connectionAllocator) .setExpiration(checkConnection) .build(); - // end::expensiveExpirationWithEveryExample[] + // @end assertThat(connectionPool).isNotNull(); } } diff --git a/src/test/java/extensions/ExecutorExtension.java b/src/test/java/extensions/ExecutorExtension.java index 2bad62a3..7305559e 100644 --- a/src/test/java/extensions/ExecutorExtension.java +++ b/src/test/java/extensions/ExecutorExtension.java @@ -160,7 +160,7 @@ void verifyAllThreadsTerminatedSuccessfully() { joiner.add(frame.toString()); } assertThat(state).as("Unexpected thread state: " + thread + - " (id " + thread.getId() + ") stack trace: \n" + joiner) + " (id " + thread.threadId() + ") stack trace: \n" + joiner) .isEqualTo(Thread.State.TERMINATED); } } @@ -177,9 +177,9 @@ void dumpAllThreads() { "\n===[ Dumping stack traces for all created threads ]===\n"); Set createdThreads = new HashSet<>(); for (Thread thread : threads) { - createdThreads.add(thread.getId()); + createdThreads.add(thread.threadId()); StackTraceElement[] stackTrace = thread.getStackTrace(); - printStackTrace(thread, infos.get(thread.getId()), stackTrace); + printStackTrace(thread, infos.get(thread.threadId()), stackTrace); } System.err.println( "\n===[ End stack traces for all created threads ]===\n"); @@ -190,8 +190,8 @@ void dumpAllThreads() { Thread.getAllStackTraces().entrySet(); for (Map.Entry entry : entries) { Thread thread = entry.getKey(); - if (!createdThreads.contains(thread.getId())) { - printStackTrace(thread, infos.get(thread.getId()), entry.getValue()); + if (!createdThreads.contains(thread.threadId())) { + printStackTrace(thread, infos.get(thread.threadId()), entry.getValue()); } } System.err.println( @@ -211,7 +211,7 @@ private void printStackTrace( locks.put(monitor.getLockedStackFrame(), monitor); } System.err.printf("\"%s\" #%s prio=%s daemon=%s tid=0 nid=0 %s%n java.lang.Thread.State: %s%n", - thread.getName(), thread.getId(), thread.getPriority(), thread.isDaemon(), + thread.getName(), thread.threadId(), thread.getPriority(), thread.isDaemon(), state.toString().toLowerCase(), state); for (StackTraceElement ste : stackTrace) { System.err.printf("\tat %s%n", ste);