87 lines
2.6 KiB
Java
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);
|
|
}
|
|
|
|
}
|