Skip to content

Commit

Permalink
Simpler surface of EntityCommandGrouper
Browse files Browse the repository at this point in the history
  • Loading branch information
tinwelint committed Apr 8, 2019
1 parent 9055a87 commit 7b78476
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 111 deletions.
Expand Up @@ -19,23 +19,38 @@
*/
package org.neo4j.kernel.impl.api.index;

import org.eclipse.collections.api.LongIterable;
import org.eclipse.collections.impl.list.mutable.primitive.LongArrayList;

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

import org.neo4j.kernel.impl.transaction.command.Command;
import org.neo4j.kernel.impl.transaction.command.Command.NodeCommand;
import org.neo4j.kernel.impl.transaction.command.Command.PropertyCommand;
import org.neo4j.kernel.impl.transaction.command.Command.RelationshipCommand;

/**
* Groups property commands by entity. The commands are provided from a list of transaction commands.
* Most entity updates include both the entity command as well as property commands, but sometimes
* only property commands for an entity exists in the list and this grouper handles both scenarios.
* Commands are appended to an array and then sorted before handed over for being processed.
* Hence one entity group can look like any of these combinations:
* <ul>
* <li>Entity command ({@link NodeCommand} or {@link RelationshipCommand} followed by zero or more {@link PropertyCommand property commands}
* for that entity</li>
* <li>zero or more {@link PropertyCommand property commands}, all for the same node</li>
* </ul>
* <p>
* Typical interaction goes like this:
* <ol>
* <li>All commands are added with {@link #add(Command)}</li>
* <li>Get a cursor to the sorted commands using {@link #sortAndAccessGroups()}</li>
* <li>Call {@link #clear()} and use this instance again for another set of commands</li>
* </ol>
*/
public class EntityCommandGrouper<ENTITY extends Command>
{
/**
* Enforces the order described on the class-level javadoc above.
*/
private final Comparator<Command> COMMAND_COMPARATOR = new Comparator<Command>()
{
@Override
Expand All @@ -56,20 +71,13 @@ private long entityId( Command command )

private int commandType( Command command )
{
if ( command.getClass() == entityCommandClass )
{
return 0;
}
return 1;
return command.getClass() == entityCommandClass ? 0 : 1;
}
};

private final Class<ENTITY> entityCommandClass;
private Command[] commands;
private int writeCursor;
private int readCursor;
private long currentEntity;
private ENTITY currentEntityCommand;

public EntityCommandGrouper( Class<ENTITY> entityCommandClass, int sizeHint )
{
Expand All @@ -86,82 +94,80 @@ public void add( Command command )
commands[writeCursor++] = command;
}

public void sort()
public Cursor sortAndAccessGroups()
{
Arrays.sort( commands, 0, writeCursor, COMMAND_COMPARATOR );
return new Cursor();
}

public boolean nextEntity()
public void clear()
{
if ( readCursor >= writeCursor )
{
return false;
}

if ( commands[readCursor].getClass() == entityCommandClass )
{
currentEntityCommand = (ENTITY) commands[readCursor++];
currentEntity = currentEntityCommand.getKey();
}
else
if ( writeCursor > 1_000 )
{
PropertyCommand firstPropertyCommand = (PropertyCommand) commands[readCursor];
currentEntityCommand = null;
currentEntity = firstPropertyCommand.getEntityId();
// Don't continue to hog large transactions
Arrays.fill( commands, 1_000, writeCursor, null );
}
return true;
writeCursor = 0;
}

public long getCurrentEntity()
/**
* Interaction goes like this:
* <ol>
* <li>Call {@link #nextEntity()} to go to the next group, if any</li>
* <li>A group may or may not have the entity command, as accessed by {@link #currentEntityCommand()},
* either way the node id is accessible using {@link #currentEntityId()}</li>
* <li>Call {@link #nextProperty()} until it returns null, now all the {@link PropertyCommand} in this group have been accessed</li>
* </ol>
*/
public class Cursor
{
return currentEntity;
}
private int readCursor;
private long currentEntity;
private ENTITY currentEntityCommand;

public ENTITY getCurrentEntityCommand()
{
return currentEntityCommand;
}
public boolean nextEntity()
{
if ( readCursor >= writeCursor )
{
return false;
}

public PropertyCommand nextProperty()
{
if ( readCursor < writeCursor )
if ( commands[readCursor].getClass() == entityCommandClass )
{
currentEntityCommand = (ENTITY) commands[readCursor++];
currentEntity = currentEntityCommand.getKey();
}
else
{
PropertyCommand firstPropertyCommand = (PropertyCommand) commands[readCursor];
currentEntityCommand = null;
currentEntity = firstPropertyCommand.getEntityId();
}
return true;
}

public PropertyCommand nextProperty()
{
Command command = commands[readCursor];
if ( command instanceof PropertyCommand && ((PropertyCommand) command).getEntityId() == currentEntity )
if ( readCursor < writeCursor )
{
readCursor++;
return (PropertyCommand) command;
Command command = commands[readCursor];
if ( command instanceof PropertyCommand && ((PropertyCommand) command).getEntityId() == currentEntity )
{
readCursor++;
return (PropertyCommand) command;
}
}
return null;
}
return null;
}

public void clear()
{
if ( writeCursor > 1_000 )
public long currentEntityId()
{
// Don't continue to hog large transactions
Arrays.fill( commands, 1_000, writeCursor, null );
return currentEntity;
}
writeCursor = 0;
readCursor = 0;
}

public LongIterable entityIds()
{
LongArrayList list = new LongArrayList();
int cursor = 0;
long currentNode = -1;
while ( cursor < writeCursor )
public ENTITY currentEntityCommand()
{
Command candidate = commands[cursor++];
long nodeId = candidate.getClass() == entityCommandClass ? candidate.getKey() : ((PropertyCommand) candidate).getEntityId();
if ( nodeId != currentNode )
{
currentNode = nodeId;
list.add( currentNode );
}
return currentEntityCommand;
}
return list;
}
}
Expand Up @@ -36,7 +36,6 @@
public class PropertyCommandsExtractor extends TransactionApplier.Adapter
implements BatchTransactionApplier
{
// A list of relevant commands, sorted to be Node(N),Property(N),Property(N)...,Node(O),Property(O),Property(O)...,
private final EntityCommandGrouper<NodeCommand> nodeCommands = new EntityCommandGrouper<>( NodeCommand.class, 16 );
private final EntityCommandGrouper<RelationshipCommand> relationshipCommands = new EntityCommandGrouper<>( RelationshipCommand.class, 16 );
private boolean hasUpdates;
Expand Down Expand Up @@ -110,15 +109,13 @@ public boolean containsAnyEntityOrPropertyUpdate()
return hasUpdates;
}

