Implemented a distributed chat room system that reads the different processes' info from a config.txt file. Includes different types of ordering for the messages such as FIFO (first-in first-out), causal ordering, and total ordering.
In order to execute the program, cd into the bin directory. Start the program in different terminals to simulate different processes:
- For basic unicast and multicast: java BasicProcess <process #> –– (java BasicProcess #)
- For FIFO ordering: java FIFOProcess <process #> –– (java FIFOProcess #)
- For causal ordering: java CausalProcess <process #> –– (java CausalProcess #)
- For total ordering: javaTotalProcess <process #> –– (java TotalProcess #)
In order to implement ordering, I included a couple of global variables for each process. Each process has a HashMap mapping every process ID to the MetaData associated with that process. The MetaData of a process includes process info such as a process's ID, IP, and port, the socket between the current process and that process, an ObjectOutputStream from that socket that allows the current process to communicate with that process, and a boolean open to indicate whether any messages have ever been sent to that process. In addition, every process has a hold back queue. Each type of ordering has a different Message type associated with it (Message, CausalMessage, TotalMessage). Although CausalMessage and TotalMessage should extended from Message, I did not have enough time to change it before submitting.
In order to implement causal ordering, I created a vector timestamp for each process. Every time a process multicasts a message out, it increments the number that correspondg.s to that process in its vector timestamp. For every single process, the multicasting process sends an object CausalMessage. A CausalMessage includes the message passed in, the vector timestamp of the multicasting process, the process ID of the multicasting process, and the MetaData of the destination process. When a process receives a CausalMessage, it creates a new thread for each message. Each thread delays the message by a random time (to simulate network delay) and then compares its vector timestamp with the vector timestamp of the CausalMessage (let's call it mesgTimes). Both vectors grab the element at the index of the current processID. If mesgTimes's element is equal to current vector timestamp's element + 1, then we check if all of the rest of the elements of the vector timestamps are greater than the mesgTimes. If true, we deliver the message. If not, we determine if the events are concurrent by checking if each neither the current vector timestamp ≤ mesgTimes nor vice versa. If concurrent, we deliver the message. Otherwise, we store the message in the hold back queue. Every time a message is delivered, we parse our hold back queue and determine if the messages queued are ready to be delivered by running the same algorithm on them. If true, we deliver them. Otherwise, we let them stay in the hold back queue.
In order to implement total ordering, I built off of FIFO ordering. Any time a process wants to multicast, it simply unicasts its message to process 1, which is always the sequencer in my program. When process 1 receives a message, it multicasts out that message to all other processes. Every other process will receive these messages in FIFO order from process 1. Thus, total ordering is guaranteed since all processes will receive messages in FIFO order from process 1 (the sequencer). Any time a process receives a message from processor 1 (the sequencer), it compares its timestamp to the timestamp sent with the message, using FIFO ordering to determine whether to deliver the message.