com.sun.jini.outrigger
Class TxnMonitorTask

java.lang.Object
  extended by com.sun.jini.thread.RetryTask
      extended by com.sun.jini.outrigger.TxnMonitorTask
All Implemented Interfaces:
TimeConstants, TaskManager.Task, Runnable, TransactionConstants

 class TxnMonitorTask
extends RetryTask
implements TransactionConstants, TimeConstants

A task that will try to validate the state of a transaction. This uses weak references a good deal to let the other parts of the system be GC'ed as necessary.

The retry mechanism is subtle, so bear with me. The purpose is to ensure that if any activity is being blocked by a given transaction, that transaction will be tested at some point in the future (if necessary, i.e., if it still is thought to be active). We assume it to be rare that a transactions that the space thinks is active is, in fact, aborted, so the algorithm is designed to guarantee the detection without a lot of overhead, specifically without a lot of RMI calls.

Each task has three values: a nextQuery time, a mustQuery boolean that force the next query to be made, and deltaT, the time at which the following query will be scheduled. When the task is awakened at its nextQuery time, it checks to see if it must make an actual query to the transaction manager, which it will do if either mustQuery is true, or if we know about any in progress queries on the space that are blocked on the transaction. Whether or not an actual query is made, deltaT is added to nextQuery to get the nextQuery time, deltaT is doubled, and mustQuery boolean is set to false.

There are two kinds of requests that a with which transaction can cause a conflict -- those with long timeouts (such as blocking reads and takes) and those that are under short timeouts (such as reads and takes with zero-length timeouts). We will treat them separately at several points of the algorithm. A short timeout is any query whose expiration time is sooner than the nextQuery time. Any other timeout is long If a short query arrives, mustQuery is set to true.

The result is that any time a transaction causes a conflict, if the query on the space has not ended by the time of the nextQuery we will attempt to poll the transaction manager. There will also poll the transaction manager if any conflict occurred on a query on the space with a short timeout.

The first time a transaction causes a conflict, we schedule a time in the future at which we will poll its status. We do not poll right away because often a transaction will complete on its own before we get to that time, making the check unnecessary. An instant poll is, therefore, unnecessarily aggressive, since giving an initial grace time will usually mean no poll is made at all. So if the first conflict occurs at T0, the nextQuery value will be T0+INITIAL_GRACE, the boolean will be true to force that poll to happen, and deltaT will be set to INITIAL_GRACE.

Author:
Sun Microsystems, Inc.
See Also:
TxnMonitor

Field Summary
private static long BETWEEN_EXCEPTIONS
          The retry time when we have an encountered an exception
private  long deltaT
          next value added to nextQuery
private  int failCnt
          count of RemoteExceptions
private static long INITIAL_GRACE
          The initial grace period before the first query.
private static Logger logger
          Logger for logging transaction related information
private static long MAX_DELTA_T
          The largest value that deltaT will reach.
private static int MAX_FAILURES
          The maximum number of failures allowed in a row before we simply give up on the transaction and consider it aborted.
private  TxnMonitor monitor
          the monitor we were made by
private  boolean mustQuery
          When we're given an opportunity to poll the transaction manager for the txn's state, do so.
private  long nextQuery
          The next time we need to poll the transaction manager to get txn's actual state.
private  Map queries
          All the queries on the space (not queries to the transaction manager) waiting for txn to be resolved.
private  Txn txn
          transaction being monitored
 
Fields inherited from interface net.jini.core.transaction.server.TransactionConstants
ABORTED, ACTIVE, COMMITTED, NOTCHANGED, PREPARED, VOTING
 
Fields inherited from interface com.sun.jini.constants.TimeConstants
DAYS, HOURS, MINUTES, SECONDS
 
Constructor Summary
TxnMonitorTask(Txn txn, TxnMonitor monitor, TaskManager manager, WakeupManager wakeupMgr)
          Create a new TxnMonitorTask.
 
Method Summary
(package private)  void add(QueryWatcher query)
          Add in a resource.
(package private)  void addSibling(Txn txn)
          Add a ``sibling'' transaction, one that is now blocking progress on one of the same entries.
