Skip to content

Commit

Permalink
Add consistency checker support for relationship indexes.
Browse files Browse the repository at this point in the history
An analog for PropertyAndNodeIndexedCheck is not added, though.
  • Loading branch information
chrisvest committed Sep 5, 2018
1 parent 9823b98 commit 3bc3c99
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 7 deletions.
Expand Up @@ -25,12 +25,16 @@
import org.neo4j.consistency.store.RecordAccess; import org.neo4j.consistency.store.RecordAccess;
import org.neo4j.consistency.store.synthetic.IndexEntry; import org.neo4j.consistency.store.synthetic.IndexEntry;
import org.neo4j.internal.kernel.api.schema.SchemaDescriptor; import org.neo4j.internal.kernel.api.schema.SchemaDescriptor;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.storageengine.api.schema.StoreIndexDescriptor; import org.neo4j.storageengine.api.schema.StoreIndexDescriptor;


public class IndexCheck implements RecordCheck<IndexEntry, ConsistencyReport.IndexConsistencyReport> public class IndexCheck implements RecordCheck<IndexEntry, ConsistencyReport.IndexConsistencyReport>
{ {
private final long[] entityTokenLongIds; private final long[] entityTokenLongIds;
private final SchemaDescriptor.PropertySchemaType propertySchemaType; private final SchemaDescriptor.PropertySchemaType propertySchemaType;
private final EntityType entityType;
private NodeInUseWithCorrectLabelsCheck<IndexEntry,ConsistencyReport.IndexConsistencyReport> nodeChecker;
private RelationshipInUseWithCorrectRelationshipTypeCheck<IndexEntry,ConsistencyReport.IndexConsistencyReport> relationshipChecker;


public IndexCheck( StoreIndexDescriptor indexRule ) public IndexCheck( StoreIndexDescriptor indexRule )
{ {
Expand All @@ -42,13 +46,32 @@ public IndexCheck( StoreIndexDescriptor indexRule )
entityTokenLongIds[i] = entityTokenIntIds[i]; entityTokenLongIds[i] = entityTokenIntIds[i];
} }
propertySchemaType = schema.propertySchemaType(); propertySchemaType = schema.propertySchemaType();
entityType = schema.entityType();
if ( entityType == EntityType.NODE )
{
nodeChecker = new NodeInUseWithCorrectLabelsCheck<>( entityTokenLongIds, propertySchemaType, false );
}
if ( entityType == EntityType.RELATIONSHIP )
{
relationshipChecker = new RelationshipInUseWithCorrectRelationshipTypeCheck<>( entityTokenLongIds );
}
} }


@Override @Override
public void check( IndexEntry record, CheckerEngine<IndexEntry, ConsistencyReport.IndexConsistencyReport> engine, RecordAccess records ) public void check( IndexEntry record, CheckerEngine<IndexEntry, ConsistencyReport.IndexConsistencyReport> engine, RecordAccess records )
{ {
NodeInUseWithCorrectLabelsCheck<IndexEntry,ConsistencyReport.IndexConsistencyReport> checker = long id = record.getId();
new NodeInUseWithCorrectLabelsCheck<>( entityTokenLongIds, propertySchemaType, false ); if ( entityType == EntityType.NODE )
engine.comparativeCheck( records.node( record.getId() ), checker ); {
engine.comparativeCheck( records.node( id ), nodeChecker );
}
else if ( entityType == EntityType.RELATIONSHIP )
{
engine.comparativeCheck( records.relationship( id ), relationshipChecker );
}
else
{
throw new IllegalStateException( "Don't know how to check index entry of entity type " + entityType );
}
} }
} }
Expand Up @@ -55,7 +55,7 @@ public NodeInUseWithCorrectLabelsCheck( long[] expectedEntityTokenIds, SchemaDes
this.indexLabels = sortAndDeduplicate( expectedEntityTokenIds ); this.indexLabels = sortAndDeduplicate( expectedEntityTokenIds );
} }


