strangedb-core/src/main/java/it/cavallium/strangedb/database/references/DatabaseReferencesMetadata....

87 lines
2.6 KiB
Java

package it.cavallium.strangedb.database.references;
import it.cavallium.strangedb.database.IReferencesMetadata;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static it.cavallium.strangedb.database.IBlocksMetadata.EMPTY_BLOCK_ID;
import static it.cavallium.strangedb.database.IBlocksMetadata.ERROR_BLOCK_ID;
public class DatabaseReferencesMetadata implements IReferencesMetadata {
private final AsynchronousFileChannel metaFileChannel;
private final int REF_META_BYTES_COUNT = Long.BYTES;
private final DatabaseReferencesMetadataCache cache;
private long firstFreeReference;
public DatabaseReferencesMetadata(Path refMetaFile) throws IOException {
metaFileChannel = AsynchronousFileChannel.open(refMetaFile, StandardOpenOption.READ, StandardOpenOption.WRITE);
firstFreeReference = metaFileChannel.size() / REF_META_BYTES_COUNT;
this.cache = new DatabaseReferencesMetadataCache(this::writeReferenceToDisk);
}
@Override
public long getReference(long reference) throws IOException {
if (reference >= firstFreeReference) {
return EMPTY_BLOCK_ID;
}
long block;
if ((block = cache.get(reference)) != ERROR_BLOCK_ID) {
return block;
}
ByteBuffer buffer = ByteBuffer.allocate(REF_META_BYTES_COUNT);
try {
metaFileChannel.read(buffer, reference * REF_META_BYTES_COUNT).get();
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e.getCause());
}
buffer.flip();
block = buffer.getLong();
if (buffer.limit() != 0 && block != 0xFFFFFFFFFFFFFFFFL) {
cache.put(reference, block);
return block;
} else {
cache.put(reference, EMPTY_BLOCK_ID);
return EMPTY_BLOCK_ID;
}
}
@Override
public long newReference(long blockId) throws IOException {
long newReference = firstFreeReference++;
cache.put(newReference, blockId);
return newReference;
}
@Override
public void editReference(long reference, long blockId) throws IOException {
cache.put(reference, blockId);
}
@Override
public void close() throws IOException {
cache.close();
metaFileChannel.close();
}
@Override
public long getFirstFreeReference() {
return firstFreeReference;
}
private Future<Integer> writeReferenceToDisk(long reference, long blockId) {
ByteBuffer data = ByteBuffer.allocate(REF_META_BYTES_COUNT);
data.putLong(blockId);
data.flip();
return metaFileChannel.write(data, reference * REF_META_BYTES_COUNT);
}
}