Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare transaction during rollback #201

Open
alexo134 opened this issue Dec 18, 2023 · 0 comments
Open

Prepare transaction during rollback #201

alexo134 opened this issue Dec 18, 2023 · 0 comments

Comments

@alexo134
Copy link

Our application, based on Spring Boot 3.1.6 with latest Transaction Essentials 6.0.0, is connected to PostgreSQL 13.x.
Provided to us, Postgres instance has disabled prepared transactions (max_prepared_transactions set t 0).
Everything runs ok until a transaction rollback caused by transaction timeout, for example.
Atomikos then tries to execute "prepare transaction" statement on the connection even though we have only single resource (database connection) in the JTA transaction.
It's causing an exception in the driver as the prepared transactions are disabled:

2023-12-01 12:01:46.314 ERROR [6569bcc933d1962e4739abd7b1abb390] 1 --- [nerThread-52867] c.a.datasource.xa.XAResourceTransaction  : XA resource 'dataSource': prepare for XID 'XID: 3139322E3136382E3133302E3130312E746D313730313432383434323635303130303235:3139322E3136382E3133302E3130312E746D313035363735' raised -7: the XA resource has become unavailable org.postgresql.xa.PGXAException: Error preparing transaction. prepare xid=XID: 3139322E3136382E3133302E3130312E746D313730313432383434323635303130303235:3139322E3136382E3133302E3130312E746D313035363735
    at org.postgresql.xa.PGXAConnection.prepare(PGXAConnection.java:365) ~[postgresql-42.6.0.jar:42.6.0]
    at com.atomikos.datasource.xa.XAResourceTransaction.prepare(XAResourceTransaction.java:304) ~[transactions-jta-6.0.0-jakarta.jar:na]
    at com.atomikos.icatch.imp.PrepareMessage.send(PrepareMessage.java:40) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.PrepareMessage.send(PrepareMessage.java:19) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.PropagationMessage.submit(PropagationMessage.java:67) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.Propagator$PropagatorThread.run(Propagator.java:63) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.Propagator.submitPropagationMessage(Propagator.java:42) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.ActiveStateHandler.prepare(ActiveStateHandler.java:172) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:522) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:681) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:279) ~[transactions-6.0.0.jar:na]
    at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:178) ~[transactions-jta-6.0.0-jakarta.jar:na]
    at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:428) ~[transactions-jta-6.0.0-jakarta.jar:na]
    at com.atomikos.icatch.jta.UserTransactionManager.commit(UserTransactionManager.java:160) ~[transactions-jta-6.0.0-jakarta.jar:na]
    at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1026) ~[spring-tx-6.0.11.jar:6.0.11]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) ~[spring-tx-6.0.11.jar:6.0.11]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) ~[spring-tx-6.0.11.jar:6.0.11]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:660) ~[spring-tx-6.0.11.jar:6.0.11
 ...
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
  Hint: Set max_prepared_transactions to a nonzero value.
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2713) ~[postgresql-42.6.0.jar:42.6.0]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2401) ~[postgresql-42.6.0.jar:42.6.0]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:368) ~[postgresql-42.6.0.jar:42.6.0]

After investigation, we have found the problematic code in the CoordinatorImp class:

    protected void terminate ( boolean commit ) throws HeurRollbackException,
            HeurMixedException, SysException, java.lang.SecurityException,
            HeurCommitException, HeurHazardException, RollbackException,
            IllegalStateException

    {    
    	synchronized ( fsm_ ) {
    		if ( commit ) {
    			if ( participants_.size () <= 1 ) {
    				commit ( true );
    			} else {
    				int prepareResult = prepare ();
    				// make sure to only do commit if NOT read only
    				if ( prepareResult != Participant.READ_ONLY )
    					commit ( false );
    			}
    		} else {
    			rollback ();
    		}
    	}
    }

Participants count should be maximum one as we have only one database.
After debugging, we have found that an additional "fake" participant RollbackOnlyParticipant was added to the list to make rollback happen.
Therefore, the coordinator is treating this transaction as it had multiple resources.

In my opinion, rollback participant should not be considered as a normal resource.

Additionally, I've created a setup with Non-XA data source (and local-transaction-mode set to true) to avoid calling prepare statement. But still a simple rollback is causing strange warning and exception:

From AtomikosNonXAParticipant.prepare():

c.a.j.internal.AtomikosNonXAParticipant  : com.atomikos.jdbc.AtomikosNonXADataSourceBean 'nonXaDataSource' [NB: this resource does not support two-phase commit unless configured as readOnly]

and error:

com.atomikos.icatch.RollbackException: Prepare failed because one or more resources refused to commit. This transaction has been rolled back instead. The cause could be either:
1. a transaction timeout (in which case you should see additional timeout warnings in this log file), or
2. inability to reach the resource (in which case you should see network errors), or
3. a resource-internal cause that we can’t inspect
	at com.atomikos.icatch.imp.ActiveStateHandler.prepare(ActiveStateHandler.java:207) ~[transactions-6.0.0.jar:na]
	at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:522) ~[transactions-6.0.0.jar:na]
	at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:681) ~[transactions-6.0.0.jar:na]

Expecting here just a simple rollback of a timed out transaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant