Iterating region.values() Using JTA Throws java.lang.IllegalStateException: The Region Collection is not Transactional but is being Used in a Transaction
search cancel

Iterating region.values() Using JTA Throws java.lang.IllegalStateException: The Region Collection is not Transactional but is being Used in a Transaction

book

Article ID: 294200

calendar_today

Updated On:

Products

VMware Tanzu Gemfire

Issue/Introduction

Symptoms:

When starting a JTA transaction with GemFire as the transaction coordinator, and then using the collection of all region values via Region.values(), you will get a "java.lang.IllegalStateException" if you attempt to iterate through that collection. The complete message will be the following:

"java.lang.IllegalStateException: The Region collection is not transactional but is being used in a transaction."

Environment


Cause

The issue is caused by an issue in the JTA implementation in GemFire.

RCA

The reason of this error seems to be the absence of discoverJTA() in the Region.values() method. So, when Region.values() is invoked the first time, the EntriesSet is created with myTX = null since the transactions aren't associated. If you are iterating prior to invoking other operations, such as a get(), everything works because there is no transaction on a region yet (EntriesSet.myTx = null && topRegion.isTX() = false).  As soon as you invoke get(), however, (or any other method where discoverJTA is invoked) then all regions become transactional and the next execution of EntriesSet.iterator() fails due to the following contradiction: (EntriesSet.myTx = null && topRegion.isTX() = true).

Everything works if Region.values() is invoked alone in a transaction as shown in the code example below. It fails if you invoke, for instance, a get() on another or the same region before starting iteration over the collection returned by values().

Region<String, String> myRegion = cache.getRegion("TestRegion");
try
{ 
 Context ctx = cache.getJNDIContext(); 
 UserTransaction tx = (UserTransaction) ctx.lookup("java:/UserTransaction"); 
 tx.begin(); 
 Collection values = myRegion.values(); 
 values.iterator().next(); 
 tx.commit(); }
catch (Exception e)
{ // handle the exception }

Resolution

To work around this issue, you need to make sure there are no region.get() or .put() between the region.values() and the iteration of the values. If a Region.get() or .put() is needed, you should execute those methods prior to calling Region.values().