Beispiel #1
0
        /// <summary>
        /// Enqueue message for local handling after transaction completes
        /// </summary>
        /// <param name="message"></param>
        /// <param name="targetActivation"></param>
        private void EnqueueRequest(Message message, ActivationData targetActivation)
        {
            var overloadException = targetActivation.CheckOverloaded(logger);

            if (overloadException != null)
            {
                MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedError(message, "Overload2");
                RejectMessage(message, Message.RejectionTypes.Overloaded, overloadException, "Target activation is overloaded " + targetActivation);
                return;
            }
            if (Message.WriteMessagingTraces)
            {
                message.AddTimestamp(Message.LifecycleTag.EnqueueWaiting);
            }

            bool enqueuedOk = targetActivation.EnqueueMessage(message);

            if (!enqueuedOk)
            {
                ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "EnqueueRequest");
            }

            // Dont count this as end of processing. The message will come back after queueing via HandleIncomingRequest.

#if DEBUG
            // This is a hot code path, so using #if to remove diags from Release version
            // Note: Caller already holds lock on activation
            if (logger.IsVerbose2)
            {
                logger.Verbose2(ErrorCode.Dispatcher_EnqueueMessage,
                                "EnqueueMessage for {0}: targetActivation={1}", message.TargetActivation, targetActivation.DumpStatus());
            }
#endif
        }
Beispiel #2
0
        public Message CreateResponseMessage()
        {
            var response = new Message(this.Category, Directions.Response)
            {
                Id                 = this.Id,
                IsReadOnly         = this.IsReadOnly,
                IsAlwaysInterleave = this.IsAlwaysInterleave,
                TargetSilo         = this.SendingSilo
            };

            if (this.ContainsHeader(Header.SENDING_GRAIN))
            {
                response.SetHeader(Header.TARGET_GRAIN, this.GetHeader(Header.SENDING_GRAIN));
                if (this.ContainsHeader(Header.SENDING_ACTIVATION))
                {
                    response.SetHeader(Header.TARGET_ACTIVATION, this.GetHeader(Header.SENDING_ACTIVATION));
                }
            }

            response.SendingSilo = this.TargetSilo;
            if (this.ContainsHeader(Header.TARGET_GRAIN))
            {
                response.SetHeader(Header.SENDING_GRAIN, this.GetHeader(Header.TARGET_GRAIN));
                if (this.ContainsHeader(Header.TARGET_ACTIVATION))
                {
                    response.SetHeader(Header.SENDING_ACTIVATION, this.GetHeader(Header.TARGET_ACTIVATION));
                }
                else if (this.TargetGrain.IsSystemTarget)
                {
                    response.SetHeader(Header.SENDING_ACTIVATION, ActivationId.GetSystemActivation(TargetGrain, TargetSilo));
                }
            }

            if (this.ContainsHeader(Header.TIMESTAMPS))
            {
                response.SetHeader(Header.TIMESTAMPS, this.GetHeader(Header.TIMESTAMPS));
            }
            if (this.ContainsHeader(Header.DEBUG_CONTEXT))
            {
                response.SetHeader(Header.DEBUG_CONTEXT, this.GetHeader(Header.DEBUG_CONTEXT));
            }
            if (this.ContainsHeader(Header.CACHE_INVALIDATION_HEADER))
            {
                response.SetHeader(Header.CACHE_INVALIDATION_HEADER, this.GetHeader(Header.CACHE_INVALIDATION_HEADER));
            }
            if (this.ContainsHeader(Header.EXPIRATION))
            {
                response.SetHeader(Header.EXPIRATION, this.GetHeader(Header.EXPIRATION));
            }
            if (Message.WriteMessagingTraces)
            {
                response.AddTimestamp(LifecycleTag.CreateResponse);
            }

            RequestContext.ExportToMessage(response);

            return(response);
        }
