You are here: Blog » Release notes

Release notes

Feature193912
Add support for Hazelcast 4

You can now use Hazelcast 4 with our JTA/XA transactions, via an additional module "transactions-hazelcast4". This was required due to breaking API changes that were introduced in Hazelcast 4.

Technical details

When using the prior Hazelcast integration (made for Hazelcast 3, not 4) you would get the following exception when trying to configure a JTA/XA enabled HazelcastInstance:

java.lang.UnsupportedOperationException: Client config object only supports adding new data structure configurations
at com.hazelcast.client.impl.clientside.ClientDynamicClusterConfig.getLicenseKey(ClientDynamicClusterConfig.java:897)
at com.hazelcast.config.ConfigXmlGenerator.generate(ConfigXmlGenerator.java:129)
at com.atomikos.hazelcast.HazelcastTransactionalResource.<init>(HazelcastTransactionalResource.java:23)
at com.atomikos.hazelcast.AtomikosHazelcastInstance.<init>(AtomikosHazelcastInstance.java:31)
at com.atomikos.hazelcast.AtomikosHazelcastInstanceFactory.createAtomikosInstance(AtomikosHazelcastInstanceFactory.java:17)
at ...

Changes impacting client API

If you are using the recommended configuration method then nothing changes, although we did simplify the event com.atomikos.hazelcast4.HazelcastDetectedEvent to contain only the uniqueResourceName. The rest of the information (i.e., password and XML configuration information) has been removed from the event.

Bug190537
Allow SessionHandleState reuse after closing a pooled connection with recycleActiveConnectionsInTransaction=true

Severity:4
Affected version(s):5.0.104

Description

When setting recycleActiveConnectionsInTransaction=true, you can now reuse connections more flexibly.

Technical details

Consider the following use case with recycleActiveConnectionsInTransaction enabled:

Method foo():

  1. Open connection c1
  2. Do SQL with c1
  3. Call method bar()
  4. Do more SQLs with connection c1
  5. Close c1

Method bar():

  1. Open connection c2
  2. Do SQL with c2
  3. Close c2

With recycleActiveConnectionsInTransaction=true, c1 will be the same connection instance as c2.

So after method bar() closes c2, c1 will also be closed and this caused errors like these in step 4 of method foo():

The underlying XA session is closed
                at com.atomikos.jdbc.internal.AtomikosSQLException.throwAtomikosSQLException(AtomikosSQLException.java:29)
                at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.enlist(AtomikosJdbcConnectionProxy.java:108)
                at com.atomikos.jdbc.internal.AtomikosJdbcConnectionProxy.updateTransactionContext(AtomikosJdbcConnectionProxy.java:61)
                at com.atomikos.jdbc.internal.AbstractJdbcConnectionProxy.prepareStatement(AbstractJdbcConnectionProxy.java:64)
                at sun.reflect.GeneratedMethodAccessor228.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at com.atomikos.util.DynamicProxySupport.callProxiedMethod(DynamicProxySupport.java:162)
                at com.atomikos.util.DynamicProxySupport.invoke(DynamicProxySupport.java:116)
                at com.sun.proxy.$Proxy801.prepareStatement(Unknown Source)

Changes impacting client API

None.

Feature190375
Allow recycling of active connections within the same transaction

You can now allow recycling of active JDBC/XA pooled connections within the same transaction, before they are "closed" by the application. This means that certain deadlock scenarios can be avoided.

Technical details

Imagine the following use case:

  1. start a JTA transaction
  2. get a JDBC/XA connection (c1) from the pool via getConnection()
  3. do some SQL on c1
  4. get a second JDBC/XA connection (c2) from the pool via getConnection()

Before this feature, step 4 would return a different physical connection from the pool. This would trigger a new XA branch, with unspecified isolation (locking) behaviour with respect to any updates performed via the connection in step 2. This could even cause deadlocks.

Therefore, people have asked us to allow for step 4 to reuse the same connection, c1. You can now enable this new behaviour by calling setRecycleActiveConnectionsInTransaction(true) on the AtomikosDataSourceBean.

Changes impacting client API

A new, optional setter on our datasource. The default is false for backward compatibility.

ExtremeTransactions 5.0.103
Release notes for 5.0.103

11 Mar 2021 | Guy Pardon | ExtremeTransactions

Bug189921
Avoid that exceptions (when writing a checkpoint) needlessly corrupt the transaction log

Severity:2
Affected version(s):5.0.x, 4.0.x

Description

You now no longer get "Log corrupted - restart JVM" exceptions after you interrupt a thread that is writing to the transaction log file, or after any other exception that make a log checkpoint fail.

Technical details

Any exceptions during a checkpoint (such as when a thread was interrupted during transaction log file I/O) would lead to a generic exception handling block in our com.atomikos.recovery.fs.CachedRepository class, leaving the instance in an invalid state:

2021-03-01 16:15:56.662 ERROR 41669 --- [pool-1-thread-1] c.a.recovery.fs.FileSystemRepository     : Failed to write checkpoint

java.nio.channels.ClosedByInterruptException: null
   at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202) ~[na:1.8.0_192]
   at sun.nio.ch.FileChannelImpl.force(FileChannelImpl.java:392) ~[na:1.8.0_192]
   at com.atomikos.recovery.fs.FileSystemRepository.writeCheckpoint(FileSystemRepository.java:196) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.performCheckpoint(CachedRepository.java:84) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.put(CachedRepository.java:77) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.OltpLogImp.write(OltpLogImp.java:46) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.persistence.imp.StateRecoveryManagerImp.preEnter(StateRecoveryManagerImp.java:51) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.finitestates.FSMImp.notifyListeners(FSMImp.java:164) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.finitestates.FSMImp.setState(FSMImp.java:251) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.setState(CoordinatorImp.java:284) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorStateHandler.commitFromWithinCallback(CoordinatorStateHandler.java:346) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.ActiveStateHandler$6.doCommit(ActiveStateHandler.java:273) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorStateHandler.commitWithAfterCompletionNotification(CoordinatorStateHandler.java:587) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.ActiveStateHandler.commit(ActiveStateHandler.java:268) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.commit(CoordinatorImp.java:550) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:682) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:279) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:168) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:428) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.jta.UserTransactionManager.commit(UserTransactionManager.java:160) [transactions-jta-5.0.9-SNAPSHOT.jar:na]
   at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1035) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:152) [spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
   at com.example.atomikos.AtomikosApplicationTests.lambda$4(AtomikosApplicationTests.java:78) [test-classes/:na]
   at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_192]
   at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_192]

Later requests trying to read from the transaction logs would get systematic corruption errors like this:

com.atomikos.recovery.LogReadException: Log corrupted - restart JVM
   at com.atomikos.recovery.fs.CachedRepository.assertNotCorrupted(CachedRepository.java:137) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.CachedRepository.findAllCommittingCoordinatorLogEntries(CachedRepository.java:145) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.recovery.fs.RecoveryLogImp.getExpiredPendingCommittingTransactionRecordsAt(RecoveryLogImp.java:52) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.RecoveryDomainService.performRecovery(RecoveryDomainService.java:76) ~[transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.icatch.imp.RecoveryDomainService$1.alarm(RecoveryDomainService.java:55) [transactions-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.timing.PooledAlarmTimer.notifyListeners(PooledAlarmTimer.java:101) [atomikos-util-5.0.9-SNAPSHOT.jar:na]
   at com.atomikos.timing.PooledAlarmTimer.run(PooledAlarmTimer.java:88) [atomikos-util-5.0.9-SNAPSHOT.jar:na]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_192]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_192]
   at java.lang.Thread.run(Thread.java:748) [na:1.8.0_192]

This has now been fixed.

Changes impacting client API

None.

Bug190034
Spring Boot JDBC metadata: improve getActive method

Severity:3
Affected version(s):5.0.x

Description

The method getActive() in the DataSourceBeanMetadata classes of module transactions-springboot2 now no longer returns the total number of open connections, but rather the number of connections that are currently being used by the application.

Technical details

Due to a misunderstanding of Spring Boot's semantics, this method returned the wrong result: the total number of open connections in the pool, rather than the number of connections being used. This has now been fixed.

Changes impacting client API

None.

Bug190035
Spring Boot JDBC metadata: support wrapped datasources

Severity:3
Affected version(s):5.0.x

Description

You can now retrieve meaningful DataSourcePoolMetadata in Spring Boot, even if one of our datasources is used in wrapped or proxied mode in your Spring Boot runtime.

Technical details

We used to return metadata in the following style:

if (dataSource instanceof AtomikosDataSourceBean) {
         return new AtomikosDataSourceBeanMetadata((AtomikosDataSourceBean) dataSource);
}

(and similar for our AtomikosNonXADataSourceBean class)

This would not work if the dataSource presented is wrapped or proxied. So we now use the built-in Spring Boot DataSourceUnwrapper.unwrap to handle those cases.

Changes impacting client API

None.

Issue
PostgreSQL: XAResource ignores transaction timeout

Severity:2
Affected version(s):5.0.x, 4.0.x, 3.9.x

Description

The XA implementation of PostgreSQL ignores the transaction timeout, which means that you may have long-lived orphaned SQL sessions in your database server.

Technical details

