Skip to content

Instantly share code, notes, and snippets.

@quoll
Created August 22, 2019 05:57
Show Gist options
  • Save quoll/a57a3c85ce5f5b45dd658a6b04b6f550 to your computer and use it in GitHub Desktop.
Save quoll/a57a3c85ce5f5b45dd658a6b04b6f550 to your computer and use it in GitHub Desktop.
Linked Lists on Mapped File Buffers
package mapped;
import java.io.File;
import java.io.Closeable;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
public class BufferList implements Closeable {
public static int ELEMENT_SIZE = 2 * Integer.BYTES;
public static int NULL = -1;
private static int NEXT_OFFSET = 0;
private static int VALUE_OFFSET = 1;
private final RandomAccessFile file;
private final FileChannel fileChannel;
private ByteBuffer buffer;
private int nextAvailable;
public BufferList() throws IOException {
this("buffer.bin", 20);
}
public BufferList(int length) throws IOException {
this("buffer.bin", length);
}
public BufferList(String filename) throws IOException {
this(filename, 20);
}
public BufferList(String filename, int length) throws IOException {
long fileLength = ELEMENT_SIZE * length;
File ioFile = new File(filename);
boolean exists = ioFile.exists();
file = new RandomAccessFile(filename, "rw");
if (exists) {
nextAvailable = (int)(file.length() / ELEMENT_SIZE);
if (file.length() > fileLength) {
fileLength = file.length();
} else if (fileLength > file.length()) {
file.setLength(fileLength);
}
} else {
nextAvailable = 0;
}
fileChannel = file.getChannel();
buffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileLength);
}
public void close() throws IOException {
fileChannel.truncate(nextAvailable * ELEMENT_SIZE);
fileChannel.force(true);
file.close();
}
public Element addToHead(int value) {
return addToHead(null, value);
}
public Element addToHead(Element nextElt, int value) {
if (nextAvailable * ELEMENT_SIZE >= buffer.capacity()) {
throw new RuntimeException("Out of memory");
}
return new Element(nextAvailable++, nextElt, value);
}
public static String listString(Element element) {
Element next = element.getNext();
String valueString = Integer.toString(element.getValue());
if (next == null) return valueString;
else return valueString + ", " + listString(next);
}
public class Element {
private final IntBuffer intBuffer;
private final int index;
Element(int index) {
this.index = index;
int offset = index * ELEMENT_SIZE;
if (offset > buffer.limit()) {
intBuffer = buffer.limit(offset + ELEMENT_SIZE).position(offset).slice().asIntBuffer();
} else {
intBuffer = buffer.position(offset).limit(offset + ELEMENT_SIZE).slice().asIntBuffer();
}
}
Element(int index, Element next, int value) {
this(index);
setNext(next);
setValue(value);
}
Element(int index, int value) {
this(index, null, value);
}
public int getIndex() {
return index;
}
public int getValue() {
return intBuffer.get(VALUE_OFFSET);
}
public Element getNext() {
int nextId = intBuffer.get(NEXT_OFFSET);
return nextId == NULL ? null : new Element(nextId);
}
public Element setValue(int value) {
intBuffer.put(VALUE_OFFSET, value);
return this;
}
public Element setNext(Element next) {
intBuffer.put(NEXT_OFFSET, next == null ? NULL : next.getIndex());
return this;
}
public String toString() {
return listString(this);
}
}
}
package mapped;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.nio.ByteBuffer;
public class MultiExample {
public static void main(String[] args) throws IOException {
BufferList bufferList = new BufferList("buffer.bin", 20);
BufferList.Element list1, list2, list3;
list1 = bufferList.addToHead(34);
list1 = bufferList.addToHead(list1, 21);
list1 = bufferList.addToHead(list1, 13);
list2 = bufferList.addToHead(list1, 8); // note that this is list2
list1 = bufferList.addToHead(list2, 5);
list1 = bufferList.addToHead(list1, 3);
list1 = bufferList.addToHead(list1, 2);
list1 = bufferList.addToHead(list1, 1);
list1 = bufferList.addToHead(list1, 1);
list2 = bufferList.addToHead(list2, 7);
list2 = bufferList.addToHead(list2, 6);
list2 = bufferList.addToHead(list2, 5);
list3 = bufferList.addToHead(6);
list3 = bufferList.addToHead(list3, 2);
list3 = bufferList.addToHead(list3, 9);
list3 = bufferList.addToHead(list3, 5);
list3 = bufferList.addToHead(list3, 1);
list3 = bufferList.addToHead(list3, 4);
list3 = bufferList.addToHead(list3, 1);
list3 = bufferList.addToHead(list3, 3);
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
writeLists(list1, list2, list3);
bufferList.close();
}
static void writeLists(BufferList.Element... lists) throws IOException {
RandomAccessFile file = new RandomAccessFile("meta.bin", "rw");
for (BufferList.Element element: lists) {
file.writeInt(element.getIndex());
}
file.close();
}
}
package mapped;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.nio.ByteBuffer;
public class MultiExample2 {
public static void main(String[] args) throws IOException {
BufferList bufferList = new BufferList("buffer.bin");
for (BufferList.Element list: readLists(bufferList)) {
System.out.println(list);
}
}
static BufferList.Element[] readLists(BufferList bufferList) throws IOException {
RandomAccessFile file = new RandomAccessFile("meta.bin", "r");
int length = (int)(file.length() / Integer.BYTES);
BufferList.Element[] lists = new BufferList.Element[length];
for (int number = 0; number < length; number++) {
lists[number] = bufferList.new Element(file.readInt());
}
file.close();
return lists;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment