public void compute(
Vertex<LongWritable, BrachaTouegDeadlockVertexValue, LongWritable> vertex,
Iterable<BrachaTouegDeadlockMessage> messages)
throws IOException {
BrachaTouegDeadlockVertexValue value;
long superstep = getSuperstep();
if (superstep == 0) {
/* Phase to exchange the sender vertex IDs on the incoming edges.
It also prepares the internal state of the vertex */
initAlgorithm(vertex);
/* After each vertex collects the messages sent by the parents, the
initiator node starts the algorithm by means of a NOTIFY message */
} else if (superstep == 1) {
/* get the value/state of the vertex */
value = vertex.getValue();
if (LOG.isDebugEnabled()) {
LOG.debug("Vertex ID " + vertex.getId() + " status is:");
LOG.debug("\tpending requests? " + value.hasPendingRequests());
LOG.debug("\tis free? " + value.isFree());
LOG.debug("\tis notified? " + value.isNotified());
}
/* collect all the incoming senders IDs */
for (BrachaTouegDeadlockMessage message : messages) {
value.addParent(Long.valueOf(message.getSenderId()));
}
/* debugging purpose: print all the parents of the vertex */
if (LOG.isDebugEnabled()) {
logParents(vertex);
if (isInitiator(vertex)) {
LOG.debug("Vertex ID " + vertex.getId() + " start the algorithm.");
}
}
if (isInitiator(vertex)) {
/* the initiator starts the algorithm */
notifyVertices(vertex);
} else {
/* The Pregel model prescribes that each node starts in the "active"
state. In some cases the Bracha-Toueg Algorithm leaves some nodes
untouched causing the algorithm never to end. To avoid this
situation at algorithm initialization all the nodes except the
initiator (which by default is active) will vote to halt so that
the unused vertices will not produce an infinite computation. Later,
only when required the vote will be triggered. */
vertex.voteToHalt();
return;
}
/* At this point the actual deadlock detection algorithm is started. */
} else {
Long ackSenderId;
value = vertex.getValue();
/* process all the incoming messages and act based on the type of
message received */
for (BrachaTouegDeadlockMessage message : messages) {
long type = message.getType();
if (LOG.isDebugEnabled()) {
LOG.debug("Vertex ID " + vertex.getId() + " received: " + message);
}
if (type == BrachaTouegDeadlockMessage.NOTIFY) {
handleNotifyMessage(vertex, message);
} else if (type == BrachaTouegDeadlockMessage.GRANT) {
handleGrantMessage(vertex, message);
} else if (type == BrachaTouegDeadlockMessage.DONE ||
type == BrachaTouegDeadlockMessage.ACK) {
/* Both ACK and DONE Messages are handled in the same way. The
action take afterwards is independent on these types of
messages. */
value.receivedMessage(message.getSenderId(), message.getType());
}
}
ackSenderId = value.getIdWithInHoldAck();
if (value.isFree() &&
!value.isWaitingForMessage(BrachaTouegDeadlockMessage.ACK) &&
!ackSenderId.equals(BrachaTouegDeadlockVertexValue.INVALID_ID)) {
sendAckMessage(ackSenderId, vertex);
value.setIdWithInHoldAck(BrachaTouegDeadlockVertexValue.INVALID_ID);
}
/* if all the ACK and DONE messages have been received, the vertex can
send the pending DONE message to the parent and vote to halt */
if (value.isNotified() &&
!value.isWaitingForMessage(BrachaTouegDeadlockMessage.ACK) &&
!value.isWaitingForMessage(BrachaTouegDeadlockMessage.DONE)) {
Long senderId = value.getIdWithInHoldDone();
if (LOG.isDebugEnabled()) {
LOG.debug("Vertex ID " + vertex.getId() +
" sent the last DONE message.");
LOG.debug("Vertex ID " + vertex.getId() + " voted to halt.");
}
/* the initiator vertex does not need to send the DONE message since
it is the starting point of the algorithm */
if (!isInitiator(vertex) &&
!senderId.equals(BrachaTouegDeadlockVertexValue.INVALID_ID)) {
sendMessage(vertex.getId().get(), senderId,
BrachaTouegDeadlockMessage.DONE);
value.setIdWithInHoldDone(BrachaTouegDeadlockVertexValue.INVALID_ID);
}
vertex.voteToHalt();
}
}