public EntityCommandGrouper<NodeCommand> getNodeCommands()
public EntityCommandGrouper<NodeCommand>.Cursor getNodeCommands()
{
nodeCommands.sort();
return nodeCommands;
return nodeCommands.sortAndAccessGroups();
}

public EntityCommandGrouper<RelationshipCommand> getRelationshipCommands()
public EntityCommandGrouper<RelationshipCommand>.Cursor getRelationshipCommands()
{
relationshipCommands.sort();
return relationshipCommands;
return relationshipCommands.sortAndAccessGroups();
}
}
Expand Up @@ -45,7 +45,7 @@ public PropertyPhysicalToLogicalConverter( PropertyStore propertyStore )
/**
* Converts physical changes to PropertyRecords for a entity into logical updates
*/
public void convertPropertyRecord( EntityCommandGrouper<?> changes, EntityUpdates.Builder properties )
public void convertPropertyRecord( EntityCommandGrouper<?>.Cursor changes, EntityUpdates.Builder properties )
{
mapBlocks( changes );

Expand Down Expand Up @@ -115,7 +115,7 @@ else if ( beforeKey > afterKey )
}
}

private void mapBlocks( EntityCommandGrouper<?> changes )
private void mapBlocks( EntityCommandGrouper<?>.Cursor changes )
{
beforeBlocksCursor = 0;
afterBlocksCursor = 0;
Expand Down
Expand Up @@ -84,7 +84,8 @@ protected Iterator<IndexEntryUpdate<SchemaDescriptor>> createNestedIterator( Ind
}

@Override
public void feed( EntityCommandGrouper<Command.NodeCommand> nodeCommands, EntityCommandGrouper<Command.RelationshipCommand> relationshipCommands )
public void feed( EntityCommandGrouper<Command.NodeCommand>.Cursor nodeCommands,
EntityCommandGrouper<Command.RelationshipCommand>.Cursor relationshipCommands )
{
throw new UnsupportedOperationException();
}
Expand Down
Expand Up @@ -45,7 +45,8 @@ public Iterator<IndexEntryUpdate<SchemaDescriptor>> iterator()
}

