@Test public void testClear() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(15L))); offHeapStore.put("1", "one"); offHeapStore.put("2", "two"); offHeapStore.put("3", "three"); offHeapStore.clear(); assertThat(offHeapStore.get("1"), is(nullValue())); assertThat(offHeapStore.get("2"), is(nullValue())); assertThat(offHeapStore.get("3"), is(nullValue())); }
private void performEvictionTest(TestTimeSource timeSource, ExpiryPolicy<Object, Object> expiry, EvictionAdvisor<String, byte[]> evictionAdvisor) throws StoreAccessException { AbstractOffHeapStore<String, byte[]> offHeapStore = createAndInitStore(timeSource, expiry, evictionAdvisor); try { @SuppressWarnings("unchecked") StoreEventListener<String, byte[]> listener = mock(StoreEventListener.class); offHeapStore.getStoreEventSource().addEventListener(listener); byte[] value = getBytes(MemoryUnit.KB.toBytes(200)); offHeapStore.put("key1", value); offHeapStore.put("key2", value); offHeapStore.put("key3", value); offHeapStore.put("key4", value); offHeapStore.put("key5", value); offHeapStore.put("key6", value); Matcher<StoreEvent<String, byte[]>> matcher = eventType(EventType.EVICTED); verify(listener, atLeast(1)).onEvent(argThat(matcher)); } finally { destroyStore(offHeapStore); } }
@Test public void testInvalidateKeyPresent() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(15L))); offHeapStore.put("1", "one"); final AtomicReference<Store.ValueHolder<String>> invalidated = new AtomicReference<>(); offHeapStore.setInvalidationListener((key, valueHolder) -> invalidated.set(valueHolder)); offHeapStore.invalidate("1"); assertThat(invalidated.get().get(), equalTo("one")); validateStats(offHeapStore, EnumSet.of(LowerCachingTierOperationsOutcome.InvalidateOutcome.REMOVED)); assertThat(offHeapStore.get("1"), is(nullValue())); }
@Test public void testIteratorDoesNotSkipOrExpiresEntries() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMillis(10L))); offHeapStore.put("key1", "value1"); offHeapStore.put("key2", "value2"); timeSource.advanceTime(11L); offHeapStore.put("key3", "value3"); offHeapStore.put("key4", "value4"); final List<String> expiredKeys = new ArrayList<>(); offHeapStore.getStoreEventSource().addEventListener(event -> { if (event.getType() == EventType.EXPIRED) { expiredKeys.add(event.getKey()); } }); List<String> iteratedKeys = new ArrayList<>(); Store.Iterator<Cache.Entry<String, Store.ValueHolder<String>>> iterator = offHeapStore.iterator(); while(iterator.hasNext()) { iteratedKeys.add(iterator.next().getKey()); } assertThat(iteratedKeys, containsInAnyOrder("key1", "key2", "key3", "key4")); assertThat(expiredKeys.isEmpty(), is(true)); }
@Test public void testGetAndRemoveExpiredElementReturnsNull() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(15L))); assertThat(offHeapStore.getAndRemove("1"), is(nullValue())); offHeapStore.put("1", "one"); final AtomicReference<Store.ValueHolder<String>> invalidated = new AtomicReference<>(); offHeapStore.setInvalidationListener((key, valueHolder) -> invalidated.set(valueHolder)); timeSource.advanceTime(20); assertThat(offHeapStore.getAndRemove("1"), is(nullValue())); assertThat(invalidated.get().get(), equalTo("one")); assertThat(invalidated.get().isExpired(timeSource.getTimeMillis()), is(true)); assertThat(getExpirationStatistic(offHeapStore).count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS), is(1L)); }
@Test public void testGetAndRemoveValue() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.noExpiration()); offHeapStore.put("1", "one"); assertThat(offHeapStore.getAndRemove("1").get(), equalTo("one")); validateStats(offHeapStore, EnumSet.of(LowerCachingTierOperationsOutcome.GetAndRemoveOutcome.HIT_REMOVED)); assertThat(offHeapStore.get("1"), is(nullValue())); }
@Test public void testComputeOnExpiredEntry() throws StoreAccessException { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(10L))); offHeapStore.put("key", "value"); timeSource.advanceTime(20L); offHeapStore.getAndCompute("key", (mappedKey, mappedValue) -> { assertThat(mappedKey, is("key")); assertThat(mappedValue, Matchers.nullValue()); return "value2"; }); assertThat(getExpirationStatistic(offHeapStore).count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS), is(1L)); }
@Test public void testComputeIfAbsentOnExpiredEntry() throws StoreAccessException { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(10L))); offHeapStore.put("key", "value"); timeSource.advanceTime(20L); offHeapStore.computeIfAbsent("key", mappedKey -> { assertThat(mappedKey, is("key")); return "value2"; }); assertThat(getExpirationStatistic(offHeapStore).count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS), is(1L)); }
@Test public void testExpiryUpdateException() throws Exception { offHeapStore = createAndInitStore(timeSource, new ExpiryPolicy<String, String>() { @Override public Duration getExpiryForCreation(String key, String value) { return ExpiryPolicy.INFINITE; } @Override public Duration getExpiryForAccess(String key, Supplier<? extends String> value) { return ExpiryPolicy.INFINITE; } @Override public Duration getExpiryForUpdate(String key, Supplier<? extends String> oldValue, String newValue) { if (timeSource.getTimeMillis() > 0) { throw new RuntimeException(); } return ExpiryPolicy.INFINITE; } }); offHeapStore.put("key", "value"); assertThat(offHeapStore.get("key").get(), is("value")); timeSource.advanceTime(1000); offHeapStore.put("key", "newValue"); assertNull(offHeapStore.get("key")); }
@Test public void testExpiryEventFiredOnExpiredCachedEntry() throws StoreAccessException { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(10L))); final List<String> expiredKeys = new ArrayList<>(); offHeapStore.getStoreEventSource().addEventListener(event -> { if (event.getType() == EventType.EXPIRED) { expiredKeys.add(event.getKey()); } }); offHeapStore.put("key1", "value1"); offHeapStore.put("key2", "value2"); offHeapStore.get("key1"); // Bring the entry to the caching tier timeSource.advanceTime(11); // Expire the elements offHeapStore.get("key1"); offHeapStore.get("key2"); assertThat(expiredKeys, containsInAnyOrder("key1", "key2")); assertThat(getExpirationStatistic(offHeapStore).count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS), is(2L)); }
@Test public void testGetAndFaultOnExpiredEntry() throws StoreAccessException { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(10L))); try { offHeapStore.put("key", "value"); timeSource.advanceTime(20L); Store.ValueHolder<String> valueHolder = offHeapStore.getAndFault("key"); assertThat(valueHolder, nullValue()); assertThat(getExpirationStatistic(offHeapStore).count(StoreOperationOutcomes.ExpirationOutcome.SUCCESS), is(1L)); } finally { destroyStore(offHeapStore); } }
@Test public void testWriteBackOfValueHolder() throws StoreAccessException { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(15L))); offHeapStore.put("key1", "value1"); timeSource.advanceTime(10); OffHeapValueHolder<String> valueHolder = (OffHeapValueHolder<String>)offHeapStore.get("key1"); assertThat(valueHolder.lastAccessTime(), is(10L)); timeSource.advanceTime(10); assertThat(offHeapStore.get("key1"), notNullValue()); timeSource.advanceTime(16); assertThat(offHeapStore.get("key1"), nullValue()); }
@Test public void testGetWithExpiryOnAccess() throws Exception { offHeapStore = createAndInitStore(timeSource, expiry().access(Duration.ZERO).build()); offHeapStore.put("key", "value"); final AtomicReference<String> expired = new AtomicReference<>(); offHeapStore.getStoreEventSource().addEventListener(event -> { if (event.getType() == EventType.EXPIRED) { expired.set(event.getKey()); } }); assertThat(offHeapStore.get("key"), valueHeld("value")); assertThat(expired.get(), is("key")); }
@Test public void testExpiryCreateException() throws Exception { offHeapStore = createAndInitStore(timeSource, new ExpiryPolicy<String, String>() { @Override public Duration getExpiryForCreation(String key, String value) { throw new RuntimeException(); } @Override public Duration getExpiryForAccess(String key, Supplier<? extends String> value) { throw new AssertionError(); } @Override public Duration getExpiryForUpdate(String key, Supplier<? extends String> oldValue, String newValue) { throw new AssertionError(); } }); offHeapStore.put("key", "value"); assertNull(offHeapStore.get("key")); }
@Test public void testIteratorWithSingleNonExpiredEntry() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMillis(10L))); offHeapStore.put("key1", "value1"); timeSource.advanceTime(5L); Store.Iterator<Cache.Entry<String, Store.ValueHolder<String>>> iterator = offHeapStore.iterator(); assertTrue(iterator.hasNext()); assertThat(iterator.next().getKey(), is("key1")); }
@Test public void testIteratorWithSingleExpiredEntry() throws Exception { offHeapStore = createAndInitStore(timeSource, ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMillis(10L))); offHeapStore.put("key1", "value1"); timeSource.advanceTime(11L); Store.Iterator<Cache.Entry<String, Store.ValueHolder<String>>> iterator = offHeapStore.iterator(); assertTrue(iterator.hasNext()); assertThat(iterator.next().getKey(), equalTo("key1")); assertFalse(iterator.hasNext()); }
@Test public void testFlushUpdatesAccessStats() throws StoreAccessException { ExpiryPolicy<Object, Object> expiry = ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMillis(15L)); offHeapStore = createAndInitStore(timeSource, expiry); try { final String key = "foo"; final String value = "bar"; offHeapStore.put(key, value); final Store.ValueHolder<String> firstValueHolder = offHeapStore.getAndFault(key); offHeapStore.put(key, value); final Store.ValueHolder<String> secondValueHolder = offHeapStore.getAndFault(key); timeSource.advanceTime(10); ((AbstractValueHolder) firstValueHolder).accessed(timeSource.getTimeMillis(), expiry.getExpiryForAccess(key, () -> value)); timeSource.advanceTime(10); ((AbstractValueHolder) secondValueHolder).accessed(timeSource.getTimeMillis(), expiry.getExpiryForAccess(key, () -> value)); assertThat(offHeapStore.flush(key, new DelegatingValueHolder<>(firstValueHolder)), is(false)); assertThat(offHeapStore.flush(key, new DelegatingValueHolder<>(secondValueHolder)), is(true)); timeSource.advanceTime(10); // this should NOT affect assertThat(offHeapStore.getAndFault(key).lastAccessTime(), is(secondValueHolder.creationTime() + 20)); } finally { destroyStore(offHeapStore); } }
@Test public void testExpiryAccessException() throws Exception { offHeapStore = createAndInitStore(timeSource, new ExpiryPolicy<String, String>() { @Override public Duration getExpiryForCreation(String key, String value) { return ExpiryPolicy.INFINITE; } @Override public Duration getExpiryForAccess(String key, Supplier<? extends String> value) { throw new RuntimeException(); } @Override public Duration getExpiryForUpdate(String key, Supplier<? extends String> oldValue, String newValue) { return null; } }); offHeapStore.put("key", "value"); assertThat(offHeapStore.get("key"), valueHeld("value")); assertNull(offHeapStore.get("key")); }
@Test public void testComputeExpiresOnAccess() throws StoreAccessException { timeSource.advanceTime(1000L); offHeapStore = createAndInitStore(timeSource, expiry().access(Duration.ZERO).update(Duration.ZERO).build()); offHeapStore.put("key", "value"); Store.ValueHolder<String> result = offHeapStore.computeAndGet("key", (s, s2) -> s2, () -> false, () -> false); assertThat(result, valueHeld("value")); }
@Test public void testComputeExpiresOnUpdate() throws StoreAccessException { timeSource.advanceTime(1000L); offHeapStore = createAndInitStore(timeSource, expiry().access(Duration.ZERO).update(Duration.ZERO).build()); offHeapStore.put("key", "value"); Store.ValueHolder<String> result = offHeapStore.computeAndGet("key", (s, s2) -> "newValue", () -> false, () -> false); assertThat(result, valueHeld("newValue")); }