public void create( PropertyRecord property ) { property.setCreated(); PropertyRecord before = new PropertyRecord( property.getId() ); if ( property.isNodeSet() ) { before.setNodeId( property.getNodeId() ); } if ( property.isRelSet() ) { before.setRelId( property.getRelId() ); } update( before, property ); }
private static PropertyRecord propertyRecord( PropertyBlock... propertyBlocks ) { PropertyRecord record = new PropertyRecord( 0 ); if ( propertyBlocks != null ) { record.setInUse( true ); for ( PropertyBlock propertyBlock : propertyBlocks ) { record.addPropertyBlock( propertyBlock ); } } record.setNodeId( 0 ); return record; }
private void writePropertyRecord( WritableChannel channel, PropertyRecord record ) throws IOException byte flags = bitFlags( bitFlag( record.inUse(), Record.IN_USE.byteValue() ), bitFlag( record.getRelId() != -1, Record.REL_PROPERTY.byteValue() ), bitFlag( record.requiresSecondaryUnit(), Record.REQUIRE_SECONDARY_UNIT ), bitFlag( record.hasSecondaryUnitId(), Record.HAS_SECONDARY_UNIT ), bitFlag( record.isUseFixedReferences(), Record.USES_FIXED_REFERENCE_FORMAT ) ); channel.putLong( record.getNextProp() ).putLong( record.getPrevProp() ); // 8 + 8 long nodeId = record.getNodeId(); long relId = record.getRelId(); if ( nodeId != -1 ) if ( record.hasSecondaryUnitId() ) channel.putLong( record.getSecondaryUnitId() ); channel.put( (byte) record.numberOfProperties() ); // 1 for ( PropertyBlock block : record ) writePropertyBlock( channel, block ); writeDynamicRecords( channel, record.getDeletedRecords() );
private PropertyRecord propertyRecord( long nextPropertyId ) { propertyRecord.clear(); propertyRecord.setInUse( true ); propertyRecord.setId( nextPropertyId ); primitiveRecord().setIdTo( propertyRecord ); propertyRecord.setCreated(); return propertyRecord; }
public void setPropertyBlock( PropertyBlock block ) { removePropertyBlock( block.getKeyIndexId() ); addPropertyBlock( block ); }
@Override public PropertyRecord clone() { PropertyRecord result = (PropertyRecord) new PropertyRecord( getId() ).initialize( inUse() ); result.nextProp = nextProp; result.prevProp = prevProp; result.entityId = entityId; result.entityType = entityType; System.arraycopy( blocks, 0, result.blocks, 0, blocks.length ); result.blocksCursor = blocksCursor; for ( int i = 0; i < blockRecordsCursor; i++ ) { result.blockRecords[i] = blockRecords[i].clone(); } result.blockRecordsCursor = blockRecordsCursor; result.blocksLoaded = blocksLoaded; if ( deletedRecords != null ) { for ( DynamicRecord deletedRecord : deletedRecords ) { result.addDeletedRecord( deletedRecord.clone() ); } } return result; }
assert propRecord.size() == 0; long prevProp = propRecord.getPrevProp(); long nextProp = propRecord.getNextProp(); if ( primitive.getNextProp() == propRecord.getId() ) assert propRecord.getPrevProp() == Record.NO_PREVIOUS_PROPERTY.intValue() : propRecord + " for " + primitive; assert prevPropRecord.inUse() : prevPropRecord + "->" + propRecord + " for " + primitive; prevPropRecord.setNextProp( nextProp ); prevPropRecord.setChanged( primitive ); assert nextPropRecord.inUse() : propRecord + "->" + nextPropRecord + " for " + primitive; nextPropRecord.setPrevProp( prevProp ); nextPropRecord.setChanged( primitive ); propRecord.setInUse( false ); propRecord.setPrevProp( Record.NO_PREVIOUS_PROPERTY.intValue() ); propRecord.setNextProp( Record.NO_NEXT_PROPERTY.intValue() ); propRecord.setChanged( primitive ); assert traverser.assertPropertyChain( primitive, propertyRecords );
@Override protected void assertRecordsEqual( PropertyRecord actualRecord, PropertyRecord expectedRecord ) { assertNotNull( "actualRecord", actualRecord ); assertNotNull( "expectedRecord", expectedRecord ); assertThat( "getDeletedRecords", actualRecord.getDeletedRecords(), is( expectedRecord.getDeletedRecords() ) ); assertThat( "getNextProp", actualRecord.getNextProp(), is( expectedRecord.getNextProp() ) ); assertThat( "getEntityId", actualRecord.getNodeId(), is( expectedRecord.getNodeId() ) ); assertThat( "getPrevProp", actualRecord.getPrevProp(), is( expectedRecord.getPrevProp() ) ); assertThat( "getRelId", actualRecord.getRelId(), is( expectedRecord.getRelId() ) ); assertThat( "getId", actualRecord.getId(), is( expectedRecord.getId() ) ); assertThat( "getLongId", actualRecord.getId(), is( expectedRecord.getId() ) ); List<PropertyBlock> actualBlocks = Iterables.asList( actualRecord ); List<PropertyBlock> expectedBlocks = Iterables.asList( expectedRecord ); assertThat( "getPropertyBlocks().size", actualBlocks.size(), is( expectedBlocks.size() ) ); for ( int i = 0; i < actualBlocks.size(); i++ ) { PropertyBlock actualBlock = actualBlocks.get( i ); PropertyBlock expectedBlock = expectedBlocks.get( i ); assertPropertyBlocksEqual( i, actualBlock, expectedBlock ); } }
@Test void shouldReportPreviousPropertyNotInUse() { // given PropertyRecord property = inUse( new PropertyRecord( 42 ) ); PropertyRecord prev = add( notInUse( new PropertyRecord( 51 ) ) ); property.setPrevProp( prev.getId() ); // when ConsistencyReport.PropertyConsistencyReport report = check( property ); // then verify( report ).prevNotInUse( prev ); verifyNoMoreInteractions( report ); }
@Override public void read( PropertyRecord record, PageCursor cursor, RecordLoad mode, int recordSize ) { int offset = cursor.getOffset(); byte headerByte = cursor.getByte(); boolean inUse = isInUse( headerByte ); if ( mode.shouldLoad( inUse ) ) { int blockCount = headerByte >>> 4; long recordId = record.getId(); record.initialize( inUse, toAbsolute( Reference.decode( cursor ), recordId ), toAbsolute( Reference.decode( cursor ), recordId ) ); if ( (blockCount > record.getBlockCapacity()) | (RECORD_SIZE - (cursor.getOffset() - offset) < blockCount * Long.BYTES) ) { cursor.setCursorException( "PropertyRecord claims to contain more blocks than can fit in a record" ); return; } while ( blockCount-- > 0 ) { record.addLoadedBlock( cursor.getLong() ); } } }
@Test void shouldReportPropertyKeyNotInUse() { // given PropertyRecord property = inUse( new PropertyRecord( 42 ) ); PropertyKeyTokenRecord key = add( notInUse( new PropertyKeyTokenRecord( 0 ) ) ); PropertyBlock block = propertyBlock( key, PropertyType.INT, 0 ); property.addPropertyBlock( block ); // when ConsistencyReport.PropertyConsistencyReport report = check( property ); // then verify( report ).keyNotInUse( block, key ); verifyNoMoreInteractions( report ); }
@Override public void assertRecordsEquals( PropertyRecord written, PropertyRecord read ) { assertEquals( written.getPrevProp(), read.getPrevProp() ); assertEquals( written.getNextProp(), read.getNextProp() ); assertEquals( written.isNodeSet(), read.isNodeSet() ); if ( written.isNodeSet() ) { assertEquals( written.getNodeId(), read.getNodeId() ); } else { assertEquals( written.getRelId(), read.getRelId() ); } assertEquals( written.numberOfProperties(), read.numberOfProperties() ); Iterator<PropertyBlock> writtenBlocks = written.iterator(); Iterator<PropertyBlock> readBlocks = read.iterator(); while ( writtenBlocks.hasNext() ) { assertTrue( readBlocks.hasNext() ); assertBlocksEquals( writtenBlocks.next(), readBlocks.next() ); } }
@Override public Generator<PropertyRecord> property() { return ( recordSize, format, recordId ) -> { PropertyRecord record = new PropertyRecord( recordId ); int maxProperties = random.intBetween( 1, 4 ); StandaloneDynamicRecordAllocator stringAllocator = new StandaloneDynamicRecordAllocator(); StandaloneDynamicRecordAllocator arrayAllocator = new StandaloneDynamicRecordAllocator(); record.setInUse( true ); int blocksOccupied = 0; for ( int i = 0; i < maxProperties && blocksOccupied < 4; ) { PropertyBlock block = new PropertyBlock(); // Dynamic records will not be written and read by the property record format, // that happens in the store where it delegates to a "sub" store. PropertyStore.encodeValue( block, random.nextInt( tokenBits ), random.nextValue(), stringAllocator, arrayAllocator, true ); int tentativeBlocksWithThisOne = blocksOccupied + block.getValueBlocks().length; if ( tentativeBlocksWithThisOne <= 4 ) { record.addPropertyBlock( block ); blocksOccupied = tentativeBlocksWithThisOne; } } record.setPrevProp( randomLongOrOccasionallyNull( propertyBits ) ); record.setNextProp( randomLongOrOccasionallyNull( propertyBits ) ); return record; }; }
assert propRecord.inUse() : primitive + "->" + Arrays.toString( toCheck.toArray() ); assert propRecord.size() <= PropertyType.getPayloadSize() : propRecord + " size " + propRecord.size(); nextIdToFetch = propRecord.getNextProp(); assert first.getPrevProp() == Record.NO_PREVIOUS_PROPERTY.intValue() : primitive + "->" + Arrays.toString( toCheck.toArray() ); assert last.getNextProp() == Record.NO_NEXT_PROPERTY.intValue() : primitive + "->" + Arrays.toString( toCheck.toArray() ); assert current.getPrevProp() == previous.getId() : primitive + "->" + Arrays.toString( toCheck.toArray() ); assert previous.getNextProp() == current.getId() : primitive + "->" + Arrays.toString( toCheck.toArray() );
@Override protected PropertyRecord createExistingRecord( boolean light ) { PropertyRecord record = new PropertyRecord( ID ); record.setId( ID ); record.setNextProp( 2 ); record.setPrevProp( 4 ); record.setInUse( true ); PropertyBlock block = new PropertyBlock(); DynamicRecordAllocator stringAllocator = new ReusableRecordsAllocator( 64, new DynamicRecord( 7 ) ); Value value = Values.of( "a string too large to fit in the property block itself" ); PropertyStore.encodeValue( block, 6, value, stringAllocator, null, true ); if ( light ) { block.getValueRecords().clear(); } record.setPropertyBlock( block ); return record; }
@Test void shouldReportNextPropertyNotInUse() { // given PropertyRecord property = inUse( new PropertyRecord( 42 ) ); PropertyRecord next = add( notInUse( new PropertyRecord( 51 ) ) ); property.setNextProp( next.getId() ); // when ConsistencyReport.PropertyConsistencyReport report = check( property ); // then verify( report ).nextNotInUse( next ); verifyNoMoreInteractions( report ); }
@Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { // structurally correct, but does not have the 'mandatory' property with the 'draconian' label NodeRecord node = new NodeRecord( next.node(), false, -1, next.property() ); node.setInUse( true ); node.setLabelField( inlinedLabelsLongRepresentation( draconian ), Collections.emptySet() ); PropertyRecord property = new PropertyRecord( node.getNextProp(), node ); property.setInUse( true ); PropertyBlock block = new PropertyBlock(); block.setSingleBlock( key1 | (((long) PropertyType.INT.intValue()) << 24) | (1337L << 28) ); property.addPropertyBlock( block ); tx.create( node ); tx.create( property ); } } );
public static PropertyCommand createProperty( long id, PropertyType type, int key, long... valueRecordIds ) { PropertyRecord record = new PropertyRecord( id ); record.setInUse( true ); record.setCreated(); PropertyBlock block = new PropertyBlock(); if ( valueRecordIds.length == 0 ) { PropertyStore.encodeValue( block, key, Values.of( 123 ), null, null, true ); } else { PropertyStore.setSingleBlockValue( block, key, type, valueRecordIds[0] ); block.setValueRecords( dynamicRecords( valueRecordIds ) ); } record.addPropertyBlock( block ); return new PropertyCommand( new PropertyRecord( id ), record ); }
@Override public boolean visitPropertyCommand( PropertyCommand command ) { if ( command.getAfter().isNodeSet() ) { createOrAddToGroup( command, command.getAfter().getNodeId(), propertyCommandsByNodeIds ); } else if ( command.getAfter().isRelSet() ) { createOrAddToGroup( command, command.getAfter().getRelId(), propertyCommandsByRelationshipIds ); } return false; }
private void existingChain( ExpectedRecord... initialRecords ) { PropertyRecord prev = null; for ( ExpectedRecord initialRecord : initialRecords ) { PropertyRecord record = this.records.create( propertyStore.nextId(), primitive.record ).forChangingData(); record.setInUse( true ); existingRecord( record, initialRecord ); if ( prev == null ) { // This is the first one, update primitive to point to this primitive.record.setNextProp( record.getId() ); } else { // link property records together record.setPrevProp( prev.getId() ); prev.setNextProp( record.getId() ); } prev = record; } }