package rocks.inspectit.shared.all.storage.nio;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import rocks.inspectit.shared.all.storage.nio.bytebuffer.ByteBufferFactory;
/**
* Tests the {@link ByteBufferProvider}.
*
* @author Ivan Senic
*
*/
@SuppressWarnings("PMD")
public class ByteBufferProviderTest {
/**
* To be tested.
*/
private ByteBufferProvider byteBufferProvider;
/**
* Creates new instance before each test.
*/
@BeforeMethod
public void init() {
byteBufferProvider = new ByteBufferProvider(new ByteBufferFactory(1), 1);
byteBufferProvider.setBufferPoolMaxDirectMemoryOccupancy(0.6f);
byteBufferProvider.setBufferPoolMinDirectMemoryOccupancy(0.3f);
}
/**
* Test that the created capacity of the buffer will be as wanted.
*/
@Test(invocationCount = 5)
public void capacity() throws IOException {
int maxCapacity = 1000;
Random random = new Random();
// at least 1
int wantedCapacity = 1 + random.nextInt(maxCapacity);
byteBufferProvider.setBufferSize(wantedCapacity);
byteBufferProvider.setPoolMaxCapacity(maxCapacity);
byteBufferProvider.init();
ByteBuffer buffer = byteBufferProvider.acquireByteBuffer();
assertThat(buffer, is(notNullValue()));
assertThat(buffer.capacity(), is(equalTo(wantedCapacity)));
}
/**
* Tests that no buffer will be created after max pool capacity has been reached.
*/
@Test
public void creationUntilMax() throws IOException {
int maxCapacity = 3;
byteBufferProvider.setBufferSize(1);
byteBufferProvider.setPoolMaxCapacity(maxCapacity);
byteBufferProvider.init();
for (int i = 0; i < maxCapacity; i++) {
ByteBuffer buffer = byteBufferProvider.acquireByteBuffer();
assertThat(buffer, is(notNullValue()));
}
assertThat(byteBufferProvider.getBufferPoolSize(), is(equalTo(0)));
}
/**
* Tests that a buffer will not be returned to the queue after a release when the available
* capacity is above or equal to min capacity.
*/
@Test
public void relaseAfterMin() throws IOException {
byteBufferProvider.setBufferSize(1);
byteBufferProvider.setPoolMaxCapacity(3);
byteBufferProvider.setPoolMinCapacity(1);
byteBufferProvider.init();
ByteBuffer buffer1 = byteBufferProvider.acquireByteBuffer();
ByteBuffer buffer2 = byteBufferProvider.acquireByteBuffer();
assertThat(byteBufferProvider.getCreatedCapacity(), is(equalTo(2L)));
assertThat(byteBufferProvider.getAvailableCapacity(), is(equalTo(0L)));
byteBufferProvider.releaseByteBuffer(buffer1);
byteBufferProvider.releaseByteBuffer(buffer2);
assertThat(byteBufferProvider.getCreatedCapacity(), is(equalTo(1L)));
assertThat(byteBufferProvider.getAvailableCapacity(), is(equalTo(1L)));
assertThat(byteBufferProvider.getBufferPoolSize(), is(equalTo(1)));
}
/**
* Tests that acquire and release of the buffer will have the correct side effects.
*/
@Test
public void acquireAndRelease() throws IOException {
byteBufferProvider.setBufferSize(1);
byteBufferProvider.setPoolMaxCapacity(2);
byteBufferProvider.setPoolMinCapacity(1);
byteBufferProvider.init();
assertThat(byteBufferProvider.getCreatedCapacity(), is(equalTo(0L)));
assertThat(byteBufferProvider.getAvailableCapacity(), is(equalTo(0L)));
ByteBuffer buffer = byteBufferProvider.acquireByteBuffer();
assertThat(buffer, is(notNullValue()));
assertThat(byteBufferProvider.getBufferPoolSize(), is(equalTo(0)));
assertThat(byteBufferProvider.getCreatedCapacity(), is(equalTo(1L)));
assertThat(byteBufferProvider.getAvailableCapacity(), is(equalTo(0L)));
byteBufferProvider.releaseByteBuffer(buffer);
assertThat(byteBufferProvider.getBufferPoolSize(), is(equalTo(1)));
assertThat(byteBufferProvider.getCreatedCapacity(), is(equalTo(1L)));
assertThat(byteBufferProvider.getAvailableCapacity(), is(equalTo(1L)));
}
/**
* Test that IOException will be thrown when there is no buffer available any more.
*/
@Test(expectedExceptions = IOException.class)
public void bufferNotAvailable() throws IOException {
byteBufferProvider.setBufferSize(1);
byteBufferProvider.setPoolMaxCapacity(1);
byteBufferProvider.setPoolMinCapacity(0);
byteBufferProvider.init();
// first acquire to work
ByteBuffer buffer = byteBufferProvider.acquireByteBuffer();
assertThat(buffer, is(notNullValue()));
// second to fail
buffer = byteBufferProvider.acquireByteBuffer();
}
/**
* Stress the provider with several thread proving that the byte buffer provider won't block
* under heavy load.
*/
@Test
public void providerStressed() throws Throwable {
byteBufferProvider.setBufferSize(1);
byteBufferProvider.setPoolMaxCapacity(3);
byteBufferProvider.setPoolMinCapacity(1);
byteBufferProvider.init();
int threadCount = 5;
final int iterationsPerThread = 100000;
final AtomicInteger totalCount = new AtomicInteger(threadCount * iterationsPerThread);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < iterationsPerThread; i++) {
try {
ByteBuffer buffer = byteBufferProvider.acquireByteBuffer();
assertThat(buffer, is(notNullValue()));
byteBufferProvider.releaseByteBuffer(buffer);
totalCount.decrementAndGet();
} catch (IOException ioException) {
// if IOException occurs we will repeat the try
i--;
}
}
}
}).start();
}
int sleepTime = 500;
int totalSlept = 0;
int maxSleepTime = 2 * 60 * 1000;
while (totalCount.get() > 0) {
try {
Thread.sleep(sleepTime);
totalSlept += sleepTime;
if (totalSlept > maxSleepTime) {
Assert.fail("Waiting for the byte buffer stressed test is over " + maxSleepTime + " milliseconds. Test is failed.");
}
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}
}