/** * @deprecated use {@link #initialize(boolean, boolean, long, int, int)} instead. */ @Deprecated public static DynamicRecord dynamicRecord( long id, boolean inUse, boolean isStartRecord, long nextBlock, int type, byte [] data ) { DynamicRecord record = new DynamicRecord( id ); record.setInUse( inUse ); record.setStartRecord( isStartRecord ); record.setNextBlock( nextBlock ); record.setType( type ); record.setData( data ); return record; }
@Override protected DynamicRecord createNullRecord( long id ) { DynamicRecord record = new DynamicRecord( id ); record.setNextBlock( 0 ); record.setData( new byte[0] ); return record; }
@Test public void shouldReportSelfReferentialNext() { // given DynamicRecord property = add( inUse( fill( record( 42 ) ) ) ); property.setNextBlock( property.getId() ); // when ConsistencyReport.DynamicConsistencyReport report = check( property ); // then verify( report ).selfReferentialNext(); verifyNoMoreInteractions( report ); }
@Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { DynamicRecord schema = new DynamicRecord( next.schema() ); DynamicRecord schemaBefore = schema.clone(); schema.setNextBlock( next.schema() ); // Point to a record that isn't in use. StoreIndexDescriptor rule = indexRule( schema.getId(), label1, key1, DESCRIPTOR ); schema.setData( SchemaRuleSerialization.serialize( rule ) ); tx.createSchema( asList( schemaBefore ), asList( schema ), rule ); } } );
@Test public void dynamicRecordCursorReadsInUseRecords() { try ( AbstractDynamicStore store = newTestableDynamicStore() ) { DynamicRecord first = createDynamicRecord( 1, store, 0 ); DynamicRecord second = createDynamicRecord( 2, store, 0 ); DynamicRecord third = createDynamicRecord( 3, store, 10 ); store.setHighId( 3 ); first.setNextBlock( second.getId() ); store.updateRecord( first ); second.setNextBlock( third.getId() ); store.updateRecord( second ); Iterator<DynamicRecord> records = store.getRecords( 1, NORMAL ).iterator(); assertTrue( records.hasNext() ); assertEquals( first, records.next() ); assertTrue( records.hasNext() ); assertEquals( second, records.next() ); assertTrue( records.hasNext() ); assertEquals( third, records.next() ); assertFalse( records.hasNext() ); } }
@Test public void shouldReportRecordWithEmptyNext() { // given DynamicRecord property = inUse( fill( record( 42 ) ) ); DynamicRecord next = add( inUse( record( 7 ) ) ); property.setNextBlock( next.getId() ); // when ConsistencyReport.DynamicConsistencyReport report = check( property ); // then verify( report ).emptyNextBlock( next ); verifyNoMoreInteractions( report ); }
@Test public void shouldReportNextRecordNotInUse() { // given DynamicRecord property = inUse( fill( record( 42 ) ) ); DynamicRecord next = add( notInUse( record( 7 ) ) ); property.setNextBlock( next.getId() ); // when ConsistencyReport.DynamicConsistencyReport report = check( property ); // then verify( report ).nextNotInUse( next ); verifyNoMoreInteractions( report ); }
@Test public void dynamicRecordCursorReadsNotInUseRecords() { try ( AbstractDynamicStore store = newTestableDynamicStore() ) { DynamicRecord first = createDynamicRecord( 1, store, 0 ); DynamicRecord second = createDynamicRecord( 2, store, 0 ); DynamicRecord third = createDynamicRecord( 3, store, 10 ); store.setHighId( 3 ); first.setNextBlock( second.getId() ); store.updateRecord( first ); second.setNextBlock( third.getId() ); store.updateRecord( second ); second.setInUse( false ); store.updateRecord( second ); Iterator<DynamicRecord> records = store.getRecords( 1, FORCE ).iterator(); assertTrue( records.hasNext() ); assertEquals( first, records.next() ); assertTrue( records.hasNext() ); DynamicRecord secondReadRecord = records.next(); assertEquals( second, secondReadRecord ); assertFalse( secondReadRecord.inUse() ); // because mode == FORCE we can still move through the chain assertTrue( records.hasNext() ); assertEquals( third, records.next() ); assertFalse( records.hasNext() ); } }
@Test public void shouldReportNonFullRecordWithNextReference() { // given DynamicRecord property = inUse( fill( record( 42 ), blockSize - 1 ) ); DynamicRecord next = add( inUse( fill( record( 7 ), blockSize / 2 ) ) ); property.setNextBlock( next.getId() ); // when ConsistencyReport.DynamicConsistencyReport report = check( property ); // then verify( report ).recordNotFullReferencesNext(); verifyNoMoreInteractions( report ); }
@Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { long nodeId = ((long[]) getRightArray( readFullByteArrayFromHeavyRecords( chain, ARRAY ) ).asObject())[0]; NodeRecord before = inUse( new NodeRecord( nodeId, false, -1, -1 ) ); NodeRecord after = inUse( new NodeRecord( nodeId, false, -1, -1 ) ); DynamicRecord record1 = chain.get( 0 ).clone(); DynamicRecord record2 = chain.get( 1 ).clone(); DynamicRecord record3 = chain.get( 2 ).clone(); record3.setNextBlock( record2.getId() ); before.setLabelField( dynamicPointer( chain ), chain ); after.setLabelField( dynamicPointer( chain ), asList( record1, record2, record3 ) ); tx.update( before, after ); } } );
@Test public void shouldNotReportAnythingForRecordWithConsistentReferences() { // given DynamicRecord property = inUse( fill( record( 42 ) ) ); DynamicRecord next = add( inUse( fill( record( 7 ), blockSize / 2 ) ) ); property.setNextBlock( next.getId() ); // when ConsistencyReport.DynamicConsistencyReport report = check( property ); // then verifyNoMoreInteractions( report ); }
private DynamicRecord readDynamicRecord( ReadableChannel channel ) throws IOException { // id+type+in_use(byte)+nr_of_bytes(int)+next_block(long) long id = channel.getLong(); assert id >= 0 && id <= (1L << 36) - 1 : id + " is not a valid dynamic record id"; int type = channel.getInt(); byte inUseFlag = channel.get(); boolean inUse = (inUseFlag & Record.IN_USE.byteValue()) != 0; DynamicRecord record = new DynamicRecord( id ); record.setInUse( inUse, type ); if ( inUse ) { record.setStartRecord( (inUseFlag & Record.FIRST_IN_CHAIN.byteValue()) != 0 ); int nrOfBytes = channel.getInt(); assert nrOfBytes >= 0 && nrOfBytes < ((1 << 24) - 1) : nrOfBytes + " is not valid for a number of bytes field of " + "a dynamic record"; long nextBlock = channel.getLong(); assert (nextBlock >= 0 && nextBlock <= (1L << 36 - 1)) || (nextBlock == Record.NO_NEXT_BLOCK.intValue()) : nextBlock + " is not valid for a next record field of " + "a dynamic record"; record.setNextBlock( nextBlock ); byte[] data = new byte[nrOfBytes]; channel.get( data, nrOfBytes ); record.setData( data ); } return record; }
@Test void shouldReportDynamicRecordOwnedByTwoOtherDynamicRecords() { // given RecordAccessStub records = new RecordAccessStub(); OwnerCheck decorator = new OwnerCheck( true, DynamicStore.STRING ); RecordCheck<DynamicRecord, ConsistencyReport.DynamicConsistencyReport> checker = decorator .decorateDynamicChecker( RecordType.STRING_PROPERTY, dummyDynamicCheck( configureDynamicStore( 50 ), DynamicStore.STRING ) ); DynamicRecord record1 = records.add( inUse( string( new DynamicRecord( 1 ) ) ) ); DynamicRecord record2 = records.add( inUse( string( new DynamicRecord( 2 ) ) ) ); DynamicRecord record3 = records.add( inUse( string( new DynamicRecord( 3 ) ) ) ); record1.setNextBlock( record3.getId() ); record2.setNextBlock( record3.getId() ); // when ConsistencyReport.DynamicConsistencyReport report1 = check( ConsistencyReport.DynamicConsistencyReport.class, checker, record1, records ); ConsistencyReport.DynamicConsistencyReport report2 = check( ConsistencyReport.DynamicConsistencyReport.class, checker, record2, records ); // then verifyNoMoreInteractions( report1 ); verify( report2 ).nextMultipleOwners( record1 ); verifyNoMoreInteractions( report2 ); }
@Test void shouldReportDynamicRecordOwnedByRelationshipLabelAndOtherDynamicRecord() { // given RecordAccessStub records = new RecordAccessStub(); OwnerCheck decorator = new OwnerCheck( true, DynamicStore.RELATIONSHIP_TYPE ); RecordCheck<DynamicRecord, ConsistencyReport.DynamicConsistencyReport> dynChecker = decorator.decorateDynamicChecker( RecordType.RELATIONSHIP_TYPE_NAME, dummyDynamicCheck( configureDynamicStore( 50 ), DynamicStore.RELATIONSHIP_TYPE ) ); RecordCheck<RelationshipTypeTokenRecord, ConsistencyReport.RelationshipTypeConsistencyReport> labelCheck = decorator.decorateRelationshipTypeTokenChecker( dummyRelationshipLabelCheck() ); DynamicRecord owned = records.addRelationshipTypeName( inUse( string( new DynamicRecord( 42 ) ) ) ); DynamicRecord dynamic = records.addRelationshipTypeName( inUse( string( new DynamicRecord( 1 ) ) ) ); RelationshipTypeTokenRecord label = records.add( inUse( new RelationshipTypeTokenRecord( 1 ) ) ); dynamic.setNextBlock( owned.getId() ); label.setNameId( (int) owned.getId() ); // when ConsistencyReport.RelationshipTypeConsistencyReport labelReport = check( ConsistencyReport.RelationshipTypeConsistencyReport.class, labelCheck, label, records ); ConsistencyReport.DynamicConsistencyReport dynReport = check( ConsistencyReport.DynamicConsistencyReport.class, dynChecker, dynamic, records ); // then verifyNoMoreInteractions( labelReport ); verify( dynReport ).nextMultipleOwners( label ); verifyNoMoreInteractions( dynReport ); }
@Test void shouldReportDynamicRecordOwnedByOtherDynamicRecordAndRelationshipLabel() { // given RecordAccessStub records = new RecordAccessStub(); OwnerCheck decorator = new OwnerCheck( true, DynamicStore.RELATIONSHIP_TYPE ); RecordCheck<DynamicRecord, ConsistencyReport.DynamicConsistencyReport> dynChecker = decorator.decorateDynamicChecker( RecordType.RELATIONSHIP_TYPE_NAME, dummyDynamicCheck( configureDynamicStore( 50 ), DynamicStore.RELATIONSHIP_TYPE ) ); RecordCheck<RelationshipTypeTokenRecord, ConsistencyReport.RelationshipTypeConsistencyReport> labelCheck = decorator.decorateRelationshipTypeTokenChecker( dummyRelationshipLabelCheck() ); DynamicRecord owned = records.addRelationshipTypeName( inUse( string( new DynamicRecord( 42 ) ) ) ); DynamicRecord dynamic = records.addRelationshipTypeName( inUse( string( new DynamicRecord( 1 ) ) ) ); RelationshipTypeTokenRecord label = records.add( inUse( new RelationshipTypeTokenRecord( 1 ) ) ); dynamic.setNextBlock( owned.getId() ); label.setNameId( (int) owned.getId() ); // when ConsistencyReport.DynamicConsistencyReport dynReport = check( ConsistencyReport.DynamicConsistencyReport.class, dynChecker, dynamic, records ); ConsistencyReport.RelationshipTypeConsistencyReport labelReport = check( ConsistencyReport.RelationshipTypeConsistencyReport.class, labelCheck, label, records ); // then verifyNoMoreInteractions( dynReport ); verify( labelReport ).nameMultipleOwners( dynamic ); verifyNoMoreInteractions( labelReport ); }
@Test void shouldReportDynamicRecordOwnedByPropertyAndOtherDynamic() { // given RecordAccessStub records = new RecordAccessStub(); OwnerCheck decorator = new OwnerCheck( true, DynamicStore.STRING ); RecordCheck<DynamicRecord, ConsistencyReport.DynamicConsistencyReport> dynChecker = decorator .decorateDynamicChecker( RecordType.STRING_PROPERTY, dummyDynamicCheck( configureDynamicStore( 50 ), DynamicStore.STRING ) ); RecordCheck<PropertyRecord, ConsistencyReport.PropertyConsistencyReport> propChecker = decorator .decoratePropertyChecker( dummyPropertyChecker() ); DynamicRecord owned = records.add( inUse( string( new DynamicRecord( 42 ) ) ) ); DynamicRecord dynamic = records.add( inUse( string( new DynamicRecord( 100 ) ) ) ); dynamic.setNextBlock( owned.getId() ); PropertyRecord property = records.add( inUse( new PropertyRecord( 1 ) ) ); PropertyKeyTokenRecord key = records.add( inUse( new PropertyKeyTokenRecord( 10 ) ) ); property.addPropertyBlock( propertyBlock( key, PropertyType.STRING, owned.getId() ) ); // when ConsistencyReport.PropertyConsistencyReport propReport = check( ConsistencyReport.PropertyConsistencyReport.class, propChecker, property, records ); ConsistencyReport.DynamicConsistencyReport dynReport = check( ConsistencyReport.DynamicConsistencyReport.class, dynChecker, dynamic, records ); // then verifyNoMoreInteractions( propReport ); verify( dynReport ).nextMultipleOwners( property ); verifyNoMoreInteractions( dynReport ); }
@Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { DynamicRecord string = new DynamicRecord( next.stringProperty() ); string.setInUse( true ); string.setCreated(); string.setType( PropertyType.STRING.intValue() ); string.setNextBlock( next.stringProperty() ); string.setData( UTF8.encode( "hello world" ) ); PropertyBlock block = new PropertyBlock(); block.setSingleBlock( (((long) PropertyType.STRING.intValue()) << 24) | (string.getId() << 28) ); block.addValueRecord( string ); PropertyRecord property = new PropertyRecord( next.property() ); property.addPropertyBlock( block ); tx.create( property ); } } );
@Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { DynamicRecord array = new DynamicRecord( next.arrayProperty() ); array.setInUse( true ); array.setCreated(); array.setType( ARRAY.intValue() ); array.setNextBlock( next.arrayProperty() ); array.setData( UTF8.encode( "hello world" ) ); PropertyBlock block = new PropertyBlock(); block.setSingleBlock( (((long) ARRAY.intValue()) << 24) | (array.getId() << 28) ); block.addValueRecord( array ); PropertyRecord property = new PropertyRecord( next.property() ); property.addPropertyBlock( block ); tx.create( property ); } } );
@Test public void shouldReportRelationshipLabelNameInconsistencies() throws Exception { // given final Reference<Integer> inconsistentName = new Reference<>(); fixture.apply( new GraphStoreFixture.Transaction() { @Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { inconsistentName.set( next.relationshipType() ); tx.relationshipType( inconsistentName.get(), "FOO" ); } } ); StoreAccess access = fixture.directStoreAccess().nativeStores(); DynamicRecord record = access.getRelationshipTypeNameStore().getRecord( inconsistentName.get(), access.getRelationshipTypeNameStore().newRecord(), FORCE ); record.setNextBlock( record.getId() ); access.getRelationshipTypeNameStore().updateRecord( record ); // when ConsistencySummaryStatistics stats = check(); // then on( stats ).verify( RecordType.RELATIONSHIP_TYPE_NAME, 1 ) .andThatsAllFolks(); }
@Test public void shouldReportPropertyKeyNameInconsistencies() throws Exception { // given final Reference<Integer> inconsistentName = new Reference<>(); fixture.apply( new GraphStoreFixture.Transaction() { @Override protected void transactionData( GraphStoreFixture.TransactionDataBuilder tx, GraphStoreFixture.IdGenerator next ) { inconsistentName.set( next.propertyKey() ); tx.propertyKey( inconsistentName.get(), "FOO" ); } } ); StoreAccess access = fixture.directStoreAccess().nativeStores(); DynamicRecord record = access.getPropertyKeyNameStore().getRecord( inconsistentName.get() + 1, access.getPropertyKeyNameStore().newRecord(), FORCE ); record.setNextBlock( record.getId() ); access.getPropertyKeyNameStore().updateRecord( record ); // when ConsistencySummaryStatistics stats = check(); // then on( stats ).verify( RecordType.PROPERTY_KEY_NAME, 1 ) .andThatsAllFolks(); }