private static async Task <Result <VotingResult> > VoteAsync(IRaftClusterMember voter, long term, IAuditTrail <IRaftLogEntry> auditTrail, CancellationToken token) { var lastIndex = auditTrail.GetLastIndex(false); var lastTerm = await auditTrail.GetTermAsync(lastIndex, token).ConfigureAwait(false); VotingResult result; try { var response = await voter.VoteAsync(term, lastIndex, lastTerm, token).ConfigureAwait(false); term = response.Term; result = response.Value ? VotingResult.Granted : VotingResult.Rejected; } catch (OperationCanceledException) { result = VotingResult.Canceled; } catch (MemberUnavailableException) { result = VotingResult.NotAvailable; term = -1L; } return(new Result <VotingResult>(term, result)); }
//true if at least one entry from current term is stored on this node; otherwise, false private static async Task <Result <bool> > AppendEntriesAsync(IRaftClusterMember member, long commitIndex, long term, IAuditTrail <ILogEntry> transactionLog, ILogger logger, CancellationToken token) { var currentIndex = transactionLog.GetLastIndex(false); logger.ReplicationStarted(member.Endpoint, currentIndex); var precedingIndex = Math.Max(0, member.NextIndex - 1); var precedingTerm = (await transactionLog.GetEntryAsync(precedingIndex).ConfigureAwait(false) ?? transactionLog.First).Term; var entries = currentIndex >= member.NextIndex ? await transactionLog.GetEntriesAsync(member.NextIndex).ConfigureAwait(false) : Array.Empty <ILogEntry>(); logger.ReplicaSize(member.Endpoint, entries.Count, precedingIndex, precedingTerm); //trying to replicate var result = await member .AppendEntriesAsync(term, entries, precedingIndex, precedingTerm, commitIndex, token) .ConfigureAwait(false); if (result.Value) { logger.ReplicationSuccessful(member.Endpoint, member.NextIndex); member.NextIndex.VolatileWrite(currentIndex + 1); //checks whether the at least one entry from current term is stored on this node result = result.SetValue(entries.Any(entry => entry.Term == term)); } else { logger.ReplicationFailed(member.Endpoint, member.NextIndex.DecrementAndGet()); } return(result); }
internal VotingState(IRaftClusterMember voter, long term, IAuditTrail <IRaftLogEntry> auditTrail, CancellationToken token) { Voter = voter; // ensure parallel requesting of votes Task = System.Threading.Tasks.Task.Run(() => VoteAsync(voter, term, auditTrail, token)); }
internal Replicator(IRaftClusterMember member, long commitIndex, long term, long precedingIndex, long precedingTerm, ILogger logger, CancellationToken token) { this.member = member; this.precedingIndex = precedingIndex; this.precedingTerm = precedingTerm; this.commitIndex = commitIndex; this.term = term; this.logger = logger; this.token = token; }
// TODO: Replace with required init properties in the next version of C# internal Replicator( IAuditTrail <IRaftLogEntry> auditTrail, IRaftClusterMember member, long commitIndex, long currentIndex, long term, long precedingIndex, long precedingTerm, ILogger logger, CancellationToken token) { this.auditTrail = auditTrail; this.member = member; this.precedingIndex = precedingIndex; this.precedingTerm = precedingTerm; this.commitIndex = commitIndex; this.currentIndex = currentIndex; this.term = term; this.logger = logger; this.token = token; }
internal VotingState(IRaftClusterMember voter, long term, IAuditTrail <IRaftLogEntry> auditTrail, CancellationToken token) { Voter = voter; Task = VoteAsync(voter, term, auditTrail, token); }
bool ILocalMember.IsLeader(IRaftClusterMember member) => ReferenceEquals(Leader, member);
bool IHostingContext.IsLeader(IRaftClusterMember member) => ReferenceEquals(Leader, member);
bool ILocalMember.IsLeader(IRaftClusterMember member) => throw new NotImplementedException();
ValueTask IPersistentState.UpdateVotedForAsync(IRaftClusterMember member) { votedFor = member; return(new ValueTask()); }
bool IPersistentState.IsVotedFor(IRaftClusterMember member) { var lastVote = votedFor; return(lastVote is null || ReferenceEquals(lastVote, member)); }