diff --git a/src/main/java/stormpot/BSlot.java b/src/main/java/stormpot/BSlot.java index 66e0cda4..ca5912dd 100644 --- a/src/main/java/stormpot/BSlot.java +++ b/src/main/java/stormpot/BSlot.java @@ -103,6 +103,11 @@ public long getAgeMillis() { return TimeUnit.NANOSECONDS.toMillis(NanoClock.elapsed(createdNanos)); } + @Override + public long getCreatedNanoTime() { + return createdNanos; + } + @Override public long getClaimCount() { return claims; diff --git a/src/main/java/stormpot/SlotInfo.java b/src/main/java/stormpot/SlotInfo.java index 13099031..07ab10b7 100644 --- a/src/main/java/stormpot/SlotInfo.java +++ b/src/main/java/stormpot/SlotInfo.java @@ -31,6 +31,15 @@ public interface SlotInfo { */ long getAgeMillis(); + /** + * Get the approximate {@link System#nanoTime()} timestamp for when the object + * was allocated. + * @return The object allocation {@link System#nanoTime()} timestamp. + */ + default long getCreatedNanoTime() { + return 0; + } + /** * Get the number of times the object has been claimed since it was * allocated. diff --git a/src/test/java/blackbox/AllocatorBasedPoolTest.java b/src/test/java/blackbox/AllocatorBasedPoolTest.java index 2d77f67f..cd89b58d 100644 --- a/src/test/java/blackbox/AllocatorBasedPoolTest.java +++ b/src/test/java/blackbox/AllocatorBasedPoolTest.java @@ -15,6 +15,7 @@ */ package blackbox; +import org.assertj.core.data.Offset; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -468,8 +469,15 @@ void slotInfoMustHaveAgeInMillis(Taps taps) throws InterruptedException { void slotInfoAgeMustResetAfterAllocation(Taps taps) throws InterruptedException { final AtomicBoolean hasExpired = new AtomicBoolean(); final AtomicLong age = new AtomicLong(); + final AtomicLong expectedAge = new AtomicLong(); + final AtomicLong createdNanoTime = new AtomicLong(); builder.setExpiration(expire( - $capture($age(age), $expiredIf(hasExpired)))); + $capture(info -> { + age.set(info.getAgeMillis()); + long created = info.getCreatedNanoTime(); + createdNanoTime.set(created); + expectedAge.set(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - created)); + }, $expiredIf(hasExpired)))); noBackgroundExpirationChecking(); // Reallocations will fail, causing the slot to be poisoned. // Then, the poisoned slot will not be reallocated again, but rather @@ -481,6 +489,8 @@ void slotInfoAgeMustResetAfterAllocation(Taps taps) throws InterruptedException Thread.sleep(100); // time transpires tap.claim(longTimeout).release(); long firstAge = age.get(); // age is now at least 5 ms + long firstCreatedNanoTime = createdNanoTime.get(); + assertThat(firstAge).isCloseTo(expectedAge.get(), Offset.offset(25L)); hasExpired.set(true); try { tap.claim(longTimeout).release(); @@ -491,26 +501,39 @@ void slotInfoAgeMustResetAfterAllocation(Taps taps) throws InterruptedException // new object should have a new age tap.claim(longTimeout).release(); long secondAge = age.get(); // age should be less than age of prev. obj. - assertThat(secondAge).isLessThan(firstAge); + assertThat(secondAge).isCloseTo(expectedAge.get(), Offset.offset(25L)); + long secondCreatedNanoTime = createdNanoTime.get(); + assertThat(secondCreatedNanoTime).isNotEqualTo(firstCreatedNanoTime); } @ParameterizedTest @EnumSource(Taps.class) void slotInfoAgeMustResetAfterReallocation(Taps taps) throws InterruptedException { final AtomicLong age = new AtomicLong(); + final AtomicLong expectedAge = new AtomicLong(); + final AtomicLong createdNanoTime = new AtomicLong(); builder.setExpiration(expire( - $capture($age(age), $fresh))); + $capture(info -> { + age.set(info.getAgeMillis()); + long created = info.getCreatedNanoTime(); + createdNanoTime.set(created); + expectedAge.set(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - created)); + }, $fresh))); createPool(); PoolTap tap = taps.get(this); tap.claim(longTimeout).release(); Thread.sleep(100); // time transpires GenericPoolable obj = tap.claim(longTimeout); long firstAge = age.get(); + long firstCreatedNanoTime = createdNanoTime.get(); + assertThat(firstAge).isCloseTo(expectedAge.get(), Offset.offset(25L)); obj.expire(); // cause reallocation obj.release(); tap.claim(longTimeout).release(); // new object, new age long secondAge = age.get(); - assertThat(secondAge).isLessThan(firstAge); + assertThat(secondAge).isCloseTo(expectedAge.get(), Offset.offset(25L)); + long secondCreatedNanoTime = createdNanoTime.get(); + assertThat(secondCreatedNanoTime).isNotEqualTo(firstCreatedNanoTime); } /**