package org.infinispan.container.offheap;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.infinispan.Cache;
import org.infinispan.commons.marshall.WrappedByteArray;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.container.DataContainer;
import org.infinispan.configuration.cache.StorageType;
import org.infinispan.filter.KeyFilter;
import org.infinispan.test.MultipleCacheManagersTest;
import org.testng.annotations.Test;
@Test(groups = "stress", testName = "commands.OffHeapMultiNodeTest", timeOut = 15*60*1000)
public class OffHeapMultiNodeStressTest extends MultipleCacheManagersTest {
@Override
protected void createCacheManagers() throws Throwable {
ConfigurationBuilder dcc = getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, true);
dcc.memory().storageType(StorageType.OFF_HEAP);
createCluster(dcc, 4);
waitForClusterToForm();
}
static DataContainer<WrappedByteArray, WrappedByteArray> castDC(Object obj) {
return (DataContainer<WrappedByteArray, WrappedByteArray>) obj;
}
public void testLotsOfWritesAndFewRemoves() throws Exception {
final int WRITE_THREADS = 5;
final int REMOVE_THREADS = 2;
final int INSERTIONCOUNT = 2048;
final int REMOVECOUNT = 1;
ExecutorService execService = Executors.newFixedThreadPool(WRITE_THREADS + REMOVE_THREADS);
ExecutorCompletionService<Void> service = new ExecutorCompletionService<>(
execService);
try {
final Map<byte[], byte[]> map = cache(0);
for (int i = 0; i < WRITE_THREADS; ++i) {
service.submit(() -> {
for (int j = 0; j < INSERTIONCOUNT; ++j) {
byte[] hcc = randomBytes(KEY_SIZE);
map.put(hcc, hcc);
}
return null;
});
}
for (int i = 0; i < REMOVE_THREADS; ++i) {
service.submit(() -> {
for (int j = 0; j < REMOVECOUNT; ++j) {
Iterator<Map.Entry<byte[], byte[]>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
map.remove(iterator.next().getKey());
}
}
return null;
});
}
for (int i = 0; i < WRITE_THREADS + REMOVE_THREADS; ++i) {
Future<Void> future = service.poll(10, TimeUnit.SECONDS);
if (future == null) {
throw new TimeoutException();
}
future.get();
}
} finally {
execService.shutdown();
execService.awaitTermination(1000, TimeUnit.SECONDS);
}
}
public void testWritesAndRemovesWithExecutes() throws Exception {
final int WRITE_THREADS = 5;
final int REMOVE_THREADS = 2;
final int EXECUTE_THREADS = 2;
final int INSERTIONCOUNT = 2048;
final int REMOVECOUNT = 1;
final int EXECUTECOUNT = 2;
ExecutorService execService = Executors.newFixedThreadPool(WRITE_THREADS + REMOVE_THREADS + EXECUTE_THREADS);
ExecutorCompletionService<Void> service = new ExecutorCompletionService<>(
execService);
try {
final Cache<byte[], byte[]> bchm = cache(0);
for (int i = 0; i < WRITE_THREADS; ++i) {
service.submit(() -> {
for (int j = 0; j < INSERTIONCOUNT; ++j) {
byte[] hcc = randomBytes(KEY_SIZE);
bchm.put(hcc, hcc);
}
return null;
});
}
for (int i = 0; i < REMOVE_THREADS; ++i) {
service.submit(() -> {
for (int j = 0; j < REMOVECOUNT; ++j) {
Iterator<Map.Entry<byte[], byte[]>> iterator = bchm.entrySet().iterator();
while (iterator.hasNext()) {
bchm.remove(iterator.next().getKey());
}
}
return null;
});
}
for (int i = 0; i < EXECUTE_THREADS; ++i) {
service.submit(() -> {
for (int j = 0; j < EXECUTECOUNT; ++j) {
DataContainer<WrappedByteArray, WrappedByteArray> container =
castDC(bchm.getAdvancedCache().getDataContainer());
container.executeTask(KeyFilter.ACCEPT_ALL_FILTER, (k, e) -> {
assertEquals(k, e.getKey());
});
}
return null;
});
}
for (int i = 0; i < WRITE_THREADS + REMOVE_THREADS + EXECUTE_THREADS; ++i) {
Future<Void> future = service.poll(10, TimeUnit.SECONDS);
if (future == null) {
throw new TimeoutException();
}
future.get();
}
} finally {
execService.shutdown();
execService.awaitTermination(10, TimeUnit.SECONDS);
}
}
final static int KEY_SIZE = 20;
byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
ThreadLocalRandom.current().nextBytes(bytes);
return bytes;
}
}