private void BecomeLeader() { _leaderAddress = null; State.LastVotedForId = State.Id; _volatileLeaderState = new VolatileLeaderState(); var peers = _peerManager.GetPeers().ToArray(); foreach (var peer in peers) { TheTrace.TraceInformation($"[{_meAsAPeer.ShortName}] setting up indices for peer {peer.Address}"); _volatileLeaderState.SetNextIndex(peer.Id, _logPersister.LastIndex + 1); _volatileLeaderState.SetMatchIndex(peer.Id, -1L); } SetupPeerAppendLogJobs(peers); OnRoleChanged(_role = Role.Leader); }
private async Task SendSnapshot( IRaftServer proxy, AsyncPolicy policy, Peer peer, long nextIndex, long matchIndex) { var logOffset = LogPersister.LogOffset; var term = State.CurrentTerm; Snapshot ss; if (!SnapshotOperator.TryGetLastSnapshot(out ss)) { throw new InvalidProgramException($"WE DO NOT HAVE A SNAPSHOT for client {peer.Address} whose nextIndex is {nextIndex} yet our LogOffset is {logOffset}"); } if (ss.LastIncludedIndex + 1 < nextIndex) { throw new InvalidProgramException($"WE DO NOT HAVE A <<PROPER>> SNAPSHOT for client {peer.Address} whose nextIndex is {nextIndex} yet our LogOffset is {logOffset}. Snapshot was have ({ss.FullName}) is short {ss.LastIncludedIndex}"); } // make a copy since it might be cleaned up or opened by another thread for another client var fileName = Path.GetTempFileName(); File.Copy(ss.FullName, fileName, true); TheTrace.TraceInformation($"[{_meAsAPeer.ShortName}] About to send Snapshot copy file {fileName} to [{peer.ShortName}] and copy of {ss.FullName}."); using (var fs = new FileStream(fileName, FileMode.Open)) { var start = 0; var total = 0; var length = fs.Length; var buffer = new byte[_settings.MaxSnapshotChunkSentInBytes]; TheTrace.TraceInformation($"[{_meAsAPeer.ShortName}] Snapshot copy file size is {length}. Location is {fileName} and copy of {ss.FullName}."); while (total < length) { var count = fs.Read(buffer, 0, buffer.Length); total += count; var result = await proxy.InstallSnapshotAsync(new InstallSnapshotRequest() { CurrentTerm = term, Data = count == buffer.Length ? buffer : buffer.Take(count).ToArray(), LastIncludedIndex = ss.LastIncludedIndex, LastIncludedTerm = term, IsDone = total == length, LeaderId = State.Id, Offset = start }); TheTrace.TraceInformation($"[{_meAsAPeer.ShortName}] Sent snapshot for peer {peer.Address} with {count} bytes totalling {total}."); start += count; if (result.CurrentTerm != term) { TheTrace.TraceWarning($"[{_meAsAPeer.ShortName}] I am sending snapshot but this peer {peer.Address} has term {result.CurrentTerm} vs my started term {term} and current term {State.CurrentTerm}."); } } } _volatileLeaderState.SetMatchIndex(peer.Id, ss.LastIncludedIndex); _volatileLeaderState.SetNextIndex(peer.Id, ss.LastIncludedIndex + 1); // the rest will be done by sending logs File.Delete(fileName); }