Beispiel #3
0
        // Check if it is OK to receive a message to its current target activation.
        private bool SiloCanAcceptRequest(Message message)
        {
            if (Message.WriteMessagingTraces)
            {
                message.AddTimestamp(Message.LifecycleTag.TaskIncoming);
            }

            return(!catalog.SiloStatusOracle.CurrentStatus.IsTerminating());
        }
Beispiel #4
0
        public void DoCallback(Message response)
        {
            if (alreadyFired)
            {
                return;
            }
            lock (this)
            {
                if (alreadyFired)
                {
                    return;
                }

                if (response.Result == Message.ResponseTypes.Rejection && response.RejectionType == Message.RejectionTypes.Transient)
                {
                    if (resendFunc(Message))
                    {
                        return;
                    }
                }

                alreadyFired = true;
                DisposeTimer();
                if (StatisticsCollector.CollectApplicationRequestsStats)
                {
                    timeSinceIssued.Stop();
                }
                if (unregister != null)
                {
                    unregister();
                }
            }
            if (Message.WriteMessagingTraces)
            {
                response.AddTimestamp(Message.LifecycleTag.InvokeIncoming);
            }
            if (logger.IsVerbose2)
            {
                logger.Verbose2("Message {0} timestamps: {1}", response, response.GetTimestampString());
            }
            if (StatisticsCollector.CollectApplicationRequestsStats)
            {
                ApplicationRequestsStatisticsGroup.OnAppRequestsEnd(timeSinceIssued.Elapsed);
            }
            // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation.
            callback(response, context);
        }
Beispiel #5
0
        /// <summary>
        /// Handle an incoming message and queue/invoke appropriate handler
        /// </summary>
        /// <param name="message"></param>
        /// <param name="targetActivation"></param>
        public void HandleIncomingRequest(Message message, ActivationData targetActivation)
        {
            lock (targetActivation)
            {
                if (targetActivation.State == ActivationState.Invalid)
                {
                    ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "HandleIncomingRequest");
                    return;
                }

                // Now we can actually scheduler processing of this request
                targetActivation.RecordRunning(message);
                var context = new SchedulingContext(targetActivation);
                if (Message.WriteMessagingTraces)
                {
                    message.AddTimestamp(Message.LifecycleTag.EnqueueWorkItem);
                }

                MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedOk(message);
                Scheduler.QueueWorkItem(new InvokeWorkItem(targetActivation, message, context), context);
            }
        }
        internal async Task Invoke(IAddressable target, IInvokable invokable, Message message)
        {
            try
            {
                // Don't process messages that have already timed out
                if (message.IsExpired)
                {
                    message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke);
                    return;
                }

                //MessagingProcessingStatisticsGroup.OnRequestProcessed(message, "Invoked");
                if (Message.WriteMessagingTraces)
                {
                    message.AddTimestamp(Message.LifecycleTag.InvokeIncoming);
                }

                RequestContext.Import(message.RequestContextData);
                if (Config.Globals.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget)
                {
                    UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message));
                    // RequestContext is automatically saved in the msg upon send and propagated to the next hop
                    // in RuntimeClient.CreateMessage -> RequestContext.ExportToMessage(message);
                }

                var invoker = invokable.GetInvoker(message.InterfaceId, message.GenericGrainType);

                object resultObject;
                try
                {
                    var request = (InvokeMethodRequest)message.BodyObject;

                    if (invoker is IGrainExtensionMethodInvoker &&
                        !(target is IGrainExtension))
                    {
                        // We are trying the invoke a grain extension method on a grain
                        // -- most likely reason is that the dynamic extension is not installed for this grain
                        // So throw a specific exception here rather than a general InvalidCastException
                        var error = String.Format(
                            "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}",
                            target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName);
                        var    exc            = new GrainExtensionNotInstalledException(error);
                        string extraDebugInfo = null;
#if DEBUG
                        extraDebugInfo = new StackTrace().ToString();
#endif
                        logger.Warn(ErrorCode.Stream_ExtensionNotInstalled,
                                    string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc);

                        throw exc;
                    }
                    resultObject = await invoker.Invoke(target, request.InterfaceId, request.MethodId, request.Arguments);
                }
                catch (Exception exc1)
                {
                    if (invokeExceptionLogger.IsVerbose || message.Direction == Message.Directions.OneWay)
                    {
                        invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException,
                                                   "Exception during Grain method call of message: " + message, exc1);
                    }
                    if (message.Direction != Message.Directions.OneWay)
                    {
                        SafeSendExceptionResponse(message, exc1);
                    }
                    return;
                }

                if (message.Direction == Message.Directions.OneWay)
                {
                    return;
                }

                SafeSendResponse(message, resultObject);
            }
            catch (Exception exc2)
            {
                logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2);
                if (message.Direction != Message.Directions.OneWay)
                {
                    SafeSendExceptionResponse(message, exc2);
                }
            }
        }
        private void SendRequestMessage(
            GrainReference target,
            Message message,
            TaskCompletionSource <object> context,
            Action <Message, TaskCompletionSource <object> > callback,
            string debugContext,
            InvokeMethodOptions options,
            string genericArguments = null)
        {
            // fill in sender
            if (message.SendingSilo == null)
            {
                message.SendingSilo = MySilo;
            }
            if (!String.IsNullOrEmpty(genericArguments))
            {
                message.GenericGrainType = genericArguments;
            }

            SchedulingContext schedulingContext = RuntimeContext.Current != null ?
                                                  RuntimeContext.Current.ActivationContext as SchedulingContext : null;

            ActivationData sendingActivation = null;

            if (schedulingContext == null)
            {
                throw new InvalidExpressionException(
                          String.Format("Trying to send a message {0} on a silo not from within grain and not from within system target (RuntimeContext is not set to SchedulingContext) "
                                        + "RuntimeContext.Current={1} TaskScheduler.Current={2}",
                                        message,
                                        RuntimeContext.Current == null ? "null" : RuntimeContext.Current.ToString(),
                                        TaskScheduler.Current));
            }
            switch (schedulingContext.ContextType)
            {
            case SchedulingContextType.SystemThread:
                throw new ArgumentException(
                          String.Format("Trying to send a message {0} on a silo not from within grain and not from within system target (RuntimeContext is of SchedulingContextType.SystemThread type)", message), "context");

            case SchedulingContextType.Activation:
                message.SendingActivation = schedulingContext.Activation.ActivationId;
                message.SendingGrain      = schedulingContext.Activation.Grain;
                sendingActivation         = schedulingContext.Activation;
                break;

            case SchedulingContextType.SystemTarget:
                message.SendingActivation = schedulingContext.SystemTarget.ActivationId;
                message.SendingGrain      = schedulingContext.SystemTarget.GrainId;
                break;
            }

            // fill in destination
            var targetGrainId = target.GrainId;

            message.TargetGrain = targetGrainId;
            if (targetGrainId.IsSystemTarget)
            {
                SiloAddress targetSilo = (target.SystemTargetSilo ?? MySilo);
                message.TargetSilo       = targetSilo;
                message.TargetActivation = ActivationId.GetSystemActivation(targetGrainId, targetSilo);
                message.Category         = targetGrainId.Equals(Constants.MembershipOracleId) ?
                                           Message.Categories.Ping : Message.Categories.System;
            }
            if (target.IsObserverReference)
            {
                message.TargetObserverId = target.ObserverId;
            }

            if (debugContext != null)
            {
                message.DebugContext = debugContext;
            }

            var oneWay = (options & InvokeMethodOptions.OneWay) != 0;

            if (context == null && !oneWay)
            {
                logger.Warn(ErrorCode.IGC_SendRequest_NullContext, "Null context {0}: {1}", message, new StackTrace());
            }

            if (Message.WriteMessagingTraces)
            {
                message.AddTimestamp(Message.LifecycleTag.Create);
            }

            if (message.IsExpirableMessage(Config.Globals))
            {
                message.Expiration = DateTime.UtcNow + ResponseTimeout + Constants.MAXIMUM_CLOCK_SKEW;
            }

            if (!oneWay)
            {
                var callbackData = new CallbackData(
                    callback,
                    TryResendMessage,
                    context,
                    message,
                    () => UnRegisterCallback(message.Id),
                    Config.Globals);
                callbacks.TryAdd(message.Id, callbackData);
                callbackData.StartTimer(ResponseTimeout);
            }

            if (targetGrainId.IsSystemTarget)
            {
                // Messages to system targets bypass the task system and get sent "in-line"
                dispatcher.TransportMessage(message);
            }
            else
            {
                dispatcher.SendMessage(message, sendingActivation);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Enqueue message for local handling after transaction completes
        /// </summary>
        /// <param name="message"></param>
        /// <param name="targetActivation"></param>
        private void EnqueueRequest(Message message, ActivationData targetActivation)
        {
            var overloadException = targetActivation.CheckOverloaded(logger);
            if (overloadException != null)
            {
                MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedError(message, "Overload2");
                RejectMessage(message, Message.RejectionTypes.Overloaded, overloadException, "Target activation is overloaded " + targetActivation);
                return;
            }
            if (Message.WriteMessagingTraces) 
                message.AddTimestamp(Message.LifecycleTag.EnqueueWaiting);
            
            bool enqueuedOk = targetActivation.EnqueueMessage(message);
            if (!enqueuedOk)
            {
                ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "EnqueueRequest");
            }

            // Dont count this as end of processing. The message will come back after queueing via HandleIncomingRequest.

#if DEBUG
            // This is a hot code path, so using #if to remove diags from Release version
            // Note: Caller already holds lock on activation
            if (logger.IsVerbose2) logger.Verbose2(ErrorCode.Dispatcher_EnqueueMessage,
                "EnqueueMessage for {0}: targetActivation={1}", message.TargetActivation, targetActivation.DumpStatus());
#endif
        }
Beispiel #9
0
        /// <summary>
        /// Handle an incoming message and queue/invoke appropriate handler
        /// </summary>
        /// <param name="message"></param>
        /// <param name="targetActivation"></param>
        public void HandleIncomingRequest(Message message, ActivationData targetActivation)
        {
            lock (targetActivation)
            {
                if (targetActivation.State == ActivationState.Invalid)
                {
                    ProcessRequestToInvalidActivation(message, targetActivation.Address, targetActivation.ForwardingAddress, "HandleIncomingRequest");
                    return;
                }

                // Now we can actually scheduler processing of this request
                targetActivation.RecordRunning(message);
                var context = new SchedulingContext(targetActivation);
                if (Message.WriteMessagingTraces) 
                    message.AddTimestamp(Message.LifecycleTag.EnqueueWorkItem);

                MessagingProcessingStatisticsGroup.OnDispatcherMessageProcessedOk(message);
                Scheduler.QueueWorkItem(new InvokeWorkItem(targetActivation, message, context), context);
            }
        }
Beispiel #10
0
        public void DoCallback(Message response)
        {
            if (alreadyFired)
                return;
            lock (this)
            {
                if (alreadyFired)
                    return;

                if (response.Result == Message.ResponseTypes.Rejection && response.RejectionType == Message.RejectionTypes.Transient)
                {
                    if (resendFunc(Message))
                    {
                        return;
                    }
                }

                alreadyFired = true;
                DisposeTimer();
                if (StatisticsCollector.CollectApplicationRequestsStats)
                {
                    timeSinceIssued.Stop();
                }
                if (unregister != null)
                {
                    unregister();
                }     
            }
            if (Message.WriteMessagingTraces) response.AddTimestamp(Message.LifecycleTag.InvokeIncoming);
            if (logger.IsVerbose2) logger.Verbose2("Message {0} timestamps: {1}", response, response.GetTimestampString());
            if (StatisticsCollector.CollectApplicationRequestsStats)
            {
                ApplicationRequestsStatisticsGroup.OnAppRequestsEnd(timeSinceIssued.Elapsed);
            }
            // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation.
            callback(response, context);
        }