The XA specification allows a transaction manager to inform the XAResource backend of transaction timeouts, so this information can be used to terminate (rollback) pending or long-lived transactions. However, PostgreSQL seems to ignore this information (see the source code on GitHub - which sometimes leads to pending SQL sessions that exceed the transaction timeout.

Possible workarounds

The following workarounds are available:

Set the queryTimeout on your JDBC Statement objects, or try setting a server-level timeout like this:

SET SESSION idle_in_transaction_session_timeout = '5min’;

If you have any other solution then please let us know - thanks!

ExtremeTransactions 5.0.102
Release notes for 5.0.102

25 Feb 2021 | Guy Pardon | ExtremeTransactions

Feature189601
Allow disabling retry on heuristic hazard participants

You can now choose to disable retrying commit or rollback for heuristic hazard transactions.

Technical details

Heuristic hazard transactions can arise out of network connectivity issues during the commit phase: if a resource gets a prepare request and subsequently becomes unreachable during commit or rollback then the transaction will go into "heuristic hazard" mode. This essentially means that commit will be retried a number of times, even if com.atomikos.icatch.oltp_max_retries is set to zero. The rationale being: it is better to terminate pending in-doubt transactions sooner rather than later because of the pending locks they may be holding on to.

If you don't want this behaviour then you can now disable this, and rely on the recovery process in the background to take care of it (which also works, but will happen only periodically). To disable, just set this new property to false:

com.atomikos.icatch.retry_on_heuristic_hazard=false

Changes impacting client API

A new startup property that can optionally be set. If not present, it will default to true to preserve compatibility with existing behaviour.

Feature189603
API extension to allow triggering recovery by the application

You can now explicitly trigger recovery in your application, via our API.

Technical details

Recovery already happens periodically, in the background. For bigger clusters that connect to the same database (or other shared resource) this can cause a high load on the backend, because of many such background threads hitting the backend at the same time. This is especially true if most cluster nodes start up at the same time with the same configuration for recovery, and are NOT using LogCloud Documentation. To alleviate this, you can now have a bit more control over when recovery happens, like this:

import com.atomikos.icatch.RecoveryService;
import com.atomikos.icatch.config.Configuration;

boolean lax = true; //false to force recovery, true to allow intelligent mode
RecoveryService rs = Configuration.getRecoveryService();
rs.performRecovery(lax);

In order for this to work, make sure to set (in jta.properties):

# set to Long.MAX_VALUE so background recovery is disabled
com.atomikos.icatch.recovery_delay=9223372036854775807L 

Changes impacting client API

We have added methods on an existing API interface, which does not break existing clients.

Bug189602
Don't call XA recovery on the XAResource on HeuristicHazard

Severity:2
Affected version(s):5.0.x

Description

From now on we no longer systematically call XAResource.recover() when failures happen during the regular commit or rollback, so the overhead for the backend is reduced.

Technical details

For historical reasons we used to call the XA recovery routine on the backed whenever commit or rollback failed. The most common cause is network glitches, meaning that big clusters with a short network problem would suddenly hit the backends with recovery for all active transactions. Since recovery can be an expensive operation, this would result in needless load on the backends.

The rationale behind this was to avoid needless commit retries (based on the value of com.atomikos.icatch.oltp_max_retries), but the overhead does not justify the possible benefit.

From now on we no longer do this, since it is either the recovery process (in the background) or the application (via our API) that controls when recovery happens.

Worst case, this can lead to needless commit retries, in which case the backend should respond with error code XAER_NOTA and our code will handle this gracefully. However, we have historical records where some older version of ActiveMQ did not behave like this. This would result in errors in the ActiveMQ log files, in turn leading to alerts for the operations team.

Changes impacting client API

If you experience issues with this, then it suffices to set com.atomikos.icatch.oltp_max_retries to zero. That will disable regular commit retries and delegate to the recovery background process.

Issue189886
Avoid using 0 for the maximum transaction timeout

Severity:2
Affected version(s):5.0.x

Description

For releases 5.0 or higher, the maximum timeout should not be set to 0 or recovery will interfere with regular application-level commits.

Technical details

The 5.0 release has a new recovery workflow that is incompatible with com.atomikos.icatch.max_timeout being zero. That is because recovery depends on the maximum timeout to perform rollback of pending (orphaned) prepared transactions in the backends. If the maximum timeout is zero then recovery (in the background) will rollback prepared transactions that are concurrently being committed in your application. This will result in heuristic exceptions and inconsistent transaction outcomes.

Keep in mind that the maximum timeout is also indicative of maximum lock duration in your databases, so choose it wisely! If you are / were depending on an unlimited maximum timeout then you are also allowing unlimited lock times.

Corporate Information

Atomikos Corporate Headquarters
Hoveniersstraat, 39/1, 2800
Mechelen, Belgium

Contact Us

Copyright 2024 Atomikos BVBA | Our Privacy Policy
By using this site you agree to our cookies. More info. That's Fine