コード例 #1
0
        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]);
            }
        }
コード例 #2
0
 public RoutingData(SwimHost host, int routeId, RouteExecution execution, RouteMode mode)
 {
     Host      = host;
     RouteId   = routeId;
     Execution = execution;
     Mode      = mode;
 }
コード例 #3
0
        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();
            }
        }
コード例 #4
0
        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);
        }
コード例 #5
0
ファイル: SwimClient.cs プロジェクト: will14smith/Toxon.Swim
        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);
        }
コード例 #6
0
        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);
            }
        }
コード例 #7
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());
            }
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
 public TransportSyncEventArgs(SyncMessage message, SwimHost remote)
 {
     Message = message;
     Remote  = remote;
 }
コード例 #11
0
 public UdpTransport(SwimHost local, UdpTransportOptions options)
 {
     _local   = local;
     _options = options;
 }
コード例 #12
0
        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());
        }
コード例 #13
0
 public TransportPingReqEventArgs(PingReqMessage message, SwimHost remote)
 {
     Message = message;
     Remote  = remote;
 }
コード例 #14
0
 public TransportUpdateEventArgs(UpdateMessage message, SwimHost remote)
 {
     Message = message;
     Remote  = remote;
 }
コード例 #15
0
 public HostSuspectEventArgs(SwimHost host)
 {
     Host = host;
 }
コード例 #16
0
 public PingReqMessage(ulong sequenceNumber, SwimHost destination)
 {
     SequenceNumber = sequenceNumber;
     Destination    = destination;
 }
コード例 #17
0
 public TransportAckEventArgs(AckMessage message, SwimHost remote)
 {
     Message = message;
     Remote  = remote;
 }