From 91ddb675edd5bb463e845fee05f63de322521319 Mon Sep 17 00:00:00 2001 From: Chris Gioran Date: Wed, 20 Apr 2016 15:36:57 +0300 Subject: [PATCH] Adds secondary unit information in serialized NodeCommands Adds boolean flags related to secondary unit usage in the first byte serialized as part of NodeCommands, in a fashion similar to RelationshipCommand. The NodeCommandTest is improved with additional assertions. --- .../impl/transaction/command/Command.java | 10 +++- .../command/PhysicalLogCommandReaderV3_0.java | 23 ++++---- .../transaction/state/NodeCommandTest.java | 55 +++++++++++++++++-- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/Command.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/Command.java index 60ed3d1e50e81..c6a695105c1f6 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/Command.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/Command.java @@ -226,13 +226,19 @@ public void serialize( WritableChannel channel ) throws IOException private boolean writeNodeRecord( WritableChannel channel, NodeRecord record ) throws IOException { - byte inUse = record.inUse() ? Record.IN_USE.byteValue() : Record.NOT_IN_USE.byteValue(); - channel.put( inUse ); + byte flags = bitFlags( bitFlag( record.inUse(), Record.IN_USE.byteValue() ), + bitFlag( record.requiresSecondaryUnit(), Record.REQUIRE_SECONDARY_UNIT ), + bitFlag( record.hasSecondaryUnitId(), Record.HAS_SECONDARY_UNIT ) ); + channel.put( flags ); if ( record.inUse() ) { channel.put( record.isDense() ? (byte) 1 : (byte) 0 ); channel.putLong( record.getNextRel() ).putLong( record.getNextProp() ); channel.putLong( record.getLabelField() ); + if( record.hasSecondaryUnitId() ) + { + channel.putLong( record.getSecondaryUnitId() ); + } } // Always write dynamic label records because we want to know which ones have been deleted // especially if the node has been deleted. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/PhysicalLogCommandReaderV3_0.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/PhysicalLogCommandReaderV3_0.java index bcb81be525871..e81f149761fd2 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/PhysicalLogCommandReaderV3_0.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/command/PhysicalLogCommandReaderV3_0.java @@ -155,7 +155,6 @@ private Command visitRelationshipCommand( ReadableChannel channel ) throws IOExc { long id = channel.getLong(); - RelationshipRecord before = readRelationshipRecord( id, channel ); if ( before == null ) { @@ -400,16 +399,11 @@ private NeoStoreRecord readNeoStoreRecord( ReadableChannel channel ) throws IOEx private NodeRecord readNodeRecord( long id, ReadableChannel channel ) throws IOException { - byte inUseFlag = channel.get(); - boolean inUse = false; - if ( inUseFlag == Record.IN_USE.byteValue() ) - { - inUse = true; - } - else if ( inUseFlag != Record.NOT_IN_USE.byteValue() ) - { - throw new IOException( "Illegal in use flag: " + inUseFlag ); - } + byte flags = channel.get(); + boolean inUse = bitFlag( flags, Record.IN_USE.byteValue() ); + boolean requiresSecondaryUnit = bitFlag( flags, Record.REQUIRE_SECONDARY_UNIT ); + boolean hasSecondaryUnit = bitFlag( flags, Record.HAS_SECONDARY_UNIT ); + NodeRecord record; Collection dynamicLabelRecords = new ArrayList<>(); long labelField = Record.NO_LABELS_FIELD.intValue(); @@ -419,6 +413,11 @@ else if ( inUseFlag != Record.NOT_IN_USE.byteValue() ) record = new NodeRecord( id, dense, channel.getLong(), channel.getLong() ); // labels labelField = channel.getLong(); + record.setRequiresSecondaryUnit( requiresSecondaryUnit ); + if( hasSecondaryUnit ) + { + record.setSecondaryUnitId( channel.getLong() ); + } } else { @@ -450,7 +449,7 @@ record = new RelationshipRecord( id, channel.getLong(), channel.getLong(), chann byte extraByte = channel.get(); record.setFirstInFirstChain( (extraByte & 0x1) > 0 ); record.setFirstInSecondChain( (extraByte & 0x2) > 0 ); - if (hasSecondaryUnit) + if ( hasSecondaryUnit ) { record.setSecondaryUnitId( channel.getLong() ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NodeCommandTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NodeCommandTest.java index cc51f36c62838..1f81c45b85155 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NodeCommandTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/state/NodeCommandTest.java @@ -41,7 +41,7 @@ import org.neo4j.kernel.impl.store.record.DynamicRecord; import org.neo4j.kernel.impl.store.record.NodeRecord; import org.neo4j.kernel.impl.transaction.command.Command; -import org.neo4j.kernel.impl.transaction.command.PhysicalLogCommandReaderV2_2; +import org.neo4j.kernel.impl.transaction.command.PhysicalLogCommandReaderV3_0; import org.neo4j.kernel.impl.transaction.log.InMemoryClosableChannel; import org.neo4j.logging.NullLogProvider; import org.neo4j.storageengine.api.CommandReader; @@ -54,6 +54,7 @@ import static org.neo4j.kernel.impl.store.DynamicNodeLabels.dynamicPointer; import static org.neo4j.kernel.impl.store.NodeLabelsField.parseLabelsField; import static org.neo4j.kernel.impl.store.ShortArray.LONG; +import static org.neo4j.kernel.impl.store.record.AbstractBaseRecord.NO_ID; import static org.neo4j.kernel.impl.store.record.DynamicRecord.dynamicRecord; import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.safeCastLongToInt; @@ -63,7 +64,7 @@ public class NodeCommandTest public static PageCacheRule pageCacheRule = new PageCacheRule(); private NodeStore nodeStore; InMemoryClosableChannel channel = new InMemoryClosableChannel(); - private final CommandReader commandReader = new PhysicalLogCommandReaderV2_2(); + private final CommandReader commandReader = new PhysicalLogCommandReaderV3_0(); @Rule public EphemeralFileSystemRule fs = new EphemeralFileSystemRule(); private NeoStores neoStores; @@ -90,6 +91,18 @@ public void shouldSerializeCreatedRecord() throws Exception assertSerializationWorksFor( new Command.NodeCommand( before, after ) ); } + @Test + public void shouldSerializeDenseRecord() throws Exception + { + // Given + NodeRecord before = new NodeRecord( 12, false, 1, 2 ); + before.setInUse( true ); + NodeRecord after = new NodeRecord( 12, true, 2, 1 ); + after.setInUse( true ); + // When + assertSerializationWorksFor( new Command.NodeCommand( before, after ) ); + } + @Test public void shouldSerializeUpdatedRecord() throws Exception { @@ -116,6 +129,26 @@ public void shouldSerializeInlineLabels() throws Exception assertSerializationWorksFor( new Command.NodeCommand( before, after ) ); } + @Test + public void shouldSerializeSecondaryUnitUsage() throws Exception + { + // Given + // a record that is changed to include a secondary unit + NodeRecord before = new NodeRecord( 13, false, 1, 2 ); + before.setInUse( true ); + before.setRequiresSecondaryUnit( false ); + before.setSecondaryUnitId( NO_ID ); // this and the previous line set the defaults, they are here for clarity + NodeRecord after = new NodeRecord( 13, false, 1, 2 ); + after.setInUse( true ); + after.setRequiresSecondaryUnit( true ); + after.setSecondaryUnitId( 14L ); + + Command.NodeCommand command = new Command.NodeCommand( before, after ); + + // Then + assertSerializationWorksFor( command ); + } + @Test public void shouldSerializeDynamicRecordLabels() throws Exception { @@ -173,12 +206,26 @@ private void assertSerializationWorksFor( org.neo4j.kernel.impl.transaction.comm assertThat( result.getMode(), equalTo( cmd.getMode() ) ); assertThat( result.getBefore(), equalTo( cmd.getBefore() ) ); assertThat( result.getAfter(), equalTo( cmd.getAfter() ) ); + // And created and dense flags should be the same + assertThat( result.getBefore().isCreated(), equalTo( cmd.getBefore().isCreated() ) ); + assertThat( result.getAfter().isCreated(), equalTo( cmd.getAfter().isCreated() ) ); + assertThat( result.getBefore().isDense(), equalTo( cmd.getBefore().isDense() ) ); + assertThat( result.getAfter().isDense(), equalTo( cmd.getAfter().isDense()) ); // And labels should be the same assertThat( labels( result.getBefore() ), equalTo( labels( cmd.getBefore() ) ) ); assertThat( labels( result.getAfter() ), equalTo( labels( cmd.getAfter() ) ) ); // And dynamic records should be the same - assertThat( result.getBefore().getDynamicLabelRecords(), equalTo( result.getBefore().getDynamicLabelRecords() ) ); - assertThat( result.getAfter().getDynamicLabelRecords(), equalTo( result.getAfter().getDynamicLabelRecords() ) ); + assertThat( result.getBefore().getDynamicLabelRecords(), equalTo( cmd.getBefore().getDynamicLabelRecords() ) ); + assertThat( result.getAfter().getDynamicLabelRecords(), equalTo( cmd.getAfter().getDynamicLabelRecords() ) ); + // And the secondary unit information should be the same + // Before + assertThat( result.getBefore().requiresSecondaryUnit(), equalTo( cmd.getBefore().requiresSecondaryUnit() ) ); + assertThat( result.getBefore().hasSecondaryUnitId(), equalTo( cmd.getBefore().hasSecondaryUnitId() ) ); + assertThat( result.getBefore().getSecondaryUnitId(), equalTo( cmd.getBefore().getSecondaryUnitId() ) ); + // and after + assertThat( result.getAfter().requiresSecondaryUnit(), equalTo( cmd.getAfter().requiresSecondaryUnit() ) ); + assertThat( result.getAfter().hasSecondaryUnitId(), equalTo( cmd.getAfter().hasSecondaryUnitId() ) ); + assertThat( result.getAfter().getSecondaryUnitId(), equalTo( cmd.getAfter().getSecondaryUnitId() ) ); } private Set labels( NodeRecord record )