/**
* Copyright (c) 2007-2009 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
*
* This file is part of SMaRt.
*
* SMaRt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMaRt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SMaRt. If not, see .
*/
package navigators.smart.paxosatwar.executionmanager;
import java.io.Serializable;
import java.security.SignedObject;
import java.util.Arrays;
import java.util.Collection;
import java.util.TreeSet;
import navigators.smart.reconfiguration.ReconfigurationManager;
import navigators.smart.tom.core.messages.TOMMessage;
import org.apache.commons.codec.binary.Base64;
/**
* This class stands for a round of an execution of a consensus
*/
public class Round implements Serializable {
private transient Execution execution; // Execution where the round belongs to
private int number; // Round's number
private int me; // Process ID
private boolean[] weakSetted;
private boolean[] strongSetted;
private byte[][] weak; // weakling accepted values from other processes
private byte[][] strong; // strongly accepted values from other processes
private Collection freeze = null; // processes where this round was freezed
private boolean frozen = false; // is this round frozen?
private boolean collected = false; // indicates if a collect message for this round was already sent
private boolean alreadyRemoved = false; // indicates if this round was removed from its execution
public byte[] propValue = null; // proposed value
public TOMMessage[] deserializedPropValue = null; //utility var
public byte[] propValueHash = null; // proposed value hash
public SignedObject[] proofs; // proof from other processes
private ReconfigurationManager manager;
/**
* Creates a new instance of Round for acceptors
* @param manager Reconfiguration Manager
* @param parent Execution to which this round belongs
* @param number Number of the round
*/
protected Round(ReconfigurationManager manager, Execution parent, int number) {
this.execution = parent;
this.number = number;
this.manager = manager;
//ExecutionManager manager = execution.getManager();
this.me = manager.getStaticConf().getProcessId();
//int[] acceptors = manager.getAcceptors();
int n = manager.getCurrentViewN();
weakSetted = new boolean[n];
strongSetted = new boolean[n];
Arrays.fill(weakSetted, false);
Arrays.fill(strongSetted, false);
if (number == 0) {
this.weak = new byte[n][];
this.strong = new byte[n][];
Arrays.fill((Object[]) weak, null);
Arrays.fill((Object[]) strong, null);
} else {
Round previousRound = execution.getRound(number - 1, manager);
this.weak = previousRound.getWeak();
this.strong = previousRound.getStrong();
}
}
/**
* Set this round as removed from its execution
*/
public void setRemoved() {
this.alreadyRemoved = true;
}
/**
* Informs if this round was removed from its execution
* @return True if it is removed, false otherwise
*/
public boolean isRemoved() {
return this.alreadyRemoved;
}
/**
* Adds a collect proof from another replica
*
* @param acceptor replica which sent the proof
* @param proof proof received
*/
public void setCollectProof(int acceptor, SignedObject proof) {
if (proofs == null) {
proofs = new SignedObject[weak.length];
Arrays.fill((SignedObject[]) proofs, null);
}
//******* EDUARDO BEGIN **************//
proofs[this.manager.getCurrentViewPos(acceptor)] = proof;
//******* EDUARDO END **************//
}
/**
* Retrieves the duration for the timeout
* @return Duration for the timeout
*/
/*public long getTimeout() {
return this.timeout;
}*/
/**
* Retrieves this round's number
* @return This round's number
*/
public int getNumber() {
return number;
}
/**
* Retrieves this round's execution
* @return This round's execution
*/
public Execution getExecution() {
return execution;
}
/**
* Informs if there is a weakly accepted value from a replica
* @param acceptor The replica ID
* @return True if there is a weakly accepted value from a replica, false otherwise
*/
public boolean isWeakSetted(int acceptor) {
return weak[this.manager.getCurrentViewPos(acceptor)] != null;
}
/**
* Informs if there is a strongly accepted value from a replica
* @param acceptor The replica ID
* @return True if there is a strongly accepted value from a replica, false otherwise
*/
public boolean isStrongSetted(int acceptor) {
//******* EDUARDO BEGIN **************//
return strong[this.manager.getCurrentViewPos(acceptor)] != null;
//******* EDUARDO END **************//
}
/**
* Retrives the weakly accepted value from the specified replica
* @param acceptor The replica ID
* @return The value weakly accepted from the specified replica
*/
public byte[] getWeak(int acceptor) {
//******* EDUARDO BEGIN **************//
return this.weak[this.manager.getCurrentViewPos(acceptor)];
//******* EDUARDO END **************//
}
/**
* Retrives all weakly accepted value from all replicas
* @return The values weakly accepted from all replicas
*/
public byte[][] getWeak() {
return this.weak;
}
/**
* Sets the weakly accepted value from the specified replica
* @param acceptor The replica ID
* @param value The value weakly accepted from the specified replica
*/
public void setWeak(int acceptor, byte[] value) { // TODO: Condicao de corrida?
//******* EDUARDO BEGIN **************//
int p = this.manager.getCurrentViewPos(acceptor);
if (!weakSetted[p] && !isFrozen()) { //it can only be setted once
weak[p] = value;
weakSetted[p] = true;
}
//******* EDUARDO END **************//
}
/**
* Retrives the strongly accepted value from the specified replica
* @param acceptor The replica ID
* @return The value strongly accepted from the specified replica
*/
public byte[] getStrong(int acceptor) {
//******* EDUARDO BEGIN **************//
return strong[this.manager.getCurrentViewPos(acceptor)];
//******* EDUARDO END **************//
}
/**
* Retrives all strongly accepted values from all replicas
* @return The values strongly accepted from all replicas
*/
public byte[][] getStrong() {
return strong;
}
/**
* Sets the strongly accepted value from the specified replica
* @param acceptor The replica ID
* @param value The value strongly accepted from the specified replica
*/
public void setStrong(int acceptor, byte[] value) { // TODO: condicao de corrida?
//******* EDUARDO BEGIN **************//
int p = this.manager.getCurrentViewPos(acceptor);
if (!strongSetted[p] && !isFrozen()) { //it can only be setted once
strong[p] = value;
strongSetted[p] = true;
}
//******* EDUARDO END **************//
}
/**
* Indicates if a collect message for this round was already sent
* @return True if done so, false otherwise
*/
public boolean isCollected() {
return collected;
}
/**
* Establishes that a collect message for this round was already sent
*/
public void collect() {
collected = true;
}
/**
* Indicates if this round is frozen
* @return True if so, false otherwise
*/
public boolean isFrozen() {
return frozen;
}
/**
* Establishes that this round is frozen
*/
public void freeze() {
frozen = true;
addFreeze(me);
}
/**
* Establishes that a replica locally freezed this round
* @param acceptor replica that locally freezed this round
*/
public void addFreeze(int acceptor) {
if (freeze == null) {
freeze = new TreeSet();
}
freeze.add(acceptor);
}
/**
* Retrieves the ammount of replicas that locally freezed this round
* @return Ammount of replicas that locally freezed this round
*/
public int countFreeze() {
return freeze.size();
}
/**
* Retrives the ammount of replicas from which this process weakly accepted a specified value
* @param value The value in question
* @return Ammount of replicas from which this process weakly accepted the specified value
*/
public int countWeak(byte[] value) {
return count(weakSetted,weak, value);
}
/**
* Retrives the ammount of replicas from which this process strongly accepted a specified value
* @param value The value in question
* @return Ammount of replicas from which this process strongly accepted the specified value
*/
public int countStrong(byte[] value) {
return count(strongSetted,strong, value);
}
/**
* Counts how many times 'value' occurs in 'array'
* @param array Array where to count
* @param value Value to count
* @return Ammount of times that 'value' was find in 'array'
*/
private int count(boolean[] arraySetted,byte[][] array, byte[] value) {
if (value != null) {
int counter = 0;
for (int i = 0; i < array.length; i++) {
if (arraySetted != null && arraySetted[i] && Arrays.equals(value, array[i])) {
counter++;
}
}
return counter;
}
return 0;
}
/*************************** DEBUG METHODS *******************************/
/**
* Print round information.
*/
@Override
public String toString() {
StringBuffer buffWeak = new StringBuffer(1024);
StringBuffer buffStrong = new StringBuffer(1024);
StringBuffer buffDecide = new StringBuffer(1024);
buffWeak.append("W=(");
buffStrong.append("S=(");
buffDecide.append("D=(");
//recall that weak.length = strong.length = decide.length
for (int i = 0; i < weak.length - 1; i++) {
buffWeak.append(str(weak[i]) + " [" + (weak[i] != null ? weak[i].length : 0) + " bytes] ,");
buffStrong.append(str(strong[i]) + " [" + (strong[i] != null ? strong[i].length : 0) + " bytes] ,");
}
buffWeak.append(str(weak[weak.length - 1]) + " [" + (weak[weak.length - 1] != null ? weak[weak.length - 1].length : 0) + " bytes])");
buffStrong.append(str(strong[strong.length - 1]) + " [" + (strong[strong.length - 1] != null ? strong[strong.length - 1].length : 0) + " bytes])");
return "eid=" + execution.getId() + " r=" + getNumber() + " " + buffWeak + " " + buffStrong + " " + buffDecide;
}
private String str(byte[] obj) {
if(obj == null) {
return "*";
} else {
return Base64.encodeBase64String(obj);
}
}
@Override
public boolean equals(Object o) {
return this == o;
}
/**
* Clear all round info.
*/
public void clear() {
int n = manager.getCurrentViewN();
weakSetted = new boolean[n];
strongSetted = new boolean[n];
Arrays.fill(weakSetted, false);
Arrays.fill(strongSetted, false);
this.weak = new byte[n][];
this.strong = new byte[n][];
Arrays.fill((Object[]) weak, null);
Arrays.fill((Object[]) strong, null);
}
}