Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.3.2
-
Fix Version/s: 1.3.3
-
Labels:None
-
Number of attachments :
Description
Looking at this code in run()
Iterator it = ResourceRegistrar.getResourcesUniqueNames().iterator();
while (it.hasNext()) {
String name = (String) it.next();
registeredResources.put(name, ResourceRegistrar.get(name));
}
Since ResourceRegistrar.getResourcesUniqueNames() returns not a view but a new HashSet, by the time ResourceRegistrar.get(name) is called that key/value pair may be gone and that get will return null.
Activity
Ludovic Orban
made changes -
| Field | Original Value | New Value |
|---|---|---|
| Fix Version/s | 1.3.3 [ 14658 ] |
Ludovic Orban
made changes -
| Status | Open [ 1 ] | Resolved [ 5 ] |
| Resolution | Fixed [ 1 ] |
Ludovic Orban
made changes -
| Status | Resolved [ 5 ] | Closed [ 6 ] |
Here's how I fixed the above locally:
in Recoverer:
public void run() { try { committedCount = 0; rolledbackCount = 0; // Query resources from ResourceRegistrar and copy to registeredResources //fix for BTM-45 registeredResources.putAll(ResourceRegistrar.getCopyOfResources()); // get list of in-flight transactions that should not be recovered and the list // of dangling journal records should be collected atomically to avoid race conditions Map danglingRecords; Set inFlightGtrids = new HashSet(); if (TransactionManagerServices.isTransactionManagerRunning()) { Map inFlightTransactions = TransactionManagerServices.getTransactionManager().getInFlightTransactions(); synchronized (inFlightTransactions) { inFlightGtrids = inFlightTransactions.keySet(); danglingRecords = TransactionManagerServices.getJournal().collectDanglingRecords(); } } else { danglingRecords = TransactionManagerServices.getJournal().collectDanglingRecords(); } // 1. call recover on all known resources Set unrecoverableResourceNames = recoverAllResources(inFlightGtrids); // 1.1. unregister unrecoverable resources Iterator itUnrecoverable = unrecoverableResourceNames.iterator(); while (itUnrecoverable.hasNext()) { String uniqueName = (String) itUnrecoverable.next(); if (log.isDebugEnabled()) log.debug("closing unrecoverable resource " + uniqueName); XAResourceProducer producer = (XAResourceProducer) registeredResources.remove(uniqueName); producer.close(); } // 1.2. register a task to retry registration, if needed if (isRetryUnrecoverableResourcesRegistrationEnabled()) { int intervalInMinutes = TransactionManagerServices.getConfiguration().getRetryUnrecoverableResourcesRegistrationInterval(); TransactionManagerServices.getTaskScheduler().scheduleRetryUnrecoverableResourcesRegistration(new Date(System.currentTimeMillis() + intervalInMinutes * 60 * 1000)); } else if (log.isDebugEnabled()) log.debug("will not retry unrecoverable resources registration"); // 2. commit dangling COMMITTING transactions Set committedGtrids = commitDanglingTransactions(inFlightGtrids, danglingRecords); committedCount = committedGtrids.size(); // 3. rollback any remaining recovered transaction rolledbackCount = rollbackAbortedTransactions(committedGtrids); log.info("recovery committed " + committedCount + " dangling transaction(s) and rolled back " + rolledbackCount + " aborted transaction(s) on " + registeredResources.size() + " resource(s) [" + getRegisteredResourcesUniqueNames() + "]" + (isRetryUnrecoverableResourcesRegistrationEnabled() ? ", discarded " + unrecoverableResourceNames.size() + " unrecoverable resource(s) [" + buildUniqueNamesString(unrecoverableResourceNames) + "]": "")); this.completionException = null; } catch (Exception ex) { this.completionException = ex; if (log.isDebugEnabled()) log.debug("recovery failed, registered resource(s): " + getRegisteredResourcesUniqueNames(), ex); } finally { recoveredXidSets.clear(); registeredResources.clear(); } }in ResourceRegistrar:
//private static Map resources = new HashMap(); final private static ConcurrentMap<String, XAResourceProducer> resources = new ConcurrentHashMap<String, XAResourceProducer>(); //to address BTM-45 public synchronized static Map<String, XAResourceProducer> getCopyOfResources() { return new HashMap<String, XAResourceProducer>(resources); }