private static long[] sortAndDeduplicate( long[] labels ) static long[] sortAndDeduplicate( long[] labels )
{ {
if ( ArrayUtils.isNotEmpty( labels ) ) if ( ArrayUtils.isNotEmpty( labels ) )
{ {
Expand Down
Expand Up @@ -47,6 +47,7 @@
import org.neo4j.kernel.impl.store.record.PropertyBlock; import org.neo4j.kernel.impl.store.record.PropertyBlock;
import org.neo4j.kernel.impl.store.record.PropertyRecord; import org.neo4j.kernel.impl.store.record.PropertyRecord;
import org.neo4j.kernel.impl.store.record.Record; import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
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;
Expand Down Expand Up @@ -98,14 +99,15 @@ private void matchIndexesToNode(
IntObjectMap<PropertyBlock> nodePropertyMap = null; IntObjectMap<PropertyBlock> nodePropertyMap = null;
for ( StoreIndexDescriptor indexRule : indexes.onlineRules() ) for ( StoreIndexDescriptor indexRule : indexes.onlineRules() )
{ {
if ( indexRule.schema().isAffected( labels ) ) SchemaDescriptor schema = indexRule.schema();
if ( schema.entityType() == EntityType.NODE && schema.isAffected( labels ) )
{ {
if ( nodePropertyMap == null ) if ( nodePropertyMap == null )
{ {
nodePropertyMap = properties( propertyReader.propertyBlocks( propertyRecs ) ); nodePropertyMap = properties( propertyReader.propertyBlocks( propertyRecs ) );
} }


int[] indexPropertyIds = indexRule.schema().getPropertyIds(); int[] indexPropertyIds = schema.getPropertyIds();
if ( nodeHasSchemaProperties( nodePropertyMap, indexPropertyIds ) ) if ( nodeHasSchemaProperties( nodePropertyMap, indexPropertyIds ) )
{ {
Value[] values = getPropertyValues( nodePropertyMap, indexPropertyIds ); Value[] values = getPropertyValues( nodePropertyMap, indexPropertyIds );
Expand Down
@@ -0,0 +1,66 @@
/*
* 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.consistency.checking.full;

import java.util.Arrays;

import org.neo4j.consistency.checking.CheckerEngine;
import org.neo4j.consistency.checking.ComparativeRecordChecker;
import org.neo4j.consistency.report.ConsistencyReport;
import org.neo4j.consistency.store.RecordAccess;
import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;

import static org.neo4j.consistency.checking.full.NodeInUseWithCorrectLabelsCheck.sortAndDeduplicate;

public class RelationshipInUseWithCorrectRelationshipTypeCheck
<RECORD extends AbstractBaseRecord, REPORT extends ConsistencyReport.RelationshipInUseWithCorrectRelationshipTypeReport>
implements ComparativeRecordChecker<RECORD,RelationshipRecord, REPORT>
{
private final long[] indexRelationshipTypes;

public RelationshipInUseWithCorrectRelationshipTypeCheck( long[] expectedEntityTokenIds )
{
this.indexRelationshipTypes = sortAndDeduplicate( expectedEntityTokenIds );
}

@Override
public void checkReference( RECORD record, RelationshipRecord relationshipRecord, CheckerEngine<RECORD,REPORT> engine, RecordAccess records )
{
if ( relationshipRecord.inUse() )
{
// Relationship indexes are always semantically multi-token, which means that the relationship record just need to have one of the possible
// relationship types mentioned by the index. Relationships can't have more than one type anyway.
long type = relationshipRecord.getType();
if ( Arrays.binarySearch( indexRelationshipTypes, type ) < 0 )
{
// The relationship did not have any of the relationship types mentioned by the index.
for ( long indexRelationshipType : indexRelationshipTypes )
{
engine.report().relationshipDoesNotHaveExpectedRelationshipType( relationshipRecord, indexRelationshipType );
}
}
}
else
{
engine.report().relationshipNotInUse( relationshipRecord );
}
}
}
Expand Up @@ -479,6 +479,13 @@ interface NodeInUseWithCorrectLabelsReport extends ConsistencyReport
void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId ); void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId );
} }


interface RelationshipInUseWithCorrectRelationshipTypeReport extends ConsistencyReport
{
void relationshipNotInUse( RelationshipRecord referredRelationshipRecord );

void relationshipDoesNotHaveExpectedRelationshipType( RelationshipRecord referredRelationshipRecord, long expectedRelationshipTypeId );
}

interface LabelScanConsistencyReport extends NodeInUseWithCorrectLabelsReport interface LabelScanConsistencyReport extends NodeInUseWithCorrectLabelsReport
{ {
@Override @Override
Expand All @@ -498,16 +505,24 @@ interface LabelScanConsistencyReport extends NodeInUseWithCorrectLabelsReport
void dirtyIndex(); void dirtyIndex();
} }


interface IndexConsistencyReport extends NodeInUseWithCorrectLabelsReport interface IndexConsistencyReport extends NodeInUseWithCorrectLabelsReport, RelationshipInUseWithCorrectRelationshipTypeReport
{ {
@Override @Override
@Documented( "This index entry refers to a node record that is not in use." ) @Documented( "This index entry refers to a node record that is not in use." )
void nodeNotInUse( NodeRecord referredNodeRecord ); void nodeNotInUse( NodeRecord referredNodeRecord );


@Override
@Documented( "This index entry refers to a relationship record that is not in use." )
void relationshipNotInUse( RelationshipRecord referredRelationshipRecord );

@Override @Override
@Documented( "This index entry refers to a node that does not have the expected label." ) @Documented( "This index entry refers to a node that does not have the expected label." )
void nodeDoesNotHaveExpectedLabel( NodeRecord referredNodeRecord, long expectedLabelId ); void nodeDoesNotHaveExpectedLabel( NodeRecord referredNodeRecord, long expectedLabelId );


@Override
@Documented( "This index entry refers to a relationship that does not have the expected relationship type." )
void relationshipDoesNotHaveExpectedRelationshipType( RelationshipRecord referredRelationshipRecord, long expectedRelationshipTypeId );

@Override @Override
@Documented( "This node record has a label that is not found in the index for this node" ) @Documented( "This node record has a label that is not found in the index for this node" )
void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId ); void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId );
Expand Down

0 comments on commit 3bc3c99

Please sign in to comment.