From 133610f28cb4c901a9cb28954b529b42aa4a9143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Finn=C3=A9?= Date: Thu, 13 Sep 2018 14:28:54 +0200 Subject: [PATCH] Avoid GenericKeyState[] in generic key Instead let NativeIndexKey extend GenericKeyState(!). GenericLayout will instantiate more efficient key instances for single-value instances, instances which won't have GenericKey -> GenericKeyState[] -> GenericKeyState indirection, but will instead directly operate on the state inside the GenericKey which is a GenericKeyState. --- .../impl/index/schema/AbstractArrayType.java | 1 + .../index/schema/CompositeGenericKey.java | 78 ++++++---- .../schema/GenericIndexKeyValidator.java | 6 +- .../kernel/impl/index/schema/GenericKey.java | 60 ++++++++ .../impl/index/schema/GenericKeyState.java | 4 +- .../impl/index/schema/GenericLayout.java | 33 +++-- .../schema/GenericNativeIndexAccessor.java | 6 +- .../schema/GenericNativeIndexPopulator.java | 4 +- .../schema/GenericNativeIndexProvider.java | 2 +- .../schema/GenericNativeIndexReader.java | 16 +- .../impl/index/schema/NativeIndexKey.java | 15 +- .../impl/index/schema/SingleGenericKey.java | 139 ++++++++++++++++++ .../impl/index/schema/StringIndexKey.java | 8 + .../schema/GenericIndexKeyValidatorTest.java | 8 +- .../schema/GenericKeyStateFormatTest.java | 8 +- .../index/schema/GenericKeyStateTest.java | 10 +- 16 files changed, 323 insertions(+), 75 deletions(-) create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKey.java create mode 100644 community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SingleGenericKey.java diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/AbstractArrayType.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/AbstractArrayType.java index 6eeab52aabae6..bc0c6863001a1 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/AbstractArrayType.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/AbstractArrayType.java @@ -212,6 +212,7 @@ static boolean setArrayLengthWhenReading( GenericKeyState state, PageCursor curs if ( state.arrayLength < 0 || state.arrayLength > BIGGEST_REASONABLE_ARRAY_LENGTH ) { setCursorException( cursor, "non-valid array length, " + state.arrayLength ); + state.arrayLength = 0; return false; } return true; 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 2805770c5c6e1..e23bca735886f 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 @@ -31,14 +31,17 @@ import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; -import static java.lang.String.format; - -class CompositeGenericKey extends NativeIndexKey +/** + * {@link GenericKey} which has an array of {@link GenericKeyState} inside and can therefore hold composite key state. + * For single-keys please instead use the more efficient {@link SingleGenericKey}. + */ +class CompositeGenericKey extends GenericKey { private GenericKeyState[] states; CompositeGenericKey( int slots, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings ) { + super( spatialSettings ); states = new GenericKeyState[slots]; for ( int i = 0; i < states.length; i++ ) { @@ -113,11 +116,11 @@ void initAsPrefixHigh( int stateSlot, String prefix ) } @Override - int compareValueTo( CompositeGenericKey other ) + int compareValueTo( GenericKey other ) { for ( int i = 0; i < states.length; i++ ) { - int comparison = states[i].compareValueTo( other.states[i] ); + int comparison = states[i].compareValueTo( other.stateSlot( i ) ); if ( comparison != 0 ) { return comparison; @@ -126,63 +129,60 @@ int compareValueTo( CompositeGenericKey other ) return 0; } - void copyValuesFrom( CompositeGenericKey key ) + @Override + void copyValuesFrom( GenericKey key ) { - if ( key.states.length != states.length ) + if ( key.numberOfStateSlots() != states.length ) { - throw new IllegalArgumentException( "Different state lengths " + key.states.length + " vs " + states.length ); + throw new IllegalArgumentException( "Different state lengths " + key.numberOfStateSlots() + " vs " + states.length ); } - for ( int i = 0; i < key.states.length; i++ ) + for ( int i = 0; i < states.length; i++ ) { - states[i].copyFrom( key.states[i] ); + states[i].copyFrom( key.stateSlot( i ) ); } } + @Override int size() { int size = ENTITY_ID_SIZE; for ( GenericKeyState state : states ) { - size += state.size(); + size += state.stateSize(); } return size; } + @Override void write( PageCursor cursor ) { - cursor.putLong( getEntityId() ); for ( GenericKeyState state : states ) { state.put( cursor ); } } - void read( PageCursor cursor, int keySize ) + @Override + boolean read( PageCursor cursor, int keySize ) { - if ( keySize < ENTITY_ID_SIZE ) - { - initializeToDummyValue( cursor ); - cursor.setCursorException( format( "Failed to read CompositeGenericKey due to keySize < ENTITY_ID_SIZE, more precisely %d", keySize ) ); - return; - } - - initialize( cursor.getLong() ); int offset = cursor.getOffset(); for ( GenericKeyState state : states ) { - if ( !state.read( cursor, keySize ) ) + if ( !state.get( cursor, keySize ) ) { - initializeToDummyValue( cursor ); - return; + initializeToDummyValue(); + return false; } int offsetAfterRead = cursor.getOffset(); keySize -= offsetAfterRead - offset; offset = offsetAfterRead; } + return true; } - private void initializeToDummyValue( PageCursor cursor ) + @Override + void initializeToDummyValue() { setEntityId( Long.MIN_VALUE ); for ( GenericKeyState state : states ) @@ -208,27 +208,41 @@ public String toString() return joiner.toString(); } - public static void minimalSplitter( CompositeGenericKey left, CompositeGenericKey right, CompositeGenericKey into ) + @Override + void minimalSplitter( GenericKey left, GenericKey right, GenericKey into ) { int firstStateToDiffer = 0; int compare = 0; - while ( compare == 0 && firstStateToDiffer < right.states.length ) + int stateCount = right.numberOfStateSlots(); + + // It's really quite assumed that all these keys have the same number of state slots. + // It's not a practical runtime concern, so merely an assertion here + assert right.numberOfStateSlots() == stateCount; + assert into.numberOfStateSlots() == stateCount; + + while ( compare == 0 && firstStateToDiffer < stateCount ) { - GenericKeyState leftState = left.states[firstStateToDiffer]; - GenericKeyState rightState = right.states[firstStateToDiffer]; + GenericKeyState leftState = left.stateSlot( firstStateToDiffer ); + GenericKeyState rightState = right.stateSlot( firstStateToDiffer ); firstStateToDiffer++; compare = leftState.compareValueTo( rightState ); } firstStateToDiffer--; // Rewind last increment for ( int i = 0; i < firstStateToDiffer; i++ ) { - into.states[i].copyFrom( right.states[i] ); + into.stateSlot( i ).copyFrom( right.stateSlot( i ) ); } - for ( int i = firstStateToDiffer; i < into.states.length; i++ ) + for ( int i = firstStateToDiffer; i < stateCount; i++ ) { - GenericKeyState.minimalSplitter( left.states[i], right.states[i], into.states[i] ); + GenericKeyState.minimalSplitter( left.stateSlot( i ), right.stateSlot( i ), into.stateSlot( i ) ); } into.setCompareId( right.getCompareId() ); into.setEntityId( right.getEntityId() ); } + + @Override + GenericKeyState stateSlot( int slot ) + { + return states[slot]; + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidator.java index 3b910b9b1e6d4..60856583f49f0 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidator.java @@ -42,11 +42,11 @@ class GenericIndexKeyValidator implements Validator { private final int maxLength; - private final Layout layout; + private final Layout layout; private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings; private final int maxNumberOfCRSs; - GenericIndexKeyValidator( int maxLength, Layout layout, + GenericIndexKeyValidator( int maxLength, Layout layout, IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, int pageSize ) { this.maxLength = maxLength; @@ -143,7 +143,7 @@ private static int stringWorstCaseLength( int stringLength ) private int actualLength( Value[] values ) { - CompositeGenericKey key = layout.newKey(); + GenericKey key = layout.newKey(); key.initialize( 0 /*doesn't quite matter for size calculations, but an important method to call*/ ); for ( int i = 0; i < values.length; i++ ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKey.java new file mode 100644 index 0000000000000..b2b3c9fe2149b --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericKey.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import org.neo4j.io.pagecache.PageCursor; +import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache; +import org.neo4j.values.storable.CoordinateReferenceSystem; +import org.neo4j.values.storable.Value; + +/** + * Key abstraction to handle single or composite keys. + */ +abstract class GenericKey extends NativeIndexKey +{ + GenericKey( IndexSpecificSpaceFillingCurveSettingsCache spatialSettings ) + { + super( spatialSettings ); + } + + @Override + void assertValidValue( int stateSlot, Value value ) + { + // No need, we can handle all values + } + + abstract void initFromDerivedSpatialValue( int stateSlot, CoordinateReferenceSystem crs, long derivedValue, Inclusion inclusion ); + + abstract void initAsPrefixLow( int stateSlot, String prefix ); + + abstract void initAsPrefixHigh( int stateSlot, String prefix ); + + abstract void copyValuesFrom( GenericKey key ); + + abstract int size(); + + abstract void write( PageCursor cursor ); + + abstract boolean read( PageCursor cursor, int keySize ); + + abstract void minimalSplitter( GenericKey left, GenericKey right, GenericKey into ); + + abstract GenericKeyState stateSlot( int slot ); +} 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 61f04b5cf2df7..187ac20fbad79 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 @@ -238,7 +238,7 @@ static void minimalSplitter( GenericKeyState left, GenericKeyState right, Generi right.type.minimalSplitter( left, right, into ); } - int size() + int stateSize() { return type.valueSize( this ) + TYPE_ID_SIZE; } @@ -254,7 +254,7 @@ void put( PageCursor cursor ) type.putValue( cursor, this ); } - boolean read( PageCursor cursor, int size ) + boolean get( PageCursor cursor, int size ) { if ( size <= TYPE_ID_SIZE ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericLayout.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericLayout.java index 60126c893bda9..64ed4819524f4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericLayout.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericLayout.java @@ -22,7 +22,10 @@ import org.neo4j.io.pagecache.PageCursor; import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache; -class GenericLayout extends IndexLayout +import static java.lang.String.format; +import static org.neo4j.kernel.impl.index.schema.NativeIndexKey.ENTITY_ID_SIZE; + +class GenericLayout extends IndexLayout { private final int numberOfSlots; private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings; @@ -35,13 +38,17 @@ class GenericLayout extends IndexLayout } @Override - public CompositeGenericKey newKey() + public GenericKey newKey() { - return new CompositeGenericKey( numberOfSlots, spatialSettings ); + return numberOfSlots == 1 + // An optimized version which has the GenericKeyState built-in w/o indirection + ? new SingleGenericKey( spatialSettings ) + // A version which has an indirection to GenericKeyState[] + : new CompositeGenericKey( numberOfSlots, spatialSettings ); } @Override - public CompositeGenericKey copyKey( CompositeGenericKey key, CompositeGenericKey into ) + public GenericKey copyKey( GenericKey key, GenericKey into ) { into.setEntityId( key.getEntityId() ); into.setCompareId( key.getCompareId() ); @@ -50,20 +57,28 @@ public CompositeGenericKey copyKey( CompositeGenericKey key, CompositeGenericKey } @Override - public int keySize( CompositeGenericKey key ) + public int keySize( GenericKey key ) { return key.size(); } @Override - public void writeKey( PageCursor cursor, CompositeGenericKey key ) + public void writeKey( PageCursor cursor, GenericKey key ) { + cursor.putLong( key.getEntityId() ); key.write( cursor ); } @Override - public void readKey( PageCursor cursor, CompositeGenericKey into, int keySize ) + public void readKey( PageCursor cursor, GenericKey into, int keySize ) { + if ( keySize < ENTITY_ID_SIZE ) + { + into.initializeToDummyValue(); + cursor.setCursorException( format( "Failed to read CompositeGenericKey due to keySize < ENTITY_ID_SIZE, more precisely %d", keySize ) ); + } + + into.initialize( cursor.getLong() ); into.read( cursor, keySize ); } @@ -74,9 +89,9 @@ public boolean fixedSize() } @Override - public void minimalSplitter( CompositeGenericKey left, CompositeGenericKey right, CompositeGenericKey into ) + public void minimalSplitter( GenericKey left, GenericKey right, GenericKey into ) { - CompositeGenericKey.minimalSplitter( left, right, into ); + left.minimalSplitter( left, right, into ); } IndexSpecificSpaceFillingCurveSettingsCache getSpaceFillingCurveSettings() diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexAccessor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexAccessor.java index 1e78332dce20d..dc8d50a39a342 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexAccessor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexAccessor.java @@ -36,13 +36,13 @@ import org.neo4j.storageengine.api.schema.StoreIndexDescriptor; import org.neo4j.values.storable.Value; -class GenericNativeIndexAccessor extends NativeIndexAccessor +class GenericNativeIndexAccessor extends NativeIndexAccessor { private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings; private final SpaceFillingCurveConfiguration configuration; private Validator validator; - GenericNativeIndexAccessor( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout layout, + GenericNativeIndexAccessor( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout layout, RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor, IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, SpaceFillingCurveConfiguration configuration ) throws IOException { @@ -54,7 +54,7 @@ class GenericNativeIndexAccessor extends NativeIndexAccessor tree ) + protected void afterTreeInstantiation( GBPTree tree ) { validator = new GenericIndexKeyValidator( tree.keyValueSizeCap(), layout, spaceFillingCurveSettings, pageCache.pageSize() ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexPopulator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexPopulator.java index 2242337e43d86..c32b183b75f09 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexPopulator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexPopulator.java @@ -35,14 +35,14 @@ import static org.neo4j.kernel.impl.index.schema.NativeIndexes.deleteIndex; -class GenericNativeIndexPopulator extends NativeIndexPopulator +class GenericNativeIndexPopulator extends NativeIndexPopulator { private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings; private final IndexDirectoryStructure directoryStructure; private final SpaceFillingCurveConfiguration configuration; private final boolean archiveFailedIndex; - GenericNativeIndexPopulator( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout layout, + GenericNativeIndexPopulator( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout layout, IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings, IndexDirectoryStructure directoryStructure, SpaceFillingCurveConfiguration configuration, boolean archiveFailedIndex ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexProvider.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexProvider.java index fb5214a5ace57..65d341c9373ff 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexProvider.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/GenericNativeIndexProvider.java @@ -102,7 +102,7 @@ * We COULD allow this query and do filter during scan instead and take the extra cost into account when planning queries. * As of writing this, there is no such filtering implementation. */ -public class GenericNativeIndexProvider extends NativeIndexProvider +public class GenericNativeIndexProvider extends NativeIndexProvider { public static final String KEY = NATIVE_BTREE10.providerName(); public static final IndexProviderDescriptor DESCRIPTOR = new IndexProviderDescriptor( KEY, NATIVE_BTREE10.providerVersion() ); 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 cae64fd177e03..86350b9536577 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 @@ -42,12 +42,12 @@ import static org.neo4j.kernel.impl.index.schema.NativeIndexKey.Inclusion.LOW; import static org.neo4j.kernel.impl.index.schema.NativeIndexKey.Inclusion.NEUTRAL; -class GenericNativeIndexReader extends NativeIndexReader +class GenericNativeIndexReader extends NativeIndexReader { private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings; private final SpaceFillingCurveConfiguration configuration; - GenericNativeIndexReader( GBPTree tree, IndexLayout layout, + GenericNativeIndexReader( GBPTree tree, IndexLayout layout, IndexDescriptor descriptor, IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, SpaceFillingCurveConfiguration configuration ) { @@ -98,8 +98,8 @@ public void query( IndexProgressor.NodeValueClient client, IndexOrder indexOrder { // Here's a sub-query that we'll have to do for this geometry range. Build this query from all predicates // and when getting to the geometry range predicate that sparked these sub-query chenanigans, swap in this sub-query in its place. - CompositeGenericKey treeKeyFrom = layout.newKey(); - CompositeGenericKey treeKeyTo = layout.newKey(); + GenericKey treeKeyFrom = layout.newKey(); + GenericKey treeKeyTo = layout.newKey(); initializeFromToKeys( treeKeyFrom, treeKeyTo ); boolean needFiltering = initializeRangeForGeometrySubQuery( treeKeyFrom, treeKeyTo, query, crs, range ); startSeekForInitializedRange( multiProgressor, treeKeyFrom, treeKeyTo, query, indexOrder, needFiltering, needsValues ); @@ -134,7 +134,7 @@ public void query( IndexProgressor.NodeValueClient client, IndexOrder indexOrder * 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, + private boolean initializeRangeForGeometrySubQuery( GenericKey treeKeyFrom, GenericKey treeKeyTo, IndexQuery[] query, CoordinateReferenceSystem crs, SpaceFillingCurve.LongRange range ) { boolean needsFiltering = false; @@ -188,12 +188,12 @@ private boolean initializeRangeForGeometrySubQuery( CompositeGenericKey treeKeyF } @Override - boolean initializeRangeForQuery( CompositeGenericKey treeKeyFrom, CompositeGenericKey treeKeyTo, IndexQuery[] query ) + boolean initializeRangeForQuery( GenericKey treeKeyFrom, GenericKey treeKeyTo, IndexQuery[] query ) { return initializeRangeForGeometrySubQuery( treeKeyFrom, treeKeyTo, query, null, null ); } - private static void initFromForRange( int stateSlot, RangePredicate rangePredicate, CompositeGenericKey treeKeyFrom ) + private static void initFromForRange( int stateSlot, RangePredicate rangePredicate, GenericKey treeKeyFrom ) { Value fromValue = rangePredicate.fromValue(); if ( fromValue == Values.NO_VALUE ) @@ -207,7 +207,7 @@ private static void initFromForRange( int stateSlot, RangePredicate rangePred } } - private static void initToForRange( int stateSlot, RangePredicate rangePredicate, CompositeGenericKey treeKeyTo ) + private static void initToForRange( int stateSlot, RangePredicate rangePredicate, GenericKey treeKeyTo ) { Value toValue = rangePredicate.toValue(); if ( toValue == Values.NO_VALUE ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexKey.java index 6ef998b698721..8aa5e102cea45 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeIndexKey.java @@ -20,11 +20,11 @@ package org.neo4j.kernel.impl.index.schema; import org.neo4j.index.internal.gbptree.GBPTree; -import org.neo4j.kernel.impl.store.TemporalValueWriterAdapter; +import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache; import org.neo4j.values.storable.Value; import org.neo4j.values.storable.ValueGroup; -abstract class NativeIndexKey> extends TemporalValueWriterAdapter +abstract class NativeIndexKey> extends GenericKeyState { static final int ENTITY_ID_SIZE = Long.BYTES; @@ -40,6 +40,17 @@ enum Inclusion private long entityId; private boolean compareId = DEFAULT_COMPARE_ID; + NativeIndexKey( IndexSpecificSpaceFillingCurveSettingsCache settings ) + { + super( settings ); + } + + NativeIndexKey() + { + // TODO just kidding + super( null ); + } + /** * Marks that comparisons with this key requires also comparing entityId, this allows functionality * of inclusive/exclusive bounds of range queries. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SingleGenericKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SingleGenericKey.java new file mode 100644 index 0000000000000..e570ed28c2396 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SingleGenericKey.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import org.neo4j.io.pagecache.PageCursor; +import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache; +import org.neo4j.values.storable.CoordinateReferenceSystem; +import org.neo4j.values.storable.Value; +import org.neo4j.values.storable.ValueGroup; + +/** + * {@link GenericKey} which can handle single-keys and operates on its {@link GenericKeyState} inside it, since it actually has + * that state inside of it. + * For composite keys please use {@link CompositeGenericKey}. + */ +class SingleGenericKey extends GenericKey +{ + SingleGenericKey( IndexSpecificSpaceFillingCurveSettingsCache settings ) + { + super( settings ); + } + + @Override + void writeValue( int stateSlot, Value value, Inclusion inclusion ) + { + writeValue( value, inclusion ); + } + + @Override + void initialize( long entityId ) + { + super.initialize( entityId ); + clear(); + } + + @Override + void initFromDerivedSpatialValue( int stateSlot, CoordinateReferenceSystem crs, long derivedValue, Inclusion inclusion ) + { + writePointDerived( crs, derivedValue, inclusion ); + } + + @Override + void initAsPrefixLow( int stateSlot, String prefix ) + { + initAsPrefixLow( prefix ); + } + + @Override + void initAsPrefixHigh( int stateSlot, String prefix ) + { + initAsPrefixHigh( prefix ); + } + + @Override + void copyValuesFrom( GenericKey key ) + { + copyFrom( key ); + } + + @Override + void write( PageCursor cursor ) + { + put( cursor ); + } + + @Override + int size() + { + return ENTITY_ID_SIZE + stateSize(); + } + + @Override + boolean read( PageCursor cursor, int keySize ) + { + return get( cursor, keySize ); + } + + @Override + void minimalSplitter( GenericKey left, GenericKey right, GenericKey into ) + { + GenericKeyState.minimalSplitter( left, right, into ); + into.setCompareId( right.getCompareId() ); + into.setEntityId( right.getEntityId() ); + } + + @Override + GenericKeyState stateSlot( int slot ) + { + assert slot == 0; + return this; + } + + @Override + Value[] asValues() + { + return new Value[] {asValue()}; + } + + @Override + void initValueAsLowest( int stateSlot, ValueGroup valueGroup ) + { + initValueAsLowest( valueGroup ); + } + + @Override + void initValueAsHighest( int stateSlot, ValueGroup valueGroup ) + { + initValueAsHighest( valueGroup ); + } + + @Override + int numberOfStateSlots() + { + return 1; + } + + @Override + int compareValueTo( GenericKey other ) + { + return compareValueTo( (GenericKeyState) other ); + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexKey.java index cbb759a6ebfb3..2c648c00d520c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringIndexKey.java @@ -191,6 +191,14 @@ public void writeString( char value ) writeString( String.valueOf( value ) ); } + @Override + public void writeUTF8( byte[] bytes, int offset, int length ) + { + this.bytes = bytes; + bytesLength = length; + bytesDereferenced = true; + } + void copyFrom( StringIndexKey key ) { copyFrom( key, key.bytesLength ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidatorTest.java index 9ac6baee39015..22a53fb01b997 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidatorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericIndexKeyValidatorTest.java @@ -62,7 +62,7 @@ public class GenericIndexKeyValidatorTest public void shouldNotBotherSerializingToRealBytesIfFarFromThreshold() { // given - Layout layout = mock( Layout.class ); + Layout layout = mock( Layout.class ); doThrow( RuntimeException.class ).when( layout ).newKey(); GenericIndexKeyValidator validator = new GenericIndexKeyValidator( 120, layout, mock( IndexSpecificSpaceFillingCurveSettingsCache.class ), PAGE_SIZE ); @@ -76,7 +76,7 @@ public void shouldNotBotherSerializingToRealBytesIfFarFromThreshold() public void shouldInvolveSerializingToRealBytesIfMayCrossThreshold() { // given - Layout layout = mock( Layout.class ); + Layout layout = mock( Layout.class ); when( layout.newKey() ).thenReturn( new CompositeGenericKey( 3, spatialSettings() ) ); GenericIndexKeyValidator validator = new GenericIndexKeyValidator( 48, layout, mock( IndexSpecificSpaceFillingCurveSettingsCache.class ), PAGE_SIZE ); @@ -103,7 +103,7 @@ public void shouldReportCorrectValidationErrorsOnRandomlyGeneratedValues() GenericLayout layout = new GenericLayout( slots, spatialSettings() ); GenericIndexKeyValidator validator = new GenericIndexKeyValidator( maxLength, layout, mock( IndexSpecificSpaceFillingCurveSettingsCache.class ), PAGE_SIZE ); - CompositeGenericKey key = layout.newKey(); + GenericKey key = layout.newKey(); int countOk = 0; int countNotOk = 0; @@ -170,7 +170,7 @@ private IndexSpecificSpaceFillingCurveSettingsCache spatialSettings() new ConfiguredSpaceFillingCurveSettingsCache( Config.defaults() ), new HashMap<>() ); } - private static int actualSize( Value[] tuple, CompositeGenericKey key ) + private static int actualSize( Value[] tuple, GenericKey key ) { key.initialize( 0 ); for ( int i = 0; i < tuple.length; i++ ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateFormatTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateFormatTest.java index aaf1312366e84..3f9e76af6e3ac 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateFormatTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateFormatTest.java @@ -197,7 +197,7 @@ private void readFormatVersion( PageCursor c ) private void putData( PageCursor c ) { GenericLayout layout = getLayout(); - CompositeGenericKey key = layout.newKey(); + GenericKey key = layout.newKey(); for ( Value value : values ) { initializeFromValue( key, value ); @@ -206,7 +206,7 @@ private void putData( PageCursor c ) } } - private void initializeFromValue( CompositeGenericKey key, Value value ) + private void initializeFromValue( GenericKey key, Value value ) { key.initialize( ENTITY_ID ); for ( int i = 0; i < NUMBER_OF_SLOTS; i++ ) @@ -218,8 +218,8 @@ private void initializeFromValue( CompositeGenericKey key, Value value ) private void verifyData( PageCursor c ) { GenericLayout layout = getLayout(); - CompositeGenericKey readCompositeKey = layout.newKey(); - CompositeGenericKey comparison = layout.newKey(); + GenericKey readCompositeKey = layout.newKey(); + GenericKey comparison = layout.newKey(); for ( Value value : values ) { int keySize = c.getInt(); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateTest.java index d5e14dd6f0fbc..20d41acb1fe0c 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/GenericKeyStateTest.java @@ -147,9 +147,9 @@ void readWhatIsWritten( ValueGenerator valueGenerator ) // Then GenericKeyState readState = newKeyState(); - int size = writeState.size(); + int size = writeState.stateSize(); cursor.setOffset( offset ); - assertTrue( readState.read( cursor, size ), "failed to read" ); + assertTrue( readState.get( cursor, size ), "failed to read" ); assertEquals( 0, readState.compareValueTo( writeState ), "key states are not equal" ); Value readValue = readState.asValue(); assertEquals( value, readValue, "deserialized values are not equal" ); @@ -262,7 +262,7 @@ void mustReportCorrectSize( ValueGenerator valueGenerator ) int offsetBefore = cursor.getOffset(); // When - int reportedSize = state.size(); + int reportedSize = state.stateSize(); state.put( cursor ); int offsetAfter = cursor.getOffset(); @@ -415,7 +415,7 @@ void shouldNeverOverwriteDereferencedTextValues() // and we should not overwrite the second value when we read back the first value from page genericKeyState.clear(); - genericKeyState.read( cursor, keySize ); + genericKeyState.get( cursor, keySize ); Value dereferencedValue3 = genericKeyState.asValue(); assertEquals( srcValue, dereferencedValue3 ); assertEquals( srcValue2, dereferencedValue2 ); @@ -453,7 +453,7 @@ private void shouldReadBackToExactOriginalValue( Value srcValue ) // when reading it back state.clear(); - state.read( cursor, keySize ); + state.get( cursor, keySize ); // then it should also be retrieved as char value Value retrievedValueAfterReadFromCursor = state.asValue();