private static IndexDefineCommand definitions( MutableObjectIntMap<String> names, MutableObjectIntMap<String> keys ) { IndexDefineCommand definitions = new IndexDefineCommand(); definitions.init( names, keys ); return definitions; } }
@Override public void addRelationship( String indexName, long id, String key, Object value, long startNode, long endNode ) { AddRelationshipCommand command = new AddRelationshipCommand(); command.init( definitions().getOrAssignIndexNameId( indexName ), id, definitions().getOrAssignKeyId( key ), value, startNode, endNode ); addCommand( indexName, command ); }
public String getIndexName( int id ) { return getFromMap( idToIndexName, id ); }
IndexDefineCommand idc = new IndexDefineCommand(); int count = IndexDefineCommand.HIGHEST_POSSIBLE_ID; idc.getOrAssignKeyId( "key" + i ); idc.getOrAssignIndexNameId( "index" + i ); idc.getOrAssignKeyId( "dropThatOverflows" ); fail( "IndexDefineCommand should not allow more than " + count + " indexes per transaction" ); idc.getOrAssignIndexNameId( "dropThatOverflows" ); fail( "IndexDefineCommand should not allow more than " + count + " keys per transaction" );
@Test public void shouldReadNoKeyIdAsMinusOne() throws Exception { // GIVEN InMemoryClosableChannel channel = new InMemoryClosableChannel(); IndexDefineCommand definitions = new IndexDefineCommand(); int indexNameId = 10; definitions.init( ObjectIntHashMap.newWithKeysValues( "myindex", indexNameId ), new ObjectIntHashMap<>() ); definitions.serialize( channel ); RemoveCommand removeCommand = new IndexCommand.RemoveCommand(); removeCommand.init( indexNameId, IndexEntityType.Node.id(), 1234, -1, null ); removeCommand.serialize( channel ); // WHEN PhysicalLogCommandReaderV2_2_4 reader = new PhysicalLogCommandReaderV2_2_4(); assertTrue( reader.read( channel ) instanceof IndexDefineCommand ); RemoveCommand readRemoveCommand = (RemoveCommand) reader.read( channel ); // THEN assertEquals( removeCommand.getIndexNameId(), readRemoveCommand.getIndexNameId() ); assertEquals( removeCommand.getEntityType(), readRemoveCommand.getEntityType() ); assertEquals( removeCommand.getEntityId(), readRemoveCommand.getEntityId() ); assertEquals( removeCommand.getKeyId(), readRemoveCommand.getKeyId() ); assertNull( removeCommand.getValue() ); } }
private static AddNodeCommand addNodeToIndex( IndexDefineCommand definitions, String indexName, long nodeId ) { AddNodeCommand command = new AddNodeCommand(); command.init( definitions.getOrAssignIndexNameId( indexName ), nodeId, (byte) 0, "some value" ); return command; }
String indexName = defineCommand.getIndexName( command.getIndexNameId() ); Map<String,TransactionApplier> applierByIndex = applierByIndexMap( command ); TransactionApplier applier = applierByIndex.get( indexName );
private IndexDefineCommand definitions() { if ( defineCommand == null ) { defineCommand = new IndexDefineCommand(); } return defineCommand; }
public int getOrAssignKeyId( String key ) { return getOrAssignId( keyIdRange, idToKey, nextKeyId, key ); }
private boolean visitIndexAddCommand( IndexCommand command, EntityId entityId ) { try { CommitContext context = commitContext( command ); String key = definitions.getKey( command.getKeyId() ); Object value = command.getValue(); // Below is a check for a null value where such a value is ignored. This may look strange, but the // reason is that there was this bug where adding a null value to an index would be fine and written // into the log as a command, to later fail during application of that command, i.e. here. // There was a fix introduced to throw IllegalArgumentException out to user right away if passing in // null or object that had toString() produce null. Although databases already affected by this would // not be able to recover, which is why this check is here. if ( value != null ) { context.ensureWriterInstantiated(); context.indexType.addToDocument( context.getDocument( entityId, true ).document, key, value ); } } catch ( ExplicitIndexNotFoundKernelException ignore ) { // Pretend the index never existed. } return false; }
@Test public void testVisitIndexDefineCommand() throws Exception { IndexDefineCommand cmd = mock( IndexDefineCommand.class ); when( cmd.handle( any( CommandVisitor.class ) ) ).thenCallRealMethod(); // WHEN boolean result = facade.visitIndexDefineCommand( cmd ); // THEN InOrder inOrder = inOrder( txApplier1, txApplier2, txApplier3 ); inOrder.verify( txApplier1 ).visitIndexDefineCommand( cmd ); inOrder.verify( txApplier2 ).visitIndexDefineCommand( cmd ); inOrder.verify( txApplier3 ).visitIndexDefineCommand( cmd ); inOrder.verifyNoMoreInteractions(); assertFalse( result ); }
@Test public void tracksRelationshipCommands() { ExplicitIndexTransactionStateImpl state = newExplicitIndexTxState(); state.removeRelationship( "index1", 1, "key1", "value1" ); state.addRelationship( "index1", 1, "key2", "value2", 11, 11 ); state.removeRelationship( "index1", 2, "key1", "value3" ); state.addRelationship( "index1", 3, "key2", "value4", 22, 22 ); state.addRelationship( "index2", 4, "key1", "value5", 33, 33 ); IndexDefineCommand indexDefinedCommand = new IndexDefineCommand(); indexDefinedCommand.getOrAssignIndexNameId( "index1" ); indexDefinedCommand.getOrAssignIndexNameId( "index2" ); indexDefinedCommand.getOrAssignKeyId( "key1" ); indexDefinedCommand.getOrAssignKeyId( "key2" ); Set<Command> expectedCommands = new HashSet<>( Arrays.asList( indexDefinedCommand, removeRelationship( 1, 1, 1, "value1" ), addRelationship( 1, 1, 2, "value2", 11, 11 ), removeRelationship( 1, 2, 1, "value3" ), addRelationship( 1, 3, 2, "value4", 22, 22 ), addRelationship( 2, 4, 1, "value5", 33, 33 ) ) ); assertEquals( expectedCommands, extractCommands( state ) ); }
@Override public void deleteIndex( IndexEntityType entityType, String indexName ) { DeleteCommand command = new DeleteCommand(); command.init( definitions().getOrAssignIndexNameId( indexName ), entityType.id() ); addCommand( indexName, command, true ); }
private CommitContext commitContext( IndexCommand command ) throws ExplicitIndexNotFoundKernelException { Map<String,CommitContext> contextMap = commitContextMap( command.getEntityType() ); String indexName = definitions.getIndexName( command.getIndexNameId() ); CommitContext context = contextMap.get( indexName ); if ( context == null ) { IndexIdentifier identifier = new IndexIdentifier( IndexEntityType.byId( command.getEntityType() ), indexName ); // TODO the fact that we look up index type from config here using the index store // directly should be avoided. But how can we do it in, say recovery? // The `dataSource.getType()` call can throw an exception if the index is concurrently deleted. // To avoid bubbling an exception during commit, we instead ignore the commands related to that index, // and proceed as if the index never existed, and thus cannot accept any modifications. IndexType type = dataSource.getType( identifier, recovery ); context = new CommitContext( dataSource, identifier, type, recovery ); contextMap.put( indexName, context ); } return context; }
private IndexDefineCommand definitions() { if ( defineCommand == null ) { defineCommand = new IndexDefineCommand(); } return defineCommand; }
public int getOrAssignIndexNameId( String indexName ) { return getOrAssignId( indexNameIdRange, idToIndexName, nextIndexNameId, indexName ); }
@Override public boolean visitIndexRemoveCommand( RemoveCommand command ) { try { CommitContext context = commitContext( command ); String key = definitions.getKey( command.getKeyId() ); Object value = command.getValue(); context.ensureWriterInstantiated(); CommitContext.DocumentContext document = context.getDocument( new IdData( command.getEntityId() ), false ); if ( document != null ) { context.indexType.removeFromDocument( document.document, key, value ); } } catch ( ExplicitIndexNotFoundKernelException ignore ) { // Pretend the index never existed. } return false; }
@Test public void tracksNodeCommands() { ExplicitIndexTransactionStateImpl state = newExplicitIndexTxState(); state.addNode( "index1", 1, "key1", "value1" ); state.removeNode( "index1", 1, "key2", "value2" ); state.addNode( "index1", 2, "key1", "value3" ); state.addNode( "index1", 3, "key2", "value4" ); state.removeNode( "index2", 4, "key1", "value5" ); IndexDefineCommand indexDefinedCommand = new IndexDefineCommand(); indexDefinedCommand.getOrAssignIndexNameId( "index1" ); indexDefinedCommand.getOrAssignIndexNameId( "index2" ); indexDefinedCommand.getOrAssignKeyId( "key1" ); indexDefinedCommand.getOrAssignKeyId( "key2" ); Set<Command> expectedCommands = new HashSet<>( Arrays.asList( indexDefinedCommand, addNode( 1, 1, 1, "value1" ), removeNode( 1, 1, 2, "value2" ), addNode( 1, 2, 1, "value3" ), addNode( 1, 3, 2, "value4" ), removeNode( 2, 4, 1, "value5" ) ) ); assertEquals( expectedCommands, extractCommands( state ) ); }
private static IndexDefineCommand definitions( MutableObjectIntMap<String> names, MutableObjectIntMap<String> keys ) { IndexDefineCommand definitions = new IndexDefineCommand(); definitions.init( names, keys ); return definitions; }
@Override public void addNode( String indexName, long id, String key, Object value ) { AddNodeCommand command = new AddNodeCommand(); command.init( definitions().getOrAssignIndexNameId( indexName ), id, definitions().getOrAssignKeyId( key ), value ); addCommand( indexName, command ); }