bftsmart.consensus.Round.java Source code

Java tutorial

Introduction

Here is the source code for bftsmart.consensus.Round.java

Source

/**
Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
    
Licensed 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 bftsmart.consensus;

import bftsmart.consensus.executionmanager.Execution;
import bftsmart.consensus.messages.PaxosMessage;
import java.io.Serializable;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;

import bftsmart.reconfiguration.ServerViewController;
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[] writeSetted;
    private boolean[] acceptSetted;
    private byte[][] write; // WRITE values from other processes
    private byte[][] accept; // accepted values from other processes

    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 ServerViewController controller;

    /**
     * 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
     */
    public Round(ServerViewController controller, Execution parent, int number) {
        this.execution = parent;
        this.number = number;
        this.controller = controller;
        this.proof = new HashSet<PaxosMessage>();
        //ExecutionManager manager = execution.getManager();

        this.lastView = controller.getCurrentView();
        this.me = controller.getStaticConf().getProcessId();

        //int[] acceptors = manager.getAcceptors();
        int n = controller.getCurrentViewN();

        writeSetted = new boolean[n];
        acceptSetted = new boolean[n];

        Arrays.fill(writeSetted, false);
        Arrays.fill(acceptSetted, false);

        if (number == 0) {
            this.write = new byte[n][];
            this.accept = new byte[n][];

            Arrays.fill((Object[]) write, null);
            Arrays.fill((Object[]) accept, null);
        } else {
            Round previousRound = execution.getRound(number - 1, controller);

            this.write = previousRound.getWrite();
            this.accept = previousRound.getAccept();
        }
    }

    // If a view change takes place and concurrentely this consensus is still
    // receiving messages, the write and accept arrays must be updated
    private void updateArrays() {

        if (lastView.getId() != controller.getCurrentViewId()) {

            int n = controller.getCurrentViewN();

            byte[][] write = new byte[n][];
            byte[][] accept = new byte[n][];

            boolean[] writeSetted = new boolean[n];
            boolean[] acceptSetted = new boolean[n];

            Arrays.fill(writeSetted, false);
            Arrays.fill(acceptSetted, false);

            for (int pid : lastView.getProcesses()) {

                if (controller.isCurrentViewMember(pid)) {

                    int currentPos = controller.getCurrentViewPos(pid);
                    int lastPos = lastView.getPos(pid);

                    write[currentPos] = this.write[lastPos];
                    accept[currentPos] = this.accept[lastPos];

                    writeSetted[currentPos] = this.writeSetted[lastPos];
                    acceptSetted[currentPos] = this.acceptSetted[lastPos];

                }
            }

            this.write = write;
            this.accept = accept;

            this.writeSetted = writeSetted;
            this.acceptSetted = acceptSetted;

            lastView = controller.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 WRITE value from a replica
     * @param acceptor The replica ID
     * @return True if there is a WRITE value from a replica, false otherwise
     */
    public boolean isWriteSetted(int acceptor) {

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0) {
            return write[p] != null;
        } else {
            return false;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Informs if there is a accepted value from a replica
     * @param acceptor The replica ID
     * @return True if there is a accepted value from a replica, false otherwise
     */
    public boolean isAcceptSetted(int acceptor) {

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0) {
            return accept[p] != null;
        } else {
            return false;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Retrives the WRITE value from the specified replica
     * @param acceptor The replica ID
     * @return The value from the specified replica
     */
    public byte[] getWrite(int acceptor) {

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0) {
            return this.write[p];
        } else {
            return null;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Retrieves all WRITE value from all replicas
     * @return The values from all replicas
     */
    public byte[][] getWrite() {
        return this.write;
    }

    /**
     * Sets the WRITE value from the specified replica
     * @param acceptor The replica ID
     * @param value The valuefrom the specified replica
     */
    public void setWrite(int acceptor, byte[] value) { // TODO: Race condition?

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0 /*&& !writeSetted[p] && !isFrozen() */) { //it can only be setted once
            write[p] = value;
            writeSetted[p] = true;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Retrieves the accepted value from the specified replica
     * @param acceptor The replica ID
     * @return The value accepted from the specified replica
     */
    public byte[] getAccept(int acceptor) {

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0) {
            return accept[p];
        } else {
            return null;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Retrieves all accepted values from all replicas
     * @return The values accepted from all replicas
     */
    public byte[][] getAccept() {
        return accept;
    }

    /**
     * Sets the accepted value from the specified replica
     * @param acceptor The replica ID
     * @param value The value accepted from the specified replica
     */
    public void setAccept(int acceptor, byte[] value) { // TODO: race condition?

        updateArrays();

        //******* EDUARDO BEGIN **************//
        int p = this.controller.getCurrentViewPos(acceptor);
        if (p >= 0 /*&& !strongSetted[p] && !isFrozen()*/) { //it can only be setted once
            accept[p] = value;
            acceptSetted[p] = true;
        }
        //******* EDUARDO END **************//
    }

    /**
     * Retrieves the amount of replicas from which this process received a WRITE value
     * @param value The value in question
     * @return Amount of replicas from which this process received the specified value
     */
    public int countWrite(byte[] value) {
        return count(writeSetted, write, value);
    }

    /**
     * Retrieves the amount of replicas from which this process accepted a specified value
     * @param value The value in question
     * @return Amount of replicas from which this process accepted the specified value
     */
    public int countAccept(byte[] value) {
        return count(acceptSetted, accept, 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 buffWrite = new StringBuffer(1024);
        StringBuffer buffAccept = new StringBuffer(1024);
        StringBuffer buffDecide = new StringBuffer(1024);

        buffWrite.append("W=(");
        buffAccept.append("S=(");
        buffDecide.append("D=(");

        for (int i = 0; i < write.length - 1; i++) {
            buffWrite.append(str(write[i]) + " [" + (write[i] != null ? write[i].length : 0) + " bytes] ,");
            buffAccept.append(str(accept[i]) + " [" + (accept[i] != null ? accept[i].length : 0) + " bytes] ,");
        }

        buffWrite.append(str(write[write.length - 1]) + " ["
                + (write[write.length - 1] != null ? write[write.length - 1].length : 0) + " bytes])");
        buffAccept.append(str(accept[accept.length - 1]) + " ["
                + (accept[accept.length - 1] != null ? accept[accept.length - 1].length : 0) + " bytes])");

        return "eid=" + execution.getId() + " r=" + getNumber() + " " + buffWrite + " " + buffAccept + " "
                + 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 = controller.getCurrentViewN();

        writeSetted = new boolean[n];
        acceptSetted = new boolean[n];

        Arrays.fill(writeSetted, false);
        Arrays.fill(acceptSetted, false);

        this.write = new byte[n][];
        this.accept = new byte[n][];

        Arrays.fill((Object[]) write, null);
        Arrays.fill((Object[]) accept, null);

        this.proof = new HashSet<PaxosMessage>();
    }
}