@Test public void shouldReturnCorrectStatusCodeOnDeadlock() throws Exception { // Given try ( Transaction tx = graphdb().beginTx() ) { graphdb().createNode( Label.label( "First" ) ); graphdb().createNode( Label.label( "Second" ) ); tx.success(); } // When I lock node:First HTTP.Response begin = http.POST( "db/data/transaction", quotedJson( "{ 'statements': [ { 'statement': 'MATCH (n:First) SET n.prop=1' } ] }" )); // and I lock node:Second, and wait for a lock on node:First in another transaction otherThread.execute( writeToFirstAndSecond() ); // and I wait for those locks to be pending assertTrue( secondNodeLocked.await( 10, TimeUnit.SECONDS ) ); Thread.sleep( 1000 ); // and I then try and lock node:Second in the first transaction HTTP.Response deadlock = http.POST( begin.location(), quotedJson( "{ 'statements': [ { 'statement': 'MATCH (n:Second) SET n.prop=1' } ] }" )); // Then assertThat( deadlock.get( "errors" ).get( 0 ).get( "code" ).getTextValue(), equalTo( DeadlockDetected.code().serialize() ) ); }
/** * Writes logs about database errors. * Short one-line message is written to both user and internal log. * Large message with stacktrace (if available) is written to internal log. * * @param error the error to log. * @see StoreLogService * @see DuplicatingLogProvider */ public void report( Neo4jError error ) { if ( error.status().code().classification() == DatabaseError ) { String message = format( "Client triggered an unexpected error [%s]: %s, reference %s.", error.status().code().serialize(), error.message(), error.reference() ); // Writing to user log gets duplicated to the internal log userLog.error( message ); // If cause/stacktrace is available write it to the internal log if ( error.cause() != null ) { debugLog.error( message, error.cause() ); } } } }
@Override public void handleSchedulingError( Throwable t ) { // if the connection is closing, don't output any logs if ( !willClose() ) { String message; Neo4jError error; if ( ExceptionUtils.hasCause( t, RejectedExecutionException.class ) ) { error = Neo4jError.from( Status.Request.NoThreadsAvailable, Status.Request.NoThreadsAvailable.code().description() ); message = String.format( "Unable to schedule bolt session '%s' for execution since there are no available threads to " + "serve it at the moment. You can retry at a later time or consider increasing max thread pool size for bolt connector(s).", id() ); } else { error = Neo4jError.fatalFrom( t ); message = String.format( "Unexpected error during scheduling of bolt session '%s'.", id() ); } log.error( message, t ); userLog.error( message ); machine.markFailed( error ); } // this will ensure that the scheduled job will be executed on this thread (fork-join pool) // and it will either send a failure response to the client or close the connection and its // related resources (if closing) processNextBatch( 1, true ); }
if( err.status().code().classification().rollbackTransaction() || ctx.implicitTransaction )
if ( statusCode.classification() == Classification.TransientError ) closeFailureMessage() + ": " + statusCode.description(), e );
@Override public void handleSchedulingError( Throwable t ) { // if the connection is closing, don't output any logs if ( !willClose() ) { String message; Neo4jError error; if ( ExceptionUtils.hasCause( t, RejectedExecutionException.class ) ) { error = Neo4jError.from( Status.Request.NoThreadsAvailable, Status.Request.NoThreadsAvailable.code().description() ); message = String.format( "Unable to schedule bolt session '%s' for execution since there are no available threads to " + "serve it at the moment. You can retry at a later time or consider increasing max thread pool size for bolt connector(s).", id() ); } else { error = Neo4jError.fatalFrom( t ); message = String.format( "Unexpected error during scheduling of bolt session '%s'.", id() ); } log.error( message, t ); userLog.error( message ); machine.markFailed( error ); } // this will ensure that the scheduled job will be executed on this thread (fork-join pool) // and it will either send a failure response to the client or close the connection and its // related resources (if closing) processNextBatch( 1, true ); }
/** * Writes logs about database errors. * Short one-line message is written to both user and internal log. * Large message with stacktrace (if available) is written to internal log. * * @param error the error to log. * @see StoreLogService * @see DuplicatingLogProvider */ public void report( Neo4jError error ) { if ( error.status().code().classification() == DatabaseError ) { String message = format( "Client triggered an unexpected error [%s]: %s, reference %s.", error.status().code().serialize(), error.message(), error.reference() ); // Writing to user log gets duplicated to the internal log userLog.error( message ); // If cause/stacktrace is available write it to the internal log if ( error.cause() != null ) { debugLog.error( message, error.cause() ); } } } }
@Override public void validateTransaction() throws KernelException { KernelTransaction tx = ctx.currentTransaction; if ( tx != null ) { Optional<Status> statusOpt = tx.getReasonIfTerminated(); if ( statusOpt.isPresent() ) { if ( statusOpt.get().code().classification().rollbackTransaction() ) { ctx.pendingTerminationNotice = statusOpt.get(); reset(); } } } }
public static boolean shouldRollBackOn( Collection<Neo4jError> errors ) { if ( errors.isEmpty() ) { return false; } for ( Neo4jError error : errors ) { if ( error.status().code().classification().rollbackTransaction() ) { return true; } } return false; } }
/** Forward an error to the currently attached callback */ private void error( Neo4jError err ) { if( err.status().code().classification() == Status.Classification.DatabaseError ) { log.error( "A database error occurred while servicing a user request: " + err ); } if ( currentCallback != null ) { currentCallback.failure( err, currentAttachment ); } }
General( Classification classification, String description ) { this.code = new Code( classification, this, description ); } }
Schema( Classification classification, String description ) { this.code = new Code( classification, this, description ); } }
public boolean shouldSerializeStackTrace() { switch ( status.code().classification() ) { case ClientError: return false; default: return true; } }
public AuthenticationException( Status status ) { this( status, status.code().description(), null ); }
private Neo4jError( Status status, Throwable cause, boolean fatal ) { this( status, status.code().description(), cause, fatal ); }
Statement( Classification classification, String description ) { this.code = new Code( classification, this, description ); } }
Request( Classification classification, String description ) { this.code = new Code( classification, this, description ); } }
private static ThrowingConsumer<HttpServletResponse, IOException> invalidAuthToken( final String message ) { return error( 401, map( "errors", singletonList( map( "code", Status.Security.Unauthorized.code().serialize(), "message", message ) ) ) ); }
/** Forward an error to the currently attached callback */ private void error( Neo4jError err ) { if( err.status().code().classification() == Status.Classification.DatabaseError ) { log.error( "A database error occurred while servicing a user request: " + err ); } if ( currentCallback != null ) { currentCallback.failure( err, currentAttachment ); } }
Cluster( Classification classification, String description ) { this.code = new Code( classification, this, description ); } }