4
\$\begingroup\$

I recently implemented a dynamic voting protocol for a replicated filesystem. I would really appreciate it if you can review the design and some choices made with regards to sharing of Locks & shared objects. The code is quite big hence I'm not going to post it all here. It was for a school project (already graded).

In this implementation I have an "Application" that makes read/write requests (simulates user activity) to the Replication client. The client itself implements the protocol and sends TCP requests for read/write access. A server (TCP) exists to receive requests from other clients (in a distributed system) and modify state based on incoming requests. Each node is both a client and server.

It would be great if you could comment on any issue you can discover in the design & multi-threading aspects.

Interactive application used to enter read/write commands in the terminal, this uses the ReplicationClient class.

package application;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;

import core.Context;
import core.OpContainer;
import core.ReplicationClient;
import comm.Server;
import filesystem.FileInfo;

public class InteractiveApplication implements Application {

static Scanner inputScanner;
Integer numberOfRequests = 1;
Integer readPercent = 100;
private ReplicationClient replicationClient;

@Override
public void runApplication() {
    printWelcomeMessage();
    inputScanner = new Scanner(System.in);
    String command = "";
    while (!(command = commandPrompt(inputScanner)).contains("exit")) {
        processCommand(command);
    }
    inputScanner.close();
    System.out.println("Exited");
}

private void processCommand(String command) {
    String[] split      = command.split("\\s");
    String operation    = "";
    String fileName     = "";

    if(split.length == 1){
        operation = split[0];
    } else {
        operation = split[0];
        fileName = split[1];
    }

    switch (operation) {
    case "read":
        processRead(fileName);
        break;
    case "write":
        processWrite(fileName, inputScanner);
        break;
    case "list":
        System.out.println("List of files");
        processList();
        break;
    case "exit":
        System.out.println("Exit");
        break;
    case "fail":
        System.out.println("Processing Node failure, Node will be down for 60 seconds.");
        processFail();
        break;
    default:
        System.out.println("Invalid command entered, please try again.");
        break;
    }
}

private void processFail() {
    Thread fail = new Thread(new Runnable() {

        @Override
        public void run() {
            Server.isFailed = true;
            try {
                Thread.sleep(60000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Server.isFailed = false;
            System.out.println("Server Recovered");
        }
    });
    fail.start();
    try {
        fail.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private void processList() {
    Set<String> files = Context.fsHandler.getReplicatedFiles().keySet();
    for(String name : files){
        System.out.println(name);
    }
}

private void processWrite(String fileName, Scanner inputScanner2) {
    System.out.println("> Enter Content");
    System.out.print("$ ");
    String newContent = inputScanner2.nextLine();
    OpContainer container = null;
    try {
        container = replicationClient.writeFile(fileName, newContent);
    } catch (IOException e) {
        System.out.println("Unable to write content to file.");
    } finally {
        if(container.isQuorumObtained()){
            replicationClient.writeUnlockFile(fileName);
        }

    }
}

private void processRead(String fileName) {
    //System.out.println("Reading filename " + fileName);
    OpContainer container = null;
    try {
        container = replicationClient.readFile(fileName);
        System.out.println(container.getContent());

    } catch (FileNotFoundException e) {
        System.out.println("File Not Found, Please try again");
    } catch (NoSuchElementException e) {
        System.out.println("EMPTY");
    } finally {
        if(container.isQuorumObtained()){
            replicationClient.readUnlockFile(fileName);
        }

    }
}

private String commandPrompt(Scanner inputScanner) {
    System.out.print("> ");
    String command = inputScanner.nextLine();
    return command.trim();
}

private void printWelcomeMessage() {
    System.out.println("Welcome to Awesome File System - AwesomeFS");
    System.out
            .println("Distributed & Replicated Fault Tolerant File System");
    System.out.println("Running in interactive mode");
    System.out.println("List of Files Available:");
    Iterator<Entry<String, FileInfo>> iter = Context.fsHandler.getReplicatedFiles().entrySet().iterator();
    while(iter.hasNext()){
        System.out.println(iter.next().getKey());
    }
    System.out.println("Available Operations: read / write");
    System.out.println("Example Command: read 1.txt");
}

@Override
public void run() {
    this.runApplication();
}

@Override
public void setNumberOfRequests(Integer number) {
    this.numberOfRequests = number;
}

@Override
public void setReadPercent(Integer percentReads) {
    this.readPercent = percentReads;
}

@Override
public void setReplicationClient(ReplicationClient client) {
    this.replicationClient = client;

}

}

ReplicationClient code:

package core;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.NoSuchElementException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import filesystem.FileInfo;

public class ReplicationClient {

static final Logger logger = LogManager.getLogger(ReplicationClient.class);

public OpContainer readFile(String fileName) throws FileNotFoundException, NoSuchElementException {

    Operation readOperation = new ReadOperation();
    boolean readQObtained = readOperation.processOperation(fileName);

    //If read quorum obtained, read the file

    OpContainer container = new OpContainer(fileName, readQObtained, content);
    return container;

}// ReadFile ENDS

public void readUnlockFile(String fileName) {
    Operation readUnlock = new ReadOperation();
    readUnlock.unlockFile(fileName);
}// Read Unlock ENDS

public OpContainer writeFile(String fileName, String content)
        throws FileNotFoundException {
    Operation writeOperation = new WriteOperation();

    // Blocking call, will not return till quorum Obtained
    boolean writeQObtained = writeOperation.processOperation(fileName);

    //If write quorum obtained, write the file
    return new OpContainer(fileName, writeQObtained, content);
}

public void writeUnlockFile(String fileName) {
    Operation writeUnlock = new WriteOperation();
    writeUnlock.unlockFile(fileName);
}// Write Unlock ENDS

}

Abstract Operation class that implements the methods for getting the read and write quorum. Since the protocol only differs slightly based on if its read or write, specific operations are in concrete ReadOperation, WriteOperation classes (not posted here)

package core;

import info.siyer.aos.clock.VectorClock;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.Semaphore;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import message.Message;
import comm.TCPClient;
import config.ContainsLock;
import config.Node;
import filesystem.FileInfo;
import filesystem.P;

public abstract class Operation {
protected final Logger logger = LogManager.getLogger(getClass());

/*
 * Abstract Methods
 */

protected abstract Message getMessage(); 

protected abstract String getOperation();

protected abstract FileInfo setFlags(FileInfo fInfo);

protected abstract ContainsLock getLock(Semaphore rwLock);

protected abstract FileInfo updateVersion(FileInfo fInfo);

protected abstract FileInfo resetFlags(FileInfo fInfo);

protected abstract Semaphore unlockLock(Semaphore rwLock);

protected abstract Message getDoneMessage();

protected abstract boolean isLocked(String fileName);


/*
 * Concrete Methods
 */

public boolean processOperation(String fileName) throws FileNotFoundException{

    FileInfo fExists = Context.fsHandler.getReplicatedFiles().get(fileName);

    if (fExists == null) {
        throw new FileNotFoundException();
    }
    boolean quorumObtained = false;
    synchronized (Context.lock) {
        // Increment my entry in the vector clock to signal my readEvent.
        String myID = Context.myInfo.getId().toString();
        Context.clock.increment(myID);
        quorumObtained = requestQuorum(fileName);
    }

    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //while(!quorumObtained){
    for(int count = 0; count < 10; count++){
        synchronized (Context.lock) {
            FileInfo fInfo = Context.fsHandler.getReplicatedFiles().get(fileName);
            if (fInfo.quorumObtained(Context.DU)) {
                quorumObtained = true;
                //TODO add logging here
                break;
            } else {
                //unlock my lock and try again
                if(isLocked(fileName)){
                    Semaphore fileSemaphore = fInfo.getFileSemaphore();
                    fileSemaphore = unlockLock(fileSemaphore);
                    fInfo.setFileSemaphore(fileSemaphore);
                    Context.fsHandler.getReplicatedFiles().put(fileName, fInfo);
                }
                abortRequest(fileName);
            }
        } // SYNC Block ENDS
        exponentialBackOff();
        quorumObtained = requestQuorum(fileName);

    }//While Quorum not obtained

    return quorumObtained;

}//Process Operation

public boolean requestQuorum(String fileName){
    synchronized (Context.lock) {

        String myID = Context.myInfo.getId().toString();

        FileInfo fInfo = Context.fsHandler.getReplicatedFiles().get(fileName);
        //ReentrantReadWriteLock rwLock = fInfo.getReadWriteLock();
        Semaphore fileSemaphore = fInfo.getFileSemaphore();
        String content = "";
        try {
            content = Context.fsHandler.getFilesystem().read(fileName);
        } catch (FileNotFoundException | NoSuchElementException e1) {
            e1.printStackTrace();
        }

        ContainsLock container  = getLock(fileSemaphore);
        boolean lockAcquired    = container.isLockAcquired();
        fileSemaphore           = container.getRwLock();
        if(lockAcquired){
            P myP = new P(myID, fInfo.getVersionNumber(), fInfo.getReplicasUpdated(), content);
            fInfo.getP().put(myID, myP);
            fInfo = setFlags(fInfo);
            String clock = VectorClock.serializeClock(Context.clock);
            Integer VN = fInfo.getVersionNumber();
            Integer RU = fInfo.getReplicasUpdated();
            // String content = "";
            try {
                content = Context.fsHandler.getFilesystem().read(
                        fileName);
            } catch (FileNotFoundException | NoSuchElementException e) {
                e.printStackTrace();
            }
            Message lockMessage = getMessage();

            lockMessage.setClock(clock);
            lockMessage.setContent(content);
            lockMessage.setFileName(fileName);
            lockMessage.setNodeID(myID);
            lockMessage.setRU(RU);
            lockMessage.setVN(VN);
            Iterator<Entry<Integer, Node>> iter = Context.nodeInfos.entrySet().iterator();

            while(iter.hasNext()){

                Entry<Integer, Node> entry = iter.next();
                Integer toNodeID = entry.getKey();
                Node node = entry.getValue();
                String hostName = node.getHost();
                Integer port = Integer.parseInt(node.getPort());
                /*
                 * TCPClient.sendMessage(message, hostName, port,
                 * toNodeID);
                 */
                if (toNodeID != Context.myInfo.getId()) {
                    try {
                        TCPClient.sendMessage(lockMessage, hostName,port, toNodeID.toString());
                    } catch (IOException e) {
                        logger.error("Unable to send Message to node: " + toNodeID);
                        e.printStackTrace();
                    }
                }           
            }//While Sending to all nodes ENDS

        }//If lock Acquired ENDS
        else {
            return false;
        }
        fInfo.setFileSemaphore(fileSemaphore);
        Context.fsHandler.getReplicatedFiles().put(fileName, fInfo);
    }//Sync Block ENDS

    return false;
}

public void unlockFile(String fileName){

    synchronized (Context.lock) {
        FileInfo fExists = Context.fsHandler.getReplicatedFiles().get(
                fileName);

        if (fExists == null) {
            return;
        }

        String myID = Context.myInfo.getId().toString();
        // Increment Vector Clock to indicate my send event;
        Context.clock.increment(myID);

        try {
            PrintWriter out = new PrintWriter(new BufferedWriter(
                    new FileWriter("testClocks/" + fileName + ".clock", true)));
            StringBuilder sb = new StringBuilder();
            sb.append(VectorClock.serializeClock(Context.clock) + "::");
            sb.append(getOperation());
            out.println(sb.toString());
            out.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        FileInfo fInfo  = Context.fsHandler.getReplicatedFiles().get(fileName);
        fInfo           = updateVersion(fInfo);
        Integer replicasUpdated = fInfo.getP().size();
        fInfo.setReplicasUpdated(replicasUpdated);
        Message doneMsg = getDoneMessage(); 

        String content = "";
        Integer VN = fInfo.getVersionNumber();
        Integer RU = fInfo.getReplicasUpdated();
        String clock = VectorClock.serializeClock(Context.clock);

        try {
            content = Context.fsHandler.getFilesystem().read(fileName);
        } catch (FileNotFoundException | NoSuchElementException e) {
            e.printStackTrace();
        }
        doneMsg.setClock(clock);
        doneMsg.setContent(content); 
        doneMsg.setFileName(fileName);
        doneMsg.setNodeID(myID);
        doneMsg.setRU(RU);
        doneMsg.setVN(VN);

        for (Entry<String, P> entry : fInfo.getP().entrySet()) {
            String key = entry.getKey();

            // Dont send done message to myself
            if (key.equals(myID)) {
                continue;
            }
            P pi = entry.getValue();
            String ID = pi.getNodeID();
            Node node = Context.nodeInfos.get(Integer.parseInt(ID));
            String hostName = node.getHost();
            Integer port = Integer.parseInt(node.getPort());
            Integer count = pi.getCount();

            for (int i = 1; i <= count; i++) {
                try {
                    TCPClient.sendMessage(doneMsg, hostName, port, ID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }// For every time we received lock message from this node ends

        }// For each Pi in P we send done read message to unlock
        Semaphore fSemaphore = fInfo.getFileSemaphore();
        fSemaphore = unlockLock(fSemaphore);
        fInfo = resetFlags(fInfo);
        fInfo.setFileSemaphore(fSemaphore);
        Context.fsHandler.getReplicatedFiles().put(fileName, fInfo);
    }//Sync Block ENDS
}

public void abortRequest(String fileName){

    synchronized (Context.lock) {

        FileInfo fInfo = Context.fsHandler.getReplicatedFiles().get(fileName);
        String myID = Context.myInfo.getId().toString();

        Message abortMsg = getAbortMessage();
        abortMsg.setFileName(fileName);
        abortMsg.setNodeID(myID);

        for (Entry<String, P> entry : fInfo.getP().entrySet()) {
            String key = entry.getKey();

            // Dont send done message to myself
            if (key.equals(myID)) {
                continue;
            }
            P pi = entry.getValue();
            String ID = pi.getNodeID();
            Node node = Context.nodeInfos.get(Integer.parseInt(ID));
            String hostName = node.getHost();
            Integer port = Integer.parseInt(node.getPort());
            Integer count = pi.getCount();

            for (int i = 1; i <= count; i++) {
                try {
                    TCPClient.sendMessage(abortMsg, hostName, port, ID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }// For every time we received lock message from this node ends

        }// For each Pi in P we send done read message to unlock

        fInfo = resetFlags(fInfo);
        //fInfo.setReadWriteLock(rwLock);
        Context.fsHandler.getReplicatedFiles().put(fileName, fInfo);
    }


}

protected abstract Message getAbortMessage();

private void exponentialBackOff() {

    // Exponential Backoff
    long backoffDuration = 50;
    try {
        backoffDuration = Context.backoff.nextBackOffMillis();
    } catch (IOException e) {
        e.printStackTrace();
    }
    logger.debug("Backoff for " + backoffDuration);
    if (backoffDuration > Context.backoff.getMaxIntervalMillis()) {
        Context.backoff.reset();
    }

    try {
        Thread.sleep(backoffDuration);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}
}

The server class that receives requests from the client. As a note I didn't want to do the massive IF ELSE block but I was having trouble deserializing implementations of the Message interface using GSON. Was pressed for time so didn't implement a custom deseralizer.



    package comm;

    import info.siyer.aos.clock.VectorClock;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;

    import com.google.gson.Gson;

    import core.Context;
    import message.AbortReadMessage;
    import message.AbortWriteMessage;
    import message.DoneReadMessage;
    import message.DoneWriteMessage;
    import message.Message;
    import message.ReadMessage;
    import message.ReadSuccessMessage;
    import message.WriteMessage;
    import message.WriteSuccessMessage;
    import message.handler.AbortReadMessageHandler;
    import message.handler.AbortWriteMessageHandler;
    import message.handler.DoneReadMessageHandler;
    import message.handler.DoneWriteMessageHandler;
    import message.handler.ReadMessageHandler;
    import message.handler.ReadSuccessMessageHandler;
    import message.handler.WriteMessageHandler;
    import message.handler.WriteSuccessMessageHandler;


    /*
     * This class implements a singleton TCP server.
     */

    public class Server extends Thread {

        private static Server server = null;
        public static volatile Boolean isRunning = true;
        public static volatile Boolean isFailed = false;
        public static ServerSocket serverSock = null;
        private static Integer port = 100;
        private static Logger logger = null;
        private static Gson serverGson = new Gson();
        public void setPort(Integer por) {
            port = por;
        }

        //Private constructor
        private Server() {

        }

        //Get singleton instance if it exists, otherwise create it and return instance.
        public static Server getInstance() {
            logger = LogManager.getLogger(Server.class);

            if (server == null) {
                server = new Server();
                server.setName("Server");
            }
            return server;
        }

        @Override
        public void run() {
            Logger logger = LogManager.getLogger(Server.class);
            logger.debug("Starting TCP Server to listen for CS Requests");
            go();

        }


        public static void go()
        {
            try
            {
                //Create a server socket at port 5000
                serverSock = new ServerSocket(Server.port);
                logger.info("Server listening on port:" + Server.port);
                //Server goes into a permanent loop accepting connections from clients          
                while(isRunning)
                {
                    logger.debug("Accpeting Requests now..");
                    //Listens for a connection to be made to this socket and accepts it
                    //The method blocks until a connection is made
                    Socket sock = serverSock.accept();
                    BufferedReader inFromClient =
                               new BufferedReader(new InputStreamReader(sock.getInputStream()));
                    StringBuilder sb = new StringBuilder();
                    String line = inFromClient.readLine();
                    while(line != null){
                        sb.append(line);
                        line = inFromClient.readLine();
                    }
                    logger.debug("Started Request Handler to handle request.");

                    //Handle Message String
                    String messageStr       = sb.toString();
                    Message message         = null;
                    if(messageStr.contains("\"READ\"")){
                        message = serverGson.fromJson(messageStr, ReadMessage.class);
                    } else if(messageStr.contains("\"READSUCCESS\"")){
                        message = serverGson.fromJson(messageStr, ReadSuccessMessage.class);
                    }else if(messageStr.contains("\"DONEREAD\"")){
                        message = serverGson.fromJson(messageStr, DoneReadMessage.class);
                    }else if(messageStr.contains("\"WRITE\"")){
                        message = serverGson.fromJson(messageStr, WriteMessage.class);
                    }else if(messageStr.contains("\"WRITESUCCESS\"")){
                        message = serverGson.fromJson(messageStr, WriteSuccessMessage.class);
                    }else if(messageStr.contains("\"DONEWRITE\"")){
                        message = serverGson.fromJson(messageStr, DoneWriteMessage.class);
                    }else if(messageStr.contains("\"ABORTWRITE\"")){
                        message = serverGson.fromJson(messageStr, AbortWriteMessage.class);
                    }else if(messageStr.contains("\"ABORTREAD\"")){
                        message = serverGson.fromJson(messageStr, AbortReadMessage.class);
                    } else {
                        logger.error("Could not determine message type, Aborting");
                        continue;
                    }

                    String messageType = message.getType();
                    logger.debug(messageType);
                    VectorClock msgClk = null;
                    logger.debug(message.getClock());

                    if(message.getClock() != null){
                         msgClk = VectorClock.deserializeClock(message);
                         synchronized (Context.lock) {
                                Context.clock = Context.clock.merge(msgClk);
                                Context.clock.increment(message.getNodeID());
                            }
                    } else {
                        logger.debug("Did not find clock");
                    }

                    logger.debug(messageStr);

                    if(isFailed){
                        logger.debug("SERVER DOWN. IGNORING REQUEST.");
                        continue;
                    }
                    if(messageType.equals("READ")){
                        new ReadMessageHandler().handleMessage(message);
                    } else if (messageType.equals("WRITE")){
                        new WriteMessageHandler().handleMessage(message);
                    } else if (messageType.equals("READSUCCESS")){
                        new ReadSuccessMessageHandler().handleMessage(message);
                    } else if (messageType.equals("WRITESUCCESS")){
                        new WriteSuccessMessageHandler().handleMessage(message);
                    } else if (messageType.equals("DONEREAD")){
                        new DoneReadMessageHandler().handleMessage(message);
                    } else if (messageType.equals("DONEWRITE")){
                        new DoneWriteMessageHandler().handleMessage(message);
                    }else if (messageType.equals("ABORTREAD")){ 
                        new AbortReadMessageHandler().handleMessage(message);
                    }else if (messageType.equals("ABORTWRITE")){
                        new AbortWriteMessageHandler().handleMessage(message);
                    }else {
                        logger.error("Unable to handle unkown message type");
                    }

                }//While Server is Running ENDS

            }//Try Block ENDS
            catch(IOException ex)
            {
                if(isRunning == true){
                    ex.printStackTrace();
                    logger.error(ex.getMessage());
                }
                else {
                    logger.info("Server Shut Down");
                }

            }
            finally{
                try {
                    serverSock.close();
                } catch (IOException e) {
                    if(isRunning == true){
                        e.printStackTrace();
                        logger.error(e.getMessage());
                    }
                    else {
                        logger.info("Server Shut Down");
                    }
                }
            }//Finally ShutDown Server gracefully
        }

    }
    

One of the message handler class, other handlers are pretty much the same or simpler.

public class ReadMessageHandler implements MessageHandler<Message>{

static final Logger logger = LogManager.getLogger(ReadMessageHandler.class);

@Override
public void handleMessage(Message message) {

    String toNodeId = message.getNodeID();
    logger.debug("In READ Message Handler from "+toNodeId);
    synchronized(Context.lock)
    {
        if(message.getType().equals("READ"))
        {
            String fName    = message.getFileName();
            FileInfo fInfo  = Context.fsHandler.getReplicatedFiles().get(fName);

            Semaphore  rwLock=fInfo.getFileSemaphore();
            if(rwLock.tryAcquire())
            {
                //1. Get Read Content
                //2. Get clockVN, RU from FInfo
                //3. Serialize clock form context
                //4. use TCP client to send
                //Preserve the state.
                String content="";
                try {
                    content=Context.fsHandler.getFilesystem().read(fName);
                } catch (FileNotFoundException e) {
                    logger.error("File Not found exception");
                    e.printStackTrace();
                } catch (NoSuchElementException e) {

                    logger.error("There is no element in the FileSystem");
                    e.printStackTrace();
                }
                int RU=fInfo.getReplicasUpdated();
                int VN=fInfo.getVersionNumber();
                String clockStr=VectorClock.serializeClock(Context.clock);
                Message readSuccessMessage=new ReadSuccessMessage();
                readSuccessMessage.setClock(clockStr);
                readSuccessMessage.setContent(content);
                readSuccessMessage.setFileName(fName);
                readSuccessMessage.setRU(RU);
                readSuccessMessage.setVN(VN);
                readSuccessMessage.setNodeID(Context.myInfo.getId().toString());
                Node toNode=Context.nodeInfos.get(Integer.parseInt(toNodeId));
                Integer port= Integer.parseInt(toNode.getPort());
                String hostName = toNode.getHost();
                try {
                    TCPClient.sendMessage(readSuccessMessage, hostName, port, toNodeId);
                } catch (IOException e) {
                    logger.error("Unable to send message to Node: "+toNodeId);
                    e.printStackTrace();
                }
                fInfo.setFileSemaphore(rwLock);
                Context.fsHandler.getReplicatedFiles().put(fName, fInfo);
            }
            //No else was required since that is the case of abort.
        }
    }       
}

}

The Context class (used to share state between Client & Server including locks for Critical Sections)

package core;

import info.siyer.aos.clock.VectorClock;

import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.math3.distribution.ExponentialDistribution;

import com.google.api.client.util.ExponentialBackOff;

import config.Node;
import filesystem.FileSystemHandler;

/*
* Shared application context
*/
public class Context {

public static volatile Object lock = new Object();
public static volatile FileSystemHandler fsHandler;
public static volatile ExponentialDistribution requestDelay;
public static volatile Node myInfo;
public static volatile ConcurrentHashMap<Integer, Node> nodeInfos = new ConcurrentHashMap<>();
public static volatile ExponentialBackOff backoff;
public static volatile VectorClock clock;
public static volatile String DU = "1";
}
\$\endgroup\$
2
  • \$\begingroup\$ How much code are we talking about? We'll only review what you post here. Trust me, we see some large posts 'round these parts. \$\endgroup\$
    – RubberDuck
    Jul 2, 2015 at 18:49
  • \$\begingroup\$ Alright, I'll go ahead and post the 5 - 6 classes which are most important. Most of the other stuff is just for testing/user simulation. \$\endgroup\$
    – Sid
    Jul 2, 2015 at 21:00

1 Answer 1

2
\$\begingroup\$
if(split.length == 1){
    operation = split[0];
} else {
    operation = split[0];
    fileName = split[1];
}

Looks like you could simplify this...

operation = split[0];
if(split.length != 1){
    fileName = split[1];
}

public class Server extends Thread {

Don't extend Thread. Implement Runnable instead. By extending Thread it's not possible for constructs like thread pools to run your server. What's more, "restarting" a server isn't possible either, because a thread that has stopped cannot be restarted. You can, however, rerun a runnable on a new Thread.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.