public ThrottlingTester(IActorRef remoteRef, IActorRef controller) { _remoteRef = remoteRef; _controller = controller; Receive <string>(s => s.Equals("start"), s => { Self.Tell("sendNext"); _startTime = SystemNanoTime.GetNanos(); }); Receive <string>(s => s.Equals("sendNext") && _messageCount > 0, s => { _remoteRef.Tell("ping"); Self.Tell("sendNext"); _messageCount--; }); Receive <string>(s => s.Equals("pong"), s => { _received++; if (_received >= MessageCount) { _controller.Tell(SystemNanoTime.GetNanos() - _startTime); } }); }
public override bool Write(ByteString payload) { var tokens = payload.Length; //need to declare recursive delegates first before they can self-reference //might want to consider making this consumer function strongly typed: http://blogs.msdn.com/b/wesdyer/archive/2007/02/02/anonymous-recursion-in-c.aspx Func <ThrottleMode, bool> tryConsume = null; tryConsume = currentBucket => { var timeOfSend = SystemNanoTime.GetNanos(); var res = currentBucket.TryConsumeTokens(timeOfSend, tokens); var newBucket = res.Item1; var allow = res.Item2; if (allow) { return(OutboundThrottleMode.CompareAndSet(currentBucket, newBucket) || tryConsume(OutboundThrottleMode.Value)); } return(false); }; var throttleMode = OutboundThrottleMode.Value; if (throttleMode is Blackhole) { return(true); } var success = tryConsume(OutboundThrottleMode.Value); return(success && WrappedHandle.Write(payload)); }
private void ForwardOrDelay(ByteString payload) { if (InboundThrottleMode is Blackhole) { // Do nothing } else { if (!ThrottledMessages.Any()) { var tokens = payload.Length; var res = InboundThrottleMode.TryConsumeTokens(SystemNanoTime.GetNanos(), tokens); var newBucket = res.Item1; var success = res.Item2; if (success) { InboundThrottleMode = newBucket; UpstreamListener.Notify(new InboundPayload(payload)); } else { ThrottledMessages.Enqueue(payload); ScheduleDequeue(InboundThrottleMode.TimeToAvailable(SystemNanoTime.GetNanos(), tokens)); } } else { ThrottledMessages.Enqueue(payload); } } }
private void InitializeFSM() { When(ThrottlerState.WaitExposedHandle, @event => { if (@event.FsmEvent is ThrottlerManager.Handle && @event.StateData is Uninitialized) { // register to downstream layer and wait for origin OriginalHandle.ReadHandlerSource.SetResult(new ActorHandleEventListener(Self)); return (GoTo(ThrottlerState.WaitOrigin) .Using( new ExposedHandle( @event.FsmEvent.AsInstanceOf <ThrottlerManager.Handle>().ThrottlerHandle))); } return(null); }); When(ThrottlerState.WaitOrigin, @event => { if (@event.FsmEvent is InboundPayload && @event.StateData is ExposedHandle) { var b = @event.FsmEvent.AsInstanceOf <InboundPayload>().Payload; ThrottledMessages.Enqueue(b); var origin = PeekOrigin(b); if (origin != null) { Manager.Tell(new ThrottlerManager.Checkin(origin, @event.StateData.AsInstanceOf <ExposedHandle>().Handle)); return(GoTo(ThrottlerState.WaitMode)); } return(Stay()); } return(null); }); When(ThrottlerState.WaitMode, @event => { if (@event.FsmEvent is InboundPayload) { var b = @event.FsmEvent.AsInstanceOf <InboundPayload>().Payload; ThrottledMessages.Enqueue(b); return(Stay()); } if (@event.FsmEvent is ThrottleMode && @event.StateData is ExposedHandle) { var mode = @event.FsmEvent.AsInstanceOf <ThrottleMode>(); var exposedHandle = @event.StateData.AsInstanceOf <ExposedHandle>().Handle; InboundThrottleMode = mode; try { if (mode is Blackhole) { ThrottledMessages = new Queue <ByteString>(); exposedHandle.Disassociate(); return(Stop()); } else { AssociationHandler.Notify(new InboundAssociation(exposedHandle)); var self = Self; exposedHandle.ReadHandlerSource.Task.ContinueWith( r => new ThrottlerManager.Listener(r.Result), TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously) .PipeTo(self); return(GoTo(ThrottlerState.WaitUpstreamListener)); } } finally { Sender.Tell(SetThrottleAck.Instance); } } return(null); }); When(ThrottlerState.WaitUpstreamListener, @event => { if (@event.FsmEvent is InboundPayload) { var b = @event.FsmEvent.AsInstanceOf <InboundPayload>(); ThrottledMessages.Enqueue(b.Payload); return(Stay()); } if (@event.FsmEvent is ThrottlerManager.Listener) { UpstreamListener = @event.FsmEvent.AsInstanceOf <ThrottlerManager.Listener>().HandleEventListener; Self.Tell(new Dequeue()); return(GoTo(ThrottlerState.Throttling)); } return(null); }); When(ThrottlerState.WaitModeAndUpstreamListener, @event => { if (@event.FsmEvent is ThrottlerManager.ListenerAndMode) { var listenerAndMode = @event.FsmEvent.AsInstanceOf <ThrottlerManager.ListenerAndMode>(); UpstreamListener = listenerAndMode.HandleEventListener; InboundThrottleMode = listenerAndMode.Mode; Self.Tell(new Dequeue()); return(GoTo(ThrottlerState.Throttling)); } if (@event.FsmEvent is InboundPayload) { var b = @event.FsmEvent.AsInstanceOf <InboundPayload>(); ThrottledMessages.Enqueue(b.Payload); return(Stay()); } return(null); }); When(ThrottlerState.Throttling, @event => { if (@event.FsmEvent is ThrottleMode) { var mode = @event.FsmEvent.AsInstanceOf <ThrottleMode>(); InboundThrottleMode = mode; if (mode is Blackhole) { ThrottledMessages = new Queue <ByteString>(); } CancelTimer(DequeueTimerName); if (ThrottledMessages.Any()) { ScheduleDequeue(InboundThrottleMode.TimeToAvailable(SystemNanoTime.GetNanos(), ThrottledMessages.Peek().Length)); } Sender.Tell(SetThrottleAck.Instance); return(Stay()); } if (@event.FsmEvent is InboundPayload) { ForwardOrDelay(@event.FsmEvent.AsInstanceOf <InboundPayload>().Payload); return(Stay()); } if (@event.FsmEvent is Dequeue) { if (ThrottledMessages.Any()) { var payload = ThrottledMessages.Dequeue(); UpstreamListener.Notify(new InboundPayload(payload)); InboundThrottleMode = InboundThrottleMode.TryConsumeTokens(SystemNanoTime.GetNanos(), payload.Length).Item1; if (ThrottledMessages.Any()) { ScheduleDequeue(InboundThrottleMode.TimeToAvailable(SystemNanoTime.GetNanos(), ThrottledMessages.Peek().Length)); } } return(Stay()); } return(null); }); WhenUnhandled(@event => { // we should always set the throttling mode if (@event.FsmEvent is ThrottleMode) { InboundThrottleMode = @event.FsmEvent.AsInstanceOf <ThrottleMode>(); Sender.Tell(SetThrottleAck.Instance); return(Stay()); } if (@event.FsmEvent is Disassociated) { return(Stop()); // not notifying the upstream handler is intentional: we are relying on heartbeating } if (@event.FsmEvent is FailWith) { var reason = @event.FsmEvent.AsInstanceOf <FailWith>().FailReason; if (UpstreamListener != null) { UpstreamListener.Notify(new Disassociated(reason)); } return(Stop()); } return(null); }); if (Inbound) { StartWith(ThrottlerState.WaitExposedHandle, Uninitialized.Instance); } else { OriginalHandle.ReadHandlerSource.SetResult(new ActorHandleEventListener(Self)); StartWith(ThrottlerState.WaitModeAndUpstreamListener, Uninitialized.Instance); } }