All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bitronix.tm.recovery.IncrementalRecoverer Maven / Gradle / Ivy

There is a newer version: 62
Show newest version
/*
 * Copyright (C) 2006-2013 Bitronix Software (http://www.bitronix.be)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package bitronix.tm.recovery;

import bitronix.tm.BitronixXid;
import bitronix.tm.TransactionManagerServices;
import bitronix.tm.internal.LogDebugCheck;
import bitronix.tm.internal.XAResourceHolderState;
import bitronix.tm.journal.JournalRecord;
import bitronix.tm.resource.common.XAResourceProducer;
import bitronix.tm.utils.Decoder;
import bitronix.tm.utils.Uid;

import jakarta.transaction.Status;
import javax.transaction.xa.XAException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Incremental resource recoverer.
 *
 * @author Ludovic Orban
 */
public class IncrementalRecoverer
{

	private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(IncrementalRecoverer.class.toString());
	private static final String FAILED_RESOURCE_STRING = "failed recovering resource ";

	private IncrementalRecoverer()
	{
		//No config required
	}

	/**
	 * Run incremental recovery on the specified resource.
	 *
	 * @param xaResourceProducer
	 * 		the resource to recover.
	 *
	 * @throws RecoveryException
	 * 		when an error preventing recovery happens.
	 */
	public static void recover(XAResourceProducer xaResourceProducer) throws RecoveryException
	{
		String uniqueName = xaResourceProducer.getUniqueName();
		if (LogDebugCheck.isDebugEnabled())
		{
			log.finer("start of incremental recovery on resource " + uniqueName);
		}

		try
		{
			XAResourceHolderState xaResourceHolderState = xaResourceProducer.startRecovery();
			boolean success = true;
			Set xids = RecoveryHelper.recover(xaResourceHolderState);
			if (LogDebugCheck.isDebugEnabled())
			{
				log.finer(xids.size() + " dangling transaction(s) found on resource");
			}
			Map danglingRecords = TransactionManagerServices.getJournal()
			                                                      .collectDanglingRecords();
			if (LogDebugCheck.isDebugEnabled())
			{
				log.finer(danglingRecords.size() + " dangling transaction(s) found in journal");
			}

			int commitCount = 0;
			int rollbackCount = 0;
			for (BitronixXid xid : xids)
			{
				Uid gtrid = xid.getGlobalTransactionIdUid();

				JournalRecord tlog = (JournalRecord) danglingRecords.get(gtrid);
				if (tlog != null)
				{
					if (LogDebugCheck.isDebugEnabled())
					{
						log.finer("committing " + xid);
					}
					success &= RecoveryHelper.commit(xaResourceHolderState, xid);
					updateJournal(xid.getGlobalTransactionIdUid(), uniqueName, Status.STATUS_COMMITTED);
					commitCount++;
				}
				else
				{
					if (LogDebugCheck.isDebugEnabled())
					{
						log.finer("rolling back " + xid);
					}
					success &= RecoveryHelper.rollback(xaResourceHolderState, xid);
					updateJournal(xid.getGlobalTransactionIdUid(), uniqueName, Status.STATUS_ROLLEDBACK);
					rollbackCount++;
				}
			}

			// if recovery isn't successful we don't mark the resource as failed: heuristics might have happened
			// but communication with the resouce is working.
			if (!success)
			{
				throw new RecoveryException("error recovering resource '" + uniqueName + "' due to an incompatible heuristic decision");
			}

			xaResourceProducer.setFailed(false);

			log.info("incremental recovery committed " + commitCount + " dangling transaction(s) and rolled back " + rollbackCount +
			         " aborted transaction(s) on resource [" + uniqueName + "]" +
			         ((TransactionManagerServices.getConfiguration()
			                                     .isCurrentNodeOnlyRecovery()) ? " (restricted to serverId '" + TransactionManagerServices.getConfiguration()
			                                                                                                                              .getServerId() + "')" : ""));

		}
		catch (XAException | IOException | RuntimeException ex)
		{
			xaResourceProducer.setFailed(true);
			throw new RecoveryException(FAILED_RESOURCE_STRING + uniqueName, ex);
		}
		catch (RecoveryException ex)
		{
			xaResourceProducer.setFailed(true);
			throw ex;
		}
		finally
		{
			xaResourceProducer.endRecovery();
			if (LogDebugCheck.isDebugEnabled())
			{
				log.finer("end of incremental recovery on resource " + uniqueName);
			}
		}
	}

	/**
	 * Method updateJournal ...
	 *
	 * @param gtrid
	 * 		of type Uid
	 * @param uniqueName
	 * 		of type String
	 * @param status
	 * 		of type int
	 *
	 * @throws IOException
	 * 		when
	 */
	private static void updateJournal(Uid gtrid, String uniqueName, int status) throws IOException
	{
		if (LogDebugCheck.isDebugEnabled())
		{
			log.finer("updating journal, adding " + Decoder.decodeStatus(status) + " entry for [" + uniqueName + "] on GTRID [" + gtrid + "]");
		}
		Set participatingUniqueNames = new HashSet<>();
		participatingUniqueNames.add(uniqueName);
		TransactionManagerServices.getJournal()
		                          .log(status, gtrid, participatingUniqueNames);
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy