ensure BSFiles use blocks that are aligned to 512 Byte offsets
This commit is contained in:
@@ -17,6 +17,7 @@ public class DiskStorage implements AutoCloseable {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(DiskStorage.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(DiskStorage.class);
|
||||||
|
|
||||||
private static final long FREE_LIST_ROOT_OFFSET = 0;
|
private static final long FREE_LIST_ROOT_OFFSET = 0;
|
||||||
|
private static final long NO_POINTER = 0;
|
||||||
private static final int FREE_LIST_NEXT_POINTER = 0;
|
private static final int FREE_LIST_NEXT_POINTER = 0;
|
||||||
private static final int FREE_LIST_PREV_POINTER = 8;
|
private static final int FREE_LIST_PREV_POINTER = 8;
|
||||||
private static final int FREE_LIST_SIZE = 16;
|
private static final int FREE_LIST_SIZE = 16;
|
||||||
@@ -31,11 +32,13 @@ public class DiskStorage implements AutoCloseable {
|
|||||||
fileChannel = FileChannel.open(databaseFile, StandardOpenOption.READ, StandardOpenOption.WRITE,
|
fileChannel = FileChannel.open(databaseFile, StandardOpenOption.READ, StandardOpenOption.WRITE,
|
||||||
StandardOpenOption.CREATE);
|
StandardOpenOption.CREATE);
|
||||||
|
|
||||||
|
initIfNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initIfNew() throws IOException {
|
||||||
if (fileChannel.size() == 0) {
|
if (fileChannel.size() == 0) {
|
||||||
// file is new -> add root of the free list
|
// file is new -> add root of the free list
|
||||||
// TODO implement a real free list
|
writeFreeListRootNodePosition(NO_POINTER);
|
||||||
final var src = ByteBuffer.allocate(8);
|
|
||||||
fileChannel.write(src, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,4 +236,14 @@ public class DiskStorage implements AutoCloseable {
|
|||||||
freeListFirstBlock.putLong(0, freeListRootNodePosition);
|
freeListFirstBlock.putLong(0, freeListRootNodePosition);
|
||||||
fileChannel.write(freeListFirstBlock, FREE_LIST_ROOT_OFFSET);
|
fileChannel.write(freeListFirstBlock, FREE_LIST_ROOT_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void ensureAlignmentForNewBlocks(final int alignment) throws IOException {
|
||||||
|
final long size = fileChannel.size();
|
||||||
|
final int alignmentMismatch = Math.floorMod(size, alignment);
|
||||||
|
if (alignmentMismatch != 0) {
|
||||||
|
// The next allocated block would not be aligned. Therefore we allocate a
|
||||||
|
// throw-away block.
|
||||||
|
allocateNewBlock(alignment - alignmentMismatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public class DataStore implements AutoCloseable {
|
|||||||
listingFilePath = storageBasePath.resolve("listing.csv");
|
listingFilePath = storageBasePath.resolve("listing.csv");
|
||||||
diskStorageFilePath = storageBasePath.resolve("data.bs");
|
diskStorageFilePath = storageBasePath.resolve("data.bs");
|
||||||
diskStorage = new DiskStorage(diskStorageFilePath);
|
diskStorage = new DiskStorage(diskStorageFilePath);
|
||||||
|
diskStorage.ensureAlignmentForNewBlocks(BSFile.BLOCK_SIZE);
|
||||||
initListingFileIfNotExists();
|
initListingFileIfNotExists();
|
||||||
init(diskStorage);
|
init(diskStorage);
|
||||||
listingFile = new RandomAccessFile(listingFilePath.toFile(), "rw");
|
listingFile = new RandomAccessFile(listingFilePath.toFile(), "rw");
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.lucares.pdb.api.Tags;
|
import org.lucares.pdb.api.Tags;
|
||||||
|
import org.lucares.pdb.blockstorage.BSFile;
|
||||||
import org.lucares.pdb.datastore.Doc;
|
import org.lucares.pdb.datastore.Doc;
|
||||||
import org.lucares.utils.CollectionUtils;
|
import org.lucares.utils.CollectionUtils;
|
||||||
import org.lucares.utils.file.FileUtils;
|
import org.lucares.utils.file.FileUtils;
|
||||||
@@ -106,6 +107,14 @@ public class DataStoreTest {
|
|||||||
Assert.assertEquals(docsFlamingoJennifer.size(), 1, "doc for docsFlamingoJennifer");
|
Assert.assertEquals(docsFlamingoJennifer.size(), 1, "doc for docsFlamingoJennifer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBlockAlignment() throws IOException {
|
||||||
|
|
||||||
|
dataStore = new DataStore(dataDirectory);
|
||||||
|
final Tags eagleTim = Tags.create("bird", "eagle", "name", "Tim");
|
||||||
|
final long eagleTimBlockOffset = dataStore.createNewFile(eagleTim);
|
||||||
|
Assert.assertEquals(eagleTimBlockOffset % BSFile.BLOCK_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertSearch(final String query, final Tags... tags) {
|
private void assertSearch(final String query, final Tags... tags) {
|
||||||
final List<Doc> actualDocs = dataStore.search(query);
|
final List<Doc> actualDocs = dataStore.search(query);
|
||||||
final List<Long> actual = CollectionUtils.map(actualDocs, Doc::getRootBlockNumber);
|
final List<Long> actual = CollectionUtils.map(actualDocs, Doc::getRootBlockNumber);
|
||||||
|
|||||||
Reference in New Issue
Block a user