Skip to content

Commit

Permalink
Thoroughly test index entry hashing of all property types and fix a f…
Browse files Browse the repository at this point in the history
…ew bugs
  • Loading branch information
chrisvest committed Aug 24, 2017
1 parent a77d570 commit 10c227f
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 20 deletions.
Expand Up @@ -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
{
Expand All @@ -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();
Expand Down Expand Up @@ -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 );

Expand Down Expand Up @@ -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
Expand All @@ -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() );
Expand Down
Expand Up @@ -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
{
Expand All @@ -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<Long> 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<Long> 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} ) ) );
}
}

0 comments on commit 10c227f

Please sign in to comment.