/** * In case the transactions do not have the commands to apply, use this method to apply any commands you want with a * given {@link ApplyFunction} instead. * * @param applier to use * @param function which knows what to do with the {@link TransactionApplier}. * @param transactions are only used to create {@link TransactionApplier}s. The actual work is delegated to the * function. * @return the boolean-and result of all function operations. */ public static boolean apply( BatchTransactionApplier applier, ApplyFunction function, TransactionToApply... transactions ) throws Exception { boolean result = true; for ( TransactionToApply tx : transactions ) { try ( TransactionApplier txApplier = applier.startTx( tx, new LockGroup() ) ) { result &= function.apply( txApplier ); } } applier.close(); return result; } }
@Test public void shouldReleaseAllLocksWhenExitingTheLockGroupRegion() { // given Lock lock1 = mock( Lock.class ); Lock lock2 = mock( Lock.class ); Lock lock3 = mock( Lock.class ); // when try ( LockGroup locks = new LockGroup() ) { locks.add( lock1 ); locks.add( lock2 ); locks.add( lock3 ); } // then verify( lock1, times( 1 ) ).release(); verify( lock2, times( 1 ) ).release(); verify( lock3, times( 1 ) ).release(); } }
@Override public boolean visitNodeCommand( Command.NodeCommand command ) { // acquire lock lockGroup.add( lockService.acquireNodeLock( command.getKey(), LockService.LockType.WRITE_LOCK ) ); // update store updateStore( neoStores.getNodeStore(), command ); return false; }
@Override public boolean visitRelationshipCommand( Command.RelationshipCommand command ) { lockGroup.add( lockService.acquireRelationshipLock( command.getKey(), LockService.LockType.WRITE_LOCK ) ); updateStore( neoStores.getRelationshipStore(), command ); return false; }
@Override public void apply( CommandsToApply batch, TransactionApplicationMode mode ) throws Exception { // Have these command appliers as separate try-with-resource to have better control over // point between closing this and the locks above try ( IndexActivator indexActivator = new IndexActivator( indexingService ); LockGroup locks = new LockGroup(); BatchTransactionApplier batchApplier = applier( mode, indexActivator ) ) { while ( batch != null ) { try ( TransactionApplier txApplier = batchApplier.startTx( batch, locks ) ) { batch.accept( txApplier ); } batch = batch.next(); } } catch ( Throwable cause ) { TransactionApplyKernelException kernelException = new TransactionApplyKernelException( cause, "Failed to apply transaction: %s", batch ); databaseHealth.panic( kernelException ); throw kernelException; } }
@Override public boolean visitPropertyCommand( Command.PropertyCommand command ) { // acquire lock if ( command.getNodeId() != -1 ) { lockGroup.add( lockService.acquireNodeLock( command.getNodeId(), LockService.LockType.WRITE_LOCK ) ); } else if ( command.getRelId() != -1 ) { lockGroup.add( lockService.acquireRelationshipLock( command.getRelId(), LockService.LockType.WRITE_LOCK ) ); } updateStore( neoStores.getPropertyStore(), command ); return false; }
/** * Simply calls through to the {@link TransactionRepresentation#accept(Visitor)} method for each {@link * TransactionToApply} given. This assumes that the {@link BatchTransactionApplier} will return {@link * TransactionApplier}s which actually do the work and that the transaction has all the relevant data. * * @param applier to use * @param transactions to apply */ public static void apply( BatchTransactionApplier applier, TransactionToApply... transactions ) throws Exception { for ( TransactionToApply tx : transactions ) { try ( TransactionApplier txApplier = applier.startTx( tx, new LockGroup() ) ) { tx.transactionRepresentation().accept( txApplier ); } } applier.close(); }
@Override public boolean visitNodeCommand( Command.NodeCommand command ) { // acquire lock lockGroup.add( lockService.acquireNodeLock( command.getKey(), LockService.LockType.WRITE_LOCK ) ); // update store updateStore( neoStores.getNodeStore(), command ); return false; }
private void applyToStore( Collection<StorageCommand> commands, long logIndex ) { PhysicalTransactionRepresentation representation = new PhysicalTransactionRepresentation( commands ); representation.setHeader( encodeLogIndexAsTxHeader( logIndex ), 0, 0, 0, 0L, 0L, 0 ); try ( LockGroup ignored = new LockGroup() ) { commitProcess.commit( new TransactionToApply( representation, versionContext ), CommitEvent.NULL, TransactionApplicationMode.EXTERNAL ); } catch ( TransactionFailureException e ) { throw new RuntimeException( e ); } }
@Override public boolean visitRelationshipCommand( Command.RelationshipCommand command ) { lockGroup.add( lockService.acquireRelationshipLock( command.getKey(), LockService.LockType.WRITE_LOCK ) ); updateStore( neoStores.getRelationshipStore(), command ); return false; }
private int applyToStore( Collection<StorageCommand> commands, long logIndex ) throws NoSuchEntryException { int tokenId = extractTokenId( commands ); PhysicalTransactionRepresentation representation = new PhysicalTransactionRepresentation( commands ); representation.setHeader( encodeLogIndexAsTxHeader( logIndex ), 0, 0, 0, 0L, 0L, 0 ); try ( LockGroup ignored = new LockGroup() ) { commitProcess.commit( new TransactionToApply( representation ), CommitEvent.NULL, TransactionApplicationMode.EXTERNAL ); } catch ( TransactionFailureException e ) { throw new RuntimeException( e ); } return tokenId; }
@Override public boolean visitPropertyCommand( Command.PropertyCommand command ) { // acquire lock if ( command.getNodeId() != -1 ) { lockGroup.add( lockService.acquireNodeLock( command.getNodeId(), LockService.LockType.WRITE_LOCK ) ); } else if ( command.getRelId() != -1 ) { lockGroup.add( lockService.acquireRelationshipLock( command.getRelId(), LockService.LockType.WRITE_LOCK ) ); } updateStore( neoStores.getPropertyStore(), command ); return false; }
@Override public void apply( CommandsToApply batch, TransactionApplicationMode mode ) throws Exception { // Have these command appliers as separate try-with-resource to have better control over // point between closing this and the locks above try ( IndexActivator indexActivator = new IndexActivator( indexingService ); LockGroup locks = new LockGroup(); BatchTransactionApplier batchApplier = applier( mode, indexActivator ) ) { while ( batch != null ) { try ( TransactionApplier txApplier = batchApplier.startTx( batch, locks ) ) { batch.accept( txApplier ); } batch = batch.next(); } } catch ( Throwable cause ) { TransactionApplyKernelException kernelException = new TransactionApplyKernelException( cause, "Failed to apply transaction: %s", batch ); databaseHealth.panic( kernelException ); throw kernelException; } }
@SuppressWarnings("deprecation") protected void applyTransaction( Transaction transaction ) throws TransactionFailureException { // TODO you know... we could have just appended the transaction representation to the log // and the next startup of the store would do recovery where the transaction would have been // applied and all would have been well. GraphDatabaseBuilder builder = new TestGraphDatabaseFactory().newEmbeddedDatabaseBuilder( directory ); GraphDatabaseAPI database = (GraphDatabaseAPI) builder.newGraphDatabase(); try ( LockGroup locks = new LockGroup() ) { DependencyResolver dependencyResolver = database.getDependencyResolver(); TransactionRepresentationCommitProcess commitProcess = new TransactionRepresentationCommitProcess( dependencyResolver.resolveDependency( TransactionAppender.class ), dependencyResolver.resolveDependency( TransactionRepresentationStoreApplier.class ), dependencyResolver.resolveDependency( IndexUpdatesValidator.class ) ); TransactionIdStore transactionIdStore = database.getDependencyResolver().resolveDependency( TransactionIdStore.class ); NodeStore nodes = database.getDependencyResolver().resolveDependency( NeoStores.class ).getNodeStore(); commitProcess.commit( transaction.representation( idGenerator(), masterId(), myId(), transactionIdStore.getLastCommittedTransactionId(), nodes ), locks, CommitEvent.NULL, TransactionApplicationMode.EXTERNAL ); } finally { database.shutdown(); } }