public async Task SendAsync(IReadOnlyCollection <SwimMessage> messages, SwimHost host) { var piggybackMessages = _disseminator.GetMessages().ToList(); var allMessages = messages.Concat(piggybackMessages); IReadOnlyCollection <ReadOnlyMemory <byte> > buffers = allMessages.Select(x => _messageSerializer.Serialize(x)).ToList(); while (buffers.Count > piggybackMessages.Count) { var newBuffers = await _transport.SendAsync(buffers, host); if (newBuffers.Count == buffers.Count) { throw new Exception("Failed to send first message"); } buffers = newBuffers; } var numOfPiggybackMessagesSent = piggybackMessages.Count - buffers.Count; for (var i = 0; i < numOfPiggybackMessagesSent; i++) { _disseminator.MarkMessageAsSent(piggybackMessages[i]); } }
public RoutingData(SwimHost host, int routeId, RouteExecution execution, RouteMode mode) { Host = host; RouteId = routeId; Execution = execution; Mode = mode; }
private void HandleMessage(object sender, TransportMessageEventArgs args) { var buffer = args.Buffer; var message = _messageSerializer.Deserialize(buffer.Span); var remote = new SwimHost(args.RemoteEndpoint); switch (message.Type) { case SwimMessageType.Ping: OnPing?.Invoke(this, new TransportPingEventArgs(message as PingMessage, remote)); break; case SwimMessageType.PingReq: OnPingReq?.Invoke(this, new TransportPingReqEventArgs(message as PingReqMessage, remote)); break; case SwimMessageType.Ack: OnAck?.Invoke(this, new TransportAckEventArgs(message as AckMessage, remote)); break; case SwimMessageType.Sync: OnSync?.Invoke(this, new TransportSyncEventArgs(message as SyncMessage, remote)); break; case SwimMessageType.Update: OnUpdate?.Invoke(this, new TransportUpdateEventArgs(message as UpdateMessage, remote)); break; default: throw new ArgumentOutOfRangeException(); } }
private static int SerializeHost(ref byte[] bytes, int offset, SwimHost host) { var endpoint = host.AsIPEndPoint(); var length = 0; length += MessagePackBinary.WriteBytes(ref bytes, offset + length, endpoint.Address.GetAddressBytes()); length += MessagePackBinary.WriteUInt16(ref bytes, offset + length, (ushort)endpoint.Port); return(length); }
public SwimClient(SwimHost local, SwimMeta initialMeta, SwimClientOptions options) { Local = local; Members = new MembershipList(local, initialMeta); Disseminator = new Disseminator(Members, new DisseminatorOptions()); Transport = new SwimTransport(new UdpTransport(local, new UdpTransportOptions()), Disseminator, options.MessageSerializer); FailureDetector = new FailureDetector(Transport, Members, new FailureDetectorOptions(options.Logger)); MembershipMonitor = new MembershipMonitor(Members, Transport, FailureDetector, new MembershipMonitorOptions()); Members.OnJoined += (_, args) => options.Logger.Information("Host {host} joined", args.Member.Host); Members.OnUpdated += (_, args) => options.Logger.Information("Host {host} updated", args.Member.Host); Members.OnLeft += (_, args) => options.Logger.Information("Host {host} left", args.Member.Host); }
private void HandleMessage(SwimHost host, SwimMessage message) { if (_hostMessages.TryRemove(host, out var oldMessage)) { // TODO handle false _messageAttempts.TryRemove(oldMessage, out _); } if (_hostMessages.TryAdd(host, message)) { // TODO handle false _messageAttempts.TryAdd(message, 0); } }
private async Task PingReqAsync(SwimHost targetHost) { // TODO ping random N hosts var relayHosts = _membershipList.GetRandom(_options.PingReqGroupSize).Select(member => member.Host); var cts = TimerUtils.SetTimer(() => { OnHostSuspect?.Invoke(this, new HostSuspectEventArgs(targetHost)); }, _options.PingReqTimeout); foreach (var relayHost in relayHosts) { await PingReqAsync(targetHost, relayHost, () => cts.Cancel()); } }
public async Task PingAsync(SwimHost host) { var seq = (ulong)Interlocked.Increment(ref _seq); var cts = TimerUtils.SetTimer(() => { CleanupSeq(seq); PingReqAsync(host); }, _options.PingTimeout); _seqTimeouts.AddOrUpdate(seq, cts, (_, __) => cts); await _transport.SendAsync(new[] { new PingMessage(seq), }, host); }
private async Task PingReqAsync(SwimHost targetHost, SwimHost relayHost, Action callback) { var seq = (ulong)Interlocked.Increment(ref _seq); var cts = TimerUtils.SetTimer(() => CleanupSeq(seq), _options.PingTimeout); void SeqCallback() { CleanupSeq(seq); callback(); } _seqTimeouts.AddOrUpdate(seq, cts, (_, __) => cts); _seqCallbacks.AddOrUpdate(seq, SeqCallback, (_, __) => SeqCallback); await _transport.SendAsync(new[] { new PingReqMessage(seq, targetHost), }, relayHost); }
public TransportSyncEventArgs(SyncMessage message, SwimHost remote) { Message = message; Remote = remote; }
public UdpTransport(SwimHost local, UdpTransportOptions options) { _local = local; _options = options; }
public async Task <IReadOnlyCollection <ReadOnlyMemory <byte> > > SendAsync(IReadOnlyCollection <ReadOnlyMemory <byte> > buffers, SwimHost host) { var output = new byte[_options.MaxDatagramSize]; var remainingBuffers = new Queue <ReadOnlyMemory <byte> >(buffers); var length = 0; while (length < _options.MaxDatagramSize && remainingBuffers.Count > 0) { var buffer = remainingBuffers.Dequeue(); var lengthDelta = MessagePackBinary.WriteBytes(ref output, length, buffer.ToArray()); if (length + lengthDelta > _options.MaxDatagramSize) { break; } length += lengthDelta; } if (length > 0) { await _udpClient.SendAsync(output, length, host.AsIPEndPoint()); } return(remainingBuffers.ToList()); }
public TransportPingReqEventArgs(PingReqMessage message, SwimHost remote) { Message = message; Remote = remote; }
public TransportUpdateEventArgs(UpdateMessage message, SwimHost remote) { Message = message; Remote = remote; }
public HostSuspectEventArgs(SwimHost host) { Host = host; }
public PingReqMessage(ulong sequenceNumber, SwimHost destination) { SequenceNumber = sequenceNumber; Destination = destination; }
public TransportAckEventArgs(AckMessage message, SwimHost remote) { Message = message; Remote = remote; }