/** * 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 java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import bftsmart.paxosatwar.Consensus; import bftsmart.reconfiguration.ServerViewManager; /** * This class stands for an execution of a consensus */ public class Execution { private ExecutionManager manager; // Execution manager for this execution private Consensus consensus; // Consensus instance to which this execution works for private HashMap<Integer,Round> rounds = new HashMap<Integer,Round>(2); private ReentrantLock roundsLock = new ReentrantLock(); // Lock for concurrency control private boolean decided; // Is this execution decided? private int decisionRound = -1; // round at which a desision was made //NEW ATTRIBUTES FOR THE LEADER CHANGE private int ets = 0; private TimestampValuePair quorumWeaks = new TimestampValuePair(0, new byte[0]); private HashSet<TimestampValuePair> writeSet = new HashSet<TimestampValuePair>(); public ReentrantLock lock = new ReentrantLock(); //this execution lock (called by other classes) /** * Creates a new instance of Execution for Acceptor Manager * * @param manager Execution manager for this execution * @param consensus Consensus instance to which this execution works for */ protected Execution(ExecutionManager manager, Consensus consensus) { this.manager = manager; this.consensus = consensus; } /** * This is the execution ID * @return Execution ID */ public int getId() { return consensus.getId(); } /** * This is the execution manager for this execution * @return Execution manager for this execution */ public ExecutionManager getManager() { return manager; } /** * This is the consensus instance to which this execution works for * @return Consensus instance to which this execution works for */ public Consensus getLearner() { // TODO: Why it is called getLearner? return consensus; } /** * Gets a round associated with this execution * @param number The number of the round * @return The round */ public Round getRound(int number, ServerViewManager recManager) { return getRound(number,true, recManager); } /** * Gets a round associated with this execution * @param number The number of the round * @param create if the round is to be created if not existent * @return The round */ public Round getRound(int number, boolean create, ServerViewManager recManager) { roundsLock.lock(); Round round = rounds.get(number); if(round == null && create){ round = new Round(recManager, this, number); rounds.put(number, round); } roundsLock.unlock(); return round; } /** * Increment the ETS of this replica */ public void incEts() { ets++; } /** * Store the value read from a Byzantine quorum of WEAKS * @param value */ public void setQuorumWeaks(byte[] value) { quorumWeaks = new TimestampValuePair(ets, value); } /** * Return the value read from a Byzantine quorum of WEAKS that has * previously been stored * @return the value read from a Byzantine quorum of WEAKS, if such * value has been obtained already */ public TimestampValuePair getQuorumWeaks() { return quorumWeaks; } /** * Add a value that shall be written to the writeSet * @param value Value to write to the writeSet */ public void addWritten(byte[] value) { writeSet.add(new TimestampValuePair(ets, value)); } /** * Remove an already writte value from writeSet * @param value valor a remover do writeSet */ public void removeWritten(byte[] value) { for (TimestampValuePair rv : writeSet) { if (Arrays.equals(rv.getValue(), value)) writeSet.remove(rv); } } public HashSet<TimestampValuePair> getWriteSet() { return writeSet; } /** * Creates a round associated with this execution, supposedly the next * @return The round */ public Round createRound(ServerViewManager recManager) { roundsLock.lock(); Set<Integer> keys = rounds.keySet(); int max = -1; for (int k : keys) { if (k > max) max = k; } max++; Round round = new Round(recManager, this, max); rounds.put(max, round); roundsLock.unlock(); return round; } /** * Removes rounds greater than 'limit' from this execution * * @param limit Rounds that should be kept (from 0 to 'limit') */ public void removeRounds(int limit) { roundsLock.lock(); for(Integer key : (Integer[])rounds.keySet().toArray(new Integer[0])) { if(key > limit) { Round round = rounds.remove(key); round.setRemoved(); //round.getTimeoutTask().cancel(); } } roundsLock.unlock(); } /** * The round at which a decision was possible to make * @return Round at which a decision was possible to make */ public Round getDecisionRound() { roundsLock.lock(); Round r = rounds.get(decisionRound); roundsLock.unlock(); return r; } /** * The last round of this execution * * @return Last round of this execution */ public Round getLastRound() { roundsLock.lock(); if (rounds.isEmpty()) { roundsLock.unlock(); return null; } Round r = rounds.get(rounds.size() - 1); roundsLock.unlock(); return r; } /** * Informs whether or not the execution is decided * * @return True if it is decided, false otherwise */ public boolean isDecided() { return decided; } /** * Called by the Acceptor, to set the decided value * * @param value The decided value * @param round The round at which a decision was made */ public void decided(Round round, byte[] value) { if (!decided) { decided = true; decisionRound = round.getNumber(); consensus.decided(round); manager.getTOMLayer().decided(consensus); } } }