//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 static async ValueTask <bool> IsUpToDateAsync(this IAuditTrail <ILogEntry> auditTrail, long index, long term) { var localIndex = auditTrail.GetLastIndex(false); var localTerm = (await auditTrail.GetEntryAsync(localIndex).ConfigureAwait(false) ?? auditTrail.First) .Term; return(index >= localIndex && term >= localTerm); }
private static async Task <Result <VotingResult> > VoteAsync(IRaftClusterMember voter, long term, IAuditTrail <ILogEntry> auditTrail, CancellationToken token) { var lastIndex = auditTrail.GetLastIndex(false); var lastTerm = (await auditTrail.GetEntryAsync(lastIndex).ConfigureAwait(false) ?? auditTrail.First) .Term; 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; } return(new Result <VotingResult>(term, result)); }
internal static async ValueTask <bool> ContainsAsync(this IAuditTrail <ILogEntry> auditTrail, long index, long term) => term == (await auditTrail.GetEntryAsync(index).ConfigureAwait(false) ?? auditTrail.First).Term;