From 3bc3c99cc8b580b8084af634380282cf928c5a84 Mon Sep 17 00:00:00 2001 From: Chris Vest Date: Thu, 30 Aug 2018 16:02:03 +0200 Subject: [PATCH] Add consistency checker support for relationship indexes. An analog for PropertyAndNodeIndexedCheck is not added, though. --- .../consistency/checking/full/IndexCheck.java | 29 +++++++- .../full/NodeInUseWithCorrectLabelsCheck.java | 2 +- .../full/PropertyAndNodeIndexedCheck.java | 6 +- ...InUseWithCorrectRelationshipTypeCheck.java | 66 +++++++++++++++++++ .../consistency/report/ConsistencyReport.java | 17 ++++- 5 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/RelationshipInUseWithCorrectRelationshipTypeCheck.java diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/IndexCheck.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/IndexCheck.java index 087d2b71f71e1..cdf91f1a62a3c 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/IndexCheck.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/IndexCheck.java @@ -25,12 +25,16 @@ import org.neo4j.consistency.store.RecordAccess; import org.neo4j.consistency.store.synthetic.IndexEntry; import org.neo4j.internal.kernel.api.schema.SchemaDescriptor; +import org.neo4j.storageengine.api.EntityType; import org.neo4j.storageengine.api.schema.StoreIndexDescriptor; public class IndexCheck implements RecordCheck { private final long[] entityTokenLongIds; private final SchemaDescriptor.PropertySchemaType propertySchemaType; + private final EntityType entityType; + private NodeInUseWithCorrectLabelsCheck nodeChecker; + private RelationshipInUseWithCorrectRelationshipTypeCheck relationshipChecker; public IndexCheck( StoreIndexDescriptor indexRule ) { @@ -42,13 +46,32 @@ public IndexCheck( StoreIndexDescriptor indexRule ) entityTokenLongIds[i] = entityTokenIntIds[i]; } 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 public void check( IndexEntry record, CheckerEngine engine, RecordAccess records ) { - NodeInUseWithCorrectLabelsCheck checker = - new NodeInUseWithCorrectLabelsCheck<>( entityTokenLongIds, propertySchemaType, false ); - engine.comparativeCheck( records.node( record.getId() ), checker ); + long id = record.getId(); + if ( entityType == EntityType.NODE ) + { + 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 ); + } } } diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/NodeInUseWithCorrectLabelsCheck.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/NodeInUseWithCorrectLabelsCheck.java index cfd1069ae30ea..f11c07e96f571 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/NodeInUseWithCorrectLabelsCheck.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/NodeInUseWithCorrectLabelsCheck.java @@ -55,7 +55,7 @@ public NodeInUseWithCorrectLabelsCheck( long[] expectedEntityTokenIds, SchemaDes this.indexLabels = sortAndDeduplicate( expectedEntityTokenIds ); } - private static long[] sortAndDeduplicate( long[] labels ) + static long[] sortAndDeduplicate( long[] labels ) { if ( ArrayUtils.isNotEmpty( labels ) ) { diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/PropertyAndNodeIndexedCheck.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/PropertyAndNodeIndexedCheck.java index 49d5ecd4598e0..f7b5361772e82 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/PropertyAndNodeIndexedCheck.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/PropertyAndNodeIndexedCheck.java @@ -47,6 +47,7 @@ import org.neo4j.kernel.impl.store.record.PropertyBlock; import org.neo4j.kernel.impl.store.record.PropertyRecord; 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.StoreIndexDescriptor; import org.neo4j.values.storable.Value; @@ -98,14 +99,15 @@ private void matchIndexesToNode( IntObjectMap nodePropertyMap = null; 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 ) { nodePropertyMap = properties( propertyReader.propertyBlocks( propertyRecs ) ); } - int[] indexPropertyIds = indexRule.schema().getPropertyIds(); + int[] indexPropertyIds = schema.getPropertyIds(); if ( nodeHasSchemaProperties( nodePropertyMap, indexPropertyIds ) ) { Value[] values = getPropertyValues( nodePropertyMap, indexPropertyIds ); diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/RelationshipInUseWithCorrectRelationshipTypeCheck.java b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/RelationshipInUseWithCorrectRelationshipTypeCheck.java new file mode 100644 index 0000000000000..1e27d9633e573 --- /dev/null +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/checking/full/RelationshipInUseWithCorrectRelationshipTypeCheck.java @@ -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 . + */ +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 + + implements ComparativeRecordChecker +{ + private final long[] indexRelationshipTypes; + + public RelationshipInUseWithCorrectRelationshipTypeCheck( long[] expectedEntityTokenIds ) + { + this.indexRelationshipTypes = sortAndDeduplicate( expectedEntityTokenIds ); + } + + @Override + public void checkReference( RECORD record, RelationshipRecord relationshipRecord, CheckerEngine 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 ); + } + } +} diff --git a/community/consistency-check/src/main/java/org/neo4j/consistency/report/ConsistencyReport.java b/community/consistency-check/src/main/java/org/neo4j/consistency/report/ConsistencyReport.java index 66db2576b2469..d2874fab4e67d 100644 --- a/community/consistency-check/src/main/java/org/neo4j/consistency/report/ConsistencyReport.java +++ b/community/consistency-check/src/main/java/org/neo4j/consistency/report/ConsistencyReport.java @@ -479,6 +479,13 @@ interface NodeInUseWithCorrectLabelsReport extends ConsistencyReport void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId ); } + interface RelationshipInUseWithCorrectRelationshipTypeReport extends ConsistencyReport + { + void relationshipNotInUse( RelationshipRecord referredRelationshipRecord ); + + void relationshipDoesNotHaveExpectedRelationshipType( RelationshipRecord referredRelationshipRecord, long expectedRelationshipTypeId ); + } + interface LabelScanConsistencyReport extends NodeInUseWithCorrectLabelsReport { @Override @@ -498,16 +505,24 @@ interface LabelScanConsistencyReport extends NodeInUseWithCorrectLabelsReport void dirtyIndex(); } - interface IndexConsistencyReport extends NodeInUseWithCorrectLabelsReport + interface IndexConsistencyReport extends NodeInUseWithCorrectLabelsReport, RelationshipInUseWithCorrectRelationshipTypeReport { @Override @Documented( "This index entry refers to a node record that is not in use." ) void nodeNotInUse( NodeRecord referredNodeRecord ); + @Override + @Documented( "This index entry refers to a relationship record that is not in use." ) + void relationshipNotInUse( RelationshipRecord referredRelationshipRecord ); + @Override @Documented( "This index entry refers to a node that does not have the expected label." ) 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 @Documented( "This node record has a label that is not found in the index for this node" ) void nodeLabelNotInIndex( NodeRecord referredNodeRecord, long missingLabelId );