public class TxDag extends Object
Directed Acyclic Graph (DAG) for detecting and preventing deadlocks in a
concurrent programming system. The algorithm takes advantage of certain
characteristics of the deadlock detection problem for concurrent transactions
and provides a reasonable cost solution for that domain. The design uses a
boolean matrix W to code the edges in the WAITS_FOR graph and an integer
matrix M to code the the number of different paths between two vertices.
Operations that insert one or more edges are atomic -- if a deadlock would
result, then the state of the DAG is NOT changed (a deadlock is detected when
there is a non-zero path count in the diagonal of W). The cost of the
algorithm is less than O(n^^2)
and is suitable for systems
with a multi-programming level of 100s of concurrent transactions.
This implementation is based on the online algorithm for deadlock detection
in Section 5, page 86 of:
Bayer, R. 1976. Integrity, Concurrency, and Recovery in Databases. In
Proceedings of the Proceedings of the 1st European Cooperation in informatics
on ECI Conference 1976 (August 09 - 12, 1976). K. Samelson, Ed. Lecture Notes
In Computer Science, vol. 44. Springer-Verlag, London, 79-106.
See the
citation online.
Given that w
is the directed acyclic graph of
WAITS_FOR
relation among the concurrent transactions.
w+
is the transitive closure of w
. The online
algorithm solves the problem:
Given w, w+, calculate w', w'+ where w' := w U {(ti,tj)} iff inserting an edge, or w' := w / {(ti,tj)} iff removing an edge.
The approach defines a matrix M[ t, u ]
whose cells are the
number of different paths from t
to u
. A
deadlock is identified if the update algorithm for M
computes
a non-zero value for the diagonal.
The update rules for M are as follows. "+/-" should be interpreted as "+" iff an edge is being added and "-" iff an edge is being removed. The "." operator is scalar multiplication.
The public interface is defined in terms of arbitrary objects designated by
the application as "transactions". The DAG is provisioned for a maximum
multi-programming level, which is used to dimension the internal matrices.
The choosen multi-programming level should correspond to the maximum multi-
programming level permitted, i.e., to the #of concurrent transactions which
may execute before subsequent requests for a new transaction are queued.
Internally the "transaction" objects are mapped using their hash code onto
pre-defined Integer
s corresponding to indices in [0:n-1], where n is
the provisioned multi-programming level.
This class is designed to be used internally by a class modeling a
ResourceQueue
. Edges are added when a transaction must wait
for a resource on one or more transactions in the granted group for that
resource queue. Transactions are implicitly declared as they are referenced
when adding edges. The general case is that there are N transactions in the
granted group for some resource, so
addEdges(Object blocked, Object[] running)
would be used to indicate
that a transaction must wait on the granted group.
A transaction in a granted group is guarenteed to be running and hence not
waiting on any other transaction(s). When a transaction releases a lock, the
ResourceQueue
automatically invokes
removeEdges(Object tx, boolean waiting)
with
waiting == false
in order to remove all WAITS_FOR
relationships whose target is that transaction. (The
removeEdges(Object, boolean)
method is optimized for the case when
it is known that a transaction is not waiting for any other transaction.)
The integration layer MUST explicitly invoke
removeEdges(Object, boolean)
whenever a transaction commits or
aborts in order to remove all WAITS_FOR relationships involving that
transaction. Failure to do this will result in false reporting of deadlocks
since the transaction is still "on the books". The integration layer should
specify waiting == false
iff it knows that the transaction was
NOT blocked. For example, a transaction which completes normally is never
blocked. However, if a decision is made to abort a blocked transaction, e.g.,
owing to a timeout or external directive, then the caller MUST specify
waiting == true
and a less efficient technique will be used to
remove all edges involving the specificed transaction.
Modifier and Type | Class and Description |
---|---|
static class |
TxDag.Edge
A representation of an edge in the DAG used for export of information to
the caller.
|
Modifier and Type | Field and Description |
---|---|
static boolean |
cacheOrder
This field controls whether or not the result of
getOrder() is
cached. |
protected static boolean |
DEBUG |
protected static boolean |
INFO |
protected static org.apache.log4j.Logger |
log
Logger for this class.
|
static boolean |
sortOrder
This field controls whether or not the result of
getOrder() and
getOrder(int, int) are sorted. |
static boolean |
sortOrderForDisplay
This field controls whether or not the order[] is cloned and then sorted
by
toString() . |
static int |
UNKNOWN
The constant used by
lookup(Object, boolean) to indicate that
the named vertex was not found in the DAG (-1 ). |
Constructor and Description |
---|
TxDag(int capacity)
Constructor.
|
Modifier and Type | Method and Description |
---|---|
void |
addEdge(Object blocked,
Object running)
Add an edge to the DAG.
|
void |
addEdges(Object blocked,
Object[] running)
Add a set of edges to the DAG.
|
int |
capacity()
The maximum multi-programming level supported (from the constructor).
|
TxDag.Edge[] |
getEdges(boolean closure)
Return an array of the edges asserted for the graph.
|
boolean |
hasEdge(Object blocked,
Object running)
Return
true iff the described edge exists in the graph. |
boolean |
isFull()
Return
true iff adding another transaction would exceed
the configured multi-programming capacity. |
boolean |
releaseVertex(Object tx)
|
void |
removeEdge(Object blocked,
Object running)
Removes an edge from the DAG.
|
void |
removeEdges(Object tx,
boolean waiting)
Remove all edges whose target is tx.
|
int |
size()
The current multi-programming level.
|
String |
toString()
Returns a representation of the state of the graph suitable for debugging
the algorithm.
|
protected static final org.apache.log4j.Logger log
protected static final boolean INFO
protected static final boolean DEBUG
public static boolean sortOrder
getOrder()
and
getOrder(int, int)
are sorted. Sorting is not required for
correctness, but sorting may make it easier to follow the behavior of the
algorithm. The default is false
.public static boolean sortOrderForDisplay
toString()
. The default is true
.public static boolean cacheOrder
getOrder()
is
cached. Caching is enabled by default but may be disabled for debugging.public static final int UNKNOWN
lookup(Object, boolean)
to indicate that
the named vertex was not found in the DAG (-1
).public TxDag(int capacity)
capacity
- The multi-programming level. This is the maximum number of
concurrent transactions permitted by the application.IllegalArgumentException
- If n < 2
(the minimum value for
concurrency).public int capacity()
size()
public int size()
capacity()
public boolean isFull()
true
iff adding another transaction would exceed
the configured multi-programming capacity.public boolean releaseVertex(Object tx)
mapping
and (b)
updating the list of available indices
.tx
- public void addEdge(Object blocked, Object running) throws DeadlockException
blocked -> running[ i ]
, i.e., the blocked
transaction WAITS_FOR the running transaction.blocked
- A transaction. If the transaction is not already registered as
a vertex of the graph, then it is implicitly declared by this
method. See lookup(Object, boolean)
.running
- A different transaction. If the transaction is not already
registered as a vertex of the graph, then it is implicitly
declared by this method. See lookup(Object, boolean)
.IllegalArgumentException
- If either argument is null
.IllegalArgumentException
- If the same transaction is specified for both arguments.IllegalStateException
- If the described edge already exists.DeadlockException
- If adding the edge to the DAG would result in a cycle. The
state of the DAG is unchanged if this exception is thrown.public String toString()
public void addEdges(Object blocked, Object[] running) throws DeadlockException
blocked -> running[ i ]
, i.e., the blocked
transaction WAITS_FOR the running transaction.blocked
- A transaction that is blocked waiting on one or more
transactions.running
- One or more transactions in the granted group for some
resource.IllegalArgumentException
- If either argument is null
.IllegalArgumentException
- If any element of running is null
.IllegalArgumentException
- If blocked == running[ i]
for any element
of running .IllegalArgumentException
- If running.length
is greater than the
capacity of the DAG.IllegalStateException
- If creating the described edges would cause a duplicate
edge to be asserted (either the edge already exists or it
is defined more than once by the parameters).DeadlockException
- If adding the described edges to the DAG would result in a
cycle. The state of the DAG is unchanged if this exception
is thrown.public boolean hasEdge(Object blocked, Object running)
true
iff the described edge exists in the graph.blocked
- A transaction.running
- A different transaction.IllegalArgumentException
- If either argument is null
.IllegalArgumentException
- If the same transaction is specified for both arguments.public TxDag.Edge[] getEdges(boolean closure)
TxDag.Edge
public void removeEdge(Object blocked, Object running)
Note: This method does NOT does not recycle the vertex associated with a
transaction which no longer has any incoming or outgoing edges. See
removeEdges(Object, boolean)
.
blocked
- A transaction which is currently waiting on running .running
- Another transaction.IllegalArgumentException
- If either argument is null
.IllegalArgumentException
- If the same transaction is specified for both arguments.IllegalStateException
- If the described edge does not exist.public void removeEdges(Object tx, boolean waiting)
releaseVertex(Object)
.tx
- A transaction.waiting
- When false, caller asserts that this transaction it is NOT
waiting on any other transaction. This assertion is used to
optimize the update of the path count matrix by simply
removing the row and column associated with this transaction.
When [waiting == true], a less efficient procedure is used to
update the path count matrix.
Do NOT specify [waiting == false] unless you know that the transaction is NOT waiting. In general, this knowledge is available to the 2PL locking package.
Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.