/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.internal.eviction;
import com.hazelcast.cache.impl.CacheContext;
import com.hazelcast.cache.impl.ICacheService;
import com.hazelcast.cache.impl.record.CacheObjectRecord;
import com.hazelcast.cache.impl.record.CacheRecordHashMap;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.Node;
import com.hazelcast.instance.TestUtil;
import com.hazelcast.internal.eviction.impl.evaluator.EvictionPolicyEvaluator;
import com.hazelcast.internal.eviction.impl.strategy.sampling.SampleableEvictableStore;
import com.hazelcast.internal.eviction.impl.strategy.sampling.SamplingEvictionStrategy;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.serialization.SerializationService;
import com.hazelcast.test.HazelcastSerialClassRunner;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import java.util.Collections;
import static com.hazelcast.internal.eviction.EvictionChecker.EVICT_ALWAYS;
import static com.hazelcast.internal.eviction.EvictionListener.NO_LISTENER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(HazelcastSerialClassRunner.class)
@Category(QuickTest.class)
public class EvictionStrategyTest<K, V extends Evictable, S extends SampleableEvictableStore<K, V>> extends HazelcastTestSupport {
private HazelcastInstance instance;
@Before
public void setup() {
instance = createHazelcastInstance();
}
private class SimpleEvictionCandidate implements EvictionCandidate<K, V> {
private K key;
private V value;
private SimpleEvictionCandidate(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getAccessor() {
return key;
}
@Override
public V getEvictable() {
return value;
}
@Override
public Object getKey() {
throw new UnsupportedOperationException();
}
@Override
public Object getValue() {
throw new UnsupportedOperationException();
}
@Override
public long getCreationTime() {
return getEvictable().getCreationTime();
}
@Override
public long getLastAccessTime() {
return getEvictable().getLastAccessTime();
}
@Override
public long getAccessHit() {
return getEvictable().getAccessHit();
}
}
@Test
public void evictionPolicySuccessfullyEvaluatedOnSamplingBasedEvictionStrategy() {
final int RECORD_COUNT = 100;
final int EXPECTED_EVICTED_COUNT = 1;
final int EXPECTED_EVICTED_RECORD_VALUE = RECORD_COUNT / 2;
Node node = TestUtil.getNode(instance);
SerializationService serializationService = node.getSerializationService();
ICacheService cacheService = node.getNodeEngine().getService(ICacheService.SERVICE_NAME);
CacheContext cacheContext = cacheService.getOrCreateCacheContext("MyCache");
SamplingEvictionStrategy<K, V, S> evictionStrategy = SamplingEvictionStrategy.INSTANCE;
CacheRecordHashMap cacheRecordMap = new CacheRecordHashMap(serializationService, 1000, cacheContext);
CacheObjectRecord expectedEvictedRecord = null;
Data expectedData = null;
for (int i = 0; i < RECORD_COUNT; i++) {
CacheObjectRecord record = new CacheObjectRecord(i, System.currentTimeMillis(), Long.MAX_VALUE);
Data data = serializationService.toData(i);
cacheRecordMap.put(data, record);
if (i == EXPECTED_EVICTED_RECORD_VALUE) {
expectedEvictedRecord = record;
expectedData = data;
}
}
assertNotNull(expectedEvictedRecord);
assertNotNull(expectedData);
final SimpleEvictionCandidate evictionCandidate
= new SimpleEvictionCandidate((K) expectedData, (V) expectedEvictedRecord);
// we are testing "EvictionStrategy" in this test, so we mock "EvictionPolicyEvaluator" (it's tested in another test)
EvictionPolicyEvaluator evictionPolicyEvaluator = mock(EvictionPolicyEvaluator.class);
when(evictionPolicyEvaluator.evaluate(Matchers.any(Iterable.class))).
thenReturn(Collections.singleton(evictionCandidate));
when(evictionPolicyEvaluator.getEvictionPolicyComparator()).thenReturn(null);
assertEquals(RECORD_COUNT, cacheRecordMap.size());
assertTrue(cacheRecordMap.containsKey(expectedData));
assertTrue(cacheRecordMap.containsValue(expectedEvictedRecord));
int evictedCount = evictionStrategy.evict((S) cacheRecordMap, evictionPolicyEvaluator, EVICT_ALWAYS, NO_LISTENER);
assertEquals(EXPECTED_EVICTED_COUNT, evictedCount);
assertEquals(RECORD_COUNT - EXPECTED_EVICTED_COUNT, cacheRecordMap.size());
assertFalse(cacheRecordMap.containsKey(expectedData));
assertFalse(cacheRecordMap.containsValue(expectedEvictedRecord));
}
}