diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMap.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMap.java index e729ff856e2de..7fff801ef2613 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMap.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMap.java @@ -133,41 +133,28 @@ public Iterable getAllIndexProxies() /** * Get all indexes that would be affected by changes in the input labels and/or properties - * @param labels set of labels + * @param changedLabels set of labels that have changed + * @param unchangedLabels set of labels that are unchanged * @param properties set of properties - * @return set of LabelSchemaDescriptors describing the effected indexes + * @return set of LabelSchemaDescriptors describing the potentially affected indexes */ - public Set getRelatedIndexes( long[] labels, PrimitiveIntCollection properties ) + public Set getRelatedIndexes( + long[] changedLabels, long[] unchangedLabels, PrimitiveIntCollection properties ) { - if ( labels.length == 1 && properties.isEmpty() ) + if ( changedLabels.length == 1 && properties.isEmpty() ) { - Set descriptors = descriptorsByLabel.get( (int)labels[0] ); + Set descriptors = descriptorsByLabel.get( (int)changedLabels[0] ); return descriptors == null ? Collections.emptySet() : descriptors; } - if ( labels.length == 0 && properties.size() == 1 ) + if ( changedLabels.length == 0 && properties.size() == 1 ) { - Set descriptors = descriptorsByProperty.get( properties.iterator().next() ); - return descriptors == null ? Collections.emptySet() : descriptors; + return getDescriptorsByProperties( unchangedLabels, properties ); } - Set descriptors = new HashSet<>(); - for ( long label : labels ) - { - Set toAdd = descriptorsByLabel.get( (int) label ); - if ( toAdd != null ) - { - descriptors.addAll( toAdd ); - } - } - for ( PrimitiveIntIterator property = properties.iterator(); property.hasNext(); ) - { - Set toAdd = descriptorsByProperty.get( property.next() ); - if ( toAdd != null ) - { - descriptors.addAll( toAdd ); - } - } + Set descriptors = extractIndexesByLabels( changedLabels ); + descriptors.addAll( getDescriptorsByProperties( unchangedLabels, properties ) ); + return descriptors; } @@ -239,7 +226,7 @@ private void removeFromLookup( } } - public static Map indexesByDescriptor( Map indexesById ) + private static Map indexesByDescriptor( Map indexesById ) { Map map = new HashMap<>(); for ( IndexProxy proxy : indexesById.values() ) @@ -249,7 +236,7 @@ public static Map indexesByDescriptor( Map indexIdsByDescriptor( Map indexesById ) + private static Map indexIdsByDescriptor( Map indexesById ) { Map map = new HashMap<>(); for ( Map.Entry entry : indexesById.entrySet() ) @@ -258,4 +245,90 @@ public static Map indexIdsByDescriptor( Map getDescriptorsByProperties( + long[] unchangedLabels, + PrimitiveIntCollection properties ) + { + int nIndexesForLabels = countIndexesByLabels( unchangedLabels ); + int nIndexesForProperties = countIndexesByProperties( properties ); + + if ( nIndexesForLabels == 0 || nIndexesForProperties == 0 ) + { + return Collections.emptySet(); + } + if ( nIndexesForLabels < nIndexesForProperties ) + { + return extractIndexesByLabels( unchangedLabels ); + } + else + { + return extractIndexesByProperties( properties ); + } + } + + private Set extractIndexesByLabels( long[] labels ) + { + Set set = new HashSet<>(); + for ( long label : labels ) + { + Set forLabel = descriptorsByLabel.get( (int) label ); + if ( forLabel != null ) + { + set.addAll( forLabel ); + } + } + return set; + } + + private int countIndexesByLabels( long[] labels ) + { + int count = 0; + for ( long label : labels ) + { + Set forLabel = descriptorsByLabel.get( (int) label ); + if ( forLabel != null ) + { + count += forLabel.size(); + } + } + return count; + } + + private Set extractIndexesByProperties( PrimitiveIntCollection properties ) + { + Set set = new HashSet<>(); + for ( PrimitiveIntIterator iterator = properties.iterator(); iterator.hasNext(); ) + { + Set forProperty = descriptorsByProperty.get( iterator.next() ); + if ( forProperty != null ) + { + set.addAll( forProperty ); + } + } + return set; + } + + private int countIndexesByProperties( PrimitiveIntCollection properties ) + { + int count = 0; + for ( PrimitiveIntIterator iterator = properties.iterator(); iterator.hasNext(); ) + { + Set forProperty = descriptorsByProperty.get( iterator.next() ); + if ( forProperty != null ) + { + count += forProperty.size(); + } + } + return count; + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMapReference.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMapReference.java index 9b0f63a81335c..f647f1356247e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMapReference.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexMapReference.java @@ -81,9 +81,10 @@ public Iterable getAllIndexProxies() return indexMap.getAllIndexProxies(); } - public Iterable getRelatedIndexes( long[] labels, PrimitiveIntCollection properties ) + public Iterable getRelatedIndexes( + long[] changedLabels, long[] unchangedLabels, PrimitiveIntCollection properties ) { - return indexMap.getRelatedIndexes( labels, properties ); + return indexMap.getRelatedIndexes( changedLabels, unchangedLabels, properties ); } public void setIndexMap( IndexMap newIndexMap ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexingService.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexingService.java index 2d120d12ebdac..a4fbcc5418817 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexingService.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexingService.java @@ -508,9 +508,11 @@ public void convertToIndexUpdatesAndApply( Iterable updates, IndexU @Override public Iterable> convertToIndexUpdates( NodeUpdates nodeUpdates ) { - Iterable relatedIndexes = indexMapRef.getRelatedIndexes( - nodeUpdates.labelsChanged(), - nodeUpdates.propertiesChanged() ); + Iterable relatedIndexes = + indexMapRef.getRelatedIndexes( + nodeUpdates.labelsChanged(), + nodeUpdates.labelsUnchanged(), + nodeUpdates.propertiesChanged() ); return nodeUpdates.forIndexKeys( relatedIndexes, storeView ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/NodeUpdates.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/NodeUpdates.java index e6e55c426c492..0266bf8acbf49 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/NodeUpdates.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/NodeUpdates.java @@ -136,6 +136,11 @@ public long[] labelsChanged() return SortedLongArrayUtil.symmetricDifference( labelsBefore, labelsAfter ); } + public long[] labelsUnchanged() + { + return SortedLongArrayUtil.intersect( labelsBefore, labelsAfter ); + } + public PrimitiveIntCollection propertiesChanged() { assert !hasLoadedAdditionalProperties : "Calling propertiesChanged() is not valid after non-changed " + diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/IndexTxStateUpdater.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/IndexTxStateUpdater.java index 0e121504e5b82..3c0ed3ee76f93 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/IndexTxStateUpdater.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/IndexTxStateUpdater.java @@ -103,7 +103,8 @@ public void onPropertyAdd( KernelStatement state, NodeItem node, DefinedProperty Iterator indexes = storeReadLayer.indexesAndUniqueIndexesRelatedToProperty( after.propertyKeyId() ); nodeIndexMatcher.onMatchingSchema( state, indexes, node, after.propertyKeyId(), - index -> { + index -> + { Validators.INDEX_VALUE_VALIDATOR.validate( after.value() ); OrderedPropertyValues values = getOrderedPropertyValues( state, node, after, index.schema().getPropertyIds() ); @@ -117,7 +118,8 @@ public void onPropertyRemove( KernelStatement state, NodeItem node, DefinedPrope Iterator indexes = storeReadLayer.indexesAndUniqueIndexesRelatedToProperty( before.propertyKeyId() ); nodeIndexMatcher.onMatchingSchema( state, indexes, node, before.propertyKeyId(), - index -> { + index -> + { OrderedPropertyValues values = getOrderedPropertyValues( state, node, before, index.schema().getPropertyIds() ); state.txState().indexDoUpdateEntry( index.schema(), node.id(), values, null ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexMapTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexMapTest.java index 6f829a38c0c6a..73c15dde9d6cc 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexMapTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexMapTest.java @@ -38,6 +38,7 @@ public class IndexMapTest { + private static final long[] noLabel = {}; private IndexMap indexMap; private LabelSchemaDescriptor schema3_4 = SchemaDescriptorFactory.forLabel( 3, 4 ); @@ -59,7 +60,7 @@ public void setup() public void shouldGetRelatedIndexForLabel() { assertThat( - indexMap.getRelatedIndexes( new long[]{3}, emptySet() ), + indexMap.getRelatedIndexes( label( 3 ), noLabel, emptySet() ), containsInAnyOrder( schema3_4 ) ); } @@ -67,7 +68,7 @@ public void shouldGetRelatedIndexForLabel() public void shouldGetRelatedIndexForProperty() { assertThat( - indexMap.getRelatedIndexes( new long[]{}, properties( 4 ) ), + indexMap.getRelatedIndexes( noLabel, label( 3, 4, 5 ), properties( 4 ) ), containsInAnyOrder( schema3_4 ) ); } @@ -75,7 +76,7 @@ public void shouldGetRelatedIndexForProperty() public void shouldGetRelatedIndexesForLabel() { assertThat( - indexMap.getRelatedIndexes( new long[]{5}, emptySet() ), + indexMap.getRelatedIndexes( label( 5 ), label( 3, 4 ), emptySet() ), containsInAnyOrder( schema5_6_7, schema5_8 ) ); } @@ -83,7 +84,7 @@ public void shouldGetRelatedIndexesForLabel() public void shouldGetRelatedIndexes() { assertThat( - indexMap.getRelatedIndexes( new long[]{3}, properties( 7 ) ), + indexMap.getRelatedIndexes( label( 3 ), label( 4, 5 ), properties( 7 ) ), containsInAnyOrder( schema3_4, schema5_6_7 ) ); } @@ -91,11 +92,11 @@ public void shouldGetRelatedIndexes() public void shouldGetRelatedIndexOnce() { assertThat( - indexMap.getRelatedIndexes( new long[]{3}, properties( 4 ) ), + indexMap.getRelatedIndexes( label( 3 ), noLabel, properties( 4 ) ), containsInAnyOrder( schema3_4 ) ); assertThat( - indexMap.getRelatedIndexes( new long[]{}, properties( 6, 7 ) ), + indexMap.getRelatedIndexes( noLabel, label( 5 ), properties( 6, 7 ) ), containsInAnyOrder( schema5_6_7 ) ); } @@ -103,22 +104,29 @@ public void shouldGetRelatedIndexOnce() public void shouldHandleUnrelated() { assertThat( - indexMap.getRelatedIndexes( new long[]{}, emptySet() ), + indexMap.getRelatedIndexes( noLabel, noLabel, emptySet() ), emptyIterableOf( LabelSchemaDescriptor.class ) ); assertThat( - indexMap.getRelatedIndexes( new long[]{2}, emptySet() ), + indexMap.getRelatedIndexes( label( 2 ), noLabel, emptySet() ), emptyIterableOf( LabelSchemaDescriptor.class ) ); assertThat( - indexMap.getRelatedIndexes( new long[]{}, properties( 1 ) ), + indexMap.getRelatedIndexes( noLabel, label( 2 ), properties( 1 ) ), emptyIterableOf( LabelSchemaDescriptor.class ) ); assertThat( - indexMap.getRelatedIndexes( new long[]{2}, properties( 1 ) ), + indexMap.getRelatedIndexes( label( 2 ), label( 2 ), properties( 1 ) ), emptyIterableOf( LabelSchemaDescriptor.class ) ); } + // HELPERS + + private long[] label( long... labels) + { + return labels; + } + private PrimitiveIntSet properties( int... propertyIds ) { return PrimitiveIntCollections.asSet( propertyIds );