From 8f283439e5fd25e7ecd94747e5c7158dc72c5cd6 Mon Sep 17 00:00:00 2001
From: Daniel Lucas <dl3g19@soton.ac.uk>
Date: Mon, 10 May 2021 14:58:20 +0100
Subject: [PATCH] Minor improvements to system to reduce errors and rebalance
 after a disconnect

---
 Controller.java                  |  79 +++++++++-----
 CrashTesting.sh                  |  24 +++++
 CrashTesting2.sh                 |  16 +++
 RebalanceLock.java               |   2 +-
 error.txt                        | 172 ++++++++++++++++++++++++++-----
 loggers/ControllerLogger.class   | Bin 0 -> 1638 bytes
 loggers/DstoreLogger.class       | Bin 0 -> 1492 bytes
 loggers/Logger$LoggingType.class | Bin 0 -> 1041 bytes
 loggers/Logger.class             | Bin 0 -> 2112 bytes
 9 files changed, 241 insertions(+), 52 deletions(-)
 create mode 100755 CrashTesting.sh
 create mode 100755 CrashTesting2.sh
 create mode 100644 loggers/ControllerLogger.class
 create mode 100644 loggers/DstoreLogger.class
 create mode 100644 loggers/Logger$LoggingType.class
 create mode 100644 loggers/Logger.class

diff --git a/Controller.java b/Controller.java
index 07d5edc..d3fe6ff 100644
--- a/Controller.java
+++ b/Controller.java
@@ -14,12 +14,6 @@ import java.util.HashSet;
 import java.util.Collection;
 import java.util.Collections;
 
