@Override protected void linkLoop( RelationshipRecord record ) { int typeId = record.getType(); long prevRel = cache.getAndPutRelationship( record.getFirstNode(), typeId, Direction.BOTH, record.getId(), false ); if ( prevRel == ID_NOT_FOUND ) { // First one record.setFirstInFirstChain( true ); record.setFirstInSecondChain( true ); prevRel = cache.getCount( record.getFirstNode(), typeId, Direction.BOTH ); } record.setFirstPrevRel( prevRel ); record.setSecondPrevRel( prevRel ); } }
Record( RelationshipRecord record, Record next ) { if ( record != null ) { id = record.getId(); type = record.getType(); nextProp = record.getNextProp(); firstNode = record.getFirstNode(); secondNode = record.getSecondNode(); } else { id = NO_ID; type = NO_ID; nextProp = NO_ID; firstNode = NO_ID; secondNode = NO_ID; } this.next = next; } }
private RelationshipRecord record( long startNode, int type, long endNode ) { RelationshipRecord record = new RelationshipRecord( 0 ); record.setInUse( true ); record.setFirstNode( startNode ); record.setSecondNode( endNode ); record.setType( type ); return record; } }
private boolean relIsFirstInChain( long nodeId, RelationshipRecord rel ) { return (nodeId == rel.getFirstNode() && rel.isFirstInFirstChain()) || (nodeId == rel.getSecondNode() && rel.isFirstInSecondChain()); } }
@Override public RelationshipRecord clone() { RelationshipRecord record = new RelationshipRecord( getId() ).initialize( inUse(), nextProp, firstNode, secondNode, type, firstPrevRel, firstNextRel, secondPrevRel, secondNextRel, firstInFirstChain, firstInSecondChain ); record.setSecondaryUnitId( getSecondaryUnitId() ); return record; }
@Override void set( RelationshipRecord rel, long id, boolean isFirst ) { rel.setFirstPrevRel( id ); rel.setFirstInFirstChain( isFirst ); }
@Override public RecordKey<RelationshipRecord> relationship() { return ( written, read ) -> { assertEquals( written.getNextProp(), read.getNextProp() ); assertEquals( written.getFirstNode(), read.getFirstNode() ); assertEquals( written.getSecondNode(), read.getSecondNode() ); assertEquals( written.getType(), read.getType() ); assertEquals( written.getFirstPrevRel(), read.getFirstPrevRel() ); assertEquals( written.getFirstNextRel(), read.getFirstNextRel() ); assertEquals( written.getSecondPrevRel(), read.getSecondPrevRel() ); assertEquals( written.getSecondNextRel(), read.getSecondNextRel() ); assertEquals( written.isFirstInFirstChain(), read.isFirstInFirstChain() ); assertEquals( written.isFirstInSecondChain(), read.isFirstInSecondChain() ); }; }
private void writeRelationshipRecord( WritableChannel channel, RelationshipRecord record ) throws IOException { byte flags = bitFlags( bitFlag( record.inUse(), Record.IN_USE.byteValue() ), bitFlag( record.isCreated(), Record.CREATED_IN_TX ), bitFlag( record.requiresSecondaryUnit(), Record.REQUIRE_SECONDARY_UNIT ), bitFlag( record.hasSecondaryUnitId(), Record.HAS_SECONDARY_UNIT ), bitFlag( record.isUseFixedReferences(), Record.USES_FIXED_REFERENCE_FORMAT ) ); channel.put( flags ); if ( record.inUse() ) { channel.putLong( record.getFirstNode() ).putLong( record.getSecondNode() ).putInt( record.getType() ) .putLong( record.getFirstPrevRel() ).putLong( record.getFirstNextRel() ) .putLong( record.getSecondPrevRel() ).putLong( record.getSecondNextRel() ) .putLong( record.getNextProp() ) .put( (byte) ((record.isFirstInFirstChain() ? 1 : 0) | (record.isFirstInSecondChain() ? 2 : 0)) ); if ( record.hasSecondaryUnitId() ) { channel.putLong( record.getSecondaryUnitId() ); } } else { channel.putInt( record.getType() ); } } }
private String diff( RelationshipRecord expected, RelationshipRecord actual ) { if ( actual.getId() == expected.getId() && actual.getFirstNode() == expected.getFirstNode() && actual.getSecondNode() == expected.getSecondNode() && actual.getType() == expected.getType() && actual.getFirstPrevRel() == expected.getFirstPrevRel() && actual.getFirstNextRel() == expected.getFirstNextRel() && actual.getSecondPrevRel() == expected.getSecondPrevRel() && actual.getSecondNextRel() == expected.getSecondNextRel() && actual.isFirstInFirstChain() == expected.isFirstInFirstChain() && actual.isFirstInSecondChain() == expected.isFirstInSecondChain() ) { return null; } return describeDiff( expected.toString(), actual.toString() ); }
protected static RelationshipRecord firstInChains( RelationshipRecord relationship, int count ) { relationship.setFirstInFirstChain( true ); relationship.setFirstPrevRel( count ); relationship.setFirstInSecondChain( true ); relationship.setSecondPrevRel( count ); return relationship; }
@Test void shouldReportSourceNodeWithoutChainForRelationshipInTheMiddleOfChain() { // given checkSingleDirection(); initialize( RELATIONSHIPS, NODES ); RelationshipRecord relationship = inUse( new RelationshipRecord( 42, 1, 2, 4 ) ); add( inUse( new RelationshipTypeTokenRecord( 4 ) ) ); NodeRecord source = add( inUse( new NodeRecord( 1, false, NONE, NONE ) ) ); add( inUse( new NodeRecord( 2, false, 42, NONE ) ) ); RelationshipRecord sPrev = add( inUse( new RelationshipRecord( 51, 1, 0, 0 ) ) ); relationship.setFirstPrevRel( sPrev.getId() ); relationship.setFirstInFirstChain( false ); sPrev.setFirstNextRel( relationship.getId() ); // when RelationshipConsistencyReport report = check( relationship ); // then verify( report ).sourceNodeHasNoRelationships( source ); verifyNoMoreInteractions( report ); }
@Override protected void linkLoop( RelationshipRecord record ) { long firstNextRel = cache.getAndPutRelationship( record.getFirstNode(), record.getType(), BOTH, record.getId(), true ); record.setFirstNextRel( firstNextRel ); record.setSecondNextRel( firstNextRel ); } }
@Override protected RelationshipRecord createNullRecord( long id ) { RelationshipRecord record = new RelationshipRecord( id, false, 0, 0, 0, 0, 0, 0, 0, false, false ); record.setNextProp( 0 ); return record; }
@Override protected void linkStart( RelationshipRecord record ) { int typeId = record.getType(); long firstPrevRel = cache.getAndPutRelationship( record.getFirstNode(), typeId, Direction.OUTGOING, record.getId(), false ); if ( firstPrevRel == ID_NOT_FOUND ) { // First one record.setFirstInFirstChain( true ); firstPrevRel = cache.getCount( record.getFirstNode(), typeId, Direction.OUTGOING ); } record.setFirstPrevRel( firstPrevRel ); }
@Test void shouldReportTargetNextReferencingOtherNodes() { // given RelationshipRecord relationship = inUse( new RelationshipRecord( 42, 1, 2, 4 ) ); add( inUse( new RelationshipTypeTokenRecord( 4 ) ) ); add( inUse( new NodeRecord( 1, false, 42, NONE ) ) ); add( inUse( new NodeRecord( 2, false, 42, NONE ) ) ); RelationshipRecord tNext = add( inUse( new RelationshipRecord( 51, 8, 9, 0 ) ) ); relationship.setSecondNextRel( tNext.getId() ); // when RelationshipConsistencyReport report = check( relationship ); // then verify( report ).targetNextReferencesOtherNodes( tNext ); verifyNoMoreInteractions( report ); }
@Test void shouldReportSourceNextReferencingOtherNodes() { // given RelationshipRecord relationship = inUse( new RelationshipRecord( 42, 1, 2, 4 ) ); add( inUse( new RelationshipTypeTokenRecord( 4 ) ) ); add( inUse( new NodeRecord( 1, false, 42, NONE ) ) ); add( inUse( new NodeRecord( 2, false, 42, NONE ) ) ); RelationshipRecord sNext = add( inUse( new RelationshipRecord( 51, 8, 9, 0 ) ) ); relationship.setFirstNextRel( sNext.getId() ); // when RelationshipConsistencyReport report = check( relationship ); // then verify( report ).sourceNextReferencesOtherNodes( sNext ); verifyNoMoreInteractions( report ); }
@Test void shouldReportTargetNodeWithoutChainForRelationshipInTheMiddleOfChain() { // given checkSingleDirection(); initialize( RELATIONSHIPS, NODES ); RelationshipRecord relationship = inUse( new RelationshipRecord( 42, 1, 2, 4 ) ); add( inUse( new RelationshipTypeTokenRecord( 4 ) ) ); add( inUse( new NodeRecord( 1, false, 42, NONE ) ) ); NodeRecord target = add( inUse( new NodeRecord( 2, false, NONE, NONE ) ) ); RelationshipRecord tPrev = add( inUse( new RelationshipRecord( 51, 0, 2, 0 ) ) ); relationship.setSecondPrevRel( tPrev.getId() ); relationship.setFirstInSecondChain( false ); tPrev.setSecondNextRel( relationship.getId() ); // when RelationshipConsistencyReport report = check( relationship ); // then verify( report ).targetNodeHasNoRelationships( target ); verifyNoMoreInteractions( report ); }
@Override protected void checkRelationship( RecordStore<RelationshipRecord> store, RelationshipRecord rel, RecordCheck<RelationshipRecord,ConsistencyReport.RelationshipConsistencyReport> checker ) { if ( stage != null && (stage == CheckStage.Stage6_RS_Forward || stage == CheckStage.Stage7_RS_Backward) ) { long id = rel.getId(); CacheAccess.Client client = cacheAccess.client(); countLinks( id, rel.getFirstNextRel(), client ); countLinks( id, rel.getFirstPrevRel(), client ); countLinks( id, rel.getSecondNextRel(), client ); countLinks( id, rel.getSecondPrevRel(), client ); } report.forRelationship( rel, checker ); }
private Sabotage sabotage( RelationshipStore store, long id ) { RelationshipRecord before = store.getRecord( id, store.newRecord(), RecordLoad.NORMAL ); RelationshipRecord after = before.clone(); long otherReference; if ( !after.isFirstInFirstChain() ) { after.setFirstPrevRel( otherReference = after.getFirstPrevRel() + 1 ); } else { after.setFirstNextRel( otherReference = after.getFirstNextRel() + 1 ); } store.prepareForCommit( after ); store.updateRecord( after ); RelationshipRecord other = store.getRecord( otherReference, store.newRecord(), RecordLoad.FORCE ); return new Sabotage( before, after, other ); } }
private static void breakTheChain( RecordStore<RelationshipRecord> relationshipStore ) { RelationshipRecord record = relationshipStore.getRecord( 10, relationshipStore.newRecord(), NORMAL ); long relationshipTowardsEndOfChain = record.getFirstNode(); while ( record.inUse() && !record.isFirstInFirstChain() ) { record = relationshipStore.getRecord( relationshipTowardsEndOfChain, relationshipStore.newRecord(), FORCE ); relationshipTowardsEndOfChain = record.getFirstPrevRel(); } relationshipStore.updateRecord( new RelationshipRecord( relationshipTowardsEndOfChain, 0, 0, 0 ) ); }