diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/ResourceTypes.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/ResourceTypes.java index a4b128862c49f..cdc854579421c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/ResourceTypes.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/ResourceTypes.java @@ -99,7 +99,7 @@ public static long indexEntryResourceId( long labelId, IndexQuery.ExactPredicate if ( !useStrongHashing ) { // Default - return indexEntryResourceId_2_2_0( labelId, predicates, 0 ); + return indexEntryResourceId_2_2_0( labelId, predicates ); } else { @@ -108,6 +108,11 @@ public static long indexEntryResourceId( long labelId, IndexQuery.ExactPredicate } } + static long indexEntryResourceId_2_2_0( long labelId, IndexQuery.ExactPredicate[] predicates ) + { + return indexEntryResourceId_2_2_0( labelId, predicates, 0 ); + } + private static long indexEntryResourceId_2_2_0( long labelId, IndexQuery.ExactPredicate[] predicates, int i ) { int propertyKeyId = predicates[i].propertyKeyId(); @@ -167,7 +172,7 @@ public static ResourceType fromId( int typeId ) * * @see HashFunction#incrementalXXH64() */ - private static long indexEntryResourceId_4_x( long labelId, IndexQuery.ExactPredicate... predicates ) + static long indexEntryResourceId_4_x( long labelId, IndexQuery.ExactPredicate[] predicates ) { long hash = indexEntryHash_4_x.initialise( 0x0123456789abcdefL ); @@ -209,18 +214,32 @@ else if ( type.isArray() ) hash = indexEntryHash_4_x.update( hash, len ); - for ( int j = 0; i < len; j++ ) + for ( int j = 0; j < len; j++ ) { hash = indexEntryHash_4_x.update( hash, str.charAt( j ) ); } } } - else if ( componentType == Double.class ) + else if ( componentType == Double.TYPE ) { for ( int i = 0; i < length; i++ ) { hash = indexEntryHash_4_x.update( - hash, Double.doubleToLongBits( (Double) Array.get( value, i ) ) ); + hash, Double.doubleToLongBits( Array.getDouble( value, i ) ) ); + } + } + else if ( componentType == Boolean.TYPE ) + { + for ( int i = 0; i < length; i++ ) + { + hash = indexEntryHash_4_x.update( hash, Boolean.hashCode( Array.getBoolean( value, i ) ) ); + } + } + else if ( componentType == Character.TYPE ) + { + for ( int i = 0; i < length; i++ ) + { + hash = indexEntryHash_4_x.update( hash, Array.getChar( value, i ) ); } } else @@ -235,6 +254,14 @@ else if ( type == Double.class ) { hash = indexEntryHash_4_x.update( hash, Double.doubleToLongBits( (Double) value ) ); } + else if ( type == Boolean.class ) + { + hash = indexEntryHash_4_x.update( hash, value.hashCode() ); + } + else if ( type == Character.class ) + { + hash = indexEntryHash_4_x.update( hash, (char) value ); + } else { hash = indexEntryHash_4_x.update( hash, ((Number) value).longValue() ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/IndexEntryResourceTypesTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/IndexEntryResourceTypesTest.java index 4a2a59e25f990..3fe47b3ef62cf 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/IndexEntryResourceTypesTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/IndexEntryResourceTypesTest.java @@ -26,12 +26,12 @@ import java.util.Set; import org.neo4j.helpers.collection.Iterables; -import org.neo4j.kernel.api.schema.IndexQuery; import org.neo4j.kernel.api.schema.IndexQuery.ExactPredicate; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.neo4j.helpers.collection.Iterators.array; +import static org.neo4j.kernel.api.schema.IndexQuery.exact; public class IndexEntryResourceTypesTest { @@ -43,30 +43,192 @@ public class IndexEntryResourceTypesTest @Test public void shouldProduceBackwardsCompatibleId() { - long id = ResourceTypes.indexEntryResourceId( labelId, IndexQuery.exact( propertyId, value ) ); + long id = ResourceTypes.indexEntryResourceId( labelId, exact( propertyId, value ) ); assertThat( id, equalTo( 155667838465249649L ) ); } @Test public void shouldDifferentiateBetweenIndexes() { - - ExactPredicate pred1 = IndexQuery.exact( 1, "value" ); - ExactPredicate pred2 = IndexQuery.exact( 1, "value2" ); - ExactPredicate pred3 = IndexQuery.exact( 2, "value" ); - ExactPredicate pred4 = IndexQuery.exact( 2, "value2" ); + ExactPredicate pred1 = exact( 1, "value" ); + ExactPredicate pred2 = exact( 1, "value2" ); + ExactPredicate pred3 = exact( 2, "value" ); + ExactPredicate pred4 = exact( 2, "value2" ); List ids = Arrays.asList( - ResourceTypes.indexEntryResourceId( 1, array( pred1 ) ), - ResourceTypes.indexEntryResourceId( 1, array( pred2 ) ), - ResourceTypes.indexEntryResourceId( 1, array( pred3 ) ), - ResourceTypes.indexEntryResourceId( 1, array( pred4 ) ), - ResourceTypes.indexEntryResourceId( 2, array( pred1 ) ), - ResourceTypes.indexEntryResourceId( 1, array( pred1, pred2 ) ), - ResourceTypes.indexEntryResourceId( 1, array( pred1, pred2, pred3 ) ), - ResourceTypes.indexEntryResourceId( 2, array( pred1, pred2, pred3, pred4 ) ) ); + ResourceTypes.indexEntryResourceId( 1, array( pred1 ) ), + ResourceTypes.indexEntryResourceId( 1, array( pred2 ) ), + ResourceTypes.indexEntryResourceId( 1, array( pred3 ) ), + ResourceTypes.indexEntryResourceId( 1, array( pred4 ) ), + ResourceTypes.indexEntryResourceId( 2, array( pred1 ) ), + ResourceTypes.indexEntryResourceId( 1, array( pred1, pred2 ) ), + ResourceTypes.indexEntryResourceId( 1, array( pred1, pred2, pred3 ) ), + ResourceTypes.indexEntryResourceId( 2, array( pred1, pred2, pred3, pred4 ) ) ); Set uniqueIds = Iterables.asSet( ids ); assertThat( ids.size(), equalTo( uniqueIds.size() ) ); } + + @Test + public void mustBeAbleToHashAllTypesWith220HashFunction() throws Exception + { + verifyCanHashAllTypes( ResourceTypes::indexEntryResourceId_2_2_0 ); + } + + @Test + public void mustBeAbleToHashAllTypesWith4xHashFunction() throws Exception + { + verifyCanHashAllTypes( ResourceTypes::indexEntryResourceId_4_x ); + } + + private interface IndexEntryHasher + { + long hash( long labelId, ExactPredicate[] predicates ); + } + + @SuppressWarnings( {"UnnecessaryBoxing", "BooleanConstructorCall"} ) + private void verifyCanHashAllTypes( IndexEntryHasher hasher ) + { + hasher.hash( 42, array( exact( 1, "" ) ) ); + hasher.hash( 42, array( exact( 1, "a" ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{""} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{"a"} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{"a", "b"} ) ) ); + hasher.hash( 42, array( exact( 1, true ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{true} ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{true, false} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean( true ) ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{true} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{true, false} ) ) ); + hasher.hash( 42, array( exact( 1, (byte) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte( (byte) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, (short) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Short( (short) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, 'a' ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{'a'} ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{'a', 'b'} ) ) ); + hasher.hash( 42, array( exact( 1, new Character( 'a' ) ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{'a'} ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{'a', 'b'} ) ) ); + hasher.hash( 42, array( exact( 1, (float) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Float( (float) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{1.0f} ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{1.0f, 2.0f} ) ) ); + hasher.hash( 42, array( exact( 1, 1 ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer( 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, 1 ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Long( 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{1L} ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{1L, 2L} ) ) ); + hasher.hash( 42, array( exact( 1, 1.0 ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Double( 1.0 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{1.0} ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{1.0, 2.0} ) ) ); + + hasher.hash( 42, array( exact( 1, "" ), exact( ~1, "" ) ) ); + hasher.hash( 42, array( exact( 1, "a" ), exact( ~1, "a" ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{} ), exact( ~1, new String[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{""} ), exact( ~1, new String[]{""} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{"a"} ), exact( ~1, new String[]{"a"} ) ) ); + hasher.hash( 42, array( exact( 1, new String[]{"a", "b"} ), exact( ~1, new String[]{"a", "b"} ) ) ); + hasher.hash( 42, array( exact( 1, true ), exact( ~1, true ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{} ), exact( ~1, new boolean[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{true} ), exact( ~1, new boolean[]{true} ) ) ); + hasher.hash( 42, array( exact( 1, new boolean[]{true, false} ), exact( ~1, new boolean[]{true, false} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean( true ) ), exact( ~1, new Boolean( true ) ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{} ), exact( ~1, new Boolean[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{true} ), exact( ~1, new Boolean[]{true} ) ) ); + hasher.hash( 42, array( exact( 1, new Boolean[]{true, false} ), exact( ~1, new Boolean[]{true, false} ) ) ); + hasher.hash( 42, array( exact( 1, (byte) 1 ), exact( ~1, (byte) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{} ), exact( ~1, new byte[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{1} ), exact( ~1, new byte[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new byte[]{1, 2} ), exact( ~1, new byte[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte( (byte) 1 ) ), exact( ~1, new Byte( (byte) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{} ), exact( ~1, new Byte[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{1} ), exact( ~1, new Byte[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Byte[]{1, 2} ), exact( ~1, new Byte[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, (short) 1 ), exact( ~1, (short) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{} ), exact( ~1, new short[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{1} ), exact( ~1, new short[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new short[]{1, 2} ), exact( ~1, new short[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Short( (short) 1 ) ), exact( ~1, new Short( (short) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{} ), exact( ~1, new Short[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{1} ), exact( ~1, new Short[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Short[]{1, 2} ), exact( ~1, new Short[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, 'a' ), exact( ~1, 'a' ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{} ), exact( ~1, new char[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{'a'} ), exact( ~1, new char[]{'a'} ) ) ); + hasher.hash( 42, array( exact( 1, new char[]{'a', 'b'} ), exact( ~1, new char[]{'a', 'b'} ) ) ); + hasher.hash( 42, array( exact( 1, new Character( 'a' ) ), exact( ~1, new Character( 'a' ) ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{} ), exact( ~1, new Character[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{'a'} ), exact( ~1, new Character[]{'a'} ) ) ); + hasher.hash( 42, array( exact( 1, new Character[]{'a', 'b'} ), exact( ~1, new Character[]{'a', 'b'} ) ) ); + hasher.hash( 42, array( exact( 1, (float) 1 ), exact( ~1, (float) 1 ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{} ), exact( ~1, new float[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{1} ), exact( ~1, new float[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new float[]{1, 2} ), exact( ~1, new float[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Float( (float) 1 ) ), exact( ~1, new Float( (float) 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{} ), exact( ~1, new Float[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{1.0f} ), exact( ~1, new Float[]{1.0f} ) ) ); + hasher.hash( 42, array( exact( 1, new Float[]{1.0f, 2.0f} ), exact( ~1, new Float[]{1.0f, 2.0f} ) ) ); + hasher.hash( 42, array( exact( 1, 1 ), exact( ~1, 1 ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{} ), exact( ~1, new int[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{1} ), exact( ~1, new int[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new int[]{1, 2} ), exact( ~1, new int[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer( 1 ) ), exact( ~1, new Integer( 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{} ), exact( ~1, new Integer[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{1} ), exact( ~1, new Integer[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new Integer[]{1, 2} ), exact( ~1, new Integer[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, 1 ), exact( ~1, 1 ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{} ), exact( ~1, new long[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{1} ), exact( ~1, new long[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new long[]{1, 2} ), exact( ~1, new long[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Long( 1 ) ), exact( ~1, new Long( 1 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{} ), exact( ~1, new Long[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{1L} ), exact( ~1, new Long[]{1L} ) ) ); + hasher.hash( 42, array( exact( 1, new Long[]{1L, 2L} ), exact( ~1, new Long[]{1L, 2L} ) ) ); + hasher.hash( 42, array( exact( 1, 1.0 ), exact( ~1, 1.0 ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{} ), exact( ~1, new double[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{1} ), exact( ~1, new double[]{1} ) ) ); + hasher.hash( 42, array( exact( 1, new double[]{1, 2} ), exact( ~1, new double[]{1, 2} ) ) ); + hasher.hash( 42, array( exact( 1, new Double( 1.0 ) ), exact( ~1, new Double( 1.0 ) ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{} ), exact( ~1, new Double[]{} ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{1.0} ), exact( ~1, new Double[]{1.0} ) ) ); + hasher.hash( 42, array( exact( 1, new Double[]{1.0, 2.0} ), exact( ~1, new Double[]{1.0, 2.0} ) ) ); + } }