-/*
-TO DO:
-Get rid of missing REMOVE_ACKs problem
-Distrbute files evenly (check spec for correct number of files on each store)
-*/
-
 public class Controller {
 	protected int cport; //Port to listen on
 	protected int rFactor; //Replication factor; each file is replicated across r Dstores
@@ -285,7 +279,7 @@ public class Controller {
 				synchronized(index) {
 					if(index.containsKey(filename)) {
 						entry = index.get(filename);
-						if(entry.getStatus() == IndexEntry.Status.REMOVE_IN_PROGRESS || entry.getStatus() == IndexEntry.Status.REMOVE_COMPLETE) {
+						if(entry.getStatus() == IndexEntry.Status.REMOVE_COMPLETE) {
 							index.remove(filename);
 						}
 						else {
@@ -362,7 +356,7 @@ public class Controller {
 				
 				//Remove file from index
 				synchronized(index) {
-					index.remove(filename);
+					if(index.containsKey(filename) && index.get(filename) == entry) index.remove(filename);
 				}
 			}
 		}
@@ -438,18 +432,15 @@ public class Controller {
 	void remove(Socket client, String filename) throws Exception {
 		try {
 			IndexEntry entry;
-			System.out.println("About to remove " + filename);
 			try {
 				synchronized(index) {
 					entry = index.get(filename);
 					if(entry == null || entry.getStatus() != IndexEntry.Status.STORE_COMPLETE) {
-						System.out.println("Oops, " + filename + " does not exist!");
 						throw new InvalidStatusException();
 					}
 					
 					//Update index to "remove in progress"
 					entry.setStatus(IndexEntry.Status.REMOVE_IN_PROGRESS);
-					System.out.println("Remove status for " + filename + " set!");
 				}
 			}
 			catch(InvalidStatusException e) {
@@ -457,7 +448,6 @@ public class Controller {
 				clientOut.println(Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN);
 				clientOut.flush();
 				messageSent(client, Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN);
-				System.out.println("Informed client that " + filename + " does not exist");
 				return;
 			}
 			
@@ -481,7 +471,7 @@ public class Controller {
 						}
 						else {
 							//Log error
-							System.out.println("Dstore " + dstore + " should have sent REMOVE_ACK but Controller received " + message[0]);
+							System.err.println("Dstore " + dstore + " should have sent REMOVE_ACK but Controller received " + message[0]);
 						}
 					}
 					catch(DstoreDisconnectException e) {
@@ -494,7 +484,7 @@ public class Controller {
 			//Wait for REMOVE_ACKs from all Dstores which were sent the REMOVE message
 			if(!latch.await(timeout, TimeUnit.MILLISECONDS)) {
 				//Log error
-				System.out.println("Not all REMOVE_ACKs have been received");
+				System.err.println("Not all REMOVE_ACKs have been received");
 			}
 			
 			//Update index to "remove complete"
@@ -582,6 +572,8 @@ public class Controller {
 			}
 			catch(Exception e) {e.printStackTrace();}
 			
+			if(dstoreFiles.isEmpty()) throw new Exception("All dstores have been disconnected!");
+			
 			Map<Integer,List<String>> newAlloc = allocate(dstoreFiles);
 			Map<Integer,String> sendIndex = composeRebalanceMessages(dstoreFiles, newAlloc);
 			CountDownLatch latch = new CountDownLatch(sendIndex.size());
@@ -623,6 +615,7 @@ public class Controller {
 				System.out.print(i);
 			}
 			System.out.print("\n");
+			resetSequence();
 		}
 	}
 	
@@ -646,16 +639,28 @@ public class Controller {
 	  //move files from dstores that have too many files
 	  //prioritize storing these files to dstores that don't have enough files
 	Map<Integer,List<String>> allocate(Map<Integer,List<String>> oldDstoreFiles) {
-		//Precaution made so that the input map is not modified
 		Map<Integer,List<String>> dstoreFiles = new HashMap<Integer,List<String>>();
+		List<String> availableFiles = new ArrayList<String>();
 		for(Integer i : oldDstoreFiles.keySet()) {
 			List<String> files = new ArrayList<String>();
 			for(String s : oldDstoreFiles.get(i)) {
 				if(index.containsKey(s)) files.add(s);
+				if(!availableFiles.contains(s)) availableFiles.add(s);
 			}
 			dstoreFiles.put(i, files);
 		}
 		
+		//These files have been lost to crashes and need to be removed from the index
+		synchronized(index) {
+			Iterator<String> it = index.keySet().iterator();
+			while(it.hasNext()) {
+				String file = it.next();
+				if(!availableFiles.contains(file)) {
+					it.remove();
+				}
+			}	
+		}
+		
 		class AllocComparator implements Comparator<Integer> {
 			protected int m;
 			public AllocComparator(boolean ascending) {
@@ -765,6 +770,17 @@ public class Controller {
 			}
 		}
 		
+		Map<String,Integer> hasRequire = new HashMap<String,Integer>();
+		for(String file : requireIndex.keySet()) {
+			int count = 0;
+			for(Integer dstore : oldAlloc.keySet()) {
+				if(oldAlloc.get(dstore).contains(file)) {
+					count ++;
+				}
+			}
+			hasRequire.put(file, count);
+		}
+		
 		Map<Integer,String> messages = new HashMap<Integer,String>();
 		for(Integer dstore : newAlloc.keySet()) {
 			String thisMessage = "";
@@ -779,11 +795,18 @@ public class Controller {
 				if(oldFiles.contains(file)) {
 					filesToSend ++;
 					List<Integer> thisRequire = requireIndex.get(file);
-					thisMessage = thisMessage + " " + file + " " + thisRequire.size();
-					for(Integer otherStore : thisRequire) {
-						thisMessage = thisMessage + " " + otherStore;
+					int distribution = (int) Math.ceil((double) thisRequire.size() / (double) hasRequire.get(file));
+					//thisMessage = thisMessage + " " + file + " " + thisRequire.size();
+					int numberSentTo = 0;
+					String sentTo = "";
+					while(numberSentTo < distribution && !thisRequire.isEmpty()) {
+						Integer otherStore = thisRequire.get(0);
+						sentTo = sentTo + " " + otherStore;
+						thisRequire.remove(0);
+						numberSentTo ++;
 					}
-					it.remove();
+					thisMessage = thisMessage + " " + file + " " + numberSentTo + sentTo;
+					if(thisRequire.isEmpty()) it.remove();
 				}
 			}
 			
@@ -810,8 +833,9 @@ public class Controller {
 	void removeDstore(DstoreDisconnectException e) {
 		Integer port = e.getConnection().getPort();
 		synchronized(dstores) {
-			if(dstores.get(port).equals(e.getConnection())) dstores.remove(port);
+			if(dstores.containsKey(port) && dstores.get(port).equals(e.getConnection())) dstores.remove(port);
 		}
+		
 		try {e.getConnection().getSocket().close();} catch(IOException ee) {}
 		
 		Iterator<IndexEntry> it;
@@ -819,6 +843,8 @@ public class Controller {
 		while(it.hasNext()) {
 			it.next().removeStoredBy(port);
 		}
+		
+		rebalanceLock.queueRebalance();
 	}
 	
 	Iterator<Integer> sequenceIt = null;
@@ -828,10 +854,7 @@ public class Controller {
 		while(store == null) {
 			synchronized(sequenceLock) {
 				if(sequenceIt == null || !sequenceIt.hasNext()) {
-					synchronized(dstores) {
-						if(dstores.isEmpty()) return null;
-						sequenceIt = dstores.keySet().iterator();
-					}
+					if(!resetSequence()) return null;
 				}
 				
 				store = sequenceIt.next();
@@ -841,6 +864,14 @@ public class Controller {
 		return store;
 	}
 	
+	boolean resetSequence() {
+		synchronized(sequenceLock) { synchronized(dstores) {
+			if(dstores.isEmpty()) return false;
+			sequenceIt = new HashSet<Integer>(dstores.keySet()).iterator();
+		}}
+		return true;
+	}
+	
 	void messageSent(Socket socket, String message) {
 		ControllerLogger.getInstance().messageSent(socket, message);
 	}
diff --git a/CrashTesting.sh b/CrashTesting.sh
new file mode 100755
index 0000000..0aa4753
--- /dev/null
+++ b/CrashTesting.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+java -cp .:loggers Controller 8080 $1 $3 $4 &
+echo $!
+rsec=$(($4/1000))
+processes=()
+for((i=1; i<=$2; i++)) do
+	sleep 0.2
+	n=$((8080+$i))
+	echo $n
+	s="store$i"
+	java -cp .:loggers Dstore $n 8080 $3 $s &
+	processes+=($!)
+done
+sleep 2
+java -cp .:client-1.0.2.jar ClientMain 8080 $3
+sleep $rsec
+for((i=0; i<$(($2-$1)); i++)) do
+	kill ${processes[$i]}
+done
+sleep $rsec
+for((i=1; i<=$(($2-$1)); i++)) do
+	java -cp .:loggers Dstore $((8280+$i)) 8080 $3 "storeNEW$i" &
+	sleep 0.2
+done
diff --git a/CrashTesting2.sh b/CrashTesting2.sh
new file mode 100755
index 0000000..7363605
--- /dev/null
+++ b/CrashTesting2.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+java -cp .:loggers Controller 8080 $1 $3 $4 &
+echo $!
+rsec=$(($4/1000))
+processes=()
+for((i=1; i<=$2; i++)) do
+	sleep 0.2
+	n=$((8080+$i))
+	echo $n
+	s="store$i"
+	java -cp .:loggers Dstore $n 8080 $3 $s &
+	processes+=($!)
+done
+sleep 2
+java -cp .:client-1.0.2.jar ClientMain 8080 $3 &
+kill ${processes[0]}
diff --git a/RebalanceLock.java b/RebalanceLock.java
index c2ea297..effa59d 100644
--- a/RebalanceLock.java
+++ b/RebalanceLock.java
@@ -42,7 +42,7 @@ public class RebalanceLock {
 		highPriorityWait = false;
 	}
 	
-	public void queueRebalance() {
+	public synchronized void queueRebalance() {
 		synchronized(blockLock) {
 			periodBlock.countDown();
 		}
diff --git a/error.txt b/error.txt
index 8c2cb7d..308020f 100644
--- a/error.txt
+++ b/error.txt
@@ -1,10 +1,10 @@
-FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
+FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
+FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
@@ -16,115 +16,225 @@ FileAlreadyExistsException: Error trying to store file Grandad.txt - file alread
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
+FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file AllStar.txt - file already exists
+FileAlreadyExistsException: Error trying to store file Look_Away.mp3 - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file rap.mp3 - file already exists
+FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
+FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
+FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
+FileAlreadyExistsException: Error trying to store file Look_Away.mp3 - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
+FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
+FileAlreadyExistsException: Error trying to store file rap.mp3 - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file AllStar.txt - file already exists
+DstoreDisconnectException: Dstore at port 8081 has been disconnected
+	at DstoreConnection.getDisconnectData(DstoreConnection.java:52)
+	at DstoreConnection.localReceive(DstoreConnection.java:121)
+	at DstoreConnection.receive(DstoreConnection.java:92)
+	at Controller.lambda$store$1(Controller.java:317)
+	at java.base/java.lang.Thread.run(Thread.java:832)
+DstoreDisconnectException: Dstore at port 8081 has been disconnected
+	at DstoreConnection.getDisconnectData(DstoreConnection.java:52)
+	at DstoreConnection.receive(DstoreConnection.java:84)
+	at Controller.lambda$store$1(Controller.java:317)
+	at java.base/java.lang.Thread.run(Thread.java:832)
+DstoreDisconnectException: Dstore at port 8081 has been disconnected
+	at DstoreConnection.getDisconnectData(DstoreConnection.java:52)
+	at DstoreConnection.receive(DstoreConnection.java:84)
+	at Controller.lambda$store$1(Controller.java:317)
+	at java.base/java.lang.Thread.run(Thread.java:832)
+DstoreDisconnectException: Dstore at port 8081 has been disconnected
+	at DstoreConnection.getDisconnectData(DstoreConnection.java:52)
+	at DstoreConnection.receive(DstoreConnection.java:84)
+	at Controller.lambda$store$1(Controller.java:317)
+	at java.base/java.lang.Thread.run(Thread.java:832)
+DstoreDisconnectException: Dstore at port 8081 has been disconnected
+	at DstoreConnection.getDisconnectData(DstoreConnection.java:52)
+	at DstoreConnection.receive(DstoreConnection.java:84)
+	at Controller.lambda$store$1(Controller.java:317)
+	at java.base/java.lang.Thread.run(Thread.java:832)
+Not all STORE_ACKs have been received
+Not all STORE_ACKs have been received
+Not all STORE_ACKs have been received
+Not all STORE_ACKs have been received
+Not all STORE_ACKs have been received
+FileAlreadyExistsException: Error trying to store file Look_Away.mp3 - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file rap.mp3 - file already exists
-	at Client.a(SourceFile:277)
-	at Client.store(SourceFile:183)
+java.net.SocketTimeoutException: Read timed out
+	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
+	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
+	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
+	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
+	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982)
+	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
+	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
+	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
+	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
+	at Client.store(SourceFile:239)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file AllStar.txt - file already exists
+FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file rap.mp3 - file already exists
+FileAlreadyExistsException: Error trying to store file spurk.jpg - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
+FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
+java.net.SocketTimeoutException: Read timed out
+	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
+	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
+	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
+	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
+	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982)
+	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
+	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
+	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
+	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
+	at Client.store(SourceFile:239)
+	at Client.store(SourceFile:156)
+	at ClientMain.test2Client(ClientMain.java:44)
+	at ClientMain$1.run(ClientMain.java:26)
+java.net.SocketTimeoutException: Read timed out
+	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
+	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
+	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
+	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
+	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982)
+	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
+	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
+	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
+	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
+	at Client.store(SourceFile:239)
+	at Client.store(SourceFile:156)
+	at ClientMain.test2Client(ClientMain.java:44)
+	at ClientMain$1.run(ClientMain.java:26)
+FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
+FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file rap.mp3 - file already exists
+FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
+FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file Grandad.txt - file already exists
+java.net.SocketTimeoutException: Read timed out
+	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
+	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
+	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
+	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
+	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982)
+	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
+	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
+	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
+	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
+	at Client.store(SourceFile:239)
+	at Client.store(SourceFile:156)
+	at ClientMain.test2Client(ClientMain.java:44)
+	at ClientMain$1.run(ClientMain.java:26)
+FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file spurk.jpg - file already exists
+java.net.SocketTimeoutException: Read timed out
+	at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
+	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
+	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
+	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
+	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982)
+	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:297)
+	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
+	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:181)
+	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
+	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
+	at Client.store(SourceFile:239)
+	at Client.store(SourceFile:156)
+	at ClientMain.test2Client(ClientMain.java:44)
+	at ClientMain$1.run(ClientMain.java:26)
+FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
@@ -136,7 +246,7 @@ FileAlreadyExistsException: Error trying to store file Unknown.txt - file alread
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file spurk.jpg - file already exists
+FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
@@ -148,19 +258,27 @@ FileAlreadyExistsException: Error trying to store file Grandad.txt - file alread
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file AllStar.txt - file already exists
+FileAlreadyExistsException: Error trying to store file SnowHalation.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file PumpkinHill.txt - file already exists
+FileDoesNotExistException: Error trying to load or remove file spurk.jpg - file does not exist
+	at Client.remove(SourceFile:505)
+	at ClientMain.test2Client(ClientMain.java:57)
+	at ClientMain$1.run(ClientMain.java:26)
+FileDoesNotExistException: Error trying to load or remove file Look_Away.mp3 - file does not exist
+	at Client.remove(SourceFile:505)
+	at ClientMain.test2Client(ClientMain.java:57)
+	at ClientMain$1.run(ClientMain.java:26)
+FileAlreadyExistsException: Error trying to store file AllStar.txt - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
 	at ClientMain.test2Client(ClientMain.java:44)
 	at ClientMain$1.run(ClientMain.java:26)
-FileAlreadyExistsException: Error trying to store file Unknown.txt - file already exists
+FileAlreadyExistsException: Error trying to store file GameDotCom.jpg - file already exists
 	at Client.a(SourceFile:277)
 	at Client.store(SourceFile:183)
 	at Client.store(SourceFile:156)
diff --git a/loggers/ControllerLogger.class b/loggers/ControllerLogger.class
new file mode 100644
index 0000000000000000000000000000000000000000..d1501ec440c94f5a395d546f4a803efe8e9d29ca
GIT binary patch
literal 1638
zcmX^0Z`VEs1_mpJ08R!b24;2!79Ivx1~x_p0q6X@lA`>aoYW$p{PgtHB1Q&|%)H`~
z#JuEGMg}1tbZKiY1||j$9tKVZE=C46o6Nk-5<5l)aSb1cZWR!fnU@|?S&(Y28OF}Q
z!^j|<l~|UjpP8@k>F-*RoLW$lnV-kOz{kj-f^N7%Vop(NVoId~$k@!poXq0X6fOpC
z1_6+Lf{YBJ8a`mNauV~>^@B@_GV{{GmIyO4NFgMGO7luGb5oJ*5@lr2#jq<Qu~;E5
zzeFJ^H8l^}LWRoI5-tWI1_3Sx2?h>!21!N+HjuAUi#Qmh85y{e;Q_|QAj=@f&LGdj
zpunKW$iNSFLSAZ#esF$rc4`SD15bKtiBEoVVopGQQ3)dhvxcT8NRKiPg9=CkdwOaK
zNJfZ(fkBOjL7hQ^kwH8+F+0^cKQB44Bs{Yu!#N)u7bV4@F!uEH)Wi$`P=sjlFlaLf
zGBPmd<fk(-@ca0?$Gds@xW)&Ey198qfZ`GCHso+)WZ;Dv9+sF>n##z)0t$6T1{UZ1
zlvI!*nR%&xrMXF|MInhvIjM{cyul@j$=SY%1yDX0JcNrG8MxC^OFY4D1*IDi4Nc6H
z!^j{24v%!V%$(HV(zLY93PuKyN-S>UNhvPLFG}^w&&*3rK}0+vaIHNx!x$MjY?5<8
zuC@aQZWtp2S8#r5QF1EC21W)^^f=c8*~G{o;FO<VQe0A$Sm2vll98WM%+JQ)z{TLm
z;Ka`042lOAMg|p-QhjiMW#*OTXQx8b8zgGn5|c~viz*ozW+10Xs6vRL9*KD=IjO}e
zKKc3Cr3KcQ@rERVq7j^RkR+k$JQ_*JKPf9Uxx^YdF+h!QPRz*(&MZl_=3sDRWDt(_
zOD$J$0SBc5qXMIiE@Lbs1CM83UTTqZPGWI!YB4*5Cn$M<vp#a>Wn|z6C3<L9W@qqW
zWKhKj5^O$YXYgZWki)MOoTEU&!l1~&#2~@Iz`(>H#h}BW%fQH>2jy{r$|nW}1~vvx
z27LxlA~#@QVDM#NW?*DsV36O$z<8WNa5n=}q}Fx@_RS28%NclgGjK-=@os0}-@g%T
zh#><5gAfA?0|Ns$0~-Smg9rm3gB$}tgAoG*0}BI_2q%Lvn8nDz&A`cE!eGk4$N;j$
zmVuc81Vq4=@a|?1iWCyr&LFmb69eN0xXFBARYDAG48jZo3?g7tnHd-b7+64sBLfrI
zC?y6a1}2a%w6wP~h=ZKP$N+K{$Uh7W5)7;il1PqVVK8GbhdM%<ff4LeW+5q%oe*to
zU?EusMg|K8OQ=G91{SbOgtcU}w=saQ(k=#728L}6n&|c^G6*p!F>o+gF<3)2gNy=s
zm6dTb10zB?#2yX?W(FIue{C7;7#J8h7#JDs85kK{8Qj4k%f#TpAi?0}Aj#m(;LG68
GAPE4YWP+^#

literal 0
HcmV?d00001

diff --git a/loggers/DstoreLogger.class b/loggers/DstoreLogger.class
new file mode 100644
index 0000000000000000000000000000000000000000..ac67d99e6bd1c551748d3b73a4e7891edbc42419
GIT binary patch
literal 1492
zcmX^0Z`VEs1_mnzcTNT-24;2!79Ivx1~x_p9+%>h{GwE!{PgtHB1Q&|%)H`~#JuEG
zMg~3~WGQPd1||j$9tKVZE=C46o6Nk-5<5l)2@M~JP8AT9nU@|?S&(Y&sTs!3z{AKO
zoRwIXsGpgy@9FPak(^pkl9`{!!NAAJpnz<$LSjx)YGO*I0?5qF#GK6H)D$iTZUzC6
zWrB<hq8dJ6b8-^%()EK&iZb)ktw9zDGcrgaB!WuwN-}d(k?av=WY9#hCnK>~Auqo~
zAt^OA57{z>%G44r1|bFkE(Qq(Np=P)kj2uB3~V4jfdWMwt1mUfgcukYWO*3m7~~ll
z#B&p~Q=Rkkk`qh9GfOg@^TFX*QVepxrzWNkK+&Mc!=S{V%*eo-lb`OEnUfk^nwFMX
z!N?$lshp94-^brQ-p$j;H9k1h&CN4{k%1RxNmyb|X(|VUIwJ#H3OF_y8CXDp$;iOs
zoS%{k(wmu=>Q|bZlv)&$n3R*s$iN$1l9-(Bn^*wlbHM|yn2~`yJ+;IW?0!%>5YW&>
zO$m$)0_mwGKB#UM(ZJ$KMg|U><Q$Mw>=+rCH8jH*8MuP;ON)|ILEdF#5JZk2Jy2va
zG6*>3=a&?h6eSk;rj}&nrxf$EF_?2PSTI<!GgyHF+nSL<1*B9ToFFpu%JQ>Qq3Hq=
z{%(oMCHX~_j0`i7Qw~%i#88jKyp){OVilkK{Or;KYs~OQ5<$@jPTxq9(DWFMB;=oz
zm6}{)jT{_MBb*a+a)L8UQmr`{Y#A9iAaNDX$jHFsnU|MZ<eZaOT%20W&fow_0^kgZ
zoUIrcxIqaLn#tH1oEaHZF~R|x_t+U+85!j8D+Q-^P*^Z1GB7bnFfcGMGe|M0Feo!H
zGN>{zFfcKwF>rxO3<d@UAyBGiU|?Wn;AGHX0F?`x3=9l@3@i*x3=9kkn;006GYIWw
zV2ad|-p;_jnSpUR1MhAI?noit?F{_;H-b&m0-M9az`(%6z{bGKAj-hcAkQGcpv}Ml
zGDnn?K?lrYWZ-7tWYA^MV_;+e*<#DU%m4x+U|V>1GYCZriEL*O+rNo{aRc0BKCmib
z1~vu}1_1_9u&K-pi~<ZSpz@1>32c-Bs32ruU=YyK-p(MdC9{h`hJj%#g96Bbj0_+L
zLX44QU}cbE;AfCVauN%JK7#?&NwN%#42+=Q(AvVF0CEFFGaFb?o`HkGkiiH^DaiG#
zjGGx45%xfovNJF<7=yiF!eGk4z`()4$Y936$Y8@@2M#PI273kx21f@;1}6p=1~&#t
E0FMA*(EtDd

literal 0
HcmV?d00001

diff --git a/loggers/Logger$LoggingType.class b/loggers/Logger$LoggingType.class
new file mode 100644
index 0000000000000000000000000000000000000000..a62bda1d6229f4047dd872fda4e641c5170aa594
GIT binary patch
literal 1041
zcmX^0Z`VEs1_mnz3r+?m24;2!79Ivx1~x_pA)oy8^wc615S5vi9#UD5%E-X366WX=
z>Ke?*AR6rhl0j8q&BegMz{$?Q#>2qHz|F|Onw*oLm&(W>qM_-Nl~|UjpOcuEuJ50e
zm6}{)&BegWz{k$O&%+?VAjrtThfv^}SDMSnz+RS^Q=00Z#>il*fu!3xC$YHL8c86y
zq$o2l-5S{jkO5%xg?Si67(^Kv*laTMGE3|j8N`r{g6j0t4C7!BXJlaW^N;uOcjsbY
zVh{!eh7=EjID<4Jg9tXCaxlm;G6?wl#fP{C`Fi>}`o#PD`9y-W$@4JCGDveUC^9ne
z`1{4XdHT4*<&=3C6hU&Tj0_?$IY&PixFI0@>O2gpAZyvc{x4=^5ZBPe8rX~sEYA5U
zsf-N#KACx`ex<odsYM})Nja&E3>sLxsfo=Sj0~K?ndy0nC8b5Fj10^gnqiC#95%^0
z(BM)-3TIHD+F&!o&YF>dD>%QjC^^+F6J$F#BxUG<Vw91A!!NbC#3R4Bgq^{Zk%0{&
z$H>6rnU|MZ1dh$rVnznA9%wpqFl1n2;ALQ7V0DlLMF9hYgCr<S!L%ZSG?-Qe(E?JS
z#LB?Hz{0@EpuwQYz{sG*z`&ryz{mgsT$>mew=u9EVBpxmz`(%Bpv}O*zy_9MXW(QI
zV9<f9X9A0I2{CEyVBk5xz=Wxu36zo;n84=CGcYqSGcYi)YiY}DXAs(mVYn^>0|OI-
z9s>u1K7$_Ak{SjUkee7nb~7+V3W+gqXOP&;APMHkuz)#oV2%PSn4<*dsIY-KYV3O%
zm?D`sF-QhSvTS0I3yx&n#Gn)$$+n3>EqF5nBf<q@46F<c3>*x+44e#73|tKA4BQMR
m4D1Xn3=lUNFc^Z}X2f6&rcD^k7#JA17#JCt7)%(<9V7w0gVDeM

literal 0
HcmV?d00001

diff --git a/loggers/Logger.class b/loggers/Logger.class
new file mode 100644
index 0000000000000000000000000000000000000000..642bbf6cfdb1489289c40fc83829f40627162802
GIT binary patch
literal 2112
zcmX^0Z`VEs1_mpJGA;%t24;2!79Ivx1~x_pfvm)`ME#t^ymWp4q^#8B5=I6#o6Nk-
z5<5l)W)00SP6iGJPId+^9tLg(9!3T>pZxUn)FMU(?wtJe^vt~UkjjEoMg|cdh`0)f
zf{I#$wDR#V@G}T7GB6bsGct(!fGx|+*AFPl%qs~lDN0SuwPt4!Vq_4;BE!YN!63rJ
zAj%-d$RLoOTH=$R?v|O88eE!|mRZ5bAfllOF%Rtc;F6-uymV_W1_=g9b_OXP25ANv
z6yF6`7MG;vGBOAzmlhSJ=9PqG=BD~)=Hz4+gFWgc#K6EH$HO4cpuor=o|~AR>YSgK
zoLCZ`S(4$LpI2Oxm{(HF$e^x)X{Q%fcL*{lfr40>kwFxT9#FulGN`dLsPiyrfC5$s
z6mqFW$N|X6z~k>1@8;>_8t?Dt6UoV-%Am!=pbb(j0+Vp`bBPae4f6H$bMyfz(B)y!
z11S*j_k)Xrb%O%afQP}5!HAK8GbcYiBp(!(V6R7k<V<)NOc~4=8TisuOORrRkwF|5
z%xKZZ#URLF!NXw5pv=g?UI2>EoIG|0Ygkl*BgM5MIkli9Ge3`u!HU6_hrte%;`qUe
zgG&;VvqOp!lT$&qJMb_#f?UQ6c3DVjQEp~lVh$&R1cNgVg9|7DG3S?-a51<sxU(~O
z@Gy8Xcrh~YgVRi2YKeYuesXqd2_pj!IF%$P<^<#ym4N-`3DV=k!{7_jzz*_Teo=`K
z10#b!D5?V(88kFJJu#ycYm9O*1o1EggZ#^!lb<fcz{KDW3Lb1pUo(u6fyFsLC6$qZ
z-zPIK)vq)+DYYmhF)1gNk%1TNci+SUD4z=+OvUUB(Xar_%-8qyhs!WBaOb8L7bm8t
z2B+qgFfyn?(-gw@)>wQI#>l`A)fSYRoSIpdn!?Dy6`WsMl$;8Qer`yz(*p%1BLlZz
zYH^8gD#)$Hj0^%!`S~TqB}It^zNsY{`6<QxYz!$}45<uh><sCk;LBiSPyuO#6d##+
zW%=2u`jCtW$vkd}$tC$km5dBCpw0!S3aCPep&p5ODLJXdDn9x7*`)<oJb~mb6pf&Q
z2aED(B=wL2%^Eo}p+-0-=HvutmZVy9Fk~?@urtOp>gD98b1>vEGH^sQ>e?~JDll>|
z<bioMx*#4S1CM83UTTqZPGWI!YB3`NIOL#39Xmr2BZDeNP+;>RJ3|R0gB*UP;9?dO
z94v|q91Khh3=B*RBB1h@fq{VqRGu<0FmN!iFt9R&GB7fPF)%P_F))GEacOO5VARsy
z%D}#nfq{XMA)JAMfscWifq_AgfrUYcfs;X)g#}ciGB7ZxfHFJ-6Ij0w0~-S)0|SGy
z))ofd;|x+-yBP!{wYD(`?_dz$#URVTu$@71D+4b`b_3Ws2!kaU*cl`l<QSwFA{ZDL
zm>C%57$U*$WMqh9U;!04P&e8!FoErm(%QnnzKKC)DcC&rO$?gL7}!~sGq5nPfg25R
zjU3oWHU?%9W(P(F7Elp^-7Fo#W+|bW70jRvH7f;FAu=#9sA+9u(4Wa5thJ57SbH0T
z`EmvhU!83XHd@;l>}N7?ZDMc&iEd<IWMF6DXAokrVqgM?uNVU>NH+sJgF1sag9d{f
zgC?k?2HVHMz#PQRV8z1Az{n885DT?YpMeD&C&F6V+ZbH6w=sC@>|*d^VA#eGh=?{&
zJ<Y(N%OJ#{$H2%ChhK9DR?UVCLJUR>EDZ7Ba7|!HgvN_1LlOf6g9rmNLox#+LnfHa
e29voA`3wvUprTEcfrFvIL6V`6p_rkRK@tE&dD@i#

literal 0
HcmV?d00001

-- 
GitLab