private  void logUnpackingFailure(String exceptionDescription, Level level, boolean terminal, Throwable t)
          Log failed unpacking attempt attempt
 long retryTime()
          Return the time of the next query, bumping deltaT as necessary for the next iteration.
 boolean runAfter(List tasks, int size)
          We can run in parallel with any task, so just return false.
 boolean tryOnce()
          Try to see if this transaction should be aborted.
 
Methods inherited from class com.sun.jini.thread.RetryTask
attempt, cancel, cancelled, complete, reset, run, startTime, waitFor
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

txn

private final Txn txn
transaction being monitored


monitor

private final TxnMonitor monitor
the monitor we were made by


queries

private Map queries
All the queries on the space (not queries to the transaction manager) waiting for txn to be resolved. null until we have at least one. Represented by QueryWatcher objects.


failCnt

private int failCnt
count of RemoteExceptions


nextQuery

private long nextQuery
The next time we need to poll the transaction manager to get txn's actual state.


mustQuery

private boolean mustQuery
When we're given an opportunity to poll the transaction manager for the txn's state, do so.


deltaT

private long deltaT
next value added to nextQuery


INITIAL_GRACE

private static final long INITIAL_GRACE
The initial grace period before the first query.

See Also:
Constant Field Values

BETWEEN_EXCEPTIONS

private static final long BETWEEN_EXCEPTIONS
The retry time when we have an encountered an exception

See Also:
Constant Field Values

MAX_DELTA_T

private static final long MAX_DELTA_T
The largest value that deltaT will reach.

See Also:
Constant Field Values

MAX_FAILURES

private static final int MAX_FAILURES
The maximum number of failures allowed in a row before we simply give up on the transaction and consider it aborted.

See Also:
Constant Field Values

logger

private static final Logger logger
Logger for logging transaction related information

Constructor Detail

TxnMonitorTask

TxnMonitorTask(Txn txn,
               TxnMonitor monitor,
               TaskManager manager,
               WakeupManager wakeupMgr)
Create a new TxnMonitorTask.

Method Detail

retryTime

public long retryTime()
Return the time of the next query, bumping deltaT as necessary for the next iteration. If the transaction has voted PREPARED or the manager has been giving us a RemoteException, we should retry on short times; otherwise we back off quickly.

Overrides:
retryTime in class RetryTask

runAfter

public boolean runAfter(List tasks,
                        int size)
We can run in parallel with any task, so just return false.

Specified by:
runAfter in interface TaskManager.Task
Parameters:
tasks - the tasks to consider. A read-only List, with all elements instanceof Task.
size - elements with index less than size should be considered

addSibling

void addSibling(Txn txn)
Add a ``sibling'' transaction, one that is now blocking progress on one of the same entries. For example, if a client is blocked on a read, another transaction can read the same entry, thereby also blocking that same client. This means that the transaction for the second read must be watched, too. The list of queries for the second transaction might be less that the list of those in this transaction, but the process of figuring out the subset is too expensive, since we have tried to make the checking process itself cheap, anyway. So we add all queries this task is currently monitoring to the task monitoring the second transaction. If there are no queries, then the blocking occurred because of a short query or all the queries have expired, in which case the second transaction isn't blocking the way of anything currently, so this method does nothing.

Of course, in order to avoid blocking the thread that is calling this (which is trying to perform a read, after all), we simply add each lease in this task to the monitor's queue.


tryOnce

public boolean tryOnce()
Try to see if this transaction should be aborted. This returns true (don't repeat the task) if it knows that the transaction is no longer interesting to anyone.

Specified by:
tryOnce in class RetryTask

add

void add(QueryWatcher query)
Add in a resource. The lease may already be in, in which case it is ignored, or it may be null, in which case it was a non-leased probe that was blocked and we simply set mustQuery to true.


logUnpackingFailure

private void logUnpackingFailure(String exceptionDescription,
                                 Level level,
                                 boolean terminal,
                                 Throwable t)
Log failed unpacking attempt attempt



Copyright 2007-2010, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.