strangedb-core/src/main/java/it/cavallium/strangedb/database/DatabaseFileIO.java
2019-04-20 15:55:45 +02:00

73 lines
2.2 KiB
Java

package it.cavallium.strangedb.database;
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.*;
import java.util.concurrent.atomic.AtomicLong;
public class DatabaseFileIO implements IFileIO {
private final AsynchronousFileChannel dataFileChannel;
private final AtomicLong firstFreeIndex;
private volatile boolean closed = false;
public DatabaseFileIO(Path dataFile) throws IOException {
dataFileChannel = AsynchronousFileChannel.open(dataFile, StandardOpenOption.READ, StandardOpenOption.WRITE);
firstFreeIndex = new AtomicLong(dataFileChannel.size());
}
@Override
public ByteBuffer readAt(long index, int length) throws IOException {
if (closed) throw new IOException("Database closed!");
ByteBuffer dataBuffer = ByteBuffer.allocate(length);
try {
dataFileChannel.read(dataBuffer, index).get();
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e.getCause());
}
dataBuffer.flip();
return dataBuffer;
}
@Override
public int writeAt(long index, int length, ByteBuffer data) throws IOException {
if (closed) throw new IOException("Database closed!");
return writeAt_(index, length, data);
}
private int writeAt_(long index, int length, ByteBuffer data) throws IOException {
if (data.position() != 0) {
throw new IOException("You didn't flip the ByteBuffer!");
}
firstFreeIndex.updateAndGet((firstFreeIndex) -> firstFreeIndex < index + length ? index + length : firstFreeIndex);
try {
return dataFileChannel.write(data, index).get();
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e.getCause());
}
}
@Override
public long writeAtEnd(int length, ByteBuffer data) throws IOException {
if (closed) throw new IOException("Database closed!");
long index = firstFreeIndex.getAndAdd(length);
writeAt_(index, length, data);
return index;
}
@Override
public void close() throws IOException {
if (closed) throw new IOException("Database already closed!");
closed = true;
dataFileChannel.close();
}
}