Improve column definition, more tests
This commit is contained in:
parent
0727be5866
commit
34c7ca4144
5
pom.xml
5
pom.xml
@ -29,6 +29,11 @@
|
||||
<artifactId>argparse4j</artifactId>
|
||||
<version>0.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil-core</artifactId>
|
||||
<version>8.5.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.seancfoley</groupId>
|
||||
<artifactId>ipaddress</artifactId>
|
||||
|
@ -81,7 +81,7 @@ public class Main {
|
||||
|
||||
switch (url.getScheme()) {
|
||||
case "unix" -> clientBuilder.setUnixSocket(UnixDomainSocketAddress.of(Path.of(url.getPath())));
|
||||
case "file" -> clientBuilder.setEmbeddedPath(Path.of(url.getPath()));
|
||||
case "file" -> clientBuilder.setEmbeddedPath(Path.of((url.getAuthority() != null ? url.getAuthority() : "") + url.getPath()).normalize());
|
||||
case "memory" -> clientBuilder.setEmbeddedInMemory(true);
|
||||
case "rocksdb" -> clientBuilder.setAddress(new HostName(url.getHost()).asInetSocketAddress());
|
||||
default -> throw new IllegalArgumentException("Invalid scheme: " + url.getScheme());
|
||||
|
@ -0,0 +1,34 @@
|
||||
package it.cavallium.rockserver.core.common;
|
||||
|
||||
import it.cavallium.rockserver.core.impl.ColumnInstance;
|
||||
import it.cavallium.rockserver.core.impl.XXHash32;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public enum ColumnHashType implements HashFunction {
|
||||
XXHASH32(Integer.BYTES, (inputData, hashResult) -> XXHash32.getInstance()
|
||||
.hash(inputData, 0, Math.toIntExact(inputData.byteSize()), 0, hashResult)),
|
||||
XXHASH8(Byte.BYTES, (inputData, hashResult) -> {
|
||||
var xxHash = XXHash32.getInstance().hash(Utils.toByteArray(inputData), 0, Math.toIntExact(inputData.byteSize()), 0);
|
||||
hashResult.set(ColumnInstance.BIG_ENDIAN_BYTES, 0, (byte) xxHash);
|
||||
}),
|
||||
ALLSAME8(Byte.BYTES, (inputData, hashResult) -> {
|
||||
hashResult.set(ColumnInstance.BIG_ENDIAN_BYTES, 0, (byte) 0);
|
||||
});
|
||||
|
||||
private final int bytes;
|
||||
private final HashFunction hashFunction;
|
||||
|
||||
ColumnHashType(int bytes, HashFunction hashFunction) {
|
||||
this.bytes = bytes;
|
||||
this.hashFunction = hashFunction;
|
||||
}
|
||||
|
||||
public int bytesSize() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void hash(MemorySegment inputData, MemorySegment hashResult) {
|
||||
hashFunction.hash(inputData, hashResult);
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,43 @@
|
||||
package it.cavallium.rockserver.core.common;
|
||||
|
||||
public record ColumnSchema(int[] keys, int variableLengthKeysCount, boolean hasValue) {
|
||||
public ColumnSchema {
|
||||
if (variableLengthKeysCount > keys.length) {
|
||||
throw new IllegalArgumentException("variable length keys count must be less or equal keysCount");
|
||||
import it.cavallium.rockserver.core.common.RocksDBException.RocksDBErrorType;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public record ColumnSchema(IntList keys, ObjectList<ColumnHashType> variableTailKeys, boolean hasValue) {
|
||||
|
||||
public static ColumnSchema of(IntList fixedKeys, ObjectList<ColumnHashType> variableTailKeys, boolean hasValue) {
|
||||
IntList keys;
|
||||
if (!variableTailKeys.isEmpty()) {
|
||||
keys = new IntArrayList(fixedKeys.size() + variableTailKeys.size());
|
||||
keys.addAll(fixedKeys);
|
||||
for (ColumnHashType variableTailKey : variableTailKeys) {
|
||||
keys.add(variableTailKey.bytesSize());
|
||||
}
|
||||
} else {
|
||||
keys = fixedKeys;
|
||||
}
|
||||
for (int i = 0; i < keys.length - variableLengthKeysCount; i++) {
|
||||
if (keys[i] <= 0) {
|
||||
throw new UnsupportedOperationException("Key length must be > 0");
|
||||
return new ColumnSchema(keys, variableTailKeys, hasValue);
|
||||
}
|
||||
|
||||
public ColumnSchema {
|
||||
final int keysSize = keys.size();
|
||||
final int variableKeysSize = variableTailKeys.size();
|
||||
if (variableKeysSize > keysSize) {
|
||||
throw new RocksDBException(RocksDBErrorType.KEYS_COUNT_MISMATCH, "variable length keys count must be less or equal keysCount");
|
||||
}
|
||||
for (int i = 0; i < keysSize - variableKeysSize; i++) {
|
||||
if (keys.getInt(i) <= 0) {
|
||||
throw new RocksDBException(RocksDBErrorType.KEY_LENGTH_MISMATCH, "Key length must be > 0");
|
||||
}
|
||||
}
|
||||
for (int i = keys.length - variableLengthKeysCount; i < keys.length; i++) {
|
||||
if (keys[i] <= 1) {
|
||||
throw new UnsupportedOperationException("Key hash length must be > 1");
|
||||
for (int i = keysSize - variableKeysSize; i < keysSize; i++) {
|
||||
var hash = variableTailKeys.get(i - (keysSize - variableKeysSize));
|
||||
var keySize = keys.getInt(i);
|
||||
if (keySize != hash.bytesSize()) {
|
||||
throw new RocksDBException(RocksDBErrorType.KEY_HASH_SIZE_MISMATCH, "Key hash length of type " + hash + " must be " + hash.bytesSize() + ", but it's defined as " + keySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,15 +47,39 @@ public record ColumnSchema(int[] keys, int variableLengthKeysCount, boolean hasV
|
||||
* @return an array with the length of each key, variable-length keys must have the length of their hash
|
||||
*/
|
||||
@Override
|
||||
public int[] keys() {
|
||||
public IntList keys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last n keys that are variable-length
|
||||
*/
|
||||
@Override
|
||||
public int variableLengthKeysCount() {
|
||||
return variableLengthKeysCount;
|
||||
return variableTailKeys.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* The first n keys that are fixed
|
||||
*/
|
||||
public int fixedLengthKeysCount() {
|
||||
return keys.size() - variableTailKeys.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* The first n keys that are fixed
|
||||
*/
|
||||
public int keysCount() {
|
||||
return keys.size();
|
||||
}
|
||||
|
||||
public int key(int i) {
|
||||
return keys.getInt(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param absoluteIndex index from the first fixed key
|
||||
*/
|
||||
public ColumnHashType variableTailKey(int absoluteIndex) {
|
||||
return variableTailKeys.get(absoluteIndex - fixedLengthKeysCount());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package it.cavallium.rockserver.core.common;
|
||||
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public interface HashFunction {
|
||||
|
||||
void hash(MemorySegment inputData, MemorySegment hashResult);
|
||||
}
|
@ -5,7 +5,7 @@ public class RocksDBException extends RuntimeException {
|
||||
private final RocksDBErrorType errorUniqueId;
|
||||
|
||||
public enum RocksDBErrorType {
|
||||
PUT_UNKNOWN_ERROR, PUT_2, UNEXPECTED_NULL_VALUE, PUT_1, PUT_3, GET_1, COLUMN_EXISTS, COLUMN_CREATE_FAIL, COLUMN_NOT_FOUND, COLUMN_DELETE_FAIL, CONFIG_ERROR, ROCKSDB_CONFIG_ERROR, VALUE_MUST_BE_NULL, DIRECTORY_DELETE, KEY_LENGTH_MISMATCH, UNSUPPORTED_HASH_SIZE, RAW_KEY_LENGTH_MISMATCH, KEYS_COUNT_MISMATCH, COMMIT_FAILED_TRY_AGAIN, COMMIT_FAILED, TX_NOT_FOUND, ROCKSDB_LOAD_ERROR
|
||||
PUT_UNKNOWN_ERROR, PUT_2, UNEXPECTED_NULL_VALUE, PUT_1, PUT_3, GET_1, COLUMN_EXISTS, COLUMN_CREATE_FAIL, COLUMN_NOT_FOUND, COLUMN_DELETE_FAIL, CONFIG_ERROR, ROCKSDB_CONFIG_ERROR, VALUE_MUST_BE_NULL, DIRECTORY_DELETE, KEY_LENGTH_MISMATCH, UNSUPPORTED_HASH_SIZE, RAW_KEY_LENGTH_MISMATCH, KEYS_COUNT_MISMATCH, COMMIT_FAILED_TRY_AGAIN, COMMIT_FAILED, TX_NOT_FOUND, KEY_HASH_SIZE_MISMATCH, ROCKSDB_LOAD_ERROR
|
||||
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class Utils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemorySegment toMemorySegment(byte @Nullable [] array) {
|
||||
public static MemorySegment toMemorySegment(byte... array) {
|
||||
if (array != null) {
|
||||
return MemorySegment.ofArray(array);
|
||||
} else {
|
||||
@ -59,6 +59,19 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MemorySegment toMemorySegmentSimple(int... array) {
|
||||
if (array != null) {
|
||||
var newArray = new byte[array.length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
newArray[i] = (byte) array[i];
|
||||
}
|
||||
return MemorySegment.ofArray(newArray);
|
||||
} else {
|
||||
return MemorySegment.NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(MemorySegment memorySegment) {
|
||||
return memorySegment.toArray(BIG_ENDIAN_BYTES);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package it.cavallium.rockserver.core.impl;
|
||||
|
||||
import static it.cavallium.rockserver.core.impl.ColumnInstance.BIG_ENDIAN_INT;
|
||||
import static it.cavallium.rockserver.core.impl.ColumnInstance.BIG_ENDIAN_INT_UNALIGNED;
|
||||
import static java.lang.Math.toIntExact;
|
||||
|
||||
import it.cavallium.rockserver.core.common.Utils;
|
||||
@ -122,15 +123,16 @@ public class Bucket {
|
||||
}
|
||||
|
||||
private int indexOf(MemorySegment[] bucketVariableKeys) {
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
nextElement: for (int i = 0; i < elements.size(); i++) {
|
||||
var elem = elements.get(i);
|
||||
var arrayKeys = elem.getKey();
|
||||
assert arrayKeys.length == bucketVariableKeys.length;
|
||||
for (int j = 0; j < arrayKeys.length; j++) {
|
||||
if (Utils.valueEquals(arrayKeys[j], bucketVariableKeys[j])) {
|
||||
return i;
|
||||
if (!Utils.valueEquals(arrayKeys[j], bucketVariableKeys[j])) {
|
||||
continue nextElement;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -157,7 +159,7 @@ public class Bucket {
|
||||
offset += Integer.BYTES;
|
||||
for (MemorySegment elementAtI : serializedElements) {
|
||||
var elementSize = elementAtI.byteSize();
|
||||
segment.set(BIG_ENDIAN_INT, offset, toIntExact(elementSize));
|
||||
segment.set(BIG_ENDIAN_INT_UNALIGNED, offset, toIntExact(elementSize));
|
||||
offset += Integer.BYTES;
|
||||
MemorySegment.copy(elementAtI, 0, segment, offset, elementSize);
|
||||
offset += elementSize;
|
||||
|
@ -69,7 +69,7 @@ public record ColumnInstance(ColumnFamilyHandle cfh, ColumnSchema schema, int fi
|
||||
} else {
|
||||
finalKey = arena.allocate(finalKeySizeBytes);
|
||||
long offsetBytes = 0;
|
||||
for (int i = 0; i < schema.keys().length; i++) {
|
||||
for (int i = 0; i < schema.keys().size(); i++) {
|
||||
var computedKeyAtI = computeKeyAt(arena, i, keys);
|
||||
var computedKeyAtISize = computedKeyAtI.byteSize();
|
||||
MemorySegment.copy(computedKeyAtI, 0, finalKey, offsetBytes, computedKeyAtISize);
|
||||
@ -81,20 +81,18 @@ public record ColumnInstance(ColumnFamilyHandle cfh, ColumnSchema schema, int fi
|
||||
}
|
||||
|
||||
private MemorySegment computeKeyAt(Arena arena, int i, MemorySegment[] keys) {
|
||||
if (i < schema.keys().length - schema.variableLengthKeysCount()) {
|
||||
if (keys[i].byteSize() != schema.keys()[i]) {
|
||||
if (i < schema.keys().size() - schema.variableLengthKeysCount()) {
|
||||
if (keys[i].byteSize() != schema.key(i)) {
|
||||
throw new RocksDBException(RocksDBErrorType.KEY_LENGTH_MISMATCH,
|
||||
"Key at index " + i + " has a different length than expected! Expected: " + schema.keys()[i]
|
||||
"Key at index " + i + " has a different length than expected! Expected: " + schema.key(i)
|
||||
+ ", received: " + keys[i].byteSize());
|
||||
}
|
||||
return keys[i];
|
||||
} else {
|
||||
if (schema.keys()[i] != Integer.BYTES) {
|
||||
throw new RocksDBException(RocksDBErrorType.UNSUPPORTED_HASH_SIZE,
|
||||
"Hash size different than 32-bit is currently unsupported");
|
||||
} else {
|
||||
return XXHash32.getInstance().hash(arena, keys[i], 0, 0, 0);
|
||||
}
|
||||
var tailKey = schema.variableTailKey(i);
|
||||
var hashResult = arena.allocate(tailKey.bytesSize());
|
||||
tailKey.hash(keys[i], hashResult);
|
||||
return hashResult;
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,9 +105,9 @@ public record ColumnInstance(ColumnFamilyHandle cfh, ColumnSchema schema, int fi
|
||||
}
|
||||
|
||||
private void validateKeyCount(MemorySegment[] keys) {
|
||||
if (schema.keys().length != keys.length) {
|
||||
if (schema.keys().size() != keys.length) {
|
||||
throw new RocksDBException(RocksDBErrorType.KEYS_COUNT_MISMATCH,
|
||||
"Keys count must be equal to the column keys count. Expected: " + schema.keys().length
|
||||
"Keys count must be equal to the column keys count. Expected: " + schema.keys().size()
|
||||
+ ", got: " + keys.length);
|
||||
}
|
||||
}
|
||||
@ -172,9 +170,9 @@ public record ColumnInstance(ColumnFamilyHandle cfh, ColumnSchema schema, int fi
|
||||
* Get only the variable-length keys
|
||||
*/
|
||||
public MemorySegment[] getBucketElementKeys(MemorySegment[] keys) {
|
||||
assert keys.length == schema.keys().length;
|
||||
assert keys.length == schema.keys().size();
|
||||
return Arrays.copyOfRange(keys,
|
||||
schema.keys().length - schema.variableLengthKeysCount(),
|
||||
schema.keys().length);
|
||||
schema.keys().size() - schema.variableLengthKeysCount(),
|
||||
schema.keys().size());
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,11 @@ import static java.util.Objects.requireNonNullElse;
|
||||
import static org.rocksdb.KeyMayExist.KeyMayExistEnum.kExistsWithValue;
|
||||
import static org.rocksdb.KeyMayExist.KeyMayExistEnum.kExistsWithoutValue;
|
||||
|
||||
import it.cavallium.rockserver.core.common.Callback.CallbackDelta;
|
||||
import it.cavallium.rockserver.core.common.Callback.CallbackPrevious;
|
||||
import it.cavallium.rockserver.core.common.Callback.CallbackVoid;
|
||||
import it.cavallium.rockserver.core.common.Callback;
|
||||
import it.cavallium.rockserver.core.common.Callback.GetCallback;
|
||||
import it.cavallium.rockserver.core.common.Callback.IteratorCallback;
|
||||
import it.cavallium.rockserver.core.common.Callback.PutCallback;
|
||||
import it.cavallium.rockserver.core.common.ColumnSchema;
|
||||
import it.cavallium.rockserver.core.common.Callback;
|
||||
import it.cavallium.rockserver.core.common.Delta;
|
||||
import it.cavallium.rockserver.core.common.RocksDBAPI;
|
||||
import it.cavallium.rockserver.core.common.RocksDBException.RocksDBErrorType;
|
||||
@ -39,20 +36,18 @@ import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.cliffc.high_scale_lib.NonBlockingHashMapLong;
|
||||
import org.github.gestalt.config.builder.GestaltBuilder;
|
||||
import org.github.gestalt.config.exceptions.GestaltException;
|
||||
import org.github.gestalt.config.source.ClassPathConfigSource;
|
||||
import org.github.gestalt.config.source.ClassPathConfigSourceBuilder;
|
||||
import org.github.gestalt.config.source.FileConfigSource;
|
||||
import org.github.gestalt.config.source.FileConfigSourceBuilder;
|
||||
import org.github.gestalt.config.source.StringConfigSourceBuilder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.rocksdb.*;
|
||||
import org.rocksdb.ColumnFamilyDescriptor;
|
||||
import org.rocksdb.ReadOptions;
|
||||
import org.rocksdb.RocksDB;
|
||||
import org.rocksdb.RocksDBException;
|
||||
import org.rocksdb.RocksIterator;
|
||||
import org.rocksdb.Status.Code;
|
||||
import org.rocksdb.Transaction;
|
||||
import org.rocksdb.WriteOptions;
|
||||
|
||||
public class EmbeddedDB implements RocksDBAPI, Closeable {
|
||||
|
||||
|
@ -34,7 +34,7 @@ public abstract class XXHash32 {
|
||||
* Compute the big-endian 32-bits hash of <code>buf[off:off+len]</code> using seed
|
||||
* <code>seed</code>.
|
||||
*/
|
||||
public abstract MemorySegment hash(Arena arena, MemorySegment buf, int off, int len, int seed);
|
||||
public abstract void hash(MemorySegment buf, int off, int len, int seed, MemorySegment result);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -36,8 +36,8 @@ public final class XXHash32JavaSafe extends XXHash32 {
|
||||
|
||||
public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
|
||||
public static final XXHash32 INSTANCE = new XXHash32JavaSafe();
|
||||
private static final OfInt INT_LE = ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
private static final OfInt INT_BE = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN);
|
||||
private static final OfInt INT_LE = ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
private static final OfInt INT_BE = ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);
|
||||
private static final OfByte BYTE_BE = ValueLayout.JAVA_BYTE.withOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
@Override
|
||||
@ -104,7 +104,7 @@ public final class XXHash32JavaSafe extends XXHash32 {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemorySegment hash(Arena arena, MemorySegment buf, int off, int len, int seed) {
|
||||
public void hash(MemorySegment buf, int off, int len, int seed, MemorySegment result) {
|
||||
checkRange(buf, off, len);
|
||||
|
||||
final int end = off + len;
|
||||
@ -163,7 +163,8 @@ public final class XXHash32JavaSafe extends XXHash32 {
|
||||
h32 *= PRIME3;
|
||||
h32 ^= h32 >>> 16;
|
||||
|
||||
return arena.allocate(INT_BE, h32);
|
||||
assert result.byteSize() >= Integer.BYTES;
|
||||
result.set(INT_BE, 0, h32);
|
||||
}
|
||||
|
||||
private static void checkRange(byte[] buf, int off) {
|
||||
|
@ -8,6 +8,7 @@ module rockserver.core {
|
||||
requires high.scale.lib;
|
||||
requires org.github.gestalt.core;
|
||||
requires org.github.gestalt.hocon;
|
||||
requires it.unimi.dsi.fastutil.core;
|
||||
|
||||
exports it.cavallium.rockserver.core.client;
|
||||
exports it.cavallium.rockserver.core.common;
|
||||
|
@ -1,20 +1,23 @@
|
||||
package it.cavallium.rockserver.core.impl.test;
|
||||
|
||||
import static it.cavallium.rockserver.core.common.Utils.toMemorySegmentSimple;
|
||||
|
||||
import it.cavallium.rockserver.core.client.EmbeddedConnection;
|
||||
import it.cavallium.rockserver.core.common.Callback;
|
||||
import it.cavallium.rockserver.core.common.Callback.CallbackDelta;
|
||||
import it.cavallium.rockserver.core.common.ColumnHashType;
|
||||
import it.cavallium.rockserver.core.common.ColumnSchema;
|
||||
import it.cavallium.rockserver.core.common.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
class EmbeddedDBTest {
|
||||
|
||||
private EmbeddedConnection db;
|
||||
private long colId;
|
||||
private long colId = 0L;
|
||||
|
||||
@org.junit.jupiter.api.BeforeEach
|
||||
void setUp() throws IOException {
|
||||
@ -22,7 +25,21 @@ class EmbeddedDBTest {
|
||||
System.setProperty("rockserver.core.print-config", "false");
|
||||
}
|
||||
db = new EmbeddedConnection(null, "test", null);
|
||||
this.colId = db.createColumn("put-1", new ColumnSchema(new int[]{1, 2, 1, Integer.BYTES, Integer.BYTES}, 2, true));
|
||||
createStandardColumn();
|
||||
}
|
||||
|
||||
private void createStandardColumn() {
|
||||
createColumn(ColumnSchema.of(IntList.of(1, 2, 1),
|
||||
ObjectList.of(ColumnHashType.XXHASH32, ColumnHashType.XXHASH32),
|
||||
true
|
||||
));
|
||||
}
|
||||
|
||||
private void createColumn(ColumnSchema schema) {
|
||||
if (colId != 0L) {
|
||||
db.deleteColumn(colId);
|
||||
}
|
||||
colId = db.createColumn("column-test", schema);
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.AfterEach
|
||||
@ -32,13 +49,13 @@ class EmbeddedDBTest {
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
void put() {
|
||||
void putSameBucketSameKey() {
|
||||
var key = new MemorySegment[] {
|
||||
Utils.toMemorySegment(new byte[] {3}),
|
||||
Utils.toMemorySegment(new byte[] {4, 6}),
|
||||
Utils.toMemorySegment(new byte[] {3}),
|
||||
Utils.toMemorySegment(new byte[] {1, 2, 3}),
|
||||
Utils.toMemorySegment(new byte[] {0, 0, 3, 6, 7, 8})
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
toMemorySegmentSimple(0, 0, 3, 6, 7, 8)
|
||||
};
|
||||
var value1 = MemorySegment.ofArray(new byte[] {0, 0, 3});
|
||||
var value2 = MemorySegment.ofArray(new byte[] {0, 0, 5});
|
||||
@ -52,6 +69,101 @@ class EmbeddedDBTest {
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value2));
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
void putSameBucketDifferentKey() {
|
||||
createColumn(ColumnSchema.of(IntList.of(1, 2, 1), ObjectList.of(ColumnHashType.XXHASH32, ColumnHashType.ALLSAME8), true));
|
||||
|
||||
var lastKey1 = toMemorySegmentSimple(6, 7, 8);
|
||||
var lastKey2 = toMemorySegmentSimple(6, 7, -48);
|
||||
|
||||
var key1 = new MemorySegment[] {
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
lastKey1
|
||||
};
|
||||
var key2 = new MemorySegment[] {
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
lastKey2
|
||||
};
|
||||
|
||||
var value1 = MemorySegment.ofArray(new byte[] {0, 0, 3});
|
||||
var value2 = MemorySegment.ofArray(new byte[] {0, 0, 5});
|
||||
|
||||
var delta = db.put(0, colId, key1, value1, Callback.delta());
|
||||
Assertions.assertNull(delta.previous());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value1));
|
||||
|
||||
delta = db.put(0, colId, key2, value2, Callback.delta());
|
||||
Assertions.assertNull(delta.previous());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value2));
|
||||
|
||||
delta = db.put(0, colId, key2, value1, Callback.delta());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.previous(), value2));
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Some keys have same bucket, some not
|
||||
*/
|
||||
@org.junit.jupiter.api.Test
|
||||
void putMixedBucketMixedKey() {
|
||||
createColumn(ColumnSchema.of(IntList.of(1, 2, 1), ObjectList.of(ColumnHashType.XXHASH32, ColumnHashType.XXHASH8), true));
|
||||
|
||||
var lastKey1 = toMemorySegmentSimple(6, 7, 8);
|
||||
var collidingLastKey1 = toMemorySegmentSimple(6, 7, -48);
|
||||
var lastKey2 = toMemorySegmentSimple(6, 7, 7);
|
||||
|
||||
var key1 = new MemorySegment[] {
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
lastKey1
|
||||
};
|
||||
var collidingKey1 = new MemorySegment[] {
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
collidingLastKey1
|
||||
};
|
||||
var key2 = new MemorySegment[] {
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(4, 6),
|
||||
toMemorySegmentSimple(3),
|
||||
toMemorySegmentSimple(1, 2, 3),
|
||||
lastKey2
|
||||
};
|
||||
|
||||
var value1 = MemorySegment.ofArray(new byte[] {0, 0, 3});
|
||||
var value2 = MemorySegment.ofArray(new byte[] {0, 0, 5});
|
||||
|
||||
var delta = db.put(0, colId, key1, value1, Callback.delta());
|
||||
Assertions.assertNull(delta.previous());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value1));
|
||||
|
||||
delta = db.put(0, colId, collidingKey1, value2, Callback.delta());
|
||||
Assertions.assertNull(delta.previous());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value2));
|
||||
|
||||
delta = db.put(0, colId, collidingKey1, value1, Callback.delta());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.previous(), value2));
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value1));
|
||||
|
||||
delta = db.put(0, colId, key2, value1, Callback.delta());
|
||||
Assertions.assertNull(delta.previous());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value1));
|
||||
|
||||
delta = db.put(0, colId, key2, value2, Callback.delta());
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.previous(), value1));
|
||||
Assertions.assertTrue(Utils.valueEquals(delta.current(), value2));
|
||||
}
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
void get() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -26,7 +26,8 @@ public class XXHash32Test {
|
||||
ThreadLocalRandom.current().nextBytes(bytes);
|
||||
var hash = safeXxhash32.hash(bytes, 0, bytes.length, Integer.MIN_VALUE);
|
||||
var a = Arena.global();
|
||||
var result = myXxhash32.hash(a, a.allocateArray(OfByte.JAVA_BYTE, bytes), 0, bytes.length, Integer.MIN_VALUE);
|
||||
var result = a.allocate(Integer.BYTES);
|
||||
myXxhash32.hash(a.allocateArray(OfByte.JAVA_BYTE, bytes), 0, bytes.length, Integer.MIN_VALUE, result);
|
||||
var resultInt = result.get(ColumnInstance.BIG_ENDIAN_INT, 0);
|
||||
Assertions.assertEquals(hash, resultInt);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ module rockserver.core.test {
|
||||
requires org.lz4.java;
|
||||
requires rockserver.core;
|
||||
requires org.junit.jupiter.api;
|
||||
requires it.unimi.dsi.fastutil.core;
|
||||
opens it.cavallium.rockserver.core.test;
|
||||
opens it.cavallium.rockserver.core.impl.test;
|
||||
}
|
Loading…
Reference in New Issue
Block a user