prepare more efficient query completion

adding an index that answers the question
given a query "a=b and c=", what are possible values
for c.
This commit is contained in:
2019-01-13 10:22:17 +01:00
parent 5197063ae3
commit 72e9a9ebe3
8 changed files with 338 additions and 6 deletions

View File

@@ -0,0 +1,26 @@
package org.lucares.pdb.map;
import org.lucares.pdb.map.PersistentMap.EncoderDecoder;
/**
* Used to denote empty values in {@link PersistentMap}.
* <p>
* Use {@link PersistentMap#EMPTY_ENCODER} as {@link EncoderDecoder}.
* <p>
* Implementation note: We cannot use {@link Void}, because {@link Void} cannot
* be instantiated. A {@link PersistentMap PersistentMap<&lt;String, Void&gt;}
* would have to return {@code null} for {@link PersistentMap#getValue(Object)}
* which would make it impossible to know whether the key existed or not.<br>
* {@link Empty} solves this by providing a single unmodifiable value.
*/
public final class Empty {
public static final Empty INSTANCE = new Empty();
private Empty() {
}
@Override
public String toString() {
return "<empty>";
}
}

View File

@@ -8,6 +8,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Stack;
import java.util.UUID;
@@ -87,9 +88,28 @@ public class PersistentMap<K, V> implements AutoCloseable {
}
}
private static final class EmptyCoder implements EncoderDecoder<Empty> {
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
@Override
public byte[] encode(final Empty __) {
return EMPTY_BYTE_ARRAY;
}
@Override
public Empty decode(final byte[] bytes) {
Preconditions.checkEqual(bytes.length, 0, "");
return Empty.INSTANCE;
}
}
public static final EncoderDecoder<Long> LONG_CODER = new LongCoder();
public static final EncoderDecoder<UUID> UUID_ENCODER = new UUIDCoder();
public static final EncoderDecoder<String> STRING_CODER = new StringCoder();
public static final EncoderDecoder<Empty> EMPTY_ENCODER = new EmptyCoder();
static final int BLOCK_SIZE = 4096;
static final long NODE_OFFSET_TO_ROOT_NODE = 8;
@@ -180,17 +200,27 @@ public class PersistentMap<K, V> implements AutoCloseable {
final byte[] value) throws IOException {
final PersistentMapDiskNode node = getNode(nodeOffest);
final var entry = node.getNodeEntryTo(key);
final NodeEntry entry = node.getNodeEntryTo(key);
if (entry == null || entry.isDataNode()) {
final byte[] oldValue;
if (entry == null) {
oldValue = null;
} else {
// found a NodeEntry that is either equal to key, or it is at the insertion
// point
final boolean entryIsForKey = entry.equal(key);
oldValue = entryIsForKey ? entry.getValue() : null;
// Early exit, if the oldValue equals the new value.
// We do not have to replace the value, because it would not change anything
// (just cause unnecessary write operations). But we return the oldValue so that
// the caller thinks we replaced the value.
if (Objects.equals(oldValue, value)) {
return oldValue;
}
if (entryIsForKey) {
node.removeKey(key);
}