/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.giraph.examples.utils; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Writable; /** * Vertex value used for the Bracha-Toueg Dealock algorithm */ public class BrachaTouegDeadlockVertexValue implements Writable { /** Invalid ID */ public static final Long INVALID_ID = Long.valueOf(-1); /** Vertex is free from deadlock */ private boolean isFree; /** Vertex was notified */ private boolean isNotified; /** * Active requests which need to be satisfied to free the node. * Tha hash map is needed to handle the N-out-of-M semantics. The first * parameter identifies the TAG of the request, the second identifies the * vertex id to which an edge with points. All the eequests (edges) with the * same TAG need to be satisfied to consider the vertex free. */ private HashMap<Long, ArrayList<Long>> requests; /** * Structure containing the messages awaited from the other vertices. * The algorithm guarantees that the vertex will not wait for two different * messages from the same vertex. */ private HashMap<Long, Long> waitingList; /** IDs of the parents of this vertex */ private ArrayList<Long> parents; /** id to which the ACK message needs to be sent for the first GRANT message that releases the node; -1 identifies an empty ackId */ private Long idWithInHoldAck; /** * id to which the DONE message needs to be sent for the first NOTICE * message received; -1 identifies an empty ackId */ private Long idWithInHoldDone; /** * Default constructor */ public BrachaTouegDeadlockVertexValue() { this(new HashMap<Long, ArrayList<Long>>()); } /** * Parametrized constructor * * @param requests number of requests needed to consider the node free */ public BrachaTouegDeadlockVertexValue( HashMap<Long, ArrayList<Long>> requests) { this.isFree = false; this.isNotified = false; this.requests = requests; this.waitingList = new HashMap<Long, Long>(); this.parents = new ArrayList<Long>(); this.idWithInHoldAck = INVALID_ID; this.idWithInHoldDone = INVALID_ID; } // Serialization functions ----------------------------------------------- @Override public void readFields(DataInput input) throws IOException { int sz; this.isFree = input.readBoolean(); this.isNotified = input.readBoolean(); sz = input.readInt(); for (int i = 0; i < sz; ++i) { ArrayList<Long> targets = new ArrayList<Long>(); Long tag = input.readLong(); int sw = input.readInt(); for (int j = 0; j < sw; ++j) { Long target = input.readLong(); targets.add(target); } this.requests.put(tag, targets); } sz = input.readInt(); for (int i = 0; i < sz; ++i) { Long key = input.readLong(); Long value = input.readLong(); this.waitingList.put(key, value); } sz = input.readInt(); for (int i = 0; i < sz; ++i) { this.parents.add(Long.valueOf(input.readLong())); } this.idWithInHoldAck = input.readLong(); this.idWithInHoldDone = input.readLong(); } @Override public void write(DataOutput output) throws IOException { int sz; output.writeBoolean(this.isFree); output.writeBoolean(this.isNotified); sz = this.requests.size(); output.writeInt(sz); for (Map.Entry<Long, ArrayList<Long>> entry : this.requests.entrySet()) { ArrayList<Long> targets; output.writeLong(entry.getKey()); targets = entry.getValue(); sz = targets.size(); output.writeInt(sz); for (Long target : targets) { output.writeLong(target); } } sz = this.waitingList.size(); output.writeInt(sz); for (Map.Entry<Long, Long> entry : this.waitingList.entrySet()) { output.writeLong(entry.getKey()); output.writeLong(entry.getValue()); } sz = this.parents.size(); output.writeInt(sz); for (int i = 0; i < sz; ++i) { output.writeLong(this.parents.get(i)); } output.writeLong(this.idWithInHoldAck); output.writeLong(this.idWithInHoldDone); } // Accessors ------------------------------------------------------------- /** * @return true if free, false otherwise */ public boolean isFree() { return this.isFree; } /** * the vertex is free from deadlocks */ public void setFree() { this.isFree = true; } /** * @return true if the vertex was notified, false otherwise */ public boolean isNotified() { return this.isNotified; } /** * the vertex got a notification */ public void setNotified() { this.isNotified = true; } /** * @return false if no pending requests have to be still processed to * continue the computation */ public boolean hasPendingRequests() { boolean withPendingRequests = true; if (this.requests.isEmpty()) { withPendingRequests = false; } for (Map.Entry<Long, ArrayList<Long>> request : this.requests.entrySet()) { ArrayList<Long> targets = request.getValue(); if (targets.size() == 0) { withPendingRequests = false; } } return withPendingRequests; } /** * remove the expected request from the edge on which the message arrived * * @param tag tag of the edge * @param targetId target Id to which the edge points */ public void removeRequest(LongWritable tag, LongWritable targetId) { Long l = Long.valueOf(tag.get()); ArrayList<Long> targets = this.requests.get(l); if (targets.contains(targetId.get())) { targets.remove(Long.valueOf(targetId.get())); } } /** * This function retrieves the number of pending requests for the specified * tag. Because of the N-out-of-M semantic, each time a GRANT is received * on an edge, the number of requests is reduced for the tag which the edge * is part of. * * @param tag tag related to the requests to be verified * @return number of requests pending for the tag provided */ public int getNumOfRequests(LongWritable tag) { Long l = Long.valueOf(tag.get()); ArrayList<Long> targets = this.requests.get(l); return targets.size(); } /** * Add a new message that must be expected by the node * * @param id ID of the node from which the messages is expected * @param type type of message that is awaited */ public void waitForMessage(Long id, Long type) { // waiting list should not contain two messages for the same node assert waitingList.get(id) == null; waitingList.put(id, type); } /** * Each time a message is received, it has to be removed from the queue * that keeps track of the waited messages. * * @param id ID of the node from which the messages is expected * @param type type of message that is awaited */ public void receivedMessage(Long id, Long type) { long typel; assert waitingList.get(id) != null; typel = waitingList.get(id).longValue(); assert typel > 0; waitingList.remove(id); } /** * @param type type of message to check * @return boolean true if waiting the message type, false otherwise */ public boolean isWaitingForMessage(Long type) { for (Map.Entry<Long, Long> entry : waitingList.entrySet()) { long typel = entry.getValue().longValue(); if ((typel & type) > 0) { return true; } } return false; } /** * add a parent id into the list of parents kept at the vertex side * @param parentId vertex id of the parent */ public void addParent(Long parentId) { this.parents.add(parentId); } /** * @return list of parent IDs collected */ public ArrayList<Long> getParents() { return this.parents; } /** * @return the id waiting for an ACK message */ public Long getIdWithInHoldAck() { return this.idWithInHoldAck; } /** * @param id the id to set */ public void setIdWithInHoldAck(Long id) { this.idWithInHoldAck = id; } /** * @return the id waiting for an DONE message */ public Long getIdWithInHoldDone() { return idWithInHoldDone; } /** * @param doneId the id to set */ public void setIdWithInHoldDone(Long doneId) { this.idWithInHoldDone = doneId; } @Override public String toString() { return "isFree=" + Boolean.toString(isFree); } }