@Override public void checkReference( RelationshipGroupRecord record, NodeRecord referred, CheckerEngine<RelationshipGroupRecord, RelationshipGroupConsistencyReport> engine, RecordAccess records ) { if ( !referred.inUse() ) { engine.report().ownerNotInUse(); } }
private Command visitNodeCommand( ReadableChannel channel ) throws IOException { long id = channel.getLong(); NodeRecord before = readNodeRecord( id, channel ); if ( before == null ) { return null; } NodeRecord after = readNodeRecord( id, channel ); if ( after == null ) { return null; } if ( !before.inUse() && after.inUse() ) { after.setCreated(); } return new Command.NodeCommand( before, after ); }
private Command visitNodeCommand( ReadableChannel channel ) throws IOException { long id = channel.getLong(); NodeRecord before = readNodeRecord( id, channel ); if ( before == null ) { return null; } NodeRecord after = readNodeRecord( id, channel ); if ( after == null ) { return null; } if ( !before.inUse() && after.inUse() ) { after.setCreated(); } return new Command.NodeCommand( before, after ); }
private Command visitNodeCommand( ReadableChannel channel ) throws IOException { long id = channel.getLong(); NodeRecord before = readNodeRecord( id, channel ); if ( before == null ) { return null; } NodeRecord after = readNodeRecord( id, channel ); if ( after == null ) { return null; } if ( !before.inUse() && after.inUse() ) { after.setCreated(); } return new Command.NodeCommand( before, after ); }
private Command visitNodeCommand( ReadableChannel channel ) throws IOException { long id = channel.getLong(); NodeRecord before = readNodeRecord( id, channel ); if ( before == null ) { return null; } NodeRecord after = readNodeRecord( id, channel ); if ( after == null ) { return null; } if ( !before.inUse() && after.inUse() ) { after.setCreated(); } return new Command.NodeCommand( before, after ); }
@Override public String toString() { String denseInfo = (dense ? "group" : "rel") + "=" + nextRel; String lightHeavyInfo = isLight ? "light" : dynamicLabelRecords.isEmpty() ? "heavy" : "heavy,dynlabels=" + dynamicLabelRecords; return "Node[" + getId() + ",used=" + inUse() + "," + denseInfo + ",prop=" + getNextProp() + ",labels=" + parseLabelsField( this ) + "," + lightHeavyInfo + ",secondaryUnitId=" + getSecondaryUnitId() + "]"; }
@Override public NodeRecord clone() { NodeRecord clone = new NodeRecord( getId() ).initialize( inUse(), nextProp, dense, nextRel, labels ); clone.isLight = isLight; if ( dynamicLabelRecords.size() > 0 ) { List<DynamicRecord> clonedLabelRecords = new ArrayList<>( dynamicLabelRecords.size() ); for ( DynamicRecord labelRecord : dynamicLabelRecords ) { clonedLabelRecords.add( labelRecord.clone() ); } clone.dynamicLabelRecords = clonedLabelRecords; } clone.setSecondaryUnitId( getSecondaryUnitId() ); return clone; } }
public void validateNodeRecord( NodeRecord record ) throws TransactionFailureException { if ( !record.inUse() && record.getNextRel() != Record.NO_NEXT_RELATIONSHIP.intValue() ) { throw new ConstraintViolationTransactionFailureException( "Cannot delete node<" + record.getId() + ">, because it still has relationships. " + "To delete this node, you must first delete its relationships." ); } }
@Override protected void process( NodeRecord[] batch, BatchSender sender ) throws Throwable { for ( NodeRecord node : batch ) { if ( node.inUse() ) { writer.write( labelChanges( node.getId(), EMPTY_LONG_ARRAY, get( node, nodeStore ) ) ); } } sender.send( batch ); }
@Override public Value getNodePropertyValue( long nodeId, int propertyKeyId ) { NodeRecord nodeRecord = nodeStore.newRecord(); if ( nodeStore.getRecord( nodeId, nodeRecord, FORCE ).inUse() ) { SpecificValueVisitor visitor = new SpecificValueVisitor( propertyKeyId ); try { if ( visitPropertyRecordChain( nodeRecord.getNextProp(), visitor ) ) { return visitor.foundPropertyValue; } } catch ( CircularPropertyRecordChainException e ) { // If we discover a circular reference and still haven't found the property then we won't find it. // There are other places where this circular reference will be logged as an inconsistency, // so simply catch this exception here and let this method return NO_VALUE below. } } return Values.NO_VALUE; }
/** * Deletes a node by its id, returning its properties which are now removed. * * @param nodeId The id of the node to delete. */ public void nodeDelete( long nodeId ) { NodeRecord nodeRecord = recordChangeSet.getNodeRecords().getOrLoad( nodeId, null ).forChangingData(); if ( !nodeRecord.inUse() ) { throw new IllegalStateException( "Unable to delete Node[" + nodeId + "] since it has already been deleted." ); } nodeRecord.setInUse( false ); nodeRecord.setLabelField( Record.NO_LABELS_FIELD.intValue(), markNotInUse( nodeRecord.getDynamicLabelRecords() ) ); getAndDeletePropertyChain( nodeRecord ); }
@Override protected void processCache() { RecordStore<NodeRecord> nodeStore = storeAccess.getNodeStore(); CacheAccess.Client client = cacheAccess.client(); long highId = nodeStore.getHighId(); for ( long nodeId = 0; nodeId < highId; nodeId++ ) { if ( client.getFromCache( nodeId, CacheSlots.NextRelationship.SLOT_FIRST_IN_TARGET ) == 0 ) { NodeRecord node = nodeStore.getRecord( nodeId, nodeStore.newRecord(), FORCE ); if ( node.inUse() && !node.isDense() ) { storeProcessor.processNode( nodeStore, node ); } } } } }
@Override protected void processCache() { cacheAccess.clearCache(); long[] fields = new long[] {1, 0, -1}; CacheAccess.Client client = cacheAccess.client(); try ( ResourceIterator<NodeRecord> nodeRecords = nodes.iterator() ) { while ( nodeRecords.hasNext() ) { NodeRecord node = nodeRecords.next(); if ( node.inUse() ) { fields[CacheSlots.NextRelationship.SLOT_RELATIONSHIP_ID] = node.getNextRel(); client.putToCache( node.getId(), fields ); } } } } }
@Override public Value getNodePropertyValue( long nodeId, int propertyKeyId ) throws EntityNotFoundException { NodeRecord node = nodeStore.getRecord( nodeId, nodeStore.newRecord(), FORCE ); if ( !node.inUse() ) { throw new EntityNotFoundException( EntityType.NODE, nodeId ); } long firstPropertyId = node.getNextProp(); if ( firstPropertyId == Record.NO_NEXT_PROPERTY.intValue() ) { return Values.NO_VALUE; } for ( PropertyRecord propertyRecord : propertyStore.getPropertyRecordChain( firstPropertyId ) ) { PropertyBlock propertyBlock = propertyRecord.getPropertyBlock( propertyKeyId ); if ( propertyBlock != null ) { return propertyBlock.newPropertyValue( propertyStore ); } } return Values.NO_VALUE; }
@Override public void check( NodeRecord record, CheckerEngine<NodeRecord,NodeConsistencyReport> engine, RecordAccess records ) { if ( countUpdateCondition.test( record ) ) { if ( record.inUse() ) { CacheAccess.Client client = records.cacheAccess().client(); client.putToCacheSingle( record.getId(), SLOT_IN_USE, 1 ); client.putToCacheSingle( record.getId(), SLOT_LABEL_FIELD, record.getLabelField() ); final Set<Long> labels = labelsFor( nodeStore, engine, records, record.getId() ); synchronized ( counts ) { counts.addToValue( nodeKey( WILDCARD ), 1 ); for ( long label : labels ) { counts.addToValue( nodeKey( (int) label ), 1 ); } } } } inner.check( record, engine, records ); } }
@Override public void checkReference( RECORD record, NodeRecord nodeRecord, CheckerEngine<RECORD, REPORT> engine, RecordAccess records ) { if ( nodeRecord.inUse() ) { NodeLabels nodeLabels = NodeLabelsField.parseLabelsField( nodeRecord ); if ( nodeLabels instanceof DynamicNodeLabels ) { DynamicNodeLabels dynamicNodeLabels = (DynamicNodeLabels) nodeLabels; long firstRecordId = dynamicNodeLabels.getFirstDynamicRecordId(); RecordReference<DynamicRecord> firstRecordReference = records.nodeLabels( firstRecordId ); ExpectedNodeLabelsChecker expectedNodeLabelsChecker = new ExpectedNodeLabelsChecker( nodeRecord ); LabelChainWalker<RECORD,REPORT> checker = new LabelChainWalker<>( expectedNodeLabelsChecker ); engine.comparativeCheck( firstRecordReference, checker ); nodeRecord.getDynamicLabelRecords(); // I think this is empty in production } else { long[] storeLabels = nodeLabels.get( null ); REPORT report = engine.report(); validateLabelIds( nodeRecord, storeLabels, report ); } } else if ( indexLabels.length != 0 ) { engine.report().nodeNotInUse( nodeRecord ); } }
private void writeNodeRecord( WritableChannel channel, NodeRecord 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.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. writeDynamicRecords( channel, record.getDynamicLabelRecords() ); } }
@Test public void cloneShouldProduceExactCopy() { // Given long relId = 1337L; long propId = 1338L; long inlinedLabels = 12L; NodeRecord node = new NodeRecord( 1L, false, relId, propId ); node.setLabelField( inlinedLabels, asList( new DynamicRecord( 1L ), new DynamicRecord( 2L ) ) ); node.setInUse( true ); // When NodeRecord clone = node.clone(); // Then assertEquals( node.inUse(), clone.inUse() ); assertEquals( node.getLabelField(), clone.getLabelField() ); assertEquals( node.getNextProp(), clone.getNextProp() ); assertEquals( node.getNextRel(), clone.getNextRel() ); assertThat( clone.getDynamicLabelRecords(), equalTo( node.getDynamicLabelRecords() ) ); }
@Override public EntityUpdates nodeAsUpdates( long nodeId ) { NodeRecord node = nodeStore.getRecord( nodeId, nodeStore.newRecord(), FORCE ); if ( !node.inUse() ) { return null; } long firstPropertyId = node.getNextProp(); if ( firstPropertyId == Record.NO_NEXT_PROPERTY.intValue() ) { return null; // no properties => no updates (it's not going to be in any index) } long[] labels = parseLabelsField( node ).get( nodeStore ); if ( labels.length == 0 ) { return null; // no labels => no updates (it's not going to be in any index) } EntityUpdates.Builder update = EntityUpdates.forEntity( nodeId ).withTokens( labels ); for ( PropertyRecord propertyRecord : propertyStore.getPropertyRecordChain( firstPropertyId ) ) { for ( PropertyBlock property : propertyRecord ) { Value value = property.getType().value( property, propertyStore ); update.added( property.getKeyIndexId(), value ); } } return update.build(); }