@Override
public void feed( EntityCommandGrouper<Command.NodeCommand> nodeCommands, EntityCommandGrouper<Command.RelationshipCommand> relationshipCommands )
public void feed( EntityCommandGrouper<Command.NodeCommand>.Cursor nodeCommands,
EntityCommandGrouper<Command.RelationshipCommand>.Cursor relationshipCommands )
{
throw new UnsupportedOperationException();
}
Expand Down
Expand Up @@ -31,10 +31,10 @@ public interface IndexUpdates extends Iterable<IndexEntryUpdate<SchemaDescriptor
{
/**
* Feeds updates raw material in the form of node/property commands, to create updates from.
* @param nodeCommands node data
* @param nodeCommands node data
* @param relationshipCommands relationship data
*/
void feed( EntityCommandGrouper<Command.NodeCommand> nodeCommands, EntityCommandGrouper<Command.RelationshipCommand> relationshipCommands );
void feed( EntityCommandGrouper<Command.NodeCommand>.Cursor nodeCommands, EntityCommandGrouper<Command.RelationshipCommand>.Cursor relationshipCommands );

boolean hasUpdates();
}
Expand Up @@ -51,7 +51,7 @@
* properties matching existing and online indexes; in that case the properties for that node needs to be read
* from store since the commands in that transaction cannot itself provide enough information.
*
* One instance can be {@link IndexUpdates#feed(EntityCommandGrouper,EntityCommandGrouper) fed} data about
* One instance can be {@link IndexUpdates#feed(EntityCommandGrouper.Cursor,EntityCommandGrouper.Cursor) fed} data about
* multiple transactions, to be {@link #iterator() accessed} later.
*/
public class OnlineIndexUpdates implements IndexUpdates
Expand Down Expand Up @@ -80,15 +80,15 @@ public Iterator<IndexEntryUpdate<SchemaDescriptor>> iterator()
}

@Override
public void feed( EntityCommandGrouper<NodeCommand> nodeCommands, EntityCommandGrouper<RelationshipCommand> relationshipCommands )
public void feed( EntityCommandGrouper<NodeCommand>.Cursor nodeCommands, EntityCommandGrouper<RelationshipCommand>.Cursor relationshipCommands )
{
while ( nodeCommands.nextEntity() )
{
gatherUpdatesFor( nodeCommands.getCurrentEntity(), nodeCommands.getCurrentEntityCommand(), nodeCommands );
gatherUpdatesFor( nodeCommands.currentEntityId(), nodeCommands.currentEntityCommand(), nodeCommands );
}
while ( relationshipCommands.nextEntity() )
{
gatherUpdatesFor( relationshipCommands.getCurrentEntity(), relationshipCommands.getCurrentEntityCommand(), relationshipCommands );
gatherUpdatesFor( relationshipCommands.currentEntityId(), relationshipCommands.currentEntityCommand(), relationshipCommands );
}
}

Expand All @@ -98,7 +98,7 @@ public boolean hasUpdates()
return !updates.isEmpty();
}

private void gatherUpdatesFor( long nodeId, NodeCommand nodeCommand, EntityCommandGrouper<NodeCommand> propertyCommands )
private void gatherUpdatesFor( long nodeId, NodeCommand nodeCommand, EntityCommandGrouper<NodeCommand>.Cursor propertyCommands )
{
EntityUpdates.Builder nodePropertyUpdate =
gatherUpdatesFromCommandsForNode( nodeId, nodeCommand, propertyCommands );
Expand All @@ -112,7 +112,8 @@ private void gatherUpdatesFor( long nodeId, NodeCommand nodeCommand, EntityComma
}
}

private void gatherUpdatesFor( long relationshipId, RelationshipCommand relationshipCommand, EntityCommandGrouper<RelationshipCommand> propertyCommands )
private void gatherUpdatesFor( long relationshipId, RelationshipCommand relationshipCommand,
EntityCommandGrouper<RelationshipCommand>.Cursor propertyCommands )
{
EntityUpdates.Builder relationshipPropertyUpdate = gatherUpdatesFromCommandsForRelationship( relationshipId, relationshipCommand, propertyCommands );

Expand All @@ -127,7 +128,7 @@ private void gatherUpdatesFor( long relationshipId, RelationshipCommand relation

private EntityUpdates.Builder gatherUpdatesFromCommandsForNode( long nodeId,
NodeCommand nodeChanges,
EntityCommandGrouper propertyCommandsForNode )
EntityCommandGrouper<NodeCommand>.Cursor propertyCommandsForNode )
{
long[] nodeLabelsBefore;
long[] nodeLabelsAfter;
Expand Down Expand Up @@ -173,7 +174,7 @@ private static boolean providesCompleteListOfProperties( Command entityCommand )
}

private EntityUpdates.Builder gatherUpdatesFromCommandsForRelationship( long relationshipId, RelationshipCommand relationshipCommand,
EntityCommandGrouper<?> propertyCommands )
EntityCommandGrouper<RelationshipCommand>.Cursor propertyCommands )
{
long reltypeBefore;
long reltypeAfter;
Expand Down

0 comments on commit 7b78476

Please sign in to comment.