아래에서 서버를 설정하기위한 생성자를 찾을 수 있습니다. 몇 즉, 그것이 읽기까지 있었던 마지막 시간에서 그 상태를 복원 List
객체를 (라고 log
)와 두 int
(라고 currentTerm
하고 votedFor
). 나는이 필요하므로이 "휘발성"모든 필드가 업데이트됩니다 때마다, 상대 파일도 업데이트 (그래서 일관된 상태를 upadate하게)해야 할 것 ObjectOutPutStream
이라고를 metadataWriter
하고 logWriter
. 서버가 언제든지 다운 될 수 있기 때문에 어떤 close()
방법도 쓸 수 없습니다 . EOFException
다음에 서버를 설정할 때 (읽기 작업 중) 를 피할 수있는 유일한 해결책은 flush()
매번 출력 스트림 (코드의 마지막 줄에서 수행 한 것처럼 )하는 것이라고 생각하십니까?
public ServerRMI(...)
{
...
log = new ArrayList<>();
try {
//if Log file exists then should exists Metadata too
if(Files.exists(Paths.get("Server" + id + "Log"), LinkOption.NOFOLLOW_LINKS))
{
reader = new ObjectInputStream(new FileInputStream("Server"+id+"Log"));
try
{
while(true)
log.add((LogEntry) reader.readObject());
}
catch (EOFException e){}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
reader = new ObjectInputStream(new FileInputStream("Server"+id+"Metadata"));
currentTerm = reader.readInt();
votedFor = reader.readInt();
}
else//if it is the first time that the server is set up initialize all persistent fields
{
currentTerm = 1;
votedFor = -1;
log = new ArrayList<LogEntry>();
}
logWriter = new ObjectOutputStream(new FileOutputStream("Server"+id+"Log"));
metadataWriter = new ObjectOutputStream(new FileOutputStream("Server" + id + "Metadata"));
//since creating a new ObjectOutputStream overwrite the old file with the an empty one, as first thing we rewrite the old content
for(LogEntry entry : log)
logWriter.writeObject(entry);
metadataWriter.writeInt(currentTerm);
metadataWriter.writeInt(votedFor);
metadataWriter.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
...
}
중요 사항:
누군가가 제안한 것처럼 리소스 를 사용하는 모든 방법 (및 서버의 상태를 업데이트하는 각 방법) 의 try-with-resources 가 실행 가능한 솔루션 이라고 생각하지 않습니다 . metadata
파일에 대해 괜찮을 것이기 때문입니다 int
. 파일을 업데이트 / 쓰기 할 때마다 항상 교체되지만, log
파일의 경우 변경 될 때마다 전체 목록을 작성하는 것을 의미합니다 (작업이 추가 될뿐만 아니라 교체도 마찬가지입니다!). 성능에 좋지 않다는 것!
try-with-resource를 사용하고 한 번에 전체 컬렉션을 작성하는 것이 좋으며 예외가 발생할 때까지 읽을 필요가 없습니다. 처음에 메타 데이터를 쓸 수 있습니다.
List<LogEntry> entries = ..
try (ObjectOutputStream out = new ObjectOutputStream(....)) {
out.writeObject(currentTerm);
out.writeObject(votedeFor);
out.writeObject(entries);
}
읽을 수 있습니다.
String currentTerm = "none";
String votedFor = "no-one";
List<LogEntry> entries = Collections.emptyList();
try (ObjectInputStream in = new ObjectInputStream(....)) {
currentTerm = (String) in.readObject();
votedFor = (String) in.readObject();
entries = (List<LogEntry>) in.readObject();
}
참고 : Java 7이 필요하지만 곧 EOL이 될 예정이므로 가능하면 Java 8로 업그레이드하는 것이 좋습니다.
성능에 좋지 않다고 생각합니다!
이것은 매우 다른 질문이지만 여전히 try-with-resource를 사용합니다. 해결책은 새 항목 만 추가하는 것입니다. 이렇게하려면 다음이 필요합니다.
성능이 나쁘다고 가정하기 전에 몇 밀리 초를 절약하기 위해 추가 된 복잡성이 가치가 없다는 것을 알 수 있으므로 테스트해야합니다.
BTW 당신이 정말로 성능에 관심이 있다면 ObjectOutputStream을 사용하지 마십시오. 일반적이고 유연하지만 매우 느립니다.
따라서 OutpuStreamObject (생성자 지역 변수가 아닌 클래스 필드)가 올바르게 닫히지 않습니다.
이 경우 파일이 손상됩니다. 파일의 유효성을 검사하고 유효하지 않은 데이터를 자르는 방법이 필요합니다.
내가 쓴 도서관을보세요. Chronicle Queue 지원하므로 많은 문제를 해결할 수 있습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다