Skip to content

[WIP] Unified Binary Reader/Writer #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions project-3/src/db/Project3.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import db.datastore.Database;
import db.datastore.tuple.TupleWriter;
import db.datastore.tuple.binary.BinaryTupleWriter;
import db.datastore.tuple.binary.BinaryTupleReaderWriter;
import db.datastore.tuple.string.StringTupleWriter;
import db.operators.logical.LogicalOperator;
import db.operators.physical.Operator;
Expand Down Expand Up @@ -87,7 +87,7 @@ public static void main(String args[]) {

Path outputFile = Paths.get(OUTPUT_PATH + "/query" + i++);
if (BINARY_OUTPUT) {
fileWriter = BinaryTupleWriter.get(queryPlanRoot.getHeader(), outputFile);
fileWriter = BinaryTupleReaderWriter.get(queryPlanRoot.getHeader(), outputFile);
} else {
fileWriter = StringTupleWriter.get(outputFile);
}
Expand Down
2 changes: 1 addition & 1 deletion project-3/src/db/datastore/tuple/TupleReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface TupleReader {
*
* @param index the tuple index.
*/
void seek(long index);
void seek(int index);

/**
* Close the underlying file descriptor for the reader.
Expand Down
4 changes: 4 additions & 0 deletions project-3/src/db/datastore/tuple/TupleReaderWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package db.datastore.tuple;

public interface TupleReaderWriter extends TupleReader, TupleWriter {
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package db.datastore.tuple.binary;

import db.datastore.Database;
import db.datastore.TableHeader;
import db.datastore.tuple.Tuple;
import db.datastore.tuple.TupleReader;
import db.datastore.tuple.TupleReaderWriter;
import db.performance.DiskIOStatistics;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
Expand All @@ -16,40 +18,53 @@
/**
* @inheritDoc
*/
public class BinaryTupleReader implements TupleReader {
public class BinaryTupleReaderWriter implements TupleReaderWriter {
private final TableHeader header;
private final Path path;
private final FileChannel channel;

private final ByteBuffer bb;

private long index;
private long pageNumber;
private int index;
private int pageNumber;

private boolean dirty;

/**
* Create a new reader from the file at the specified path
*
* @param path The file path, used for logging.
* @param channel The file input channel.
*/
public BinaryTupleReader(Path path, FileChannel channel) {
public BinaryTupleReaderWriter(TableHeader header, Path path, FileChannel channel) {
this.header = header;
this.path = path;
this.channel = channel;

this.bb = ByteBuffer.allocateDirect(Database.PAGE_SIZE);

this.clearPage();

this.index = -1;
this.pageNumber = -1;
this.dirty = false;

DiskIOStatistics.handles_opened += 1;
}

/**
* Get a new instance of a binary reader.
* Get a new instance of a binary reader/writer.
* @param header the header for the tuples.
* @param path The path for the binary file.
* @return The instance of the reader.
*/
public static BinaryTupleReader get(Path path) {
public static BinaryTupleReaderWriter get(TableHeader header, Path path) {
try {
return new BinaryTupleReader(path, FileChannel.open(path, StandardOpenOption.READ));
if (!Files.exists(path)) {
Files.createFile(path);
}

return new BinaryTupleReaderWriter(header, path, FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE));
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -94,15 +109,14 @@ public Tuple next() {
* @inheritDoc
*/
@Override
public void seek(long index) {
public void seek(int index) {
if (this.index == -1) {
loadPage(channel, bb);
this.index = 0;
this.peek();
}

try {
long page = index / this.getCapacity();
long offset = index % this.getCapacity();
int page = index / this.getCapacity();
int offset = index % this.getCapacity();


if (this.pageNumber != page) {
Expand All @@ -115,6 +129,73 @@ public void seek(long index) {
} catch (IOException e) {
throw new RuntimeException(e);
}

System.out.println("Seek: " + pageNumber);

}

/**
* @inheritDoc
*/
@Override
public void write(Tuple tuple) {
if (this.index == -1 || this.getRemainingCapacity() <= 0) {
this.bb.clear();
this.clearPage();

this.loadPage(channel, bb);
this.index = 0;
this.pageNumber += 1;
}

int offset = this.getTupleOffset();

this.index += 1;
this.bb.asIntBuffer().put(1, Math.max(index, this.getNumberOfTuples()));

for (int i = 0; i < tuple.fields.size(); i++) {
this.bb.asIntBuffer().put(offset + i, tuple.fields.get(i));
}

this.dirty = true;

System.out.println("Wrote: " + tuple + " to " + pageNumber + ":" + index);

if (this.getRemainingCapacity() <= 0) {
this.flush();

this.bb.clear();
this.clearPage();

this.loadPage(channel, bb);
this.index = 0;
this.pageNumber += 1;
}
}

/**
* @inheritDoc
*/
@Override
public void flush() {
System.out.println("Flush: " + pageNumber);

try {
while (this.bb.hasRemaining()) {
this.channel.write(this.bb);
}

this.channel.force(false);

this.dirty = false;

this.bb.flip();

DiskIOStatistics.writes += 1;

} catch (IOException e) {
e.printStackTrace();
}
}

/**
Expand All @@ -124,6 +205,7 @@ public void seek(long index) {
public void close() {
try {
this.channel.close();
DiskIOStatistics.handles_closed += 1;
} catch (IOException e) {
e.printStackTrace();
}
Expand All @@ -136,8 +218,14 @@ public void close() {
* @return Whether or not the page loaded.
*/
private boolean loadPage(FileChannel channel, ByteBuffer bb) {
System.out.println("Load: " + pageNumber);

if (this.dirty) {
this.flush();
}

try {
long len = channel.read(bb);
int len = channel.read(bb);

if (len == Database.PAGE_SIZE) {
bb.flip();
Expand Down Expand Up @@ -185,19 +273,50 @@ private int getNumberOfTuples() {
* @param index The page offset of the tuple which is to be loaded.
* @return The tuple at the specified offset.
*/
private Tuple getTupleOnPage(long index) {
private Tuple getTupleOnPage(int index) {
if (this.getNumberOfTuples() <= index) {
return null;
}

long startOffset = 2 + this.getTupleSize() * index;
int startOffset = 2 + this.getTupleSize() * index;

List<Integer> tupleBacking = new ArrayList<>(this.getTupleSize());

for (long i = startOffset; i < startOffset + this.getTupleSize(); i++) {
tupleBacking.add(this.bb.asIntBuffer().get((int) i));
for (int i = startOffset; i < startOffset + this.getTupleSize(); i++) {
tupleBacking.add(this.bb.asIntBuffer().get(i));
}

return new Tuple(tupleBacking);
}

/**
* Zero the page buffer.
*/
private void clearPage() {
for (int i = 0; i < Database.PAGE_SIZE / 4; i++) {
this.bb.asIntBuffer().put(i, 0);
}

this.index = 0;
this.bb.asIntBuffer().put(0, this.header.columnAliases.size());
this.bb.asIntBuffer().put(1, 0);
}

/**
* @return The number of tuples which can be written to this page.
*/
private int getRemainingCapacity() {
return (1024 - this.getTupleOffset()) / (this.header.size());
}

/**
* @return The offset of the tuple, relative to the start of the page.
*/
private int getTupleOffset() {
return 2 + this.index * this.header.size();
}

protected ByteBuffer getBb() {
return bb;
}
}
Loading