Skip to content

Commit

Permalink
Change NodeUpdates into EntityUpdates
Browse files Browse the repository at this point in the history
This means that it supports Relationship updates, and handles multi-token schema. In order to test this, multi-token schema is also introduced.
  • Loading branch information
ragadeeshu committed Jun 15, 2018
1 parent 9c24807 commit 2b83731
Show file tree
Hide file tree
Showing 36 changed files with 1,258 additions and 734 deletions.
Expand Up @@ -77,8 +77,8 @@
import org.neo4j.kernel.api.schema.index.StoreIndexDescriptor; import org.neo4j.kernel.api.schema.index.StoreIndexDescriptor;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.annotations.Documented; import org.neo4j.kernel.impl.annotations.Documented;
import org.neo4j.kernel.impl.api.index.EntityUpdates;
import org.neo4j.kernel.impl.api.index.IndexUpdateMode; import org.neo4j.kernel.impl.api.index.IndexUpdateMode;
import org.neo4j.kernel.impl.api.index.NodeUpdates;
import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig;
import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge;
import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.locking.LockService;
Expand Down Expand Up @@ -568,7 +568,7 @@ public void shouldReportNodesThatAreNotIndexed() throws Exception
{ {
for ( long nodeId : indexedNodes ) for ( long nodeId : indexedNodes )
{ {
NodeUpdates updates = storeView.nodeAsUpdates( nodeId ); EntityUpdates updates = storeView.nodeAsUpdates( nodeId );
for ( IndexEntryUpdate<?> update : updates.forIndexKeys( asList( indexDescriptor ) ) ) for ( IndexEntryUpdate<?> update : updates.forIndexKeys( asList( indexDescriptor ) ) )
{ {
updater.process( IndexEntryUpdate.remove( nodeId, indexDescriptor, update.values() ) ); updater.process( IndexEntryUpdate.remove( nodeId, indexDescriptor, update.values() ) );
Expand Down
Expand Up @@ -66,12 +66,12 @@
import org.neo4j.kernel.api.schema.index.StoreIndexDescriptor; import org.neo4j.kernel.api.schema.index.StoreIndexDescriptor;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.api.SchemaState; import org.neo4j.kernel.impl.api.SchemaState;
import org.neo4j.kernel.impl.api.index.EntityUpdates;
import org.neo4j.kernel.impl.api.index.IndexProviderMap; import org.neo4j.kernel.impl.api.index.IndexProviderMap;
import org.neo4j.kernel.impl.api.index.IndexProxy; import org.neo4j.kernel.impl.api.index.IndexProxy;
import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.api.index.IndexingService;
import org.neo4j.kernel.impl.api.index.IndexingServiceFactory; import org.neo4j.kernel.impl.api.index.IndexingServiceFactory;
import org.neo4j.kernel.impl.api.index.MultipleIndexPopulator; import org.neo4j.kernel.impl.api.index.MultipleIndexPopulator;
import org.neo4j.kernel.impl.api.index.NodeUpdates;
import org.neo4j.kernel.impl.api.index.StoreScan; import org.neo4j.kernel.impl.api.index.StoreScan;
import org.neo4j.kernel.impl.api.index.inmemory.InMemoryIndexProviderFactory; import org.neo4j.kernel.impl.api.index.inmemory.InMemoryIndexProviderFactory;
import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge;
Expand Down Expand Up @@ -164,10 +164,10 @@ public void setUp()
@Test @Test
public void applyConcurrentDeletesToPopulatedIndex() throws Throwable public void applyConcurrentDeletesToPopulatedIndex() throws Throwable
{ {
List<NodeUpdates> updates = new ArrayList<>( 2 ); List<EntityUpdates> updates = new ArrayList<>( 2 );
updates.add( NodeUpdates.forNode( country1.getId(), id( COUNTRY_LABEL ) ) updates.add( EntityUpdates.forEntity( country1.getId(), id( COUNTRY_LABEL ) )
.removed( propertyId, Values.of( "Sweden" ) ).build() ); .removed( propertyId, Values.of( "Sweden" ) ).build() );
updates.add( NodeUpdates.forNode( color2.getId(), id( COLOR_LABEL ) ) updates.add( EntityUpdates.forEntity( color2.getId(), id( COLOR_LABEL ) )
.removed( propertyId, Values.of( "green" ) ).build() ); .removed( propertyId, Values.of( "green" ) ).build() );


launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) ); launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) );
Expand All @@ -194,10 +194,10 @@ public void applyConcurrentDeletesToPopulatedIndex() throws Throwable
@Test @Test
public void applyConcurrentAddsToPopulatedIndex() throws Throwable public void applyConcurrentAddsToPopulatedIndex() throws Throwable
{ {
List<NodeUpdates> updates = new ArrayList<>( 2 ); List<EntityUpdates> updates = new ArrayList<>( 2 );
updates.add( NodeUpdates.forNode( otherNodes[0].getId(), id( COUNTRY_LABEL ) ) updates.add( EntityUpdates.forEntity( otherNodes[0].getId(), id( COUNTRY_LABEL ) )
.added( propertyId, Values.of( "Denmark" ) ).build() ); .added( propertyId, Values.of( "Denmark" ) ).build() );
updates.add( NodeUpdates.forNode( otherNodes[1].getId(), id( CAR_LABEL ) ) updates.add( EntityUpdates.forEntity( otherNodes[1].getId(), id( CAR_LABEL ) )
.added( propertyId, Values.of( "BMW" ) ).build() ); .added( propertyId, Values.of( "BMW" ) ).build() );


launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) ); launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) );
Expand All @@ -224,10 +224,10 @@ public void applyConcurrentAddsToPopulatedIndex() throws Throwable
@Test @Test
public void applyConcurrentChangesToPopulatedIndex() throws Exception public void applyConcurrentChangesToPopulatedIndex() throws Exception
{ {
List<NodeUpdates> updates = new ArrayList<>( 2 ); List<EntityUpdates> updates = new ArrayList<>( 2 );
updates.add( NodeUpdates.forNode( color2.getId(), id( COLOR_LABEL ) ) updates.add( EntityUpdates.forEntity( color2.getId(), id( COLOR_LABEL ) )
.changed( propertyId, Values.of( "green" ), Values.of( "pink" ) ).build() ); .changed( propertyId, Values.of( "green" ), Values.of( "pink" ) ).build() );
updates.add( NodeUpdates.forNode( car2.getId(), id( CAR_LABEL ) ) updates.add( EntityUpdates.forEntity( car2.getId(), id( CAR_LABEL ) )
.changed( propertyId, Values.of( "Ford" ), Values.of( "SAAB" ) ).build() ); .changed( propertyId, Values.of( "Ford" ), Values.of( "SAAB" ) ).build() );


launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) ); launchCustomIndexPopulation( labelsNameIdMap, propertyId, new UpdateGenerator( updates ) );
Expand Down Expand Up @@ -500,7 +500,7 @@ private class DynamicIndexStoreViewWrapper extends DynamicIndexStoreView
@Override @Override
public <FAILURE extends Exception> StoreScan<FAILURE> visitNodes( int[] labelIds, public <FAILURE extends Exception> StoreScan<FAILURE> visitNodes( int[] labelIds,
IntPredicate propertyKeyIdFilter, IntPredicate propertyKeyIdFilter,
Visitor<NodeUpdates,FAILURE> propertyUpdatesVisitor, Visitor<EntityUpdates,FAILURE> propertyUpdatesVisitor,
Visitor<NodeLabelUpdate,FAILURE> labelUpdateVisitor, Visitor<NodeLabelUpdate,FAILURE> labelUpdateVisitor,
boolean forceStoreScan ) boolean forceStoreScan )
{ {
Expand All @@ -520,7 +520,7 @@ private class LabelScanViewNodeStoreWrapper<FAILURE extends Exception> extends L
LabelScanViewNodeStoreWrapper( NodeStore nodeStore, LockService locks, LabelScanViewNodeStoreWrapper( NodeStore nodeStore, LockService locks,
PropertyStore propertyStore, PropertyStore propertyStore,
LabelScanStore labelScanStore, Visitor<NodeLabelUpdate,FAILURE> labelUpdateVisitor, LabelScanStore labelScanStore, Visitor<NodeLabelUpdate,FAILURE> labelUpdateVisitor,
Visitor<NodeUpdates,FAILURE> propertyUpdatesVisitor, int[] labelIds, IntPredicate propertyKeyIdFilter, Visitor<EntityUpdates,FAILURE> propertyUpdatesVisitor, int[] labelIds, IntPredicate propertyKeyIdFilter,
LabelScanViewNodeStoreScan<FAILURE> delegate, LabelScanViewNodeStoreScan<FAILURE> delegate,
Runnable customAction ) Runnable customAction )
{ {
Expand Down Expand Up @@ -585,21 +585,21 @@ public void close()
private class UpdateGenerator implements Runnable private class UpdateGenerator implements Runnable
{ {


private Iterable<NodeUpdates> updates; private Iterable<EntityUpdates> updates;


UpdateGenerator( Iterable<NodeUpdates> updates ) UpdateGenerator( Iterable<EntityUpdates> updates )
{ {
this.updates = updates; this.updates = updates;
} }


@Override @Override
public void run() public void run()
{ {
for ( NodeUpdates update : updates ) for ( EntityUpdates update : updates )
{ {
try ( Transaction transaction = embeddedDatabase.beginTx() ) try ( Transaction transaction = embeddedDatabase.beginTx() )
{ {
Node node = embeddedDatabase.getNodeById( update.getNodeId() ); Node node = embeddedDatabase.getNodeById( update.getEntityId() );
for ( int labelId : labelsNameIdMap.values() ) for ( int labelId : labelsNameIdMap.values() )
{ {
LabelSchemaDescriptor schema = SchemaDescriptorFactory.forLabel( labelId, propertyId ); LabelSchemaDescriptor schema = SchemaDescriptorFactory.forLabel( labelId, propertyId );
Expand Down Expand Up @@ -629,7 +629,7 @@ public void run()
} }
try try
{ {
for ( NodeUpdates update : updates ) for ( EntityUpdates update : updates )
{ {
Iterable<IndexEntryUpdate<SchemaDescriptor>> entryUpdates = Iterable<IndexEntryUpdate<SchemaDescriptor>> entryUpdates =
indexService.convertToIndexUpdates( update ); indexService.convertToIndexUpdates( update );
Expand Down
Expand Up @@ -43,7 +43,7 @@
import org.neo4j.kernel.api.index.IndexEntryUpdate; import org.neo4j.kernel.api.index.IndexEntryUpdate;
import org.neo4j.kernel.api.labelscan.NodeLabelUpdate; import org.neo4j.kernel.api.labelscan.NodeLabelUpdate;
import org.neo4j.kernel.api.schema.SchemaDescriptorFactory; import org.neo4j.kernel.api.schema.SchemaDescriptorFactory;
import org.neo4j.kernel.impl.api.index.NodeUpdates; import org.neo4j.kernel.impl.api.index.EntityUpdates;
import org.neo4j.kernel.impl.api.index.StoreScan; import org.neo4j.kernel.impl.api.index.StoreScan;
import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge;
import org.neo4j.kernel.impl.locking.Lock; import org.neo4j.kernel.impl.locking.Lock;
Expand Down Expand Up @@ -155,7 +155,7 @@ public void shouldLockNodesWhileReadingThem() throws Exception
{ {
// given // given
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
Visitor<NodeUpdates,Exception> visitor = mock( Visitor.class ); Visitor<EntityUpdates,Exception> visitor = mock( Visitor.class );
StoreScan<Exception> storeScan = StoreScan<Exception> storeScan =
storeView.visitNodes( new int[]{labelId}, id -> id == propertyKeyId, visitor, null, false ); storeView.visitNodes( new int[]{labelId}, id -> id == propertyKeyId, visitor, null, false );


Expand Down Expand Up @@ -196,7 +196,7 @@ public void processAllNodeProperties() throws Exception


storeViewNodeStoreScan.process( nodeRecord ); storeViewNodeStoreScan.process( nodeRecord );


NodeUpdates propertyUpdates = propertyUpdateVisitor.getPropertyUpdates(); EntityUpdates propertyUpdates = propertyUpdateVisitor.getPropertyUpdates();
assertNotNull( "Visitor should contain container with updates.", propertyUpdates ); assertNotNull( "Visitor should contain container with updates.", propertyUpdates );


LabelSchemaDescriptor index1 = SchemaDescriptorFactory.forLabel( 0, 0 ); LabelSchemaDescriptor index1 = SchemaDescriptorFactory.forLabel( 0, 0 );
Expand All @@ -212,9 +212,9 @@ public void processAllNodeProperties() throws Exception
containsInAnyOrder( index1, index2, index3 ) ); containsInAnyOrder( index1, index2, index3 ) );
} }


NodeUpdates add( long nodeId, int propertyKeyId, Object value, long[] labels ) EntityUpdates add( long nodeId, int propertyKeyId, Object value, long[] labels )
{ {
return NodeUpdates.forNode( nodeId, labels ).added( propertyKeyId, Values.of( value ) ).build(); return EntityUpdates.forEntity( nodeId, labels ).added( propertyKeyId, Values.of( value ) ).build();
} }


private void createAlistairAndStefanNodes() private void createAlistairAndStefanNodes()
Expand Down Expand Up @@ -255,36 +255,36 @@ private void getOrCreateIds() throws KernelException
} }
} }


private static class CopyUpdateVisitor implements Visitor<NodeUpdates,RuntimeException> private static class CopyUpdateVisitor implements Visitor<EntityUpdates,RuntimeException>
{ {


private NodeUpdates propertyUpdates; private EntityUpdates propertyUpdates;


@Override @Override
public boolean visit( NodeUpdates element ) throws RuntimeException public boolean visit( EntityUpdates element ) throws RuntimeException
{ {
propertyUpdates = element; propertyUpdates = element;
return true; return true;
} }


public NodeUpdates getPropertyUpdates() public EntityUpdates getPropertyUpdates()
{ {
return propertyUpdates; return propertyUpdates;
} }
} }


class NodeUpdateCollectingVisitor implements Visitor<NodeUpdates, Exception> class NodeUpdateCollectingVisitor implements Visitor<EntityUpdates, Exception>
{ {
private final Set<NodeUpdates> updates = new HashSet<>(); private final Set<EntityUpdates> updates = new HashSet<>();


@Override @Override
public boolean visit( NodeUpdates propertyUpdates ) public boolean visit( EntityUpdates propertyUpdates )
{ {
updates.add( propertyUpdates ); updates.add( propertyUpdates );
return false; return false;
} }


Set<NodeUpdates> getUpdates() Set<EntityUpdates> getUpdates()
{ {
return updates; return updates;
} }
Expand Down
Expand Up @@ -19,6 +19,10 @@
*/ */
package org.neo4j.internal.kernel.api; package org.neo4j.internal.kernel.api;


import java.util.function.IntFunction;

import org.neo4j.storageengine.api.EntityType;

/** /**
* Lookup of names from token ids. Tokens are mostly referred to by ids throughout several abstractions. * Lookup of names from token ids. Tokens are mostly referred to by ids throughout several abstractions.
* Sometimes token names are required, this is a way to lookup names in those cases. * Sometimes token names are required, this is a way to lookup names in those cases.
Expand All @@ -42,4 +46,26 @@ public interface TokenNameLookup
* @return name of property key token with given id. * @return name of property key token with given id.
*/ */
String propertyKeyGetName( int propertyKeyId ); String propertyKeyGetName( int propertyKeyId );

default String[] entityTokensGetNames( EntityType type, int[] entityTokenIds )
{
IntFunction<String> mapper;
if ( type == EntityType.NODE )
{
mapper = this::labelGetName;
}
else if ( type == EntityType.RELATIONSHIP )
{
mapper = this::relationshipTypeGetName;
}
else
{
return new String[0];
}
String[] tokenNames = new String[entityTokenIds.length];
for ( int i = 0; i < entityTokenIds.length; i++ )
{
tokenNames[i] = mapper.apply( entityTokenIds[i] );
}
return tokenNames; }
} }
@@ -0,0 +1,24 @@
/*
* 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.internal.kernel.api.schema;

public interface MultiTokenSchemaDescriptor extends SchemaDescriptor
{
}
Expand Up @@ -22,6 +22,7 @@
import java.util.function.Predicate; import java.util.function.Predicate;


import org.neo4j.internal.kernel.api.TokenNameLookup; import org.neo4j.internal.kernel.api.TokenNameLookup;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.storageengine.api.lock.ResourceType; import org.neo4j.storageengine.api.lock.ResourceType;


/** /**
Expand All @@ -36,6 +37,23 @@
*/ */
public interface SchemaDescriptor extends SchemaDescriptorSupplier public interface SchemaDescriptor extends SchemaDescriptorSupplier
{ {
int[] ANY_ENTITY_TOKEN = new int[0];

boolean isAffected( long[] entityIds );

/**
* This enum signifies how this schema should behave in regards to updates.
* {@link PropertySchemaType#COMPLETE_ALL_TOKENS} signifies that this schema unit only should be affected by updates that match the entire schema,
* i.e. when all properties are present. If you are unsure then this is probably what you want.
* {@link PropertySchemaType#PARTIAL_ANY_TOKEN} signifies that this schema unit should be affected by any update that is partial match of the schema,
* i.e. at least one of the properties of this schema unit is present.
*/
enum PropertySchemaType
{
COMPLETE_ALL_TOKENS,
PARTIAL_ANY_TOKEN
}

/** /**
* Computes some value by feeding this object into the given SchemaComputer. * Computes some value by feeding this object into the given SchemaComputer.
* *
Expand Down Expand Up @@ -89,6 +107,12 @@ default int getPropertyId()
return propertyIds[0]; return propertyIds[0];
} }


/**
* This method returns the entity token ids handled by this descriptor.
* @return the entity token ids that this schema descriptor represents
*/
int[] getEntityTokenIds();

/** /**
* Id of underlying schema descriptor key. * Id of underlying schema descriptor key.
* Key is part of schema unit that determines which resources with specified properties are applicable. * Key is part of schema unit that determines which resources with specified properties are applicable.
Expand All @@ -103,6 +127,18 @@ default int getPropertyId()
*/ */
ResourceType keyType(); ResourceType keyType();


/**
* Type of entities this schema represents.
* @return entity type
*/
EntityType entityType();

/**
* Returns the type of this schema. See {@link PropertySchemaType}.
* @return PropertySchemaType of this schema unit.
*/
PropertySchemaType propertySchemaType();

/** /**
* Create a predicate that checks whether a schema descriptor Supplier supplies the given schema descriptor. * Create a predicate that checks whether a schema descriptor Supplier supplies the given schema descriptor.
* @param descriptor The schema descriptor to check equality with. * @param descriptor The schema descriptor to check equality with.
Expand Down
Expand Up @@ -19,13 +19,16 @@
*/ */
package org.neo4j.kernel.api.schema; package org.neo4j.kernel.api.schema;


import org.apache.commons.lang3.ArrayUtils;

import java.util.Arrays; import java.util.Arrays;


import org.neo4j.internal.kernel.api.TokenNameLookup; import org.neo4j.internal.kernel.api.TokenNameLookup;
import org.neo4j.internal.kernel.api.schema.SchemaComputer; import org.neo4j.internal.kernel.api.schema.SchemaComputer;
import org.neo4j.internal.kernel.api.schema.SchemaProcessor; import org.neo4j.internal.kernel.api.schema.SchemaProcessor;
import org.neo4j.internal.kernel.api.schema.SchemaUtil; import org.neo4j.internal.kernel.api.schema.SchemaUtil;
import org.neo4j.kernel.impl.locking.ResourceTypes; import org.neo4j.kernel.impl.locking.ResourceTypes;
import org.neo4j.storageengine.api.EntityType;
import org.neo4j.storageengine.api.lock.ResourceType; import org.neo4j.storageengine.api.lock.ResourceType;


public class LabelSchemaDescriptor implements org.neo4j.internal.kernel.api.schema.LabelSchemaDescriptor public class LabelSchemaDescriptor implements org.neo4j.internal.kernel.api.schema.LabelSchemaDescriptor
Expand All @@ -39,6 +42,12 @@ public class LabelSchemaDescriptor implements org.neo4j.internal.kernel.api.sche
this.propertyIds = propertyIds; this.propertyIds = propertyIds;
} }


@Override
public boolean isAffected( long[] entityIds )
{
return ArrayUtils.contains( entityIds, labelId );
}

@Override @Override
public <R> R computeWith( SchemaComputer<R> processor ) public <R> R computeWith( SchemaComputer<R> processor )
{ {
Expand Down Expand Up @@ -76,12 +85,30 @@ public ResourceType keyType()
return ResourceTypes.LABEL; return ResourceTypes.LABEL;
} }


@Override
public EntityType entityType()
{
return EntityType.NODE;
}

@Override
public PropertySchemaType propertySchemaType()
{
return PropertySchemaType.COMPLETE_ALL_TOKENS;
}

@Override @Override
public int[] getPropertyIds() public int[] getPropertyIds()
{ {
return propertyIds; return propertyIds;
} }


@Override
public int[] getEntityTokenIds()
{
return new int[]{labelId};
}

@Override @Override
public boolean equals( Object o ) public boolean equals( Object o )
{ {
Expand Down

0 comments on commit 2b83731

Please sign in to comment.