Looking for SYT9 5xHIT 25/26 test answers and solutions? Browse our comprehensive collection of verified answers for SYT9 5xHIT 25/26 at elearning.tgm.ac.at.
Get instant access to accurate answers and detailed explanations for your course questions. Our community-driven platform helps students succeed!
Im Raft-Paper die Regeln für die einzelnen Rollen der Server folgendermaßen definiert worden:
Im Java Code der Raft-grpc Implementierung ist folgende Funktion vorhanden:
private void startElection() {
if (suspended || state == NodeState.LEADER) {
return;
}
// Pre-vote phase: Check if election would be successful before disrupting cluster
log.info("Starting pre-vote phase for node {}", config.getNodeId());
boolean preVoteSuccessful = performPreVote();
if (!preVoteSuccessful) {
log.info("Pre-vote failed for node {}, not starting actual election", config.getNodeId());
startElectionTimer();
return;
}
log.info("Pre-vote successful! Starting actual election...");
logEvent(RaftEvent.EventType.STATE_CHANGE,
"FOLLOWER → CANDIDATE");
state = NodeState.CANDIDATE;
currentTerm.incrementAndGet();
logEvent(RaftEvent.EventType.TERM_INCREASED,
"Term increased to " + currentTerm.get());
votedFor = config.getNodeId();
currentLeader = null;
// Persist state change (CRITICAL for Raft safety - must persist before sending RequestVote RPCs)
persistenceService.saveState(config.getNodeId(), currentTerm.get(), votedFor);
int votesReceived = 1;
int votesNeeded = (stubs.size() + 2) / 2;
log.info("Node {} starting election for term {}", config.getNodeId(), currentTerm.get());
logEvent(RaftEvent.EventType.ELECTION_START,
"Starting election, need " + votesNeeded + " votes");
int lastLogIndex = getLastLogIndex();
int lastLogTerm = getLogTermAt(lastLogIndex);
VoteRequest voteRequest = VoteRequest.newBuilder()
.setTerm(currentTerm.get())
.setCandidateId(config.getNodeId())
.setLastLogIndex(lastLogIndex)
.setLastLogTerm(lastLogTerm)
.build();
for (Map.Entry<String, RaftServiceGrpc.RaftServiceBlockingStub> entry : stubs.entrySet()) {
try {
VoteResponse response = entry.getValue().requestVote(voteRequest);
if (response.getTerm() > currentTerm.get()) {
becomeFollower(response.getTerm());
return;
}
if (response.getVoteGranted()) {
votesReceived++;
log.info("Received vote from {} ({}/{})", entry.getKey(), votesReceived, votesNeeded);
logEvent(RaftEvent.EventType.VOTE_GRANTED,
"Vote granted from " + entry.getKey() + " (" + votesReceived + "/" + votesNeeded + ")");
} else {
logEvent(RaftEvent.EventType.VOTE_DENIED,
"Vote denied from " + entry.getKey());
}
} catch (Exception e) {
log.warn("Failed to request vote from {}: {}", entry.getKey(), e.getMessage());
}
}
if (votesReceived >= votesNeeded && state == NodeState.CANDIDATE) {
logEvent(RaftEvent.EventType.ELECTION_WON,
"Won election with " + votesReceived + " votes");
becomeLeader();
} else {
log.info("Election failed. Votes received: {}, needed: {}", votesReceived, votesNeeded);
logEvent(RaftEvent.EventType.ELECTION_LOST,
"Lost election: " + votesReceived + "/" + votesNeeded + " votes");
startElectionTimer();
}
}
Welche Aussagen treffen dabei zu?
Im Raft-Paper ist die RPC Funktion RequestVote folgendermaßen definiert worden:
Im Java Code der Raft-grpc Implementierung ist die Funktion so implementiert worden:
public VoteResponse handleVoteRequest(VoteRequest request) {
log.info("Received vote request from {} for term {}", request.getCandidateId(), request.getTerm());
// Deny votes when suspended
if (suspended) {
log.info("Denying vote request - node is suspended");
return VoteResponse.newBuilder()
.setTerm(currentTerm.get())
.setVoteGranted(false)
.build();
}
if (request.getTerm() > currentTerm.get()) {
becomeFollower(request.getTerm());
}
boolean voteGranted = false;
if (request.getTerm() < currentTerm.get()) {
voteGranted = false;
logEvent(RaftEvent.EventType.VOTE_DENIED,
"Denied vote to " + request.getCandidateId() + " (stale term " + request.getTerm() + ")");
} else if (votedFor == null || votedFor.equals(request.getCandidateId())) {
int lastLogIndex = getLastLogIndex();
int lastLogTerm = getLogTermAt(lastLogIndex);
boolean logUpToDate = request.getLastLogTerm() > lastLogTerm ||
(request.getLastLogTerm() == lastLogTerm && request.getLastLogIndex() >= lastLogIndex);
if (logUpToDate) {
votedFor = request.getCandidateId();
voteGranted = true;
lastHeartbeat = System.currentTimeMillis();
// Persist vote (CRITICAL for Raft safety - must persist before responding)
persistenceService.saveState(config.getNodeId(), currentTerm.get(), votedFor);
startElectionTimer();
log.info("Voted for {}", request.getCandidateId());
logEvent(RaftEvent.EventType.VOTE_GRANTED,
"Granted vote to " + request.getCandidateId() + " for term " + request.getTerm());
} else {
logEvent(RaftEvent.EventType.VOTE_DENIED,
"Denied vote to " + request.getCandidateId() + " (log not up-to-date)");
}
} else {
logEvent(RaftEvent.EventType.VOTE_DENIED,
"Denied vote to " + request.getCandidateId() + " (already voted for " + votedFor + ")");
}
return VoteResponse.newBuilder()
.setTerm(currentTerm.get())
.setVoteGranted(voteGranted)
.build();
}
private void startElectionTimer() {
if (electionTask != null) {
electionTask.cancel(false);
}
int timeout = ThreadLocalRandom.current().nextInt(ELECTION_TIMEOUT_MIN, ELECTION_TIMEOUT_MAX);
electionTask = scheduler.schedule(this::startElection, timeout, TimeUnit.MILLISECONDS);
log.debug("Election timer started: {}ms", timeout);
}
Mit den folgenden gRPC Messages:
message VoteRequest {
int32 term = 1;
string candidateId = 2;
int32 lastLogIndex = 3;
int32 lastLogTerm = 4;
}
message VoteResponse {
int32 term = 1;
bool voteGranted = 2;
}
Welche Aussagen treffen dabei zu?
Im Raft-Paper ist die RPC Funktion AppendEntries folgendermaßen definiert worden:
Im Java Code der Raft-grpc Implementierung ist die Funktion so implementiert worden:
public AppendEntriesResponse handleAppendEntries(AppendEntriesRequest request) {
// Reject AppendEntries when suspended
if (suspended) {
log.debug("Rejecting AppendEntries - node is suspended");
return AppendEntriesResponse.newBuilder()
.setTerm(currentTerm.get())
.setSuccess(false)
.build();
}
lastHeartbeat = System.currentTimeMillis();
if (request.getTerm() > currentTerm.get()) {
becomeFollower(request.getTerm());
}
if (request.getTerm() < currentTerm.get()) {
return AppendEntriesResponse.newBuilder()
.setTerm(currentTerm.get())
.setSuccess(false)
.build();
}
if (state != NodeState.FOLLOWER) {
becomeFollower(request.getTerm());
}
currentLeader = request.getLeaderId();
startElectionTimer();
if (request.getEntriesCount() == 0) {
logEvent(RaftEvent.EventType.HEARTBEAT_RECEIVED,
"Heartbeat from leader " + request.getLeaderId());
}
// Check prevLogIndex/prevLogTerm consistency (logical indices)
int prevLogIndex = request.getPrevLogIndex();
if (prevLogIndex >= 0) {
// Check if we have the entry at prevLogIndex
int prevLogTerm = getLogTermAt(prevLogIndex);
if (prevLogTerm == 0 || prevLogTerm != request.getPrevLogTerm()) {
log.debug("Log consistency check failed at index {}: expected term {}, got {}",
prevLogIndex, request.getPrevLogTerm(), prevLogTerm);
return AppendEntriesResponse.newBuilder()
.setTerm(currentTerm.get())
.setSuccess(false)
.build();
}
}
// Process new entries (logical indices)
int newEntryLogicalIndex = prevLogIndex + 1;
int entriesAdded = 0;
List<LogEntry> entriesToPersist = new ArrayList<>();
for (GrpcLogEntry entry : request.getEntriesList()) {
int physicalIndex = logicalToPhysical(newEntryLogicalIndex);
// Check for conflicts
if (physicalIndex >= 0 && physicalIndex < raftLog.size()) {
if (raftLog.get(physicalIndex).getTerm() != entry.getTerm()) {
// Conflict detected - delete conflicting entries
synchronized (raftLog) {
raftLog.subList(physicalIndex, raftLog.size()).clear();
// Persist log deletion (CRITICAL for consistency)
persistenceService.deleteLogEntriesFrom(config.getNodeId(), newEntryLogicalIndex);
}
}
}
// Append if we don't have this entry
physicalIndex = logicalToPhysical(newEntryLogicalIndex);
if (physicalIndex >= raftLog.size()) {
// Convert gRPC entry back to internal LogEntry
LogEntry logEntry = convertFromGrpcLogEntry(entry);
synchronized (raftLog) {
raftLog.add(logEntry);
}
entriesToPersist.add(logEntry);
entriesAdded++;
}
newEntryLogicalIndex++;
}
// Persist all new entries in batch (CRITICAL for durability)
if (!entriesToPersist.isEmpty()) {
int startLogicalIndex = prevLogIndex + 1;
persistenceService.appendLogEntries(config.getNodeId(), startLogicalIndex, entriesToPersist);
}
if (entriesAdded > 0) {
logEvent(RaftEvent.EventType.LOG_REPLICATED,
"Replicated " + entriesAdded + " entries from leader " + request.getLeaderId());
}
// Update commit index based on leader's commit index (logical indices)
if (request.getLeaderCommit() > commitIndex.get()) {
commitIndex.set(Math.min(request.getLeaderCommit(), getLastLogIndex()));
applyCommittedEntries();
}
return AppendEntriesResponse.newBuilder()
.setTerm(currentTerm.get())
.setSuccess(true)
.setMatchIndex(getLastLogIndex()) // Logical index of last entry
.build();
}
Mit den folgenden gRPC Messages:
message AppendEntriesRequest {
int32 term = 1;
string leaderId = 2;
int32 prevLogIndex = 3;
int32 prevLogTerm = 4;
repeated GrpcLogEntry entries = 5;
int32 leaderCommit = 6;
}
message AppendEntriesResponse {
int32 term = 1;
bool success = 2;
int32 matchIndex = 3;
}
Welche Aussagen treffen dabei zu?
Consensus algorithms for practical systems typically have the following properties:
Raft guarantees that each of these properties is true at all times.
Folgende replizierte Log Struktur ist aufgetreten:
Welche Aussagen stimmen?
Welche Aussagen sind zutreffend?
One of the requirements for Raft is that safety must not depend on timing: the system must not produce incorrect results just because some event happens more quickly or slowly than expected.
Which answers are correct?