Skip to content

Stormpot 2.0

Compare
Choose a tag to compare
@chrisvest chrisvest released this 31 Dec 19:32
· 656 commits to main since this release

I have released version 2.0 of Stormpot, my Java object pooling library, to the Maven Central repositories. You can add it as a dependency in Maven like this:

	<dependency>
	  <groupId>com.github.chrisvest</groupId>
	  <artifactId>stormpot</artifactId>
	  <version>2.0</version>
	</dependency>

This version breaks backwards compatibility on a number of points, and introduces a couple of new features.

Stormpot now depends on Java6

Stormpot 1.0.1 can be used on Java5, but the new version 2.0 now needs at least Java6. The reason is something as benign as making use of new entries in the TimeUnit enum. However, I do not have a version 5 of Java installed, and I therefore cannot truly test the compatibility with this version of Java. That is why I decided to depend on Java6 instead. If you want to use Stormpot 2.0 on Java5, then you should be able to pretty easily make a fork and port it.

New Timeout value objects

In Stormpot 1.0.1, timeouts is expressed as a combination of a long value and a TimeUnit. This is identical to the way that timeouts are expressed in java.util.concurrent. However, it cannot be denied that this API pattern suffers from primitive obsession. Therefore, Stormpot 2.0 introduces a new Timeout value object to replace this pattern. The Timeout instances are immutable and thread-safe, and can easily be cached in static final fields.

No more blocking forever

Along side the introduction of the Timeout, Stormpot 2.0 also removes all blocking methods from its API, that do not take a timeout. It is generally bad practice to perform a blocking operation without a timeout, but it can still be achieved by calling a method with a timeout, in a loop. This change also made testing easier.

Resizable pools

Stormpot 2.0 introduces a new ResizablePool abstraction. This interface exposes methods for setting and getting a target size for a pool. These methods are non-blocking, and the size of the pool is eventually consistent. This allows you to respond to contention by increasing the size of a pool. You can observe that a pool is contended if its claim methods starts to return null often, for some value of "often." Note that Stormpot always strives to keep exactly the target-size number of objects allocated at any one point. Stormpot is intentionally designed without low- and high-water marks, because it requires intimate knowledge of the whole system to figure out how best to respond to a load spike. Consider, for instance, the case where you have a number of application servers all connecting to the same database. If the app servers uses pools with low/high-water marks, and suddenly experience a load spike, then the number of new connections created by all these pools suddenly reaching for the high-water mark, might be too much for the database and cause it to crash. It is nice to have self-managing autonomous systems, as long as they don't autonomously make a bad situation worse.

Programmable expirations

Stormpot 2.0 introduces a new Expiration abstraction, and removes the previous time-to-live options from the Config class. By default, the Config is set up with a TimeExpiration that has the same exact effect as the previous 10 minute time-to-live. The Expiration is a call-back interface (a SAM type) that pools use to determine if a given object has expired or not. To help make this decision, the Expiration.hasExpired method gets a SlotInfo object as a parameter. The SlotInfo object holds information about the particular Slot that represents the given object in the pool: how long ago it was allocated, how many times it has been claimed, and what object it holds. If the decision requires domain specific knowledge, then that can be put in the pooled objects themselves. This information should be enough to cover most use cases for programmable expiration.

Concluding

These features have all been implemented without reducing the performance of the pool, and without compromising the quality of the code. In fact, this release maintains the 100% test coverage in spite of implementing these new interacting features, and switching to an at least as thorough test coverage tool. If anything, the quality in this release have increased, as I have added mutation testing with PIT to the mix, and experimented with verifying the correctness of the concurrent behaviour with JPF and cJUnit. I also had the opportunity to get my code publicly peer-reviewed by the Good Code interest group at work, which yielded feedback of surprisingly good quality — I can recommend trying this to anyone, should the opportunity arise.

All in all, I am very pleased with this release. I don't know when the next one will be out, or what the headlines will be. I think I need a little break from the project now, but I guess the next version will probably be about actually adding alternative pool implementations, with different performance characteristics.

Full Changelog: https://github.com/chrisvest/stormpot/commits/stormpot-2.0