use of com.arjuna.ats.internal.arjuna.coordinator.ReaperWorkerThread in project narayana by jbosstm.
the class TransactionReaper method doCancellations.
public final void doCancellations() {
for (; ; ) {
ReaperElement e;
synchronized (_workQueue) {
try {
e = _workQueue.remove(0);
} catch (IndexOutOfBoundsException ioobe) {
break;
}
}
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("Reaper Worker " + Thread.currentThread() + " attempting to cancel " + e._control.get_uid());
}
boolean cancelled = false;
Exception exception = null;
synchronized (e) {
e._worker = Thread.currentThread();
e._status = ReaperElement.CANCEL;
e.notifyAll();
}
try {
if (e._control.running()) {
if (e._control.cancel() == ActionStatus.ABORTED) {
cancelled = true;
if (TxStats.enabled()) {
// note that we also count timeouts as application rollbacks via
// the stats unpdate in the TwoPhaseCoordinator cancel() method.
TxStats.getInstance().incrementTimeouts();
}
notifyListeners(e._control, true);
}
}
} catch (Exception e1) {
exception = e1;
}
synchronized (e) {
if (e._status == ReaperElement.ZOMBIE) {
// we need to decrement the zombie count and
// force an immediate thread exit. the reaper
// will have removed the entry from the
// transactions list and started another
// worker thread.
ReaperWorkerThread worker = (ReaperWorkerThread) Thread.currentThread();
worker.shutdown();
synchronized (this) {
_zombieCount--;
}
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_13(Thread.currentThread().toString(), e._control.get_uid(), Integer.toString(_zombieCount));
break;
} else if (cancelled && e._status == ReaperElement.CANCEL_INTERRUPTED) {
// ok the call to cancel() returned true but
// we cannot trust it because the reaper sent
// the thread an interrupt
cancelled = false;
e._status = ReaperElement.FAIL;
e.notifyAll();
} else {
e._status = (cancelled ? ReaperElement.COMPLETE : ReaperElement.FAIL);
e.notifyAll();
}
}
if (cancelled) {
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_7(Thread.currentThread().toString(), e._control.get_uid());
} else if (e._control.running()) {
if (exception != null) {
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_9(Thread.currentThread().toString(), e._control.get_uid(), exception);
} else {
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_8(Thread.currentThread().toString(), e._control.get_uid());
}
try {
if (e._control.preventCommit()) {
// log a successful preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_14(Thread.currentThread().toString(), e._control.get_uid());
notifyListeners(e._control, false);
} else {
// log a failed preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_15(Thread.currentThread().toString(), e._control.get_uid());
}
} catch (Exception e1) {
// log an exception under preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_16(Thread.currentThread().toString(), e._control.get_uid(), e1);
}
}
removeElementReaper(e);
}
}
use of com.arjuna.ats.internal.arjuna.coordinator.ReaperWorkerThread in project narayana by jbosstm.
the class TransactionReaper method check.
/**
* process all entries in the timeout queue which have
* expired. entries for newly expired transactions are passed
* to a worker thread for cancellation and requeued for
* subsequent progress checks. the worker is given a kick if
* such checks find it is wedged.
*
* Timeout is given in milliseconds.
*/
public final void check() {
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("TransactionReaper::check ()");
}
do {
final ReaperElement reaperElement;
synchronized (this) {
final long now = System.currentTimeMillis();
final long next = nextDynamicCheckTime.get();
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("TransactionReaper::check - comparing " + Long.toString(next));
}
if (now < next) {
break;
}
reaperElement = _reaperElements.getFirst();
// then use compareAndSet? Although something will need to check before sleeping anyhow...
if (reaperElement == null) {
nextDynamicCheckTime.set(Long.MAX_VALUE);
return;
} else {
final long nextTimeout = reaperElement.getAbsoluteTimeout();
if (nextTimeout > now) {
nextDynamicCheckTime.set(nextTimeout);
// nothing to do yet.
return;
}
}
}
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_18(reaperElement._control.get_uid(), reaperElement.statusName());
synchronized (reaperElement) {
switch(reaperElement._status) {
case ReaperElement.RUN:
{
// this tx has just timed out. remove it from the
// TX list, update the timeout to take account of
// cancellation period and reinsert as a cancelled
// TX. this ensures we process it again if it does
// not get cancelled in time
reaperElement._status = ReaperElement.SCHEDULE_CANCEL;
reinsertElement(reaperElement, _cancelWaitPeriod);
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("Reaper scheduling TX for cancellation " + reaperElement._control.get_uid());
}
synchronized (_workQueue) {
_workQueue.add(reaperElement);
_workQueue.notifyAll();
}
}
break;
case ReaperElement.SCHEDULE_CANCEL:
{
// hmm, a worker is taking its time to
// start processing this scheduled entry.
// we may just be running slow ... but the
// worker may be wedged under a cancel for
// some other TX. add an extra delay to
// give the worker more time to complete
// its current task and progress this
// entry to the CANCEL state. if the
// worker *is* wedged then this will
// ensure the wedged TX entry comes to the
// front of the queue.
reinsertElement(reaperElement, _cancelWaitPeriod);
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("Reaper deferring interrupt for TX scheduled for cancel " + reaperElement._control.get_uid());
}
}
break;
case ReaperElement.CANCEL:
{
// ok, the worker must be wedged under a
// call to cancel() -- kick the thread and
// reschedule the element for a later
// check to ensure the thread responded to
// the kick
StringBuilder sb = new StringBuilder();
for (StackTraceElement element : reaperElement._worker.getStackTrace()) {
sb.append(element.toString());
sb.append("\n");
}
tsLogger.i18NLogger.wedged_reaperelement(sb.toString());
reaperElement._status = ReaperElement.CANCEL_INTERRUPTED;
reaperElement._worker.interrupt();
reinsertElement(reaperElement, _cancelFailWaitPeriod);
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("TransactionReaper::check interrupting cancel in progress for " + reaperElement._control.get_uid());
}
}
break;
case ReaperElement.CANCEL_INTERRUPTED:
{
// cancellation got truly wedged -- mark
// the element as a zombie so the worker
// exits when (if?) it wakes up and create
// a new worker thread to handle further
// cancellations. then mark the
// transaction as rollback only.
reaperElement._status = ReaperElement.ZOMBIE;
synchronized (this) {
_zombieCount++;
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("Reaper " + Thread.currentThread() + " got a zombie " + reaperElement._worker + " (zombie count now " + _zombieCount + ") cancelling " + reaperElement._control.get_uid());
}
if (_zombieCount == _zombieMax) {
// log zombie overflow error call()
tsLogger.i18NLogger.error_coordinator_TransactionReaper_5(Integer.toString(_zombieCount));
}
}
_reaperWorkerThread = new ReaperWorkerThread(TransactionReaper._theReaper);
_reaperWorkerThread.setDaemon(true);
_reaperWorkerThread.start();
// log a failed cancel()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_6(reaperElement._worker.toString(), reaperElement._control.get_uid());
// ok, since the worker was wedged we need to
// remove the entry from the timeouts and
// transactions lists then mark this tx as
// rollback only. we have to log a message
// whether we succeed, fail or get interrupted
removeElementReaper(reaperElement);
try {
if (reaperElement._control.preventCommit()) {
// log a successful preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_10(reaperElement._control.get_uid());
notifyListeners(reaperElement._control, false);
} else {
// log a failed preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_11(reaperElement._control.get_uid());
}
} catch (Exception e1) {
// log an exception under preventCommit()
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_12(reaperElement._control.get_uid(), e1);
}
}
break;
case ReaperElement.FAIL:
case ReaperElement.COMPLETE:
{
// ok, the worker should remove the tx
// from the transactions queue very soon
// but we need to progress to the next
// entry so we will steal in and do it
// first
removeElementReaper(reaperElement);
}
break;
}
}
} while (true);
}
use of com.arjuna.ats.internal.arjuna.coordinator.ReaperWorkerThread in project narayana by jbosstm.
the class TransactionReaper method instantiate.
/**
* Currently we let the reaper thread run at same priority as other threads.
* Could get priority from environment.
*/
public static synchronized void instantiate() {
if (TransactionReaper._theReaper == null) {
if (tsLogger.logger.isTraceEnabled()) {
tsLogger.logger.trace("TransactionReaper::instantiate()");
}
// default to dynamic mode
TransactionReaper._dynamic = true;
String mode = arjPropertyManager.getCoordinatorEnvironmentBean().getTxReaperMode();
if (mode.compareTo(TransactionReaper.PERIODIC) == 0) {
TransactionReaper._dynamic = false;
}
if (mode.compareTo(TransactionReaper.NORMAL) == 0) {
TransactionReaper._dynamic = false;
tsLogger.i18NLogger.warn_coordinator_TransactionReaper_19();
}
long checkPeriod = Long.MAX_VALUE;
if (!TransactionReaper._dynamic) {
checkPeriod = arjPropertyManager.getCoordinatorEnvironmentBean().getTxReaperTimeout();
}
TransactionReaper._theReaper = new TransactionReaper(checkPeriod);
TransactionReaper._theReaper._cancelWaitPeriod = arjPropertyManager.getCoordinatorEnvironmentBean().getTxReaperCancelWaitPeriod();
if (TransactionReaper._theReaper._cancelWaitPeriod < 10) {
TransactionReaper._theReaper._cancelWaitPeriod = 10;
}
TransactionReaper._theReaper._cancelFailWaitPeriod = arjPropertyManager.getCoordinatorEnvironmentBean().getTxReaperCancelFailWaitPeriod();
if (TransactionReaper._theReaper._cancelFailWaitPeriod < 10) {
TransactionReaper._theReaper._cancelFailWaitPeriod = 10;
}
TransactionReaper._theReaper._zombieMax = arjPropertyManager.getCoordinatorEnvironmentBean().getTxReaperZombieMax();
if (TransactionReaper._theReaper._zombieMax <= 0) {
TransactionReaper._theReaper._zombieMax = 1;
}
_reaperThread = new ReaperThread(TransactionReaper._theReaper);
// _reaperThread.setPriority(Thread.MIN_PRIORITY);
_reaperThread.setDaemon(true);
_reaperWorkerThread = new ReaperWorkerThread(TransactionReaper._theReaper);
_reaperWorkerThread.setDaemon(true);
_reaperThread.start();
_reaperWorkerThread.start();
}
}
Aggregations