DiskStorage can allocate and free blocks of arbitrary sizes
This commit is contained in:
@@ -11,6 +11,7 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.lucares.utils.file.FileUtils;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
@@ -135,6 +136,130 @@ public class DiskStorageTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true, expectedExceptions = IllegalArgumentException.class)
|
||||
public void testAllocationSmallerThanMinimalBlockSize() throws Exception {
|
||||
final Path databaseFile = dataDirectory.resolve("db.ds");
|
||||
|
||||
try (DiskStorage ds = new DiskStorage(databaseFile)) {
|
||||
|
||||
final int blockSize = 31; // minimal block size is 32
|
||||
ds.allocateBlock(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
public void testAllocateAndFreeSingleBlockInFreeList() throws Exception {
|
||||
final Path databaseFile = dataDirectory.resolve("db.ds");
|
||||
|
||||
try (DiskStorage ds = new DiskStorage(databaseFile)) {
|
||||
|
||||
final int blockSize = 32;
|
||||
final long block_8_39 = ds.allocateBlock(blockSize);
|
||||
final long block_40_71 = ds.allocateBlock(blockSize);
|
||||
final long block_72_103 = ds.allocateBlock(blockSize);
|
||||
|
||||
Assert.assertEquals(block_8_39, 8);
|
||||
Assert.assertEquals(block_40_71, 40);
|
||||
Assert.assertEquals(block_72_103, 72);
|
||||
|
||||
ds.free(block_40_71, blockSize);
|
||||
|
||||
// should reuse the block we just freed
|
||||
final long actual_block_40_71 = ds.allocateBlock(blockSize);
|
||||
|
||||
Assert.assertEquals(actual_block_40_71, 40);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
public void testAllocateAndFreeMultipleBlocksInFreeList() throws Exception {
|
||||
final Path databaseFile = dataDirectory.resolve("db.ds");
|
||||
|
||||
try (DiskStorage ds = new DiskStorage(databaseFile)) {
|
||||
|
||||
final int blockSize = 32;
|
||||
ds.allocateBlock(blockSize);
|
||||
final long block_40_71 = ds.allocateBlock(blockSize);
|
||||
final long block_72_103 = ds.allocateBlock(blockSize);
|
||||
final long block_104_135 = ds.allocateBlock(blockSize);
|
||||
ds.allocateBlock(blockSize);
|
||||
|
||||
ds.free(block_72_103, blockSize);
|
||||
ds.free(block_104_135, blockSize);
|
||||
ds.free(block_40_71, blockSize); // the block with the smaller index is freed last, this increases line
|
||||
// coverage, because there is a branch for prepending the root node
|
||||
|
||||
// should reuse the first block we just freed
|
||||
// this removes the root node of the free list
|
||||
final long actual_block_40_71 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_40_71, 40);
|
||||
|
||||
// should reuse the second block we just freed
|
||||
final long actual_block_72_103 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_72_103, 72);
|
||||
|
||||
// should reuse the third block we just freed
|
||||
// this removes the last node of the free list
|
||||
final long actual_block_104_135 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_104_135, 104);
|
||||
|
||||
final long block_168_199 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(block_168_199, 168);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
public void testAllocateAndFreeInsertFreeNodeInTheMiddleOfTheFreeList() throws Exception {
|
||||
final Path databaseFile = dataDirectory.resolve("db.ds");
|
||||
|
||||
try (DiskStorage ds = new DiskStorage(databaseFile)) {
|
||||
|
||||
final int blockSize = 32;
|
||||
ds.allocateBlock(blockSize);
|
||||
ds.allocateBlock(blockSize);
|
||||
final long block_72_103 = ds.allocateBlock(blockSize);
|
||||
final long block_104_135 = ds.allocateBlock(blockSize);
|
||||
final long block_136_167 = ds.allocateBlock(blockSize);
|
||||
|
||||
// free the last block first, to increase code coverage
|
||||
ds.free(block_136_167, blockSize);
|
||||
ds.free(block_72_103, blockSize);
|
||||
ds.free(block_104_135, blockSize);
|
||||
|
||||
// the first free block is re-used
|
||||
final long actual_block_72_103 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_72_103, block_72_103);
|
||||
|
||||
final long actual_block_104_135 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_104_135, block_104_135);
|
||||
|
||||
final long actual_block_136_167 = ds.allocateBlock(blockSize);
|
||||
Assert.assertEquals(actual_block_136_167, block_136_167);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
public void testAllocateAndFreeMultipleBlocksWithDifferentSizes() throws Exception {
|
||||
final Path databaseFile = dataDirectory.resolve("db.ds");
|
||||
|
||||
try (DiskStorage ds = new DiskStorage(databaseFile)) {
|
||||
|
||||
final int blockSizeSmall = 32;
|
||||
final int blockSizeBig = 64;
|
||||
ds.allocateBlock(blockSizeSmall);
|
||||
ds.allocateBlock(blockSizeSmall);
|
||||
final long big_block_72_103 = ds.allocateBlock(blockSizeBig);
|
||||
final long small_block_136_167 = ds.allocateBlock(blockSizeSmall);
|
||||
ds.allocateBlock(blockSizeSmall);
|
||||
|
||||
ds.free(big_block_72_103, blockSizeBig);
|
||||
ds.free(small_block_136_167, blockSizeSmall);
|
||||
|
||||
final long actual_small_block_136_167 = ds.allocateBlock(blockSizeSmall);
|
||||
Assert.assertEquals(actual_small_block_136_167, small_block_136_167);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAllValuesAreEqual(final DiskBlock diskBlock, final byte expectedVal) {
|
||||
final byte[] buffer = diskBlock.getBuffer();
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
|
||||
Reference in New Issue
Block a user