strangedb/src/main/java/it/cavallium/strangedb/database/DatabaseBlocksMetadata.java

83 lines
2.4 KiB
Java
Raw Normal View History

2019-03-07 11:41:45 +01:00
package it.cavallium.strangedb.database;
2019-03-02 17:47:24 +01:00
2019-03-07 11:41:45 +01:00
import it.cavallium.strangedb.BlockInfo;
2019-03-02 17:47:24 +01:00
import java.io.IOException;
import java.nio.ByteBuffer;
2019-03-03 00:54:47 +01:00
import java.nio.channels.AsynchronousFileChannel;
2019-03-02 17:47:24 +01:00
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
2019-03-03 00:54:47 +01:00
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
2019-03-02 17:47:24 +01:00
public class DatabaseBlocksMetadata implements IBlocksMetadata {
2019-03-03 00:54:47 +01:00
public static final BlockInfo ERROR_BLOCK_INFO = new BlockInfo(-2, 0);
private final AsynchronousFileChannel metaFileChannel;
2019-03-02 17:47:24 +01:00
private final int BLOCK_META_BYTES_COUNT = Long.BYTES + Integer.BYTES;
2019-03-03 00:54:47 +01:00
private final DatabaseBlocksMetadataCache cache;
2019-03-02 17:47:24 +01:00
private long firstFreeBlock;
public DatabaseBlocksMetadata(Path metaFile) throws IOException {
2019-03-03 00:54:47 +01:00
metaFileChannel = AsynchronousFileChannel.open(metaFile, StandardOpenOption.READ, StandardOpenOption.WRITE);
2019-03-02 17:47:24 +01:00
firstFreeBlock = metaFileChannel.size() / BLOCK_META_BYTES_COUNT;
2019-03-03 00:54:47 +01:00
this.cache = new DatabaseBlocksMetadataCache(this::writeBlockToDisk);
2019-03-02 17:47:24 +01:00
}
@Override
public BlockInfo getBlockInfo(long blockId) throws IOException {
if (blockId == EMPTY_BLOCK_ID) {
return EMPTY_BLOCK_INFO;
}
2019-03-03 00:54:47 +01:00
BlockInfo blockInfo;
if ((blockInfo = cache.get(blockId)) != ERROR_BLOCK_INFO) {
return blockInfo;
}
2019-03-02 17:47:24 +01:00
ByteBuffer buffer = ByteBuffer.allocate(BLOCK_META_BYTES_COUNT);
2019-03-03 00:54:47 +01:00
try {
metaFileChannel.read(buffer, blockId * BLOCK_META_BYTES_COUNT).get();
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e.getCause());
}
2019-03-02 17:47:24 +01:00
buffer.flip();
long index = buffer.getLong();
int size = buffer.getInt();
2019-03-03 00:54:47 +01:00
blockInfo = new BlockInfo(index, size);
cache.put(blockId, blockInfo);
2019-03-03 00:54:47 +01:00
return blockInfo;
2019-03-02 17:47:24 +01:00
}
@Override
public long newBlock(long index, int size) throws IOException {
if (size == 0) {
return EMPTY_BLOCK_ID;
}
2019-03-02 17:47:24 +01:00
long newBlockId = firstFreeBlock++;
2019-03-03 00:54:47 +01:00
BlockInfo blockInfo = new BlockInfo(index, size);
cache.put(newBlockId, blockInfo);
2019-03-02 17:47:24 +01:00
return newBlockId;
}
@Override
public void close() throws IOException {
2019-03-03 00:54:47 +01:00
cache.close();
2019-03-02 17:47:24 +01:00
metaFileChannel.close();
}
2019-03-03 00:54:47 +01:00
private Future<Integer> writeBlockToDisk(long blockId, long index, int size) {
ByteBuffer data = ByteBuffer.allocate(BLOCK_META_BYTES_COUNT);
data.putLong(index);
data.putInt(size);
data.flip();
return metaFileChannel.write(data, blockId * BLOCK_META_BYTES_COUNT);
}
2019-03-06 23:56:04 +01:00
@Override
public long getTotalBlocksCount() {
return firstFreeBlock;
}
2019-03-02 17:47:24 +01:00
}