/*
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ehcache.impl.internal.store.offheap;
import org.ehcache.config.EvictionAdvisor;
import org.ehcache.core.spi.function.BiFunction;
import org.ehcache.core.spi.function.Function;
import org.ehcache.impl.internal.store.offheap.factories.EhcacheSegmentFactory;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* AbstractEhcacheOffHeapBackingMapTest
*/
public abstract class AbstractEhcacheOffHeapBackingMapTest {
protected abstract EhcacheOffHeapBackingMap<String, String> createTestSegment() throws IOException;
protected abstract EhcacheOffHeapBackingMap<String, String> createTestSegment(EvictionAdvisor<? super String, ? super String> evictionPredicate) throws IOException;
protected abstract void destroySegment(EhcacheOffHeapBackingMap<String, String> segment);
protected abstract void putPinned(String key, String value, EhcacheOffHeapBackingMap<String, String> segment);
protected abstract boolean isPinned(String key, EhcacheOffHeapBackingMap<String, String> segment);
protected abstract int getMetadata(String key, int mask, EhcacheOffHeapBackingMap<String, String> segment);
@Test
public void testComputeFunctionCalledWhenNoMapping() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return "value";
}
}, false);
assertThat(value, is("value"));
assertThat(segment.get("key"), is(value));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsSameNoPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return s2;
}
}, false);
assertThat(value, is("value"));
assertThat(isPinned("key", segment), is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsSamePins() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return s2;
}
}, true);
assertThat(value, is("value"));
assertThat(isPinned("key", segment), is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsSamePreservesPinWhenNoPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
putPinned("key", "value", segment);
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return s2;
}
}, false);
assertThat(value, is("value"));
assertThat(isPinned("key", segment), is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsDifferentNoPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return "otherValue";
}
}, false);
assertThat(value, is("otherValue"));
assertThat(isPinned("key", segment), is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsDifferentPins() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return "otherValue";
}
}, true);
assertThat(value, is("otherValue"));
assertThat(isPinned("key", segment), is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsDifferentClearsPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
putPinned("key", "value", segment);
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return "otherValue";
}
}, false);
assertThat(value, is("otherValue"));
assertThat(isPinned("key", segment), is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeFunctionReturnsNullRemoves() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
putPinned("key", "value", segment);
String value = segment.compute("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return null;
}
}, false);
assertThat(value, nullValue());
assertThat(segment.containsKey("key"), is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPresentNotCalledOnNotContainedKey() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
try {
segment.computeIfPresent("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
throw new UnsupportedOperationException("Should not have been called!");
}
});
} catch (UnsupportedOperationException e) {
fail("Mapping function should not have been called.");
}
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPresentReturnsSameValue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.computeIfPresent("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return s2;
}
});
assertThat(segment.get("key"), is(value));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPresentReturnsDifferentValue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.computeIfPresent("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return "newValue";
}
});
assertThat(segment.get("key"), is(value));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPresentReturnsNullRemovesMapping() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
String value = segment.computeIfPresent("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
return null;
}
});
assertThat(segment.containsKey("key"), is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedNoOpUnpinned() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
try {
segment.put("key", "value");
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
fail("Method should not be invoked");
return null;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
fail("Method should not be invoked");
return false;
}
});
assertThat(isPinned("key", segment), is(false));
assertThat(result, is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedClearsMappingOnNullReturnWithPinningFalse() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return null;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return false;
}
});
assertThat(segment.containsKey("key"), is(false));
assertThat(result, is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedClearsMappingOnNullReturnWithPinningTrue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return null;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return true;
}
});
assertThat(segment.containsKey("key"), is(false));
assertThat(result, is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedClearsPinWithoutChangingValue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return s2;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return true;
}
});
assertThat(isPinned("key", segment), is(false));
assertThat(result, is(true));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedPreservesPinWithoutChangingValue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return s2;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return false;
}
});
assertThat(isPinned("key", segment), is(true));
assertThat(result, is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedReplacesValueUnpinnedWhenUnpinFunctionFalse() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
final String newValue = "newValue";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return newValue;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return false;
}
});
assertThat(segment.get("key"), is(newValue));
assertThat(isPinned("key", segment), is(false));
assertThat(result, is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPinnedReplacesValueUnpinnedWhenUnpinFunctionTrue() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
final String newValue = "newValue";
try {
putPinned("key", value, segment);
boolean result = segment.computeIfPinned("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return newValue;
}
}, new Function<String, Boolean>() {
@Override
public Boolean apply(String s) {
assertThat(s, is(value));
return true;
}
});
assertThat(segment.get("key"), is(newValue));
assertThat(isPinned("key", segment), is(false));
assertThat(result, is(false));
} finally {
destroySegment(segment);
}
}
@Test
public void testComputeIfPresentAndPinNoOpNoMapping() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
segment.computeIfPresentAndPin("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
fail("Function should not be invoked");
return null;
}
});
}
@Test
public void testComputeIfPresentAndPinDoesPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
segment.put("key", value);
segment.computeIfPresentAndPin("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return value;
}
});
assertThat(isPinned("key", segment), is(true));
}
@Test
public void testComputeIfPresentAndPinPreservesPin() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
putPinned("key", value, segment);
segment.computeIfPresentAndPin("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return value;
}
});
assertThat(isPinned("key", segment), is(true));
}
@Test
public void testComputeIfPresentAndPinReplacesAndPins() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment();
final String value = "value";
final String newValue = "newValue";
segment.put("key", value);
segment.computeIfPresentAndPin("key", new BiFunction<String, String, String>() {
@Override
public String apply(String s, String s2) {
assertThat(s2, is(value));
return newValue;
}
});
assertThat(isPinned("key", segment), is(true));
assertThat(segment.get("key"), is(newValue));
}
@Test
public void testPutAdvicedAgainstEvictionComputesMetadata() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment(new EvictionAdvisor<String, String>() {
@Override
public boolean adviseAgainstEviction(String key, String value) {
return "please-do-not-evict-me".equals(key);
}
});
try {
segment.put("please-do-not-evict-me", "value");
assertThat(getMetadata("please-do-not-evict-me", EhcacheSegmentFactory.EhcacheSegment.ADVISED_AGAINST_EVICTION, segment), is(EhcacheSegmentFactory.EhcacheSegment.ADVISED_AGAINST_EVICTION));
} finally {
destroySegment(segment);
}
}
@Test
public void testPutPinnedAdvicedAgainstEvictionComputesMetadata() throws Exception {
EhcacheOffHeapBackingMap<String, String> segment = createTestSegment(new EvictionAdvisor<String, String>() {
@Override
public boolean adviseAgainstEviction(String key, String value) {
return "please-do-not-evict-me".equals(key);
}
});
try {
putPinned("please-do-not-evict-me", "value", segment);
assertThat(getMetadata("please-do-not-evict-me", EhcacheSegmentFactory.EhcacheSegment.ADVISED_AGAINST_EVICTION, segment), is(EhcacheSegmentFactory.EhcacheSegment.ADVISED_AGAINST_EVICTION));
} finally {
destroySegment(segment);
}
}
}