Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.kafka.raft.LeaderAndEpoch;
import org.apache.kafka.raft.OffsetAndEpoch;
import org.apache.kafka.raft.RaftClient;
import org.apache.kafka.raft.errors.NotLeaderException;
import org.apache.kafka.raft.internals.MemoryBatchReader;
import org.apache.kafka.server.common.ApiMessageAndVersion;
import org.apache.kafka.snapshot.MockRawSnapshotReader;
Expand Down Expand Up @@ -226,16 +227,20 @@ synchronized long tryAppend(int nodeId, int epoch, List<ApiMessageAndVersion> ba
}

synchronized long tryAppend(int nodeId, int epoch, LocalBatch batch) {
if (epoch != leader.epoch()) {
log.trace("tryAppend(nodeId={}, epoch={}): the provided epoch does not " +
"match the current leader epoch of {}.", nodeId, epoch, leader.epoch());
return Long.MAX_VALUE;
}
if (!leader.isLeader(nodeId)) {
log.trace("tryAppend(nodeId={}, epoch={}): the given node id does not " +
"match the current leader id of {}.", nodeId, epoch, leader.leaderId());
return Long.MAX_VALUE;
log.debug("tryAppend(nodeId={}, epoch={}): the given node id does not " +
"match the current leader id of {}.", nodeId, epoch, leader.leaderId());
throw new NotLeaderException("Append failed because the replication is not the current leader");
}

if (epoch < leader.epoch()) {
throw new NotLeaderException("Append failed because the given epoch " + epoch + " is stale. " +
"Current leader epoch = " + leader.epoch());
} else if (epoch > leader.epoch()) {
throw new IllegalArgumentException("Attempt to append from epoch " + epoch +
" which is larger than the current epoch " + leader.epoch());
}

log.trace("tryAppend(nodeId={}): appending {}.", nodeId, batch);
long offset = append(batch);
electLeaderIfNeeded();
Expand Down Expand Up @@ -723,9 +728,35 @@ public long scheduleAtomicAppend(int epoch, List<ApiMessageAndVersion> batch) {

@Override
public void resign(int epoch) {
LeaderAndEpoch curLeader = leader;
LeaderAndEpoch nextLeader = new LeaderAndEpoch(OptionalInt.empty(), curLeader.epoch() + 1);
shared.tryAppend(nodeId, curLeader.epoch(), new LeaderChangeBatch(nextLeader));
if (epoch < 0) {
throw new IllegalArgumentException("Attempt to resign from an invalid negative epoch " + epoch);
}

LeaderAndEpoch leaderAndEpoch = leaderAndEpoch();
int currentEpoch = leaderAndEpoch.epoch();

if (epoch > currentEpoch) {
throw new IllegalArgumentException("Attempt to resign from epoch " + epoch +
" which is larger than the current epoch " + currentEpoch);
Comment thread
divijvaidya marked this conversation as resolved.
Outdated
} else if (epoch < currentEpoch) {
// If the passed epoch is smaller than the current epoch, then it might mean
// that the listener has not been notified about a leader change that already
// took place. In this case, we consider the call as already fulfilled and
// take no further action.
log.debug("Ignoring call to resign from epoch {} since it is smaller than the " +
"current epoch {}", epoch, currentEpoch);
return;
}

LeaderAndEpoch nextLeader = new LeaderAndEpoch(OptionalInt.empty(), currentEpoch + 1);
try {
shared.tryAppend(nodeId, currentEpoch, new LeaderChangeBatch(nextLeader));
} catch (NotLeaderException exp) {
// the leader epoch has already advanced. resign is a no op.
log.debug("Ignoring call to resign from epoch {}. Either we are not the leader or the provided epoch is " +
"smaller than the current epoch {}", epoch, currentEpoch);
return;
}
}

@Override
Expand Down
5 changes: 4 additions & 1 deletion raft/src/main/java/org/apache/kafka/raft/RaftClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,11 @@ default void beginShutdown() {}
* Notification of successful resignation can be observed through
* {@link Listener#handleLeaderChange(LeaderAndEpoch)}.
*
* @param epoch the epoch to resign from. If this does not match the current epoch, this
* @param epoch the epoch to resign from. If this epoch is smaller than the current epoch, this
* call will be ignored.
*
* @throws IllegalArgumentException - if the passed epoch is invalid (negative or greater than current) or
* if the listener is not the leader associated with this epoch.
*/
void resign(int epoch);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public BatchAccumulator(
* @throws RecordBatchTooLargeException if the size of one record T is greater than the maximum
* batch size; if this exception is throw some of the elements in records may have
* been committed
* @throws NotLeaderException if the epoch doesn't match the leader epoch
* @throws NotLeaderException if the epoch is less than the leader epoch
* @throws IllegalArgumentException if the epoch is invalid (greater than the leader epoch)
* @throws BufferAllocationException if we failed to allocate memory for the records
*/
public long append(int epoch, List<T> records) {
Expand All @@ -123,7 +124,8 @@ public long append(int epoch, List<T> records) {
* @throws RecordBatchTooLargeException if the size of the records is greater than the maximum
* batch size; if this exception is throw none of the elements in records were
* committed
* @throws NotLeaderException if the epoch doesn't match the leader epoch
* @throws NotLeaderException if the epoch is less than the leader epoch
* @throws IllegalArgumentException if the epoch is invalid (greater than the leader epoch)
* @throws BufferAllocationException if we failed to allocate memory for the records
*/
public long appendAtomic(int epoch, List<T> records) {
Expand All @@ -132,7 +134,8 @@ public long appendAtomic(int epoch, List<T> records) {

private long append(int epoch, List<T> records, boolean isAtomic) {
if (epoch < this.epoch) {
throw new NotLeaderException("Append failed because the epoch doesn't match");
throw new NotLeaderException("Append failed because the given epoch " + epoch + " is stale. " +
"Current leader epoch = " + this.epoch());
} else if (epoch > this.epoch) {
throw new IllegalArgumentException("Attempt to append from epoch " + epoch +
" which is larger than the current epoch " + this.epoch);
Expand Down