Skip to content

Commit

Permalink
actually working subset of DurableMap, and all the changes that entailed
Browse files Browse the repository at this point in the history
  • Loading branch information
ztellman committed Nov 10, 2019
1 parent af94c71 commit 4d3cb1f
Show file tree
Hide file tree
Showing 41 changed files with 2,034 additions and 1,182 deletions.
22 changes: 22 additions & 0 deletions src/io/lacuna/bifurcan/DurableEncoding.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ public boolean equals(Object obj) {
}

interface SkippableIterator extends Iterator<Object> {
static SkippableIterator singleton(Object o) {
return new SkippableIterator() {
boolean consumed = false;

@Override
public void skip() {
consumed = true;
}

@Override
public boolean hasNext() {
return !consumed;
}

@Override
public Object next() {
consumed = true;
return o;
}
};
}

default SkippableIterator skip(int n) {
for (int i = 0; i < n; i++) {
skip();
Expand Down
94 changes: 0 additions & 94 deletions src/io/lacuna/bifurcan/DurableHashMap.java

This file was deleted.

75 changes: 62 additions & 13 deletions src/io/lacuna/bifurcan/DurableInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,70 @@

import io.lacuna.bifurcan.durable.*;

import java.io.*;
import java.io.Closeable;
import java.io.DataInput;
import java.io.EOFException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.function.Function;
import java.util.Iterator;

public interface DurableInput extends DataInput, Closeable, AutoCloseable {

int DEFAULT_BUFFER_SIZE = 1 << 16;
class Slice {
public final Slice parent;
public final long start, end;

public Slice(Slice parent, long start, long end) {
this.parent = parent;
this.start = start;
this.end = end;
}

@Override
public String toString() {
String b = "[" + start + ", " + end + "]";
return parent == null ? b : parent + " -> " + b;
}
}

static DurableInput from(Iterable<ByteBuffer> buffers) {
return new ByteBufferDurableInput(buffers);
Iterator<ByteBuffer> it = buffers.iterator();
ByteBuffer buf = it.next();
return it.hasNext()
? new MultiBufferDurableInput(buffers, new Slice(null, 0, Util.size(buffers)))
: new SingleBufferDurableInput(buf, new Slice(null, 0, buf.remaining()));
}

DurableInput slice(long start, long end);

default DurableInput sliceBytes(long bytes) {
DurableInput result = slice(position(), position() + bytes);
skipBytes(bytes);
return result;
}

DurableInput slice(long offset, long length);
default DurableInput sliceBlock(BlockPrefix.BlockType type) {
long pos = position();
BlockPrefix prefix = readPrefix();
if (prefix.type != type) {
throw new IllegalStateException("expected " + type + " at " + pos + ", got " + prefix.type + " in " + bounds());
}
return sliceBytes(prefix.length);
}

default DurableInput slice(long length) {
return slice(position(), length);
default DurableInput slicePrefixedBlock() {
long start = position();
BlockPrefix prefix = readPrefix();
long end = position() + prefix.length;
seek(start);
return sliceBytes(end - start);
}

void seek(long position);
Slice bounds();

DurableInput duplicate();

DurableInput seek(long position);

long remaining();

Expand Down Expand Up @@ -108,9 +149,17 @@ default BlockPrefix readPrefix() {
return BlockPrefix.read(this);
}

default BlockPrefix peekPrefix() {
long pos = position();
BlockPrefix prefix = readPrefix();
seek(pos);
return prefix;
}

default long skipBlock() {
long pos = position();
skipBytes(readPrefix().length);
BlockPrefix prefix = readPrefix();
skipBytes(prefix.length);
return position() - pos;
}

Expand Down
119 changes: 119 additions & 0 deletions src/io/lacuna/bifurcan/DurableMap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package io.lacuna.bifurcan;

import io.lacuna.bifurcan.durable.DurableAccumulator;
import io.lacuna.bifurcan.durable.blocks.HashMap;
import io.lacuna.bifurcan.durable.blocks.HashMapEntries;
import io.lacuna.bifurcan.durable.blocks.HashTable;
import io.lacuna.bifurcan.durable.blocks.SkipTable;

import java.util.Iterator;
import java.util.function.BiPredicate;
import java.util.function.ToIntFunction;

public class DurableMap implements IDurableCollection, IMap<Object, Object> {

private final long size;
private final HashTable.Reader hashTable;
private final SkipTable.Reader skipTable;
private final DurableInput entries;
private final DurableEncoding encoding;
private final ToIntFunction<Object> keyHash;

public DurableMap(
long size,
HashTable.Reader hashTable,
SkipTable.Reader skipTable,
DurableInput entries,
DurableEncoding encoding) {
this.size = size;
this.hashTable = hashTable;
this.skipTable = skipTable;
this.entries = entries;
this.encoding = encoding;
this.keyHash = HashMap.keyHash(encoding);
}

public static <K, V> DurableMap save(IMap<K, V> m, DurableEncoding encoding) {
DurableAccumulator out = new DurableAccumulator();
HashMap.encode(m.entries(), encoding, out);
return HashMap.decode(DurableInput.from(out.contents()), encoding);
}

private Iterator<HashMapEntries.Reader> entries(long offset) {
DurableInput in = entries.duplicate().seek(offset);
return new Iterator<HashMapEntries.Reader>() {
@Override
public boolean hasNext() {
return in.remaining() > 0;
}

@Override
public HashMapEntries.Reader next() {
return HashMapEntries.decode(in, encoding);
}
};
}

@Override
public ToIntFunction<Object> keyHash() {
return keyHash;
}

@Override
public BiPredicate<Object, Object> keyEquality() {
return encoding.keyEquality();
}

@Override
public Object get(Object key, Object defaultValue) {
int hash = keyHash.applyAsInt(key);

HashTable.Entry blockEntry = hashTable == null ? HashTable.Entry.ENTRY : hashTable.get(hash);
if (blockEntry == null) {
return defaultValue;
} else {
Iterator<HashMapEntries.Reader> it = entries(blockEntry.offset);
return HashMapEntries.get(it, hash, key, defaultValue);
}
}

@Override
public long indexOf(Object key) {
return 0;
}

@Override
public long size() {
return size;
}

@Override
public IEntry<Object, Object> nth(long index) {
SkipTable.Entry blockEntry = skipTable == null ? SkipTable.Entry.ENTRY : skipTable.floor(index);
return entries(blockEntry.offset).next().nth((int) (index - blockEntry.index));
}

@Override
public DurableMap clone() {
return this;
}

@Override
public int hashCode() {
return (int) Maps.hash(this);
}

@Override
public boolean equals(Object obj) {
if (obj instanceof IMap) {
return Maps.equals(this, (IMap) obj);
} else {
return false;
}
}

@Override
public String toString() {
return Maps.toString(this);
}
}
12 changes: 12 additions & 0 deletions src/io/lacuna/bifurcan/DurableOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,24 @@ default void write(byte[] b, int off, int len) {

void writeByte(int v);

default void writeUnsignedByte(int v) {
writeByte((byte) (v & 0xFF));
}

void writeShort(int v);

default void writeUnsignedShort(int v) {
writeShort((short) (v & 0xFFFF));
}

void writeChar(int v);

void writeInt(int v);

default void writeUnsignedInt(long v) {
writeInt((int) (v & 0xFFFFFFFFL));
}

void writeLong(long v);

void writeFloat(float v);
Expand Down
Loading

0 comments on commit 4d3cb1f

Please sign in to comment.