diff --git a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/CompositeIndexAccessorCompatibility.java b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/CompositeIndexAccessorCompatibility.java index 7e99933baeb5c..2d48dbad63a59 100644 --- a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/CompositeIndexAccessorCompatibility.java +++ b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/CompositeIndexAccessorCompatibility.java @@ -35,6 +35,7 @@ import org.neo4j.values.storable.BooleanValue; import org.neo4j.values.storable.CoordinateReferenceSystem; import org.neo4j.values.storable.DateTimeValue; +import org.neo4j.values.storable.PointArray; import org.neo4j.values.storable.PointValue; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; @@ -175,7 +176,7 @@ public void testIndexScanAndSeekExactWithExactByPoint() throws Exception @Test public void testIndexSeekExactWithRangeByString() throws Exception { - testIndexSeekExactWithRange( ValueGroup.TEXT, Values.of( "a" ), Values.of( "b" ), + testIndexSeekExactWithRange( Values.of( "a" ), Values.of( "b" ), Values.of( "Anabelle" ), Values.of( "Anna" ), Values.of( "Bob" ), @@ -186,7 +187,7 @@ public void testIndexSeekExactWithRangeByString() throws Exception @Test public void testIndexSeekExactWithRangeByNumber() throws Exception { - testIndexSeekExactWithRange( ValueGroup.NUMBER, Values.of( 303 ), Values.of( 101 ), + testIndexSeekExactWithRange( Values.of( 303 ), Values.of( 101 ), Values.of( 111 ), Values.of( 222 ), Values.of( 333 ), @@ -197,7 +198,7 @@ public void testIndexSeekExactWithRangeByNumber() throws Exception @Test public void testIndexSeekExactWithRangeByTemporal() throws Exception { - testIndexSeekExactWithRange( ValueGroup.DATE, epochDate( 303 ), epochDate( 101 ), + testIndexSeekExactWithRange( epochDate( 303 ), epochDate( 101 ), epochDate( 111 ), epochDate( 222 ), epochDate( 333 ), @@ -218,7 +219,7 @@ public void testIndexSeekExactWithRangeByBoolean() throws Exception @Test public void testIndexSeekExactWithRangeByStringArray() throws Exception { - testIndexSeekExactWithRange( ValueGroup.TEXT_ARRAY, stringArray( "a", "c" ), stringArray( "b", "c" ), + testIndexSeekExactWithRange( stringArray( "a", "c" ), stringArray( "b", "c" ), stringArray( "Anabelle", "c" ), stringArray( "Anna", "c" ), stringArray( "Bob", "c" ), @@ -230,7 +231,7 @@ public void testIndexSeekExactWithRangeByStringArray() throws Exception @Test public void testIndexSeekExactWithRangeByNumberArray() throws Exception { - testIndexSeekExactWithRange( ValueGroup.NUMBER_ARRAY, longArray( new long[]{333, 9000} ), longArray( new long[]{101, 900} ), + testIndexSeekExactWithRange( longArray( new long[]{333, 9000} ), longArray( new long[]{101, 900} ), longArray( new long[]{111, 900} ), longArray( new long[]{222, 900} ), longArray( new long[]{333, 900} ), @@ -242,7 +243,7 @@ public void testIndexSeekExactWithRangeByNumberArray() throws Exception @Test public void testIndexSeekExactWithRangeByBooleanArray() throws Exception { - testIndexSeekExactWithRange( ValueGroup.BOOLEAN_ARRAY, booleanArray( new boolean[]{true, true} ), booleanArray( new boolean[]{false, false} ), + testIndexSeekExactWithRange( booleanArray( new boolean[]{true, true} ), booleanArray( new boolean[]{false, false} ), booleanArray( new boolean[]{false, false} ), booleanArray( new boolean[]{false, true} ), booleanArray( new boolean[]{true, false} ), @@ -254,7 +255,7 @@ public void testIndexSeekExactWithRangeByBooleanArray() throws Exception @Test public void testIndexSeekExactWithRangeByTemporalArray() throws Exception { - testIndexSeekExactWithRange( ValueGroup.DATE_ARRAY, dateArray( 303, 900 ), dateArray( 101, 900 ), + testIndexSeekExactWithRange( dateArray( 303, 900 ), dateArray( 101, 900 ), dateArray( 111, 900 ), dateArray( 222, 900 ), dateArray( 333, 900 ), @@ -265,7 +266,7 @@ public void testIndexSeekExactWithRangeByTemporalArray() throws Exception @Test public void testIndexSeekExactWithRangeBySpatial() throws Exception { - testIndexSeekExactWithRange( GEOMETRY, intValue( 100 ), intValue( 10 ), + testIndexSeekExactWithRange( intValue( 100 ), intValue( 10 ), pointValue( WGS84, -10D, -10D ), pointValue( WGS84, -1D, -1D ), pointValue( WGS84, 0D, 0D ), @@ -273,7 +274,7 @@ public void testIndexSeekExactWithRangeBySpatial() throws Exception pointValue( WGS84, 10D, 10D ) ); } - private void testIndexSeekExactWithRange( ValueGroup valueGroup, Value base1, Value base2, Value obj1, Value obj2, Value obj3, Value obj4, Value obj5 ) + private void testIndexSeekExactWithRange( Value base1, Value base2, Value obj1, Value obj2, Value obj3, Value obj4, Value obj5 ) throws Exception { Assume.assumeTrue( "Assume support for granular composite queries", testSuite.supportsGranularCompositeQueries() ); @@ -307,11 +308,32 @@ private void testIndexSeekExactWithRange( ValueGroup valueGroup, Value base1, Va assertThat( query( exact( 0, base2 ), range( 1, obj1, false, obj2, true ) ), equalTo( singletonList( 7L ) ) ); assertThat( query( exact( 0, base2 ), range( 1, obj1, false, obj3, false ) ), equalTo( singletonList( 7L ) ) ); + ValueGroup valueGroup = obj1.valueGroup(); if ( valueGroup != GEOMETRY && valueGroup != GEOMETRY_ARRAY ) { - assertThat( query( exact( 0, base1 ), range( 1, obj1.valueGroup() ) ), equalTo( asList( 1L, 2L, 3L, 4L, 5L ) ) ); - assertThat( query( exact( 0, base2 ), range( 1, obj1.valueGroup() ) ), equalTo( asList( 6L, 7L, 8L, 9L, 10L ) ) ); + assertThat( query( exact( 0, base1 ), range( 1, valueGroup ) ), equalTo( asList( 1L, 2L, 3L, 4L, 5L ) ) ); + assertThat( query( exact( 0, base2 ), range( 1, valueGroup ) ), equalTo( asList( 6L, 7L, 8L, 9L, 10L ) ) ); } + else + { + CoordinateReferenceSystem crs = getCrs( obj1 ); + assertThat( query( exact( 0, base1 ), range( 1, crs ) ), equalTo( asList( 1L, 2L, 3L, 4L, 5L ) ) ); + assertThat( query( exact( 0, base2 ), range( 1, crs ) ), equalTo( asList( 6L, 7L, 8L, 9L, 10L ) ) ); + } + } + + private CoordinateReferenceSystem getCrs( Value value ) + { + if ( Values.isGeometryValue( value ) ) + { + return ((PointValue) value).getCoordinateReferenceSystem(); + } + else if ( Values.isGeometryArray( value ) ) + { + PointArray array = (PointArray) value; + return array.pointValue( 0 ).getCoordinateReferenceSystem(); + } + throw new IllegalArgumentException( "Expected some geometry value to get CRS from, but got " + value ); } private void testIndexSeekExactWithRangeByBooleanType( ValueGroup valueGroup, Value base1, Value base2, Value obj1, Value obj2 ) throws Exception @@ -479,13 +501,13 @@ private void testIndexSeekExactWithExists( Value a, Value b ) throws Exception @Test public void testIndexSeekRangeWithExistsByString() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.TEXT, "Anabelle", "Anna", "Bob", "Harriet", "William" ); + testIndexSeekRangeWithExists( "Anabelle", "Anna", "Bob", "Harriet", "William" ); } @Test public void testIndexSeekRangeWithExistsByNumber() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.NUMBER, -5, 0, 5.5, 10.0, 100.0 ); + testIndexSeekRangeWithExists( -5, 0, 5.5, 10.0, 100.0 ); } @Test @@ -496,7 +518,7 @@ public void testIndexSeekRangeWithExistsByTemporal() throws Exception DateTimeValue d3 = datetime( 10000, 100, ZoneId.of( "+01:00" ) ); DateTimeValue d4 = datetime( 10000, 100, ZoneId.of( "Europe/Stockholm" ) ); DateTimeValue d5 = datetime( 10000, 100, ZoneId.of( "+03:00" ) ); - testIndexSeekRangeWithExists( ValueGroup.DATE, d1, d2, d3, d4, d5 ); + testIndexSeekRangeWithExists( d1, d2, d3, d4, d5 ); } @Test @@ -521,7 +543,7 @@ public void testIndexSeekRangeWithExistsByBoolean() throws Exception @Test public void testIndexSeekRangeWithExistsByStringArray() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.TEXT_ARRAY, + testIndexSeekRangeWithExists( new String[]{"Anabelle", "Anabelle"}, new String[]{"Anabelle", "Anablo"}, new String[]{"Anna", "Anabelle"}, @@ -532,7 +554,7 @@ public void testIndexSeekRangeWithExistsByStringArray() throws Exception @Test public void testIndexSeekRangeWithExistsByNumberArray() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.NUMBER_ARRAY, + testIndexSeekRangeWithExists( new long[]{303, 303}, new long[]{303, 404}, new long[]{600, 303}, @@ -543,7 +565,7 @@ public void testIndexSeekRangeWithExistsByNumberArray() throws Exception @Test public void testIndexSeekRangeWithExistsByBooleanArray() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.NUMBER_ARRAY, + testIndexSeekRangeWithExists( new boolean[]{false, false}, new boolean[]{false, true}, new boolean[]{true, false}, @@ -554,7 +576,7 @@ public void testIndexSeekRangeWithExistsByBooleanArray() throws Exception @Test public void testIndexSeekRangeWithExistsByTemporalArray() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.NUMBER_ARRAY, + testIndexSeekRangeWithExists( dateArray( 303, 303 ), dateArray( 303, 404 ), dateArray( 404, 303 ), @@ -565,7 +587,7 @@ public void testIndexSeekRangeWithExistsByTemporalArray() throws Exception @Test public void testIndexSeekRangeWithExistsBySpatial() throws Exception { - testIndexSeekRangeWithExists( GEOMETRY, + testIndexSeekRangeWithExists( pointValue( Cartesian, 0D, 0D ), pointValue( Cartesian, 1D, 1D ), pointValue( Cartesian, 2D, 2D ), @@ -576,7 +598,7 @@ public void testIndexSeekRangeWithExistsBySpatial() throws Exception @Test public void testIndexSeekRangeWithExistsBySpatialArray() throws Exception { - testIndexSeekRangeWithExists( ValueGroup.GEOMETRY_ARRAY, + testIndexSeekRangeWithExists( pointArray( new PointValue[] {pointValue( Cartesian, 0D, 0D ), pointValue( Cartesian, 0D, 1D )} ), pointArray( new PointValue[] {pointValue( Cartesian, 10D, 1D ), pointValue( Cartesian, 10D, 2D )} ), pointArray( new PointValue[] {pointValue( Cartesian, 20D, 2D ), pointValue( Cartesian, 20D, 3D )} ), @@ -584,12 +606,12 @@ public void testIndexSeekRangeWithExistsBySpatialArray() throws Exception pointArray( new PointValue[] {pointValue( Cartesian, 40D, 4D ), pointValue( Cartesian, 40D, 5D )} ) ); } - private void testIndexSeekRangeWithExists( ValueGroup valueGroup, Object obj1, Object obj2, Object obj3, Object obj4, Object obj5 ) throws Exception + private void testIndexSeekRangeWithExists( Object obj1, Object obj2, Object obj3, Object obj4, Object obj5 ) throws Exception { - testIndexSeekRangeWithExists( valueGroup, Values.of( obj1 ), Values.of( obj2 ), Values.of( obj3 ), Values.of( obj4 ), Values.of( obj5 ) ); + testIndexSeekRangeWithExists( Values.of( obj1 ), Values.of( obj2 ), Values.of( obj3 ), Values.of( obj4 ), Values.of( obj5 ) ); } - private void testIndexSeekRangeWithExists( ValueGroup valueGroup, Value obj1, Value obj2, Value obj3, Value obj4, Value obj5 ) throws Exception + private void testIndexSeekRangeWithExists( Value obj1, Value obj2, Value obj3, Value obj4, Value obj5 ) throws Exception { Assume.assumeTrue( "Assume support for granular composite queries", testSuite.supportsGranularCompositeQueries() ); updateAndCommit( asList( @@ -605,6 +627,7 @@ private void testIndexSeekRangeWithExists( ValueGroup valueGroup, Value obj1, Va assertThat( query( range( 0, obj5, false, obj2, true ), exists( 1 ) ), equalTo( EMPTY_LIST ) ); assertThat( query( range( 0, null, false, obj3, false ), exists( 1 ) ), equalTo( asList( 1L, 2L ) ) ); assertThat( query( range( 0, null, true, obj3, true ), exists( 1 ) ), equalTo( asList( 1L, 2L, 3L ) ) ); + ValueGroup valueGroup = obj1.valueGroup(); if ( valueGroup != GEOMETRY && valueGroup != GEOMETRY_ARRAY ) { // This cannot be done for spatial values because each bound in a spatial query needs a coordinate reference system, diff --git a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexAccessorCompatibility.java b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexAccessorCompatibility.java index 1ca6473fe0a89..3dcb72b422c3f 100644 --- a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexAccessorCompatibility.java +++ b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/IndexAccessorCompatibility.java @@ -37,6 +37,7 @@ import org.neo4j.storageengine.api.schema.IndexDescriptor; import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.values.storable.Value; +import org.neo4j.values.storable.ValueGroup; public abstract class IndexAccessorCompatibility extends IndexProviderCompatibilityTestSuite.Compatibility { @@ -98,10 +99,16 @@ private boolean passesFilter( long entityId, IndexQuery[] predicates ) Value[] values = committedValues.get( entityId ); for ( int i = 0; i < values.length; i++ ) { - if ( !predicates[i].acceptsValue( values[i] ) ) + IndexQuery predicate = predicates[i]; + if ( predicate.valueGroup() == ValueGroup.GEOMETRY || predicate.valueGroup() == ValueGroup.GEOMETRY_ARRAY ) { - return false; + if ( !predicates[i].acceptsValue( values[i] ) ) + { + return false; + } } + // else there's no functional need to let values, other than those of GEOMETRY type, to pass through the IndexQuery filtering + // avoiding this filtering will have testing be more strict in what index readers returns. } return true; } diff --git a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/SimpleRandomizedIndexAccessorCompatibility.java b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/SimpleRandomizedIndexAccessorCompatibility.java index c1e34c88dd872..56c720c5a7d5f 100644 --- a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/SimpleRandomizedIndexAccessorCompatibility.java +++ b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/api/index/SimpleRandomizedIndexAccessorCompatibility.java @@ -39,7 +39,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; @Ignore( "Not a test. This is a compatibility suite that provides test cases for verifying" + " IndexProvider implementations. Each index provider that is to be tested by this suite" + @@ -69,18 +68,7 @@ public void testRandomValues() throws Exception .collect( Collectors.toList() ); IndexQuery.ExactPredicate exact = IndexQuery.exact( 100, value ); List result = query( exact ); - if ( isGeometryValue( value ) ) - { - // Because spatial index can have false positives we can only assert on contains - for ( Long expectedEntityId : expectedEntityIds ) - { - assertTrue( "query: " + exact, result.contains( expectedEntityId ) ); - } - } - else - { - assertThat( "query: " + exact, result, equalTo( expectedEntityIds ) ); - } + assertThat( "query: " + exact, result, equalTo( expectedEntityIds ) ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/CompositeGenericKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/CompositeGenericKey.java index 3dd238ddab72c..0f83bcf8b07bb 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/CompositeGenericKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/CompositeGenericKey.java @@ -47,17 +47,6 @@ class CompositeGenericKey extends NativeIndexKey } } - /** - * Special init method for when doing sub-queries for geometry range. This given slot will not be initialized with a {@link PointValue}, - * but a 1D value which is derived from that point, calculated based on intersecting tiles. - * - * @see SpaceFillingCurve#getTilesIntersectingEnvelope(double[], double[], SpaceFillingCurveConfiguration) - */ - void initFromDerivedSpatialValue( int stateSlot, CoordinateReferenceSystem crs, long derivedValue, Inclusion inclusion ) - { - states[stateSlot].writePointDerived( crs, derivedValue, inclusion ); - } - @Override void writeValue( int stateSlot, Value value, Inclusion inclusion ) { @@ -110,6 +99,27 @@ void initValueAsHighest( int stateSlot, ValueGroup valueGroup ) states[stateSlot].initValueAsHighest( valueGroup ); } + /** + * Special init method for when doing sub-queries for geometry range. This given slot will not be initialized with a {@link PointValue}, + * but a 1D value which is derived from that point, calculated based on intersecting tiles. + * + * @see SpaceFillingCurve#getTilesIntersectingEnvelope(double[], double[], SpaceFillingCurveConfiguration) + */ + void initFromDerivedSpatialValue( int stateSlot, CoordinateReferenceSystem crs, long derivedValue, Inclusion inclusion ) + { + states[stateSlot].writePointDerived( crs, derivedValue, inclusion ); + } + + void initAsPrefixLow( int stateSlot, String prefix ) + { + states[stateSlot].initAsPrefixLow( prefix ); + } + + void initAsPrefixHigh( int stateSlot, String prefix ) + { + states[stateSlot].initAsPrefixHigh( prefix ); + } + @Override int compareValueTo( CompositeGenericKey other ) { @@ -124,16 +134,6 @@ int compareValueTo( CompositeGenericKey other ) return 0; } - void initAsPrefixLow( int stateSlot, String prefix ) - { - states[stateSlot].initAsPrefixLow( prefix ); - } - - void initAsPrefixHigh( int stateSlot, String prefix ) - { - states[stateSlot].initAsPrefixHigh( prefix ); - } - void copyValuesFrom( CompositeGenericKey key ) { if ( key.states.length != states.length ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java index 2b708982d66fc..106865faede7c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKeyState.java @@ -76,8 +76,8 @@ public class GenericKeyState extends TemporalValueWriterAdapter>> SHIFT_TABLE; + // Immutable + private final IndexSpecificSpaceFillingCurveSettingsCache settings; + + // Mutable, meta-state Type type; NativeIndexKey.Inclusion inclusion; private boolean isArray; - private boolean isHighestArray; - private int arrayLength; - private int currentArrayOffset; - private final IndexSpecificSpaceFillingCurveSettingsCache settings; // spatial long0 (rawValueBits), long1 (coordinate reference system tableId), long2 (coordinate reference system code) // zoned date time: long0 (epochSecondUTC), long1 (nanoOfSecond), long2 (zoneId), long3 (zoneOffsetSeconds) @@ -132,22 +132,27 @@ public class GenericKeyState extends TemporalValueWriterAdapter compareGeometry( o1.long0Array[i], o1.long1, o1.long2, @@ -1028,7 +1039,7 @@ void put( PageCursor cursor ) case NUMBER: putNumberIncludingType( cursor, long0, long1 ); break; - + // array types case GEOMETRY_ARRAY: putGeometryCrs( cursor, long1, long2 ); putArray( cursor, ( c, i ) -> putGeometry( c, long0Array[i] ) ); @@ -1085,7 +1096,7 @@ private ArrayElementWriter numberArrayElementWriter( long long1 ) } } - private void putGeometryCrs( PageCursor cursor, long long1, long long2 ) + private static void putGeometryCrs( PageCursor cursor, long long1, long long2 ) { if ( (long1 & ~MASK_TABLE_PUT) != 0 ) { @@ -1105,7 +1116,7 @@ private static void put3BInt( PageCursor cursor, int value ) cursor.putByte( (byte) (value >>> Short.SIZE) ); } - private void putGeometry( PageCursor cursor, long long0 ) + private static void putGeometry( PageCursor cursor, long long0 ) { cursor.putLong( long0 ); } @@ -1241,7 +1252,7 @@ boolean read( PageCursor cursor, int size ) return readBoolean( cursor ); case NUMBER: return readNumber( cursor ); - + // array types case GEOMETRY_ARRAY: readGeometryCrs( cursor ); return readArray( cursor, ArrayType.POINT, this::readGeometryArrayItem ); @@ -1420,11 +1431,12 @@ private boolean readGeometryCrs( PageCursor cursor ) long2 = tableAndCode & MASK_CODE; try { - crs = CoordinateReferenceSystem.get( (int) long1, (int) long2 ); + CoordinateReferenceSystem.get( (int) long1, (int) long2 ); } catch ( Exception e ) { - cursor.setCursorException( e.getMessage() ); + setCursorException( cursor, e.getMessage() ); + return false; } return true; } @@ -1433,8 +1445,7 @@ private static int read3BInt( PageCursor cursor ) { int low = cursor.getShort() & 0xFFFF; int high = cursor.getByte() & 0xFF; - int i = high << Short.SIZE | low; - return i; + return high << Short.SIZE | low; } private boolean readNumber( PageCursor cursor ) @@ -1796,7 +1807,7 @@ public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) thr { if ( !isArray ) { - updateCurve( crs ); + updateCurve( crs.getTable().getTableId(), crs.getCode() ); type = Type.GEOMETRY; long0 = spaceFillingCurve.derivedValueFor( coordinate ); } @@ -1804,13 +1815,13 @@ public void writePoint( CoordinateReferenceSystem crs, double[] coordinate ) thr { if ( currentArrayOffset == 0 ) { - updateCurve( crs ); + updateCurve( crs.getTable().getTableId(), crs.getCode() ); } - else if ( this.crs != crs ) + else if ( this.long1 != crs.getTable().getTableId() || this.long2 != crs.getCode() ) { throw new IllegalStateException( format( "Tried to assign a geometry array containing different coordinate reference systems, first:%s, violating:%s at array position:%d", - this.crs, crs, currentArrayOffset ) ); + CoordinateReferenceSystem.get( (int) long1, (int) long2 ), crs, currentArrayOffset ) ); } long0Array[currentArrayOffset] = spaceFillingCurve.derivedValueFor( coordinate ); } @@ -1820,21 +1831,24 @@ void writePointDerived( CoordinateReferenceSystem crs, long derivedValue, Native { if ( isArray ) { - throw new IllegalStateException( "Not sure we're doing arrays like this, are we?" ); + throw new IllegalStateException( + "This method is intended to be called when querying, where one or more sub-ranges are derived " + + "from a queried range and each sub-range written to separate keys. " + + "As such it's unexpected that this key state thinks that it's holds state for an array" ); } type = Type.GEOMETRY; this.inclusion = inclusion; long0 = derivedValue; - updateCurve( crs ); + updateCurve( crs.getTable().getTableId(), crs.getCode() ); } - private void updateCurve( CoordinateReferenceSystem crs ) + private void updateCurve( int tableId, int code ) { - if ( this.crs == null || this.crs != crs ) + if ( this.long1 != tableId || this.long2 != code ) { - long1 = crs.getTable().getTableId(); - long2 = crs.getCode(); - spaceFillingCurve = settings.forCrs( (int) long1, (int) long2, true ); + long1 = tableId; + long2 = code; + spaceFillingCurve = settings.forCrs( tableId, code, true ); } } @@ -1911,10 +1925,10 @@ public void beginArray( int size, ArrayType arrayType ) throws RuntimeException } } - private void initializeArrayMeta( int size ) + private void initializeArrayMeta( int size, boolean isHighest ) { isArray = true; - isHighestArray = false; + isHighestArray = isHighest; arrayLength = size; currentArrayOffset = 0; } @@ -1989,6 +2003,7 @@ private void initializeTypeFromArrayType( ArrayType arrayType ) private void initializeGeometryArray( int size ) { + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); // plain long1 for tableId // plain long2 for code @@ -1996,20 +2011,20 @@ private void initializeGeometryArray( int size ) private void initializeNumberArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); // plain long1 for number type } private void initializeBooleanArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); } private void initializeTextArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); byteArrayArray = ensureBigEnough( byteArrayArray, size ); // long1 (bytesDereferenced) - Not needed because we never leak bytes from string array @@ -2019,7 +2034,7 @@ private void initializeTextArray( int size ) private void initializeDurationArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); long1Array = ensureBigEnough( long1Array, size ); long2Array = ensureBigEnough( long2Array, size ); @@ -2028,33 +2043,33 @@ private void initializeDurationArray( int size ) private void initializeLocalTimeArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); } private void initializeZonedTimeArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); long1Array = ensureBigEnough( long1Array, size ); } private void initializeDateArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); } private void initializeLocalDateTimeArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); long1Array = ensureBigEnough( long1Array, size ); } private void initializeZonedDateTimeArray( int size ) { - initializeArrayMeta( size ); + initializeArrayMeta( size, false ); long0Array = ensureBigEnough( long0Array, size ); long1Array = ensureBigEnough( long1Array, size ); long2Array = ensureBigEnough( long2Array, size ); @@ -2063,7 +2078,7 @@ private void initializeZonedDateTimeArray( int size ) private void initializeLowestArray() { - initializeArrayMeta( 0 ); + initializeArrayMeta( 0, false ); long0Array = ensureBigEnough( long0Array, 0 ); long1Array = ensureBigEnough( long1Array, 0 ); long2Array = ensureBigEnough( long2Array, 0 ); @@ -2072,12 +2087,11 @@ private void initializeLowestArray() private void initializeHighestArray() { - initializeArrayMeta( 0 ); + initializeArrayMeta( 0, true ); long0Array = ensureBigEnough( long0Array, 0 ); long1Array = ensureBigEnough( long1Array, 0 ); long2Array = ensureBigEnough( long2Array, 0 ); long3Array = ensureBigEnough( long3Array, 0 ); - isHighestArray = true; } /* */ /* */ diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexReader.java index 5ca41daf1aed6..76407f7e1b569 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexReader.java @@ -73,11 +73,10 @@ void validateQuery( IndexOrder indexOrder, IndexQuery[] predicates ) @Override public void query( IndexProgressor.NodeValueClient client, IndexOrder indexOrder, boolean needsValues, IndexQuery... query ) { - validateQuery( indexOrder, query ); - IndexQuery.GeometryRangePredicate geometryRangePredicate = getGeometryRangePredicateIfAny( query ); if ( geometryRangePredicate != null ) { + validateQuery( indexOrder, query ); try { // If there's a GeometryRangeQuery among the predicates then this query changes from a straight-forward: build from/to and seek... @@ -96,7 +95,7 @@ public void query( IndexProgressor.NodeValueClient client, IndexOrder indexOrder CompositeGenericKey treeKeyFrom = layout.newKey(); CompositeGenericKey treeKeyTo = layout.newKey(); initializeFromToKeys( treeKeyFrom, treeKeyTo ); - boolean needFiltering = initializeRangeForGeometrySubQuery( multiProgressor, treeKeyFrom, treeKeyTo, query, crs, range ); + boolean needFiltering = initializeRangeForGeometrySubQuery( treeKeyFrom, treeKeyTo, query, crs, range ); // TODO needsValues==true could be problematic, no? startSeekForInitializedRange( multiProgressor, treeKeyFrom, treeKeyTo, query, needFiltering, needsValues ); @@ -110,16 +109,28 @@ public void query( IndexProgressor.NodeValueClient client, IndexOrder indexOrder } else { - CompositeGenericKey treeKeyFrom = layout.newKey(); - CompositeGenericKey treeKeyTo = layout.newKey(); - initializeFromToKeys( treeKeyFrom, treeKeyTo ); - - boolean needFilter = initializeRangeForQuery( client, treeKeyFrom, treeKeyTo, query ); - startSeekForInitializedRange( client, treeKeyFrom, treeKeyTo, query, needFilter, needsValues ); + super.query( client, indexOrder, needsValues, query ); } } - private boolean initializeRangeForGeometrySubQuery( IndexProgressor.NodeValueClient client, CompositeGenericKey treeKeyFrom, CompositeGenericKey treeKeyTo, + /** + * Initializes {@code treeKeyFrom} and {@code treeKeyTo} from the {@link IndexQuery query}. + * Geometry range queries makes an otherwise straight-forward key construction complex in that a geometry range internally is performed + * by executing multiple sub-range queries to the index. Each of those sub-range queries still needs to construct the full composite key - + * in the case of a composite index. Therefore this method can be called either with null or non-null {@code crs} and {@code range} and + * constructing a key when coming across a {@link IndexQuery.GeometryRangePredicate} will use the provided crs/range instead + * of the predicate, where the specific range is one out of many sub-ranges calculated from the {@link IndexQuery.GeometryRangePredicate} + * by the caller. + * + * @param treeKeyFrom the "from" key to construct from the query. + * @param treeKeyTo the "to" key to construct from the query. + * @param query the query to construct keys from to later send to {@link GBPTree} when reading. + * @param crs {@link CoordinateReferenceSystem} for the specific {@code range}, if range is specified too. + * @param range sub-range of a larger {@link IndexQuery.GeometryRangePredicate} to use instead of {@link IndexQuery.GeometryRangePredicate} + * in the query. + * @return {@code true} if filtering is needed for the results from the reader, otherwise {@code false}. + */ + private boolean initializeRangeForGeometrySubQuery( CompositeGenericKey treeKeyFrom, CompositeGenericKey treeKeyTo, IndexQuery[] query, CoordinateReferenceSystem crs, SpaceFillingCurve.LongRange range ) { boolean needsFiltering = false; @@ -170,10 +181,9 @@ private boolean initializeRangeForGeometrySubQuery( IndexProgressor.NodeValueCli } @Override - boolean initializeRangeForQuery( IndexProgressor.NodeValueClient client, CompositeGenericKey treeKeyFrom, CompositeGenericKey treeKeyTo, - IndexQuery[] query ) + boolean initializeRangeForQuery( CompositeGenericKey treeKeyFrom, CompositeGenericKey treeKeyTo, IndexQuery[] query ) { - return initializeRangeForGeometrySubQuery( client, treeKeyFrom, treeKeyTo, query, null, null ); + return initializeRangeForGeometrySubQuery( treeKeyFrom, treeKeyTo, query, null, null ); } private static void initFromForRange( int stateSlot, RangePredicate rangePredicate, CompositeGenericKey treeKeyFrom ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexReader.java index bf65df49a84ec..5088782cf98b4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexReader.java @@ -128,7 +128,7 @@ public void query( IndexProgressor.NodeValueClient cursor, IndexOrder indexOrder KEY treeKeyTo = layout.newKey(); initializeFromToKeys( treeKeyFrom, treeKeyTo ); - boolean needFilter = initializeRangeForQuery( cursor, treeKeyFrom, treeKeyTo, predicates ); + boolean needFilter = initializeRangeForQuery( treeKeyFrom, treeKeyTo, predicates ); startSeekForInitializedRange( cursor, treeKeyFrom, treeKeyTo, predicates, needFilter, needsValues ); } @@ -146,7 +146,7 @@ void initializeFromToKeys( KEY treeKeyFrom, KEY treeKeyTo ) /** * @return true if query results from seek will need to be filtered through the predicates, else false */ - abstract boolean initializeRangeForQuery( IndexProgressor.NodeValueClient cursor, KEY treeKeyFrom, KEY treeKeyTo, IndexQuery[] predicates ); + abstract boolean initializeRangeForQuery( KEY treeKeyFrom, KEY treeKeyTo, IndexQuery[] predicates ); void startSeekForInitializedRange( IndexProgressor.NodeValueClient client, KEY treeKeyFrom, KEY treeKeyTo, IndexQuery[] query, boolean needFilter, boolean needsValues ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberIndexReader.java index a149a7787e692..4a36d15e3ea33 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberIndexReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberIndexReader.java @@ -26,7 +26,6 @@ import org.neo4j.internal.kernel.api.IndexQuery.RangePredicate; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.storageengine.api.schema.IndexDescriptor; -import org.neo4j.storageengine.api.schema.IndexProgressor; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; import org.neo4j.values.storable.Values; @@ -51,7 +50,7 @@ void validateQuery( IndexOrder indexOrder, IndexQuery[] predicates ) } @Override - boolean initializeRangeForQuery( IndexProgressor.NodeValueClient cursor, NumberIndexKey treeKeyFrom, NumberIndexKey treeKeyTo, IndexQuery[] predicates ) + boolean initializeRangeForQuery( NumberIndexKey treeKeyFrom, NumberIndexKey treeKeyTo, IndexQuery[] predicates ) { IndexQuery predicate = predicates[0]; switch ( predicate.type() ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexPartReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexPartReader.java index 4fb0c95085fbd..886d9ea44a7d2 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexPartReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexPartReader.java @@ -65,7 +65,7 @@ void validateQuery( IndexOrder indexOrder, IndexQuery[] predicates ) } @Override - boolean initializeRangeForQuery( IndexProgressor.NodeValueClient cursor, SpatialIndexKey treeKeyFrom, SpatialIndexKey treeKeyTo, IndexQuery[] predicates ) + boolean initializeRangeForQuery( SpatialIndexKey treeKeyFrom, SpatialIndexKey treeKeyTo, IndexQuery[] predicates ) { throw new UnsupportedOperationException( "Cannot initialize 1D range in multidimensional spatial index reader" ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexReader.java index baa1a40f7a9a2..9bfc17f4186a5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexReader.java @@ -26,7 +26,6 @@ import org.neo4j.internal.kernel.api.IndexQuery.RangePredicate; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.storageengine.api.schema.IndexDescriptor; -import org.neo4j.storageengine.api.schema.IndexProgressor; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; import org.neo4j.values.storable.Values; @@ -53,7 +52,7 @@ void validateQuery( IndexOrder indexOrder, IndexQuery[] predicates ) } @Override - boolean initializeRangeForQuery( IndexProgressor.NodeValueClient cursor, StringIndexKey treeKeyFrom, StringIndexKey treeKeyTo, IndexQuery[] predicates ) + boolean initializeRangeForQuery( StringIndexKey treeKeyFrom, StringIndexKey treeKeyTo, IndexQuery[] predicates ) { IndexQuery predicate = predicates[0]; switch ( predicate.type() ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPartReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPartReader.java index c6832cab10f41..a6f9dfc364629 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPartReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPartReader.java @@ -24,7 +24,6 @@ import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.storageengine.api.schema.IndexDescriptor; -import org.neo4j.storageengine.api.schema.IndexProgressor; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; import org.neo4j.values.storable.Values; @@ -51,7 +50,7 @@ protected void validateQuery( IndexOrder indexOrder, IndexQuery[] predicates ) } @Override - protected boolean initializeRangeForQuery( IndexProgressor.NodeValueClient cursor, KEY treeKeyFrom, KEY treeKeyTo, IndexQuery[] predicates ) + protected boolean initializeRangeForQuery( KEY treeKeyFrom, KEY treeKeyTo, IndexQuery[] predicates ) { IndexQuery predicate = predicates[0]; switch ( predicate.type() ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/config/IndexSpecificSpaceFillingCurveSettingsCacheTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/config/IndexSpecificSpaceFillingCurveSettingsCacheTest.java index 10b3bff98c43c..395bdaf508716 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/config/IndexSpecificSpaceFillingCurveSettingsCacheTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/config/IndexSpecificSpaceFillingCurveSettingsCacheTest.java @@ -79,7 +79,7 @@ void shouldHaveInitialIndexSpecificSettingsPlusRequestedOnes() } @Test - void shouldNotCreateIndexSpecificSettingFOrReadRequest() + void shouldNotCreateIndexSpecificSettingForReadRequest() { // given Map initialSettings = new HashMap<>();