Java tutorial
/** * 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 <http://www.gnu.org/licenses/>. */ package bftsmart.paxosatwar.executionmanager; import bftsmart.paxosatwar.messages.PaxosMessage; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.TreeSet; import org.apache.commons.codec.binary.Base64; import bftsmart.reconfiguration.ServerViewManager; import bftsmart.reconfiguration.views.View; import bftsmart.tom.core.messages.TOMMessage; import java.util.HashSet; import java.util.Set; /** * This class stands for a round of an execution of a consensus */ public class Round implements Serializable { private static final long serialVersionUID = -2891450035863688295L; 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<Integer> 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 HashSet<PaxosMessage> proof; // proof from other processes private View lastView = null; private ServerViewManager manager; /** * Creates a new instance of Round for acceptors * @param parent Execution to which this round belongs * @param number Number of the round * @param timeout Timeout duration for this round */ protected Round(ServerViewManager manager, Execution parent, int number) { this.execution = parent; this.number = number; this.manager = manager; this.proof = new HashSet<PaxosMessage>(); //ExecutionManager manager = execution.getManager(); this.lastView = manager.getCurrentView(); 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(); } } // If a view change takes place and concurrentely this consensus is still // receiving messages, the weak and strong arrays must be updated private void updateArrays() { if (lastView.getId() != manager.getCurrentViewId()) { int n = manager.getCurrentViewN(); byte[][] weak = new byte[n][]; byte[][] strong = new byte[n][]; boolean[] weakSetted = new boolean[n]; boolean[] strongSetted = new boolean[n]; Arrays.fill(weakSetted, false); Arrays.fill(strongSetted, false); for (int pid : lastView.getProcesses()) { if (manager.isCurrentViewMember(pid)) { int currentPos = manager.getCurrentViewPos(pid); int lastPos = lastView.getPos(pid); weak[currentPos] = this.weak[lastPos]; strong[currentPos] = this.strong[lastPos]; weakSetted[currentPos] = this.weakSetted[lastPos]; strongSetted[currentPos] = this.strongSetted[lastPos]; } } this.weak = weak; this.strong = strong; this.weakSetted = weakSetted; this.strongSetted = strongSetted; lastView = manager.getCurrentView(); } } /** * 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; } public void addToProof(PaxosMessage pm) { proof.add(pm); } public Set<PaxosMessage> getProof() { return proof; } /** * 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) { updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0) { return weak[p] != null; } else { return false; } //******* EDUARDO END **************// } /** * 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) { updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0) { return strong[p] != null; } else { return false; } //******* 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) { updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0) { return this.weak[p]; } else { return null; } //******* 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: Race condition? updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0 && /*!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) { updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0) { return strong[p]; } else { return null; } //******* 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: race condition? updateArrays(); //******* EDUARDO BEGIN **************// int p = this.manager.getCurrentViewPos(acceptor); if (p >= 0 /*&& !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<Integer>(); } 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); this.proof = new HashSet<PaxosMessage>(); } }