package com.ctriposs.bigcache.storage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import com.ctriposs.bigcache.CacheConfig.StorageMode;
import com.ctriposs.bigcache.utils.FileUtil;
import com.ctriposs.bigcache.utils.TestUtil;
@RunWith(Parameterized.class)
public class StorageBlockTest {
private static String testDir = TestUtil.TEST_BASE_DIR + "unit/storage_block_test/";
private IStorageBlock block = null;
@Parameter(value = 0)
public StorageMode storageMode;
@Parameters
public static Collection<StorageMode[]> data() throws IOException {
StorageMode[][] data = { { StorageMode.PureFile },
{ StorageMode.MemoryMappedPlusFile },
{ StorageMode.OffHeapPlusFile } };
return Arrays.asList(data);
}
@Test
public void testBasic() throws IOException {
block = new StorageBlock(testDir, 1, StorageManager.DEFAULT_CAPACITY_PER_BLOCK, storageMode);
String testString = "Test String";
byte[] testBytes = testString.getBytes();
assertTrue(StorageManager.DEFAULT_CAPACITY_PER_BLOCK == block.getCapacity());
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(1 == block.getIndex());
// store
Pointer pointer = block.store(testBytes);
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(0 == pointer.getPosition());
assertTrue(testBytes.length == pointer.getLength());
assertTrue(testBytes.length == block.getUsed());
// retrieve
byte[] resultBytes = block.retrieve(pointer);
assertEquals(testString, new String(resultBytes));
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(0 == pointer.getPosition());
assertTrue(testBytes.length == pointer.getLength());
assertTrue(testBytes.length == block.getUsed());
// update to small
String smallTestString = "Test Str";
byte[] smallTestBytes = smallTestString.getBytes();
pointer = block.update(pointer, smallTestBytes);
assertTrue((testBytes.length - smallTestBytes.length) == block.getDirty());
double expectedRatio = (testBytes.length - smallTestBytes.length) * 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
assertTrue(0 == pointer.getPosition());
assertTrue(smallTestBytes.length == pointer.getLength());
assertTrue(smallTestBytes.length == block.getUsed());
// update to bigger
pointer = block.update(pointer, testBytes);
assertTrue(testBytes.length== block.getDirty());
expectedRatio = testBytes.length * 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
assertTrue(testBytes.length == pointer.getPosition());
assertTrue(testBytes.length == pointer.getLength());
assertTrue(testBytes.length == block.getUsed());
// remove
resultBytes = block.remove(pointer);
assertEquals(testString, new String(resultBytes));
expectedRatio = testBytes.length * 2 * 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
assertTrue(0L == block.getUsed());
// free
block.free();
assertTrue(StorageManager.DEFAULT_CAPACITY_PER_BLOCK == block.getCapacity());
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(1 == block.getIndex());
}
@Test
public void testlimitNunberOfItems() throws IOException {
block = new StorageBlock(testDir, 2, StorageManager.DEFAULT_CAPACITY_PER_BLOCK, storageMode);
int limit = 1000;
String testString = "Test String";
byte[] testBytes = testString.getBytes();
assertTrue(StorageManager.DEFAULT_CAPACITY_PER_BLOCK == block.getCapacity());
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(2 == block.getIndex());
// store
Pointer[] pointers = new Pointer[limit];
for(int i = 0; i < limit; i++) {
Pointer pointer = block.store(testBytes);
pointers[i] = pointer;
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(i * (testBytes.length) == pointer.getPosition());
assertTrue(testBytes.length == pointer.getLength());
assertTrue(testBytes.length * (i + 1) == block.getUsed());
}
// retrieve
for(int i = 0; i < limit; i++) {
byte[] resultBytes = block.retrieve(pointers[i]);
assertEquals(testString, new String(resultBytes));
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(i * (testBytes.length) == pointers[i].getPosition());
assertTrue(testBytes.length == pointers[i].getLength());
assertTrue(testBytes.length * limit == block.getUsed());
}
// update to small
String smallTestString = "Test Str";
byte[] smallTestBytes = smallTestString.getBytes();
for(int i = 0; i < limit; i++) {
pointers[i] = block.update(pointers[i], smallTestBytes);
assertTrue((i + 1) * (testBytes.length - smallTestBytes.length) == block.getDirty());
double expectedRatio = (i + 1) * (testBytes.length - smallTestBytes.length) * 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
assertTrue(i * (testBytes.length) == pointers[i].getPosition());
assertTrue(smallTestBytes.length == pointers[i].getLength());
assertTrue(testBytes.length * limit - (testBytes.length - smallTestBytes.length) * (i + 1) == block.getUsed());
}
// update to bigger
for(int i = 0; i < limit; i++) {
pointers[i] = block.update(pointers[i], testBytes);
assertTrue(((testBytes.length - smallTestBytes.length) * (limit - i - 1)) + (i + 1) * testBytes.length == block.getDirty());
double expectedRatio = (((testBytes.length - smallTestBytes.length) * (limit - i - 1)) + (i + 1) * testBytes.length )* 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
assertTrue((limit + i) * testBytes.length == pointers[i].getPosition());
assertTrue(testBytes.length == pointers[i].getLength());
}
assertTrue(testBytes.length * limit == block.getUsed());
// remove
for(int i = 0; i < limit; i++) {
byte[] resultBytes = block.remove(pointers[i]);
assertEquals(testString, new String(resultBytes));
double expectedRatio = (testBytes.length * limit + testBytes.length * (i + 1)) * 1.0 / StorageManager.DEFAULT_CAPACITY_PER_BLOCK;
assertTrue(Math.abs(expectedRatio - block.getDirtyRatio()) <= 1e-6);
}
assertTrue(0L == block.getUsed());
// free
block.free();
assertTrue(StorageManager.DEFAULT_CAPACITY_PER_BLOCK == block.getCapacity());
assertTrue(0L == block.getDirty());
assertTrue(block.getDirtyRatio() <= 1e-6);
assertTrue(2 == block.getIndex());
}
@Test
public void testStoreOverflow() throws IOException {
block = new StorageBlock(testDir, 3, 1024 * 1024 + 1023, storageMode); // 1M + 1023
byte[] sourceBytes = new byte[1024];
// populate
for(int i = 0; i < 1024; i++) {
Pointer pointer = block.store(sourceBytes);
assertNotNull(pointer);
assertTrue(i * 1024 == pointer.getPosition());
assertTrue(1024 == pointer.getLength());
}
assertTrue(1024 * 1024 == block.getUsed());
Pointer pointer = block.store(sourceBytes);
assertNull(pointer); // overflow
}
@Test
public void testUpdateOverflow() throws IOException {
block = new StorageBlock(testDir, 4, 1024 * 1024, storageMode); // 1M
byte[] sourceBytes = new byte[1024];
Pointer pointer = null;
// populate
for(int i = 0; i < 1024; i++) {
pointer = block.store(sourceBytes);
assertNotNull(pointer);
assertTrue(i * 1024 == pointer.getPosition());
assertTrue(1024 == pointer.getLength());
}
assertTrue(1024 * 1024 == block.getUsed());
pointer = block.update(pointer, new byte[512]);
assertTrue(1023 * 1024 == pointer.getPosition());
assertTrue(512 == pointer.getLength());
assertTrue(1024 * 1024 - 512 == block.getUsed());
pointer = block.update(pointer, new byte[512]);
assertTrue(1023 * 1024 == pointer.getPosition());
assertTrue(512 == pointer.getLength());
assertTrue(1024 * 1024 - 512 == block.getUsed());
pointer = block.update(pointer, new byte[513]);
assertNull(pointer); // overflow
}
@After
public void clear() throws IOException {
if (this.block != null) {
this.block.close();
}
try {
FileUtil.deleteDirectory(new File(testDir));
} catch (IllegalStateException e) {
System.gc();
try {
FileUtil.deleteDirectory(new File(testDir));
} catch (IllegalStateException e1) {
try {
Thread.sleep(3000);
} catch (InterruptedException e2) {
}
FileUtil.deleteDirectory(new File(testDir));
}
}
}
}