diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexUpdater.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexUpdater.java index 1b296a2b0135f..e2275c0506701 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexUpdater.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexUpdater.java @@ -104,7 +104,7 @@ private void assertOpen() } private static void processRemove( KEY treeKey, - IndexEntryUpdate update, Writer writer ) throws IOException + IndexEntryUpdate update, Writer writer ) throws IOException { // todo Do we need to verify that we actually removed something at all? // todo Difference between online and recovery? @@ -113,7 +113,7 @@ private static void processRe } private static void processChange( KEY treeKey, VALUE treeValue, - IndexEntryUpdate update, Writer writer, + IndexEntryUpdate update, Writer writer, ConflictDetectingValueMerger conflictDetectingValueMerger ) throws IOException, IndexEntryConflictException { @@ -128,7 +128,7 @@ private static void processCh } static void processAdd( KEY treeKey, VALUE treeValue, - IndexEntryUpdate update, Writer writer, + IndexEntryUpdate update, Writer writer, ConflictDetectingValueMerger conflictDetectingValueMerger ) throws IOException, IndexEntryConflictException { @@ -138,7 +138,7 @@ static void processAdd( KEY t assertNoConflict( update, conflictDetectingValueMerger ); } - private static void assertNoConflict( IndexEntryUpdate update, + private static void assertNoConflict( IndexEntryUpdate update, ConflictDetectingValueMerger conflictDetectingValueMerger ) throws IndexEntryConflictException { if ( conflictDetectingValueMerger.wasConflict() ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NonUniqueNumberLayout.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NonUniqueNumberLayout.java index f7c363b3926c9..e177394bb31b0 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NonUniqueNumberLayout.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NonUniqueNumberLayout.java @@ -35,7 +35,7 @@ public long identifier() @Override public int compare( NumberKey o1, NumberKey o2 ) { - int compare = Double.compare( o1.value, o2.value ); - return compare != 0 ? compare : Long.compare( o1.entityId, o2.entityId ); + int comparison = o1.compareValueTo( o2 ); + return comparison != 0 ? comparison : Long.compare( o1.entityId, o2.entityId ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberKey.java index 867cf322a2eec..ddf49e4bc19d9 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberKey.java @@ -25,18 +25,28 @@ import static org.neo4j.kernel.impl.index.schema.NumberValueConversion.assertValidSingleNumber; /** - * Includes comparison value and entity id (to be able to handle non-unique values). - * Comparison value is basically any number as a double, a conversion which is lossy by nature, - * especially for higher decimal values. Actual value is stored in {@link NumberValue} - * for ability to filter accidental coersions directly internally. + * Includes value and entity id (to be able to handle non-unique values). + * A value can be any {@link Number} and is represented as a {@code long} to store the raw bits and a type + * to say if it's a long, double or float. + * + * Distinction between double and float exists because coersions between each other and long may differ. + * TODO this should be figured out and potentially reduced to long, double types only. */ class NumberKey { static final int SIZE = - Long.SIZE + /* compare value (double represented by long) */ - Long.SIZE; /* entityId */ + Byte.BYTES + /* type of value */ + Long.BYTES + /* raw value bits */ + + // TODO this could use 6 bytes instead and have the highest 2 bits stored in the type byte + Long.BYTES; /* entityId */ + + static final byte TYPE_LONG = 0; + static final byte TYPE_FLOAT = 1; + static final byte TYPE_DOUBLE = 2; - double value; + byte type; + long rawValueBits; long entityId; /** @@ -48,35 +58,126 @@ class NumberKey */ boolean entityIdIsSpecialTieBreaker; - public void from( long entityId, Value[] values ) + void from( long entityId, Value[] values ) { - this.value = assertValidSingleNumber( values ).doubleValue(); + extractValue( assertValidSingleNumber( values ) ); this.entityId = entityId; entityIdIsSpecialTieBreaker = false; } String propertiesAsString() { - return String.valueOf( value ); + return String.valueOf( toNumberValue() ); } void initAsLowest() { - value = Double.NEGATIVE_INFINITY; + rawValueBits = Double.doubleToLongBits( Double.NEGATIVE_INFINITY ); + type = TYPE_DOUBLE; entityId = Long.MIN_VALUE; entityIdIsSpecialTieBreaker = true; } void initAsHighest() { - value = Double.POSITIVE_INFINITY; + rawValueBits = Double.doubleToLongBits( Double.POSITIVE_INFINITY ); + type = TYPE_DOUBLE; entityId = Long.MAX_VALUE; entityIdIsSpecialTieBreaker = true; } + /** + * Compares the value of this key to that of another key. + * This method is expected to be called in scenarios where inconsistent reads may happen (and later retried). + * + * @param other the {@link NumberKey} to compare to. + * @return comparison against the {@code other} {@link NumberKey}. + */ + int compareValueTo( NumberKey other ) + { + return type == TYPE_LONG && other.type == TYPE_LONG + // If both are long values then compare them directly, w/o going through double. + // This is because at high values longs have higher precision, or double lower rather, + // than double values, so converting them to doubles and comparing would have false positives. + ? Long.compare( rawValueBits, other.rawValueBits ) + + // Otherwise convert both to double and compare, with the reasoning that the long precision + // cannot be upheld anyway and double precious being higher than float precision. + : Double.compare( doubleValue(), other.doubleValue() ); + } + + /** + * @return the value as double, with potential precision loss. + */ + private double doubleValue() + { + switch ( type ) + { + case TYPE_LONG: + return rawValueBits; + case TYPE_FLOAT: + return Float.intBitsToFloat( (int) rawValueBits ); + case TYPE_DOUBLE: + return Double.longBitsToDouble( rawValueBits ); + default: + // This is interesting: because of the nature of the page cache and the point in time this method + // is called we cannot really throw exception here if type is something unexpected - it may simply + // have been an inconsistent read, which will be retried. + // It's not for us to decide here, so let's return NaN here. + return Double.NaN; + } + } + + /** + * Extracts data from a {@link Number} into state of this {@link NumberKey} instance. + * + * @param value actual {@link Number} value. + */ + private void extractValue( Number value ) + { + if ( value instanceof Double ) + { + type = TYPE_DOUBLE; + rawValueBits = Double.doubleToLongBits( (Double) value ); + } + else if ( value instanceof Float ) + { + type = TYPE_FLOAT; + rawValueBits = Float.floatToIntBits( (Float) value ); + } + else + { + type = TYPE_LONG; + rawValueBits = value.longValue(); + } + } + + /** + * Useful for getting the value as {@link Number} for e.g. printing or converting to {@link String}. + * This method isn't and should not be called on a hot path. + * + * @return a {@link Number} of correct type, i.e. {@link Long}, {@link Float} or {@link Double}. + */ + private Number toNumberValue() + { + switch ( type ) + { + case TYPE_LONG: + return rawValueBits; + case TYPE_FLOAT: + return Float.intBitsToFloat( (int)rawValueBits ); + case TYPE_DOUBLE: + return Double.longBitsToDouble( rawValueBits ); + default: + // Unlike in compareValueTo() it is assumed here that the value have been consistently read + // and that the value is put to some actual use. + throw new IllegalArgumentException( "Unexpected type " + type ); + } + } + @Override public String toString() { - return "compareValue=" + value + ",entityId=" + entityId; + return "type=" + type + ",rawValue=" + rawValueBits + ",value=" + toNumberValue() + ",entityId=" + entityId; } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberLayout.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberLayout.java index 0965ac571a6d8..5bdea2f6a9e98 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberLayout.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberLayout.java @@ -37,7 +37,8 @@ public NumberKey newKey() public NumberKey copyKey( NumberKey key, NumberKey into ) { - into.value = key.value; + into.type = key.type; + into.rawValueBits = key.rawValueBits; into.entityId = key.entityId; into.entityIdIsSpecialTieBreaker = key.entityIdIsSpecialTieBreaker; return into; @@ -46,7 +47,7 @@ public NumberKey copyKey( NumberKey key, @Override public NumberValue newValue() { - return new NumberValue(); + return NumberValue.INSTANCE; } @Override @@ -64,29 +65,27 @@ public int valueSize() @Override public void writeKey( PageCursor cursor, NumberKey key ) { - cursor.putLong( Double.doubleToRawLongBits( key.value ) ); + cursor.putByte( key.type ); + cursor.putLong( key.rawValueBits ); cursor.putLong( key.entityId ); } @Override - public void writeValue( PageCursor cursor, NumberValue key ) + public void writeValue( PageCursor cursor, NumberValue value ) { - cursor.putByte( key.type ); - cursor.putLong( key.rawValueBits ); } @Override public void readKey( PageCursor cursor, NumberKey into ) { - into.value = Double.longBitsToDouble( cursor.getLong() ); + into.type = cursor.getByte(); + into.rawValueBits = cursor.getLong(); into.entityId = cursor.getLong(); } @Override public void readValue( PageCursor cursor, NumberValue into ) { - into.type = cursor.getByte(); - into.rawValueBits = cursor.getLong(); } @Override diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValue.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValue.java index de09407a47520..63a711a2d3ef8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValue.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValue.java @@ -22,62 +22,28 @@ import org.neo4j.index.internal.gbptree.GBPTree; import org.neo4j.values.Value; -import static org.neo4j.kernel.impl.index.schema.NumberValueConversion.toValue; - /** * Value in a {@link GBPTree} handling numbers suitable for schema indexing. - * Contains actual number for internal filtering after accidental query hits due to double value coersion. + * + * NOTE: For the time being no data exists in {@link NumberValue}, but since the layout is under development + * it's very convenient to have this class still exist so that it's very easy to try out different types + * of layouts without changing the entire stack of arguments. In the end it may just be that this class + * will be deleted, but for now it sticks around. */ class NumberValue { - static final int SIZE = - Byte.SIZE + /* type */ - Long.SIZE; /* value bits */ - - static final byte LONG = 0; - static final byte FLOAT = 1; - static final byte DOUBLE = 2; + static final int SIZE = 0; - byte type; - long rawValueBits; + static final NumberValue INSTANCE = new NumberValue(); void from( Value[] values ) { - extractValue( NumberValueConversion.assertValidSingleNumber( values ) ); - } - - byte type() - { - return type; - } - - long rawValueBits() - { - return rawValueBits; - } - - private void extractValue( Number value ) - { - if ( value instanceof Double ) - { - type = DOUBLE; - rawValueBits = Double.doubleToLongBits( (Double) value ); - } - else if ( value instanceof Float ) - { - type = FLOAT; - rawValueBits = Float.floatToIntBits( (Float) value ); - } - else - { - type = LONG; - rawValueBits = value.longValue(); - } + // not needed a.t.m. } @Override public String toString() { - return "type=" + type + ",rawValue=" + rawValueBits + ",value=" + toValue( type, rawValueBits ); + return "[no value]"; } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValueConversion.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValueConversion.java index 02eae1901c891..26de36f2d9399 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValueConversion.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberValueConversion.java @@ -22,9 +22,9 @@ import org.neo4j.values.Value; import org.neo4j.values.Values; -import static org.neo4j.kernel.impl.index.schema.NumberValue.DOUBLE; -import static org.neo4j.kernel.impl.index.schema.NumberValue.FLOAT; -import static org.neo4j.kernel.impl.index.schema.NumberValue.LONG; +import static org.neo4j.kernel.impl.index.schema.NumberKey.TYPE_DOUBLE; +import static org.neo4j.kernel.impl.index.schema.NumberKey.TYPE_FLOAT; +import static org.neo4j.kernel.impl.index.schema.NumberKey.TYPE_LONG; /** * Utilities for converting number values to and from different representations. @@ -54,11 +54,11 @@ static Number toValue( byte type, long rawValueBits ) { switch ( type ) { - case LONG: + case TYPE_LONG: return rawValueBits; - case FLOAT: + case TYPE_FLOAT: return Float.intBitsToFloat( (int)rawValueBits ); - case DOUBLE: + case TYPE_DOUBLE: return Double.longBitsToDouble( rawValueBits ); default: throw new IllegalArgumentException( "Unexpected type " + type ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/UniqueNumberLayout.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/UniqueNumberLayout.java index a08ff4edd2a0e..8e3eae0bada43 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/UniqueNumberLayout.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/UniqueNumberLayout.java @@ -32,16 +32,16 @@ class UniqueNumberLayout extends NumberLayout public long identifier() { // todo Is Number.Value.SIZE a good checksum? - return Layout.namedIdentifier( IDENTIFIER_NAME, NumberValue.SIZE ); + return Layout.namedIdentifier( IDENTIFIER_NAME, NumberKey.SIZE ); } @Override public int compare( NumberKey o1, NumberKey o2 ) { - int comparison = Double.compare( o1.value, o2.value ); + int comparison = o1.compareValueTo( o2 ); if ( comparison == 0 ) { - // This is a special case where we need also compare entityId support inclusive/exclusive + // This is a special case where we need also compare entityId to support inclusive/exclusive if ( o1.entityIdIsSpecialTieBreaker || o2.entityIdIsSpecialTieBreaker ) { return Long.compare( o1.entityId, o2.entityId ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ConflictDetectingValueMergerTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ConflictDetectingValueMergerTest.java index 33cce555f02a8..b02f184e7cd6a 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ConflictDetectingValueMergerTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ConflictDetectingValueMergerTest.java @@ -80,8 +80,6 @@ private static NumberKey key( long entityId, Object value ) private static NumberValue value( Object value ) { - NumberValue result = new NumberValue(); - result.from( new Object[] {value} ); - return result; + return NumberValue.INSTANCE; } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FullScanNonUniqueIndexSamplerTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FullScanNonUniqueIndexSamplerTest.java index 92cd11bd38f7b..63222d62e8fd2 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FullScanNonUniqueIndexSamplerTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FullScanNonUniqueIndexSamplerTest.java @@ -22,14 +22,12 @@ import org.junit.Test; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; import org.neo4j.index.internal.gbptree.GBPTree; import org.neo4j.index.internal.gbptree.Writer; import org.neo4j.io.pagecache.IOLimiter; import org.neo4j.kernel.api.index.IndexEntryUpdate; +import org.neo4j.kernel.api.schema.index.IndexDescriptor; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.storageengine.api.schema.IndexSample; @@ -47,7 +45,7 @@ import static org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector.IMMEDIATE; import static org.neo4j.test.rule.PageCacheRule.config; -import static org.neo4j.kernel.impl.index.schema.NativeSchemaIndexPopulatorTest.someDuplicateIndexEntryUpdates; +import static org.neo4j.kernel.impl.index.schema.LayoutTestUtil.countUniqueValues; import static org.neo4j.values.Values.values; public class FullScanNonUniqueIndexSamplerTest extends SchemaNumberIndexTestUtil @@ -56,7 +54,7 @@ public class FullScanNonUniqueIndexSamplerTest extends SchemaNumberIndexTestUtil public void shouldIncludeAllValuesInTree() throws Exception { // GIVEN - List values = generateNumberValues(); + Number[] values = generateNumberValues(); buildTree( values ); // WHEN @@ -70,27 +68,23 @@ public void shouldIncludeAllValuesInTree() throws Exception } // THEN - assertEquals( values.size(), sample.sampleSize() ); + assertEquals( values.length, sample.sampleSize() ); assertEquals( countUniqueValues( values ), sample.uniqueValues() ); - assertEquals( values.size(), sample.indexSize() ); + assertEquals( values.length, sample.indexSize() ); } - static int countUniqueValues( List values ) + private Number[] generateNumberValues() { - return values.stream().map( Number::doubleValue ).collect( Collectors.toSet() ).size(); - } - - private List generateNumberValues() - { - List result = new ArrayList<>(); - for ( IndexEntryUpdate update : layoutUtil.someUpdates() ) + IndexEntryUpdate[] updates = layoutUtil.someUpdates(); + Number[] result = new Number[updates.length]; + for ( int i = 0; i < updates.length; i++ ) { - result.add( (Number) update.values()[0].asObject() ); + result[i] = (Number) updates[i].values()[0].asObject(); } return result; } - private void buildTree( List values ) throws IOException + private void buildTree( Number[] values ) throws IOException { try ( GBPTree gbpTree = getTree() ) { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/LayoutTestUtil.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/LayoutTestUtil.java index b057b86739a76..338f36f6dc759 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/LayoutTestUtil.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/LayoutTestUtil.java @@ -26,6 +26,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.neo4j.helpers.collection.PrefetchingIterator; import org.neo4j.index.internal.gbptree.Layout; @@ -34,10 +36,6 @@ import org.neo4j.test.rule.RandomRule; import org.neo4j.values.Values; -import static org.neo4j.kernel.impl.index.schema.NumberValue.DOUBLE; -import static org.neo4j.kernel.impl.index.schema.NumberValue.FLOAT; -import static org.neo4j.kernel.impl.index.schema.NumberValue.LONG; - abstract class LayoutTestUtil { private final IndexDescriptor indexDescriptor; @@ -60,37 +58,14 @@ IndexDescriptor indexDescriptor() void copyValue( VALUE value, VALUE intoValue ) { - intoValue.type = value.type; - intoValue.rawValueBits = value.rawValueBits; - } - - int compareValue( VALUE value1, VALUE value2 ) - { - return compareIndexedPropertyValue( value1, value2 ); } - int compareIndexedPropertyValue( NumberValue value1, NumberValue value2 ) + int compareIndexedPropertyValue( NumberKey key1, NumberKey key2 ) { - int typeCompare = Byte.compare( value1.type(), value2.type() ); + int typeCompare = Byte.compare( key1.type, key2.type ); if ( typeCompare == 0 ) { - switch ( value1.type() ) - { - case LONG: - return Long.compare( value1.rawValueBits(), value2.rawValueBits() ); - case FLOAT: - return Float.compare( - Float.intBitsToFloat( (int) value1.rawValueBits() ), - Float.intBitsToFloat( (int) value2.rawValueBits() ) ); - case DOUBLE: - return Double.compare( - Double.longBitsToDouble( value1.rawValueBits() ), - Double.longBitsToDouble( value2.rawValueBits() ) ); - default: - throw new IllegalArgumentException( - "Expected type to be LONG, FLOAT or DOUBLE (" + LONG + "," + FLOAT + "," + DOUBLE + - "). But was " + value1.type() ); - } + return Long.compare( key1.rawValueBits, key2.rawValueBits ); } return typeCompare; } @@ -179,11 +154,24 @@ private IndexEntryUpdate[] generateAddUpdatesFor( Number[] valu -Double.MAX_VALUE, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, - 0 + 0, + // These two values below coerce to the same double + 1234567890123456788L, + 1234567890123456789L }; protected IndexEntryUpdate add( long nodeId, Object value ) { return IndexEntryUpdate.add( nodeId, indexDescriptor, Values.of( value ) ); } + + static int countUniqueValues( IndexEntryUpdate[] updates ) + { + return Stream.of( updates ).map( update -> update.values()[0] ).collect( Collectors.toSet() ).size(); + } + + static int countUniqueValues( Number[] updates ) + { + return Stream.of( updates ).collect( Collectors.toSet() ).size(); + } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeNonUniqueSchemaNumberIndexPopulatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeNonUniqueSchemaNumberIndexPopulatorTest.java index 680ddab9011b5..97a32604bd174 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeNonUniqueSchemaNumberIndexPopulatorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeNonUniqueSchemaNumberIndexPopulatorTest.java @@ -23,9 +23,6 @@ import java.io.File; import java.util.Arrays; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import org.neo4j.index.internal.gbptree.Layout; import org.neo4j.io.pagecache.PageCache; import org.neo4j.kernel.api.index.IndexEntryUpdate; @@ -34,11 +31,10 @@ import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.storageengine.api.schema.IndexSample; -import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.neo4j.helpers.ArrayUtil.array; -import static org.neo4j.kernel.impl.index.schema.FullScanNonUniqueIndexSamplerTest.countUniqueValues; +import static org.neo4j.kernel.impl.index.schema.LayoutTestUtil.countUniqueValues; public class NativeNonUniqueSchemaNumberIndexPopulatorTest extends NativeSchemaNumberIndexPopulatorTest @@ -117,17 +113,11 @@ public void shouldSampleWholeIndexIfConfiguredForPopulatingSampling() throws Exc // THEN assertEquals( updates.length, sample.sampleSize() ); - assertEquals( countUniqueValuesAmongUpdates( updates ), sample.uniqueValues() ); + assertEquals( countUniqueValues( updates ), sample.uniqueValues() ); assertEquals( updates.length, sample.indexSize() ); populator.close( true ); } - private long countUniqueValuesAmongUpdates( IndexEntryUpdate[] updates ) - { - return Stream.of( updates ).map( update -> ((Number) update.values()[0]).doubleValue() ) - .collect( Collectors.toSet() ).size(); - } - @Test public void shouldSampleUpdatesIfConfiguredForOnlineSampling() throws Exception { @@ -153,7 +143,7 @@ public void shouldSampleUpdatesIfConfiguredForOnlineSampling() throws Exception // THEN assertEquals( updates.length, sample.sampleSize() ); - assertEquals( countUniqueValues( asList( updates ) ), sample.uniqueValues() ); + assertEquals( countUniqueValues( updates ), sample.uniqueValues() ); assertEquals( updates.length, sample.indexSize() ); populator.close( true ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexAccessorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexAccessorTest.java index cb51877dd6ce9..16c3cd1e53531 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexAccessorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaNumberIndexAccessorTest.java @@ -62,6 +62,7 @@ import static org.neo4j.kernel.api.index.IndexEntryUpdate.change; import static org.neo4j.kernel.api.index.IndexEntryUpdate.remove; import static org.neo4j.kernel.impl.api.index.IndexUpdateMode.ONLINE; +import static org.neo4j.kernel.impl.index.schema.LayoutTestUtil.countUniqueValues; /** * Tests for @@ -649,12 +650,6 @@ public void shouldSeeNoEntriesInAllEntriesReaderOnEmptyIndex() throws Exception assertEquals( expectedIds, ids ); } - private int countUniqueValues( IndexEntryUpdate[] updates ) - { - return Stream.of( updates ).map( update -> ((Number) update.values()[0]).doubleValue() ) - .collect( Collectors.toSet() ).size(); - } - private static Predicate lessThan( Double value ) { return t -> ((Number)t).doubleValue() < value; @@ -767,7 +762,10 @@ private final void processAll( IndexEntryUpdate... updates ) { try ( IndexUpdater updater = accessor.newUpdater( ONLINE ) ) { - processAll( updater, updates ); + for ( IndexEntryUpdate update : updates ) + { + updater.process( update ); + } } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeUniqueSchemaNumberIndexPopulatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeUniqueSchemaNumberIndexPopulatorTest.java index 72dbbabfb4b92..b74ad655c8e99 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeUniqueSchemaNumberIndexPopulatorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeUniqueSchemaNumberIndexPopulatorTest.java @@ -52,18 +52,11 @@ protected LayoutTestUtil createLayoutTestUtil() return new UniqueLayoutTestUtil(); } - @Override - protected int compareValue( NumberValue value1, NumberValue value2 ) - { - return layoutUtil.compareIndexedPropertyValue( value1, value2 ); - } - @Test public void addShouldThrowOnDuplicateValues() throws Exception { // given populator.create(); - @SuppressWarnings( "unchecked" ) IndexEntryUpdate[] updates = layoutUtil.someUpdatesWithDuplicateValues(); // when @@ -85,7 +78,6 @@ public void updaterShouldThrowOnDuplicateValues() throws Exception { // given populator.create(); - @SuppressWarnings( "unchecked" ) IndexEntryUpdate[] updates = layoutUtil.someUpdatesWithDuplicateValues(); try ( IndexUpdater updater = populator.newPopulatingUpdater( null_property_accessor ) ) { @@ -110,7 +102,6 @@ public void shouldSampleUpdates() throws Exception // GIVEN populator.create(); populator.configureSampling( true ); // has no effect, really - @SuppressWarnings( "unchecked" ) IndexEntryUpdate[] updates = layoutUtil.someUpdates(); // WHEN diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SchemaNumberIndexTestUtil.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SchemaNumberIndexTestUtil.java index e7c6a1f5bc30a..1d24d5d17ac94 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SchemaNumberIndexTestUtil.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SchemaNumberIndexTestUtil.java @@ -90,11 +90,6 @@ private void copyValue( VALUE value, VALUE intoValue ) layoutUtil.copyValue( value, intoValue ); } - protected int compareValue( VALUE value1, VALUE value2 ) - { - return layoutUtil.compareValue( value1, value2 ); - } - void verifyUpdates( IndexEntryUpdate[] updates ) throws IOException { @@ -114,7 +109,7 @@ void verifyUpdates( IndexEntryUpdate[] updates ) int keyCompare = layout.compare( h1.key(), h2.key() ); if ( keyCompare == 0 ) { - return compareValue( h1.value(), h2.value() ); + return layoutUtil.compareIndexedPropertyValue( h1.key(), h2.key() ); } else {