Because you can't update a written value without replacing the value, you have no other possibility to overwrite your metadata (currentTerm
and votedFor
) if they had changed.
For the log file you can use another approach by using an appendable FileOutputStream
, but you will get problems if you just use
logWriter = new ObjectOutputStream(new FileOutputStream("Server"+id+"Log", true));
because the ObjectOutputStream
is always writing a header first.
To overcome this problem you need to subclass the ObjectOutputStream
like
public class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
private boolean append = false;
public AppendableObjectOutputStream(String fileName, boolean appendIfExists) throws IOException {
super(new FileOutputStream(fileName, appendIfExists && Files.exists(Paths.get(fileName), LinkOption.NOFOLLOW_LINKS)));
append = appendIfExists && Files.exists(Paths.get(fileName), LinkOption.NOFOLLOW_LINKS);
}
@Override
protected void writeStreamHeader() throws IOException {
if (append) {
reset();
} else {
super.writeStreamHeader();
}
}
}
See also: http://stackoverflow.com/a/1195078/2655508
Using braces {}
for single statements while
loops too will make your code less error prone.
A ObjectInputStream
should like any other stream be closed after the usage is finished.
//if Log file exists then should exists Metadata too
Assuming that something should be can lead to problems. One could have deleted the metadatafile and you would get problems.
Your method is doing to many things. You should extract parts of it to separate methods. Like
private List<LogEntry> readLogFile(String fileName) throws IOException {
List<LogEntry> logs = new ArrayList<>();
if (Files.exists(Paths.get(fileName), LinkOption.NOFOLLOW_LINKS)) {
ObjectInputStream reader = new ObjectInputStream(new FileInputStream(fileName));
try {
//until there are LogEntry objects in the file, read them and add them to log
while (true) {
logs.add((LogEntry) reader.readObject());
}
} catch (EOFException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(reader != null){
reader.close();
}
}
}
return logs;
}
For reading the metadatafile I would suggest you create a MetaData
class which holds the voteFor
and Term
and is beeing written by using writeObject()
and read by readObject()
methods. The voteFor
and Term
should be initialized in the constructor to voteFor = -1
and Term = 1
.
This would give you the possibility to use this method
private MetaData readMetaDataFile(String fileName) throws IOException {
if (Files.exists(Paths.get(fileName), LinkOption.NOFOLLOW_LINKS)) {
ObjectInputStream reader = new ObjectInputStream(new FileInputStream(fileName));
try {
return ((MetaData) reader.readObject());
} catch (EOFException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(reader != null){
reader.close();
}
}
}
return new MetaData ();
}
Implementing the above mentioned points will lead to
MetaData metaData = null;
String logFileName = "Server" + id + "Log";
String metaDataFileName = "Server"+id+"Metadata";
try {
log = readLogFile(logFileName );
metaData = readMetaData(metaDataFileName);
logWriter = new AppendableObjectOutputStream(logFileName, true);
metadataWriter = new AppendableObjectOutputStream(metaDataFileName, false);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
but you should create the metadataWriter only if you really write the data.