/*
* 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.config.serializer;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.impl.config.copy.DefaultCopierConfiguration;
import org.ehcache.impl.config.persistence.CacheManagerPersistenceConfiguration;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.spi.serialization.SerializerException;
import org.ehcache.impl.copy.SerializingCopier;
import org.ehcache.impl.serialization.JavaSerializer;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.core.spi.service.FileBasedPersistenceContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.String.format;
import static org.ehcache.config.builders.CacheConfigurationBuilder.newCacheConfigurationBuilder;
import static org.ehcache.config.builders.CacheManagerBuilder.newCacheManagerBuilder;
import static org.ehcache.config.builders.ResourcePoolsBuilder.heap;
import static org.ehcache.config.builders.ResourcePoolsBuilder.newResourcePoolsBuilder;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* SerializerCountingTest
*/
public class SerializerCountingTest {
private static final boolean PRINT_STACK_TRACES = false;
private CacheManager cacheManager;
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Before
@SuppressWarnings("unchecked")
public void setUp() {
cacheManager = newCacheManagerBuilder()
.using(new DefaultSerializationProviderConfiguration().addSerializerFor(Serializable.class, (Class) CountingSerializer.class)
.addSerializerFor(Long.class, (Class) CountingSerializer.class)
.addSerializerFor(String.class, (Class) CountingSerializer.class))
.with(new CacheManagerPersistenceConfiguration(folder.getRoot()))
.build(true);
}
@After
public void tearDown() {
clearCounters();
if (cacheManager != null) {
cacheManager.close();
}
}
@Test
public void testOnHeapPutGet() {
Cache<Long, String> cache = cacheManager.createCache("onHeap", newCacheConfigurationBuilder(Long.class, String.class, heap(10))
.add(new DefaultCopierConfiguration<Long>(SerializingCopier.<Long>asCopierClass(), DefaultCopierConfiguration.Type.KEY))
.add(new DefaultCopierConfiguration<String>(SerializingCopier.<String>asCopierClass(), DefaultCopierConfiguration.Type.VALUE))
.build());
cache.put(42L, "TheAnswer!");
assertCounters(2, 2, 0, 1, 0, 0);
printSerializationCounters("Put OnHeap (create)");
cache.get(42L);
assertCounters(0, 0, 0, 0, 1, 0);
printSerializationCounters("Get OnHeap");
cache.put(42L, "Wrong ...");
assertCounters(2, 2, 0, 1, 0, 0);
printSerializationCounters("Put OnHeap (update)");
}
@Test
public void testOffHeapPutGet() {
Cache<Long, String> cache = cacheManager.createCache("offHeap", newCacheConfigurationBuilder(Long.class, String.class,
newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(10, MemoryUnit.MB))
.build()
);
cache.put(42L, "TheAnswer");
assertCounters(1, 0, 0, 1, 0, 0);
printSerializationCounters("Put Offheap");
cache.get(42L);
assertCounters(0, 0, 1, 0, 1, 0);
printSerializationCounters("Get Offheap fault");
cache.get(42L);
assertCounters(0, 0, 0, 0, 0, 0);
printSerializationCounters("Get Offheap faulted");
cache.put(42L, "Wrong ...");
assertCounters(1, 0, 2, 1, 0, 0);
printSerializationCounters("Put OffHeap (update faulted)");
}
@Test
public void testOffHeapOnHeapCopyPutGet() {
Cache<Long, String> cache = cacheManager.createCache("offHeap", newCacheConfigurationBuilder(Long.class, String.class,
newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES).offheap(10, MemoryUnit.MB))
.add(new DefaultCopierConfiguration<Long>(SerializingCopier.<Long>asCopierClass(), DefaultCopierConfiguration.Type.KEY))
.add(new DefaultCopierConfiguration<String>(SerializingCopier.<String>asCopierClass(), DefaultCopierConfiguration.Type.VALUE))
.build()
);
cache.put(42L, "TheAnswer");
assertCounters(2, 1, 0, 1, 0, 0);
printSerializationCounters("Put OffheapOnHeapCopy");
cache.get(42L);
assertCounters(1, 1, 1, 0, 2, 0);
printSerializationCounters("Get OffheapOnHeapCopy fault");
cache.get(42L);
assertCounters(0, 0, 0, 0, 1, 0);
printSerializationCounters("Get OffheapOnHeapCopy faulted");
cache.put(42L, "Wrong ...");
assertCounters(3, 2, 2, 1, 0, 0);
printSerializationCounters("Put OffheapOnHeapCopy (update faulted)");
}
@Test
public void testDiskOffHeapOnHeapCopyPutGet() {
Cache<Long, String> cache = cacheManager.createCache("offHeap", newCacheConfigurationBuilder(Long.class, String.class,
newResourcePoolsBuilder().heap(2, EntryUnit.ENTRIES).offheap(10, MemoryUnit.MB).disk(100, MemoryUnit.MB))
.add(new DefaultCopierConfiguration<Long>(SerializingCopier.<Long>asCopierClass(), DefaultCopierConfiguration.Type.KEY))
.add(new DefaultCopierConfiguration<String>(SerializingCopier.<String>asCopierClass(), DefaultCopierConfiguration.Type.VALUE))
.build()
);
cache.put(42L, "TheAnswer");
assertCounters(3, 2, 0, 1, 0, 0);
printSerializationCounters("Put DiskOffHeapOnHeapCopy");
cache.get(42L);
assertCounters(1, 1, 1, 0, 2, 0);
printSerializationCounters("Get DiskOffHeapOnHeapCopy fault");
cache.get(42L);
assertCounters(0, 0, 0, 0, 1, 0);
printSerializationCounters("Get DiskOffHeapOnHeapCopy faulted");
cache.put(42L, "Wrong ...");
assertCounters(3, 2, 2, 1, 0, 0);
printSerializationCounters("Put DiskOffHeapOnHeapCopy (update faulted)");
}
private void printSerializationCounters(String operation) {
System.out.println("Operation " + operation);
System.out.println(format("Key Serialization - %d / Deserialization - %d / Equals - %d", CountingSerializer.keySerializeCounter.get(), CountingSerializer.keyDeserializeCounter.get(), CountingSerializer.keyEqualsCounter.get()));
System.out.println(format("Value Serialization - %d / Deserialization - %d / Equals - %d", CountingSerializer.serializeCounter.get(), CountingSerializer.deserializeCounter.get(), CountingSerializer.equalsCounter.get()));
clearCounters();
}
private void clearCounters() {
CountingSerializer.serializeCounter.set(0);
CountingSerializer.deserializeCounter.set(0);
CountingSerializer.equalsCounter.set(0);
CountingSerializer.keySerializeCounter.set(0);
CountingSerializer.keyDeserializeCounter.set(0);
CountingSerializer.keyEqualsCounter.set(0);
}
private void assertCounters(int keySerialization, int keyDeserialization, int keyEquals, int valueSerialization, int valueDeserialization, int valueEquals) {
assertThat("Key Serialize", CountingSerializer.keySerializeCounter.get(), is(keySerialization));
assertThat("Key Deserialize", CountingSerializer.keyDeserializeCounter.get(), is(keyDeserialization));
assertThat("Key Equals", CountingSerializer.keyEqualsCounter.get(), is(keyEquals));
assertThat("Value Serialize", CountingSerializer.serializeCounter.get(), is(valueSerialization));
assertThat("Value Deserialize", CountingSerializer.deserializeCounter.get(), is(valueDeserialization));
assertThat("Value Equals", CountingSerializer.equalsCounter.get(), is(valueEquals));
}
public static class CountingSerializer<T> implements Serializer<T> {
static AtomicInteger serializeCounter = new AtomicInteger(0);
static AtomicInteger deserializeCounter = new AtomicInteger(0);
static AtomicInteger equalsCounter = new AtomicInteger(0);
static AtomicInteger keySerializeCounter = new AtomicInteger(0);
static AtomicInteger keyDeserializeCounter = new AtomicInteger(0);
static AtomicInteger keyEqualsCounter = new AtomicInteger(0);
private final JavaSerializer<T> serializer;
public CountingSerializer(ClassLoader classLoader) {
serializer = new JavaSerializer<T>(classLoader);
}
public CountingSerializer(ClassLoader classLoader, FileBasedPersistenceContext persistenceContext) {
serializer = new JavaSerializer<T>(classLoader);
}
@Override
public ByteBuffer serialize(T object) throws SerializerException {
if (PRINT_STACK_TRACES) {
new Exception().printStackTrace();
}
if (object.getClass().equals(String.class)) {
serializeCounter.incrementAndGet();
} else {
keySerializeCounter.incrementAndGet();
}
return serializer.serialize(object);
}
@Override
public T read(ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if (PRINT_STACK_TRACES) {
new Exception().printStackTrace();
}
T value = serializer.read(binary);
if (value.getClass().equals(String.class)) {
deserializeCounter.incrementAndGet();
} else {
keyDeserializeCounter.incrementAndGet();
}
return value;
}
@Override
public boolean equals(T object, ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if (PRINT_STACK_TRACES) {
new Exception().printStackTrace();
}
if (object.getClass().equals(String.class)) {
equalsCounter.incrementAndGet();
} else {
keyEqualsCounter.incrementAndGet();
}
return serializer.equals(object, binary);
}
}
}