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 StorageManagerTest { private static String testDir = TestUtil.TEST_BASE_DIR + "unit/storage_manager_test/"; private StorageManager storageManager = null; @Parameter(value = 0) public StorageMode storageMode; @Parameter(value = 1) public long size; @Parameters public static Collection<Object[]> data() throws IOException { Object[][] data = { { StorageMode.PureFile, 0 }, { StorageMode.MemoryMappedPlusFile, 2 * 1000 * 1024 * 1024 }, { StorageMode.OffHeapPlusFile, 2 * 1000 * 1024 * 1024 } }; return Arrays.asList(data); } @Test public void testBasic() throws IOException { storageManager = new StorageManager(testDir, 1024 * 1024, 2, storageMode, size); // 2M Total assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(0L == storageManager.getUsed()); String testString = "Test String"; byte[] testBytes = testString.getBytes(); // store Pointer pointer = storageManager.store(testBytes); assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(0 == pointer.getPosition()); assertTrue(testBytes.length == pointer.getLength()); assertTrue(testBytes.length == storageManager.getUsed()); // retrieve byte[] resultBytes = storageManager.retrieve(pointer); assertEquals(testString, new String(resultBytes)); assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(0 == pointer.getPosition()); assertTrue(testBytes.length == pointer.getLength()); assertTrue(testBytes.length == storageManager.getUsed()); // update to small String smallTestString = "Test Str"; byte[] smallTestBytes = smallTestString.getBytes(); pointer = storageManager.update(pointer, smallTestBytes); assertTrue((testBytes.length - smallTestBytes.length) == storageManager.getDirty()); double expectedRatio = (testBytes.length - smallTestBytes.length) * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue(0 == pointer.getPosition()); assertTrue(smallTestBytes.length == pointer.getLength()); assertTrue(smallTestBytes.length == storageManager.getUsed()); // update to bigger pointer = storageManager.update(pointer, testBytes); assertTrue(testBytes.length== storageManager.getDirty()); expectedRatio = testBytes.length * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue(testBytes.length == pointer.getPosition()); assertTrue(testBytes.length == pointer.getLength()); assertTrue(testBytes.length == storageManager.getUsed()); // remove resultBytes = storageManager.remove(pointer); assertEquals(testString, new String(resultBytes)); expectedRatio = testBytes.length * 2 * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue(0L == storageManager.getUsed()); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); // free storageManager.free(); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); } @Test public void testlimitNunberOfItems() throws IOException { storageManager = new StorageManager(testDir, 1024 * 1024, 2, storageMode, size); // 2M Total assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(0L == storageManager.getUsed()); String testString = "Test String"; byte[] testBytes = testString.getBytes(); int limit = 1000; // store Pointer[] pointers = new Pointer[limit]; for(int i = 0; i < limit; i++) { Pointer pointer = storageManager.store(testBytes); pointers[i] = pointer; assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(i * (testBytes.length) == pointer.getPosition()); assertTrue(testBytes.length == pointer.getLength()); } assertTrue(1000 * testBytes.length == storageManager.getUsed()); // retrieve for(int i = 0; i < limit; i++) { byte[] resultBytes = storageManager.retrieve(pointers[i]); assertEquals(testString, new String(resultBytes)); assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(i * (testBytes.length) == pointers[i].getPosition()); assertTrue(testBytes.length == pointers[i].getLength()); } assertTrue(1000 * testBytes.length == storageManager.getUsed()); // update to small String smallTestString = "Test Str"; byte[] smallTestBytes = smallTestString.getBytes(); for(int i = 0; i < limit; i++) { pointers[i] = storageManager.update(pointers[i], smallTestBytes); assertTrue((i + 1) * (testBytes.length - smallTestBytes.length) == storageManager.getDirty()); double expectedRatio = (i + 1) * (testBytes.length - smallTestBytes.length) * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue(i * (testBytes.length) == pointers[i].getPosition()); assertTrue(smallTestBytes.length == pointers[i].getLength()); } assertTrue(1000 * smallTestBytes.length == storageManager.getUsed()); // update to bigger for(int i = 0; i < limit; i++) { pointers[i] = storageManager.update(pointers[i], testBytes); assertTrue(((testBytes.length - smallTestBytes.length) * (limit - i - 1)) + (i + 1) * testBytes.length == storageManager.getDirty()); double expectedRatio = (((testBytes.length - smallTestBytes.length) * (limit - i - 1)) + (i + 1) * testBytes.length )* 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue((limit + i) * testBytes.length == pointers[i].getPosition()); assertTrue(testBytes.length == pointers[i].getLength()); } assertTrue(1000 * testBytes.length == storageManager.getUsed()); // remove for(int i = 0; i < limit; i++) { byte[] resultBytes = storageManager.remove(pointers[i]); assertEquals(testString, new String(resultBytes)); double expectedRatio = (testBytes.length * limit + testBytes.length * (i + 1)) * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); } assertTrue(0L == storageManager.getUsed()); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); // free storageManager.free(); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0L == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); } @SuppressWarnings("resource") @Test public void testStoreOverflow() throws IOException { storageManager = new StorageManager(testDir, 1024 * 1024, 2, storageMode, size); // 2M Total assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); byte[] sourceBytes = new byte[1024]; IStorageBlock previousBlock = null; for(int i = 0; i < 1024; i++) { Pointer pointer = storageManager.store(sourceBytes); assertNotNull(pointer); if (previousBlock == null) previousBlock = pointer.getStorageBlock(); else { assertTrue(pointer.getStorageBlock() == previousBlock); previousBlock = pointer.getStorageBlock(); } } assertTrue(1024 * 1024 == storageManager.getUsed()); Pointer pointer = storageManager.store(sourceBytes); // switch active block assertTrue(previousBlock != pointer.getStorageBlock()); previousBlock = pointer.getStorageBlock(); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(0 == storageManager.getFreeBlockCount()); assertTrue(2 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(1025 * 1024 == storageManager.getUsed()); for(int i = 1; i < 1024; i++) { pointer = storageManager.store(sourceBytes); assertNotNull(pointer); if (previousBlock == null) previousBlock = pointer.getStorageBlock(); else { assertTrue(pointer.getStorageBlock() == previousBlock); previousBlock = pointer.getStorageBlock(); } } assertTrue(2048 * 1024 == storageManager.getUsed()); pointer = storageManager.store(sourceBytes); //switch active block assertTrue(previousBlock != pointer.getStorageBlock()); previousBlock = pointer.getStorageBlock(); assertTrue(3 == storageManager.getTotalBlockCount()); assertTrue(0 == storageManager.getFreeBlockCount()); assertTrue(3 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 3 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); assertTrue(2049 * 1024 == storageManager.getUsed()); } @SuppressWarnings("resource") @Test public void testUpdateOverflow() throws IOException { storageManager = new StorageManager(testDir, 1024 * 1024, 2, storageMode, size); // 2M Total assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(1 == storageManager.getFreeBlockCount()); assertTrue(1 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(0 == storageManager.getDirty()); assertTrue(storageManager.getDirtyRatio() <= 1e-6); byte[] sourceBytes = new byte[1024]; IStorageBlock previousBlock = null; Pointer pointer = null; for(int i = 0; i < 1024; i++) { pointer = storageManager.store(sourceBytes); assertNotNull(pointer); if (previousBlock == null) previousBlock = pointer.getStorageBlock(); else { assertTrue(pointer.getStorageBlock() == previousBlock); previousBlock = pointer.getStorageBlock(); } } assertTrue(1024 * 1024 == storageManager.getUsed()); pointer = storageManager.update(pointer, new byte[512]); assertTrue(previousBlock == pointer.getStorageBlock()); // no switch assertTrue(1023 * 1024 + 512 == storageManager.getUsed()); pointer = storageManager.update(pointer, new byte[1024]); assertTrue(previousBlock != pointer.getStorageBlock()); // switch previousBlock = pointer.getStorageBlock(); assertTrue(2 == storageManager.getTotalBlockCount()); assertTrue(0 == storageManager.getFreeBlockCount()); assertTrue(2 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 2 == storageManager.getCapacity()); assertTrue(1024 == storageManager.getDirty()); double expectedRatio = 1024 * 1.0 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); assertTrue(1024 * 1024 == storageManager.getUsed()); for(int i = 1; i < 1024; i++) { pointer = storageManager.store(sourceBytes); assertNotNull(pointer); if (previousBlock == null) previousBlock = pointer.getStorageBlock(); else { assertTrue(pointer.getStorageBlock() == previousBlock); previousBlock = pointer.getStorageBlock(); } } assertTrue(2047 * 1024 == storageManager.getUsed()); pointer = storageManager.update(pointer, new byte[512]); assertTrue(previousBlock == pointer.getStorageBlock()); // no switch assertTrue(2047 * 1024 - 512 == storageManager.getUsed()); pointer = storageManager.update(pointer, new byte[1024]); assertTrue(previousBlock != pointer.getStorageBlock()); // switch previousBlock = pointer.getStorageBlock(); assertTrue(2047 * 1024 == storageManager.getUsed()); assertTrue(3 == storageManager.getTotalBlockCount()); assertTrue(0 == storageManager.getFreeBlockCount()); assertTrue(3 == storageManager.getUsedBlockCount()); assertTrue(1024 * 1024 * 3 == storageManager.getCapacity()); assertTrue(1024 * 2 == storageManager.getDirty()); expectedRatio = 1024 * 1.0 * 2 / storageManager.getCapacity(); assertTrue(Math.abs(expectedRatio - storageManager.getDirtyRatio()) <= 1e-6); } @After public void clear() throws IOException { if (this.storageManager != null) { this.storageManager.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)); } } } }