Skip to content

Commit

Permalink
Avoid GenericKeyState[] in generic key
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tinwelint committed Oct 2, 2018
1 parent 44b21a0 commit 133610f
Show file tree
Hide file tree
Showing 16 changed files with 323 additions and 75 deletions.
Expand Up @@ -212,6 +212,7 @@ static boolean setArrayLengthWhenReading( GenericKeyState state, PageCursor curs
if ( state.arrayLength < 0 || state.arrayLength > BIGGEST_REASONABLE_ARRAY_LENGTH ) if ( state.arrayLength < 0 || state.arrayLength > BIGGEST_REASONABLE_ARRAY_LENGTH )
{ {
setCursorException( cursor, "non-valid array length, " + state.arrayLength ); setCursorException( cursor, "non-valid array length, " + state.arrayLength );
state.arrayLength = 0;
return false; return false;
} }
return true; return true;
Expand Down
Expand Up @@ -31,14 +31,17 @@
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.ValueGroup; import org.neo4j.values.storable.ValueGroup;


import static java.lang.String.format; /**

* {@link GenericKey} which has an array of {@link GenericKeyState} inside and can therefore hold composite key state.
class CompositeGenericKey extends NativeIndexKey<CompositeGenericKey> * For single-keys please instead use the more efficient {@link SingleGenericKey}.
*/
class CompositeGenericKey extends GenericKey
{ {
private GenericKeyState[] states; private GenericKeyState[] states;


CompositeGenericKey( int slots, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings ) CompositeGenericKey( int slots, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings )
{ {
super( spatialSettings );
states = new GenericKeyState[slots]; states = new GenericKeyState[slots];
for ( int i = 0; i < states.length; i++ ) for ( int i = 0; i < states.length; i++ )
{ {
Expand Down Expand Up @@ -113,11 +116,11 @@ void initAsPrefixHigh( int stateSlot, String prefix )
} }


@Override @Override
int compareValueTo( CompositeGenericKey other ) int compareValueTo( GenericKey other )
{ {
for ( int i = 0; i < states.length; i++ ) 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 ) if ( comparison != 0 )
{ {
return comparison; return comparison;
Expand All @@ -126,63 +129,60 @@ int compareValueTo( CompositeGenericKey other )
return 0; 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()
{ {
int size = ENTITY_ID_SIZE; int size = ENTITY_ID_SIZE;
for ( GenericKeyState state : states ) for ( GenericKeyState state : states )
{ {
size += state.size(); size += state.stateSize();
} }
return size; return size;
} }


@Override
void write( PageCursor cursor ) void write( PageCursor cursor )
{ {
cursor.putLong( getEntityId() );
for ( GenericKeyState state : states ) for ( GenericKeyState state : states )
{ {
state.put( cursor ); 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(); int offset = cursor.getOffset();
for ( GenericKeyState state : states ) for ( GenericKeyState state : states )
{ {
if ( !state.read( cursor, keySize ) ) if ( !state.get( cursor, keySize ) )
{ {
initializeToDummyValue( cursor ); initializeToDummyValue();
return; return false;
} }
int offsetAfterRead = cursor.getOffset(); int offsetAfterRead = cursor.getOffset();
keySize -= offsetAfterRead - offset; keySize -= offsetAfterRead - offset;
offset = offsetAfterRead; offset = offsetAfterRead;
} }
return true;
} }


private void initializeToDummyValue( PageCursor cursor ) @Override
void initializeToDummyValue()
{ {
setEntityId( Long.MIN_VALUE ); setEntityId( Long.MIN_VALUE );
for ( GenericKeyState state : states ) for ( GenericKeyState state : states )
Expand All @@ -208,27 +208,41 @@ public String toString()
return joiner.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 firstStateToDiffer = 0;
int compare = 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 leftState = left.stateSlot( firstStateToDiffer );
GenericKeyState rightState = right.states[firstStateToDiffer]; GenericKeyState rightState = right.stateSlot( firstStateToDiffer );
firstStateToDiffer++; firstStateToDiffer++;
compare = leftState.compareValueTo( rightState ); compare = leftState.compareValueTo( rightState );
} }
firstStateToDiffer--; // Rewind last increment firstStateToDiffer--; // Rewind last increment
for ( int i = 0; i < firstStateToDiffer; i++ ) 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.setCompareId( right.getCompareId() );
into.setEntityId( right.getEntityId() ); into.setEntityId( right.getEntityId() );
} }

@Override
GenericKeyState stateSlot( int slot )
{
return states[slot];
}
} }
Expand Up @@ -42,11 +42,11 @@
class GenericIndexKeyValidator implements Validator<Value[]> class GenericIndexKeyValidator implements Validator<Value[]>
{ {
private final int maxLength; private final int maxLength;
private final Layout<CompositeGenericKey,NativeIndexValue> layout; private final Layout<GenericKey,NativeIndexValue> layout;
private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings; private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings;
private final int maxNumberOfCRSs; private final int maxNumberOfCRSs;


GenericIndexKeyValidator( int maxLength, Layout<CompositeGenericKey,NativeIndexValue> layout, GenericIndexKeyValidator( int maxLength, Layout<GenericKey,NativeIndexValue> layout,
IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, int pageSize ) IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, int pageSize )
{ {
this.maxLength = maxLength; this.maxLength = maxLength;
Expand Down Expand Up @@ -143,7 +143,7 @@ private static int stringWorstCaseLength( int stringLength )


private int actualLength( Value[] values ) 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*/ ); key.initialize( 0 /*doesn't quite matter for size calculations, but an important method to call*/ );
for ( int i = 0; i < values.length; i++ ) for ( int i = 0; i < values.length; i++ )
{ {
Expand Down
@@ -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 <http://www.gnu.org/licenses/>.
*/
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>
{
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 );
}
Expand Up @@ -238,7 +238,7 @@ static void minimalSplitter( GenericKeyState left, GenericKeyState right, Generi
right.type.minimalSplitter( left, right, into ); right.type.minimalSplitter( left, right, into );
} }


int size() int stateSize()
{ {
return type.valueSize( this ) + TYPE_ID_SIZE; return type.valueSize( this ) + TYPE_ID_SIZE;
} }
Expand All @@ -254,7 +254,7 @@ void put( PageCursor cursor )
type.putValue( cursor, this ); type.putValue( cursor, this );
} }


boolean read( PageCursor cursor, int size ) boolean get( PageCursor cursor, int size )
{ {
if ( size <= TYPE_ID_SIZE ) if ( size <= TYPE_ID_SIZE )
{ {
Expand Down
Expand Up @@ -22,7 +22,10 @@
import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache; import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettingsCache;


class GenericLayout extends IndexLayout<CompositeGenericKey,NativeIndexValue> import static java.lang.String.format;
import static org.neo4j.kernel.impl.index.schema.NativeIndexKey.ENTITY_ID_SIZE;

class GenericLayout extends IndexLayout<GenericKey,NativeIndexValue>
{ {
private final int numberOfSlots; private final int numberOfSlots;
private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings; private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings;
Expand All @@ -35,13 +38,17 @@ class GenericLayout extends IndexLayout<CompositeGenericKey,NativeIndexValue>
} }


@Override @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 @Override
public CompositeGenericKey copyKey( CompositeGenericKey key, CompositeGenericKey into ) public GenericKey copyKey( GenericKey key, GenericKey into )
{ {
into.setEntityId( key.getEntityId() ); into.setEntityId( key.getEntityId() );
into.setCompareId( key.getCompareId() ); into.setCompareId( key.getCompareId() );
Expand All @@ -50,20 +57,28 @@ public CompositeGenericKey copyKey( CompositeGenericKey key, CompositeGenericKey
} }


@Override @Override
public int keySize( CompositeGenericKey key ) public int keySize( GenericKey key )
{ {
return key.size(); return key.size();
} }


@Override @Override
public void writeKey( PageCursor cursor, CompositeGenericKey key ) public void writeKey( PageCursor cursor, GenericKey key )
{ {
cursor.putLong( key.getEntityId() );
key.write( cursor ); key.write( cursor );
} }


@Override @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 ); into.read( cursor, keySize );
} }


Expand All @@ -74,9 +89,9 @@ public boolean fixedSize()
} }


@Override @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() IndexSpecificSpaceFillingCurveSettingsCache getSpaceFillingCurveSettings()
Expand Down
Expand Up @@ -36,13 +36,13 @@
import org.neo4j.storageengine.api.schema.StoreIndexDescriptor; import org.neo4j.storageengine.api.schema.StoreIndexDescriptor;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;


class GenericNativeIndexAccessor extends NativeIndexAccessor<CompositeGenericKey,NativeIndexValue> class GenericNativeIndexAccessor extends NativeIndexAccessor<GenericKey,NativeIndexValue>
{ {
private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings; private final IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings;
private final SpaceFillingCurveConfiguration configuration; private final SpaceFillingCurveConfiguration configuration;
private Validator<Value[]> validator; private Validator<Value[]> validator;


GenericNativeIndexAccessor( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout<CompositeGenericKey,NativeIndexValue> layout, GenericNativeIndexAccessor( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout<GenericKey,NativeIndexValue> layout,
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor, RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor,
IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, SpaceFillingCurveConfiguration configuration ) throws IOException IndexSpecificSpaceFillingCurveSettingsCache spaceFillingCurveSettings, SpaceFillingCurveConfiguration configuration ) throws IOException
{ {
Expand All @@ -54,7 +54,7 @@ class GenericNativeIndexAccessor extends NativeIndexAccessor<CompositeGenericKey
} }


@Override @Override
protected void afterTreeInstantiation( GBPTree<CompositeGenericKey,NativeIndexValue> tree ) protected void afterTreeInstantiation( GBPTree<GenericKey,NativeIndexValue> tree )
{ {
validator = new GenericIndexKeyValidator( tree.keyValueSizeCap(), layout, spaceFillingCurveSettings, pageCache.pageSize() ); validator = new GenericIndexKeyValidator( tree.keyValueSizeCap(), layout, spaceFillingCurveSettings, pageCache.pageSize() );
} }
Expand Down
Expand Up @@ -35,14 +35,14 @@


import static org.neo4j.kernel.impl.index.schema.NativeIndexes.deleteIndex; import static org.neo4j.kernel.impl.index.schema.NativeIndexes.deleteIndex;


class GenericNativeIndexPopulator extends NativeIndexPopulator<CompositeGenericKey,NativeIndexValue> class GenericNativeIndexPopulator extends NativeIndexPopulator<GenericKey,NativeIndexValue>
{ {
private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings; private final IndexSpecificSpaceFillingCurveSettingsCache spatialSettings;
private final IndexDirectoryStructure directoryStructure; private final IndexDirectoryStructure directoryStructure;
private final SpaceFillingCurveConfiguration configuration; private final SpaceFillingCurveConfiguration configuration;
private final boolean archiveFailedIndex; private final boolean archiveFailedIndex;


GenericNativeIndexPopulator( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout<CompositeGenericKey,NativeIndexValue> layout, GenericNativeIndexPopulator( PageCache pageCache, FileSystemAbstraction fs, File storeFile, IndexLayout<GenericKey,NativeIndexValue> layout,
IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings, IndexProvider.Monitor monitor, StoreIndexDescriptor descriptor, IndexSpecificSpaceFillingCurveSettingsCache spatialSettings,
IndexDirectoryStructure directoryStructure, SpaceFillingCurveConfiguration configuration, boolean archiveFailedIndex ) IndexDirectoryStructure directoryStructure, SpaceFillingCurveConfiguration configuration, boolean archiveFailedIndex )
{ {
Expand Down

0 comments on commit 133610f

Please sign in to comment.