mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-11-14 06:45:21 +00:00
ENH: Optimized binary form for UUID (Type 1) (#1308)
* ENH: Optimized binary form for UUID (Type 1) * added missing parameter in test
This commit is contained in:
1 parent
18ca3403ac
commit
e252f71792
9 files changed
+126
-47
No files matched your search
@@ -3033,37 +3033,51 @@ public class ServerConfig {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Specify how UUID is stored.
|
||||
*/
|
||||
public enum DbUuid {
|
||||
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
AUTO_VARCHAR(true, false),
|
||||
AUTO_VARCHAR(true, false, false),
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
|
||||
*/
|
||||
AUTO_BINARY(true, true),
|
||||
AUTO_BINARY(true, true, false),
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing.
|
||||
*/
|
||||
AUTO_BINARY_OPTIMIZED(true, true, true),
|
||||
|
||||
/**
|
||||
* Store using DB VARCHAR(40).
|
||||
*/
|
||||
VARCHAR(false, false),
|
||||
VARCHAR(false, false, false),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY(16).
|
||||
*/
|
||||
BINARY(false, true);
|
||||
BINARY(false, true, false),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY(16).
|
||||
*/
|
||||
BINARY_OPTIMIZED(false, true, true);
|
||||
|
||||
boolean nativeType;
|
||||
boolean binary;
|
||||
boolean binaryOptimized;
|
||||
|
||||
DbUuid(boolean nativeType, boolean binary) {
|
||||
DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) {
|
||||
this.nativeType = nativeType;
|
||||
this.binary = binary;
|
||||
this.binaryOptimized = binaryOptimized;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3079,5 +3093,12 @@ public class ServerConfig {
|
||||
public boolean useBinary() {
|
||||
return binary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if optimized packing should be used.
|
||||
*/
|
||||
public boolean useBinaryOptimized() {
|
||||
return binaryOptimized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public final class BasicTypeConverter implements Serializable {
|
||||
/**
|
||||
* Convert the value to a UUID.
|
||||
*/
|
||||
public static UUID toUUID(Object value) {
|
||||
public static UUID toUUID(Object value, boolean optimizedBinary) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
@@ -188,7 +188,7 @@ public final class BasicTypeConverter implements Serializable {
|
||||
return UUID.fromString((String) value);
|
||||
}
|
||||
if (value instanceof byte[]) {
|
||||
return ScalarTypeUUIDBinary.convertFromBytes((byte[]) value);
|
||||
return ScalarTypeUUIDBinary.convertFromBytes((byte[]) value, optimizedBinary);
|
||||
}
|
||||
return UUID.fromString(value.toString());
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebean.SqlQuery;
|
||||
import io.ebean.SqlRow;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.util.JdbcClose;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiSqlQuery;
|
||||
@@ -173,8 +174,8 @@ public final class RelationalQueryRequest {
|
||||
* Read and return the next SqlRow.
|
||||
*/
|
||||
public SqlRow createNewRow(String dbTrueValue) throws SQLException {
|
||||
|
||||
SqlRow sqlRow = new DefaultSqlRow(estimateCapacity, 0.75f, dbTrueValue);
|
||||
ServerConfig.DbUuid dbUuid = ebeanServer.getServerConfig().getDbTypeConfig().getDbUuid();
|
||||
SqlRow sqlRow = new DefaultSqlRow(estimateCapacity, 0.75f, dbTrueValue, dbUuid.useBinaryOptimized());
|
||||
|
||||
int index = 0;
|
||||
for (String propertyName : propertyNames) {
|
||||
|
||||
@@ -34,6 +34,7 @@ public class DefaultSqlRow implements SqlRow {
|
||||
private static final long serialVersionUID = -3120927797041336242L;
|
||||
|
||||
private final String dbTrueValue;
|
||||
private final boolean optimizedBinaryUUID;
|
||||
|
||||
/**
|
||||
* The underlying map of property data.
|
||||
@@ -50,9 +51,10 @@ public class DefaultSqlRow implements SqlRow {
|
||||
* this map reaches its threshold (initialCapacity * loadFactor).
|
||||
* </p>
|
||||
*/
|
||||
public DefaultSqlRow(int initialCapacity, float loadFactor, String dbTrueValue) {
|
||||
public DefaultSqlRow(int initialCapacity, float loadFactor, String dbTrueValue, boolean optimizedBinaryUUID) {
|
||||
this.map = new LinkedHashMap<>(initialCapacity, loadFactor);
|
||||
this.dbTrueValue = dbTrueValue;
|
||||
this.optimizedBinaryUUID = optimizedBinaryUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,7 +95,7 @@ public class DefaultSqlRow implements SqlRow {
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String name) {
|
||||
return BasicTypeConverter.toUUID(get(name));
|
||||
return BasicTypeConverter.toUUID(get(name), optimizedBinaryUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -931,7 +931,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
typeMap.put(UUID.class, new ScalarTypeUUIDNative());
|
||||
} else {
|
||||
// Store UUID as binary(16) or varchar(40)
|
||||
ScalarType<?> uuidType = dbUuid.useBinary() ? new ScalarTypeUUIDBinary() : new ScalarTypeUUIDVarchar();
|
||||
ScalarType<?> uuidType = dbUuid.useBinary() ? new ScalarTypeUUIDBinary(dbUuid.useBinaryOptimized()) : new ScalarTypeUUIDVarchar();
|
||||
typeMap.put(UUID.class, uuidType);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public abstract class ScalarTypeUUIDBase extends ScalarTypeBase<UUID> implements
|
||||
|
||||
@Override
|
||||
public UUID toBeanType(Object value) {
|
||||
return BasicTypeConverter.toUUID(value);
|
||||
return BasicTypeConverter.toUUID(value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,19 +2,18 @@ package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebeaninternal.server.core.BasicTypeConverter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ScalarTypeUUIDBinary extends ScalarTypeUUIDBase {
|
||||
|
||||
protected ScalarTypeUUIDBinary() {
|
||||
private final boolean optimized;
|
||||
|
||||
|
||||
protected ScalarTypeUUIDBinary(boolean optimized) {
|
||||
super(false, Types.BINARY);
|
||||
this.optimized = optimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -24,15 +23,15 @@ public class ScalarTypeUUIDBinary extends ScalarTypeUUIDBase {
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return convertToBytes(value);
|
||||
return convertToBytes(value, optimized);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID toBeanType(Object value) {
|
||||
if (value instanceof byte[]) {
|
||||
return convertFromBytes((byte[]) value);
|
||||
return convertFromBytes((byte[]) value, optimized);
|
||||
} else {
|
||||
return BasicTypeConverter.toUUID(value);
|
||||
return BasicTypeConverter.toUUID(value, optimized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +40,7 @@ public class ScalarTypeUUIDBinary extends ScalarTypeUUIDBase {
|
||||
if (value == null) {
|
||||
b.setNull(Types.BINARY);
|
||||
} else {
|
||||
b.setBytes(convertToBytes(value));
|
||||
b.setBytes(convertToBytes(value, optimized));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +50,14 @@ public class ScalarTypeUUIDBinary extends ScalarTypeUUIDBase {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
} else {
|
||||
return convertFromBytes(bytes);
|
||||
return convertFromBytes(bytes, optimized);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from byte[] to UUID.
|
||||
*/
|
||||
public static UUID convertFromBytes(byte[] bytes) {
|
||||
public static UUID convertFromBytes(byte[] bytes, boolean optimized) {
|
||||
|
||||
int usableBytes = Math.min(bytes.length, 16);
|
||||
|
||||
@@ -70,36 +69,80 @@ public class ScalarTypeUUIDBinary extends ScalarTypeUUIDBase {
|
||||
barr[i] = bytes[j];
|
||||
}
|
||||
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(barr);
|
||||
DataInputStream inputStream = new DataInputStream(bais);
|
||||
|
||||
try {
|
||||
long msb = inputStream.readLong();
|
||||
long lsb = inputStream.readLong();
|
||||
return new UUID(msb, lsb);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Not Expecting this", e);
|
||||
long msb;
|
||||
if (optimized) {
|
||||
msb = ((long)barr[4] << 56) + // XXXXXXXX-____-____-...
|
||||
((long)(barr[5] & 255) << 48) + // -> put at end 4..7 of buf
|
||||
((long)(barr[6] & 255) << 40) +
|
||||
((long)(barr[7] & 255) << 32) +
|
||||
((long)(barr[2] & 255) << 24) + // ________-XXXX-____-...
|
||||
((barr[3] & 255) << 16) + // put at 2..3 in buf
|
||||
((barr[0] & 255) << 8) + // ________-____-XXXX-...
|
||||
((barr[1] & 255) << 0); // put at 0..1 in buf
|
||||
} else {
|
||||
msb = ((long)barr[0] << 56) + // XXXXXXXX-____-____-...
|
||||
((long)(barr[1] & 255) << 48) +
|
||||
((long)(barr[2] & 255) << 40) +
|
||||
((long)(barr[3] & 255) << 32) +
|
||||
((long)(barr[4] & 255) << 24) + // ________-XXXX-____-...
|
||||
((barr[5] & 255) << 16) +
|
||||
((barr[6] & 255) << 8) + // ________-____-XXXX-...
|
||||
((barr[7] & 255) << 0);
|
||||
}
|
||||
long lsb = ((long)barr[8] << 56) +
|
||||
((long)(barr[9] & 255) << 48) +
|
||||
((long)(barr[10] & 255) << 40) +
|
||||
((long)(barr[11] & 255) << 32) +
|
||||
((long)(barr[12] & 255) << 24) +
|
||||
((barr[13] & 255) << 16) +
|
||||
((barr[14] & 255) << 8) +
|
||||
((barr[15] & 255) << 0);
|
||||
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from UUID to byte[].
|
||||
*/
|
||||
public static byte[] convertToBytes(Object value) {
|
||||
public static byte[] convertToBytes(Object value, boolean optimized) {
|
||||
|
||||
|
||||
UUID uuid = (UUID) value;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(16);
|
||||
DataOutputStream outputStream = new DataOutputStream(baos);
|
||||
byte[] ret = new byte[16];
|
||||
long l = uuid.getMostSignificantBits();
|
||||
|
||||
try {
|
||||
outputStream.writeLong(uuid.getMostSignificantBits());
|
||||
outputStream.writeLong(uuid.getLeastSignificantBits());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Not Expecting this", e);
|
||||
if (optimized) {
|
||||
ret[0] = (byte) (l >>> 8); // was 6/7
|
||||
ret[1] = (byte) (l >>> 0);
|
||||
|
||||
ret[2] = (byte) (l >>> 24); // was 4/5
|
||||
ret[3] = (byte) (l >>> 16);
|
||||
|
||||
ret[4] = (byte) (l >>> 56); // was 0..3
|
||||
ret[5] = (byte) (l >>> 48);
|
||||
ret[6] = (byte) (l >>> 40);
|
||||
ret[7] = (byte) (l >>> 32);
|
||||
} else {
|
||||
ret[0] = (byte) (l >>> 56);
|
||||
ret[1] = (byte) (l >>> 48);
|
||||
ret[2] = (byte) (l >>> 40);
|
||||
ret[3] = (byte) (l >>> 32);
|
||||
ret[4] = (byte) (l >>> 24);
|
||||
ret[5] = (byte) (l >>> 16);
|
||||
ret[6] = (byte) (l >>> 8);
|
||||
ret[7] = (byte) (l >>> 0);
|
||||
}
|
||||
l = uuid.getLeastSignificantBits();
|
||||
ret[8] = (byte) (l >>> 56);
|
||||
ret[9] = (byte) (l >>> 48);
|
||||
ret[10] = (byte) (l >>> 40);
|
||||
ret[11] = (byte) (l >>> 32);
|
||||
ret[12] = (byte) (l >>> 24);
|
||||
ret[13] = (byte) (l >>> 16);
|
||||
ret[14] = (byte) (l >>> 8);
|
||||
ret[15] = (byte) (l >>> 0);
|
||||
|
||||
return baos.toByteArray();
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public class DefaultSqlRowTest {
|
||||
@Test
|
||||
public void test_keyConversion() {
|
||||
|
||||
DefaultSqlRow row = new DefaultSqlRow(16, 0.5f, "T");
|
||||
DefaultSqlRow row = new DefaultSqlRow(16, 0.5f, "T", false);
|
||||
row.put("Foo", "hello");
|
||||
|
||||
assertThat(row.containsKey("foo")).isTrue();
|
||||
|
||||
@@ -12,10 +12,22 @@ public class TestScalarTypeUUIDBinaryConversion {
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
byte[] bytes = ScalarTypeUUIDBinary.convertToBytes(id);
|
||||
byte[] bytes = ScalarTypeUUIDBinary.convertToBytes(id, false);
|
||||
Assert.assertEquals(16, bytes.length);
|
||||
|
||||
UUID id2 = ScalarTypeUUIDBinary.convertFromBytes(bytes);
|
||||
UUID id2 = ScalarTypeUUIDBinary.convertFromBytes(bytes, false);
|
||||
Assert.assertEquals(id, id2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConversionOptimized() {
|
||||
|
||||
UUID id = UUID.randomUUID();
|
||||
|
||||
byte[] bytes = ScalarTypeUUIDBinary.convertToBytes(id, true);
|
||||
Assert.assertEquals(16, bytes.length);
|
||||
|
||||
UUID id2 = ScalarTypeUUIDBinary.convertFromBytes(bytes, true);
|
||||
Assert.assertEquals(id, id2);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user