/// <summary>
        /// Adds CancellationToken to the grain extension
        /// so that it can be cancelled through remote call to the CancellationSourcesExtension.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="request"></param>
        /// <param name="logger"></param>
        internal static void RegisterCancellationTokens(IAddressable target, InvokeMethodRequest request, Logger logger)
        {
            for (var i = 0; i < request.Arguments.Length; i++)
            {
                var arg = request.Arguments[i];
                if (!(arg is GrainCancellationToken)) continue;
                var grainToken = ((GrainCancellationToken) request.Arguments[i]);

                CancellationSourcesExtension cancellationExtension;
                if (!SiloProviderRuntime.Instance.TryGetExtensionHandler(out cancellationExtension))
                {
                    cancellationExtension = new CancellationSourcesExtension();
                    if (!SiloProviderRuntime.Instance.TryAddExtension(cancellationExtension))
                    {
                        logger.Error(
                            ErrorCode.CancellationExtensionCreationFailed,
                            $"Could not add cancellation token extension to: {target}");
                        return;
                    }
                }

                // Replacing the half baked GrainCancellationToken that came from the wire with locally fully created one.
                request.Arguments[i] = cancellationExtension.RecordCancellationToken(grainToken.Id, grainToken.IsCancellationRequested);
            }
        }
        /// <summary>
        /// Returns the <see cref="MethodInfo"/> for the specified implementation and invocation request.
        /// </summary>
        /// <param name="implementationType">The type of the implementation.</param>
        /// <param name="request">The invocation request.</param>
        /// <returns>The <see cref="MethodInfo"/> for the specified implementation and invocation request.</returns>
        public MethodInfo GetMethodInfo(Type implementationType, InvokeMethodRequest request)
        {
            var implementation = this.implementations.GetOrAdd(
                implementationType,
                _ => new ConcurrentDictionary<int, IReadOnlyDictionary<int, MethodInfo>>());

            IReadOnlyDictionary<int, MethodInfo> interfaceMap;
            if (!implementation.TryGetValue(request.InterfaceId, out interfaceMap))
            {
                // Get the interface mapping for the current implementation.
                var interfaces = GrainInterfaceData.GetRemoteInterfaces(implementationType);
                Type interfaceType;
                if (!interfaces.TryGetValue(request.InterfaceId, out interfaceType))
                {
                    // The specified type does not implement the provided interface.
                    return null;
                }

                // Create a mapping between the interface and the implementation.
                interfaceMap = implementation.GetOrAdd(
                    request.InterfaceId,
                    _ => MapInterfaceToImplementation(interfaceType, implementationType));
            }

            // Attempt to retrieve the implementation's MethodInfo.
            MethodInfo result;
            interfaceMap.TryGetValue(request.MethodId, out result);
            return result;
        }
        public Task<object> Invoke(IAddressable grain, InvokeMethodRequest request)
        {
            var interceptor = grain as IGrainInvokeInterceptor;
            if (interceptor != null)
            {
                var methodInfo = this.GetMethodInfo(request.MethodId);
                return interceptor.Invoke(methodInfo, request, this.invoker);
            }

            return this.invoker.Invoke(grain, request);
        }
        public async Task<object> Invoke(MethodInfo methodInfo, InvokeMethodRequest request, IGrainMethodInvoker invoker)
        {
            var initialLastStreamValue = this.lastStreamValue;
            var result = await invoker.Invoke(this, request);

            // If the last stream value changed after the invoke, then the stream must have produced a value, double
            // it for testing purposes.
            if (this.lastStreamValue != initialLastStreamValue)
            {
                this.lastStreamValue *= 2;
            }

            return result;
        }
        /// <summary>
        /// Invoke a grain method.
        /// Invoker classes in generated code implement this method to provide a method call jump-table to map invoke
        /// data to a strongly typed call to the correct method on the correct interface.
        /// </summary>
        /// <param name="grain">Reference to the grain to be invoked.</param>
        /// <param name="request">The request being invoked.</param>
        /// <returns>Value promise for the result of the method invoke.</returns>
        public Task<object> Invoke(IAddressable grain, InvokeMethodRequest request)
        {
            // If the grain implements IGrainInvokeInterceptor then call its implementation, passing
            // the underlying invoker so that the grain can easily dispatch invocation to the correct method.
            var interceptor = grain as IGrainInvokeInterceptor;
            if (interceptor != null)
            {
                var methodInfo = this.GetMethodInfo(request.MethodId);
                return interceptor.Invoke(methodInfo, request, this.invoker);
            }

            // Otherwise, call the underlying invoker directly.
            return this.invoker.Invoke(grain, request);
        }
示例#6
0
        // capture stats
        async Task<object> InvokeInterceptor(MethodInfo targetMethod, InvokeMethodRequest request, IGrain grain, IGrainMethodInvoker invoker)
        {
            // round down to nearest 10 seconds to group results
            var grainName = grain.GetType().FullName;
            var stopwatch = Stopwatch.StartNew();

            // invoke grain
            object result = null;
            if (this.innerInterceptor != null)
            {
                result = await this.innerInterceptor(targetMethod, request, grain, invoker);
            }
            else
            {
                result = await invoker.Invoke(grain, request);
            }

            stopwatch.Stop();

            var elapsedMs = (double)stopwatch.ElapsedTicks / TimeSpan.TicksPerMillisecond;

            var key = $"{grainName}.{targetMethod?.Name ?? "Unknown"}";

            grainTrace.AddOrUpdate(key, _ => {
                return new GrainTraceEntry
                {
                    Count = 1,
                    SiloAddress = siloAddress,
                    ElapsedTime = elapsedMs,
                    Grain = grainName,
                    Method = targetMethod?.Name ?? "Unknown",
                    Period = DateTime.UtcNow
                };
            },
            (_, last) => {
                last.Count += 1;
                last.ElapsedTime += elapsedMs;
                return last;
            });

            return result;
        }
示例#7
0
        internal static Message CreateMessage(InvokeMethodRequest request, InvokeMethodOptions options)
        {
            var message = new Message(
                Message.Categories.Application,
                (options & InvokeMethodOptions.OneWay) != 0 ? Message.Directions.OneWay : Message.Directions.Request)
            {
                Id = CorrelationId.GetNext(),
                InterfaceId = request.InterfaceId,
                MethodId = request.MethodId,
                IsReadOnly = (options & InvokeMethodOptions.ReadOnly) != 0,
                IsUnordered = (options & InvokeMethodOptions.Unordered) != 0,
                BodyObject = request
            };
            
            if ((options & InvokeMethodOptions.AlwaysInterleave) != 0)
                message.IsAlwaysInterleave = true;

            RequestContext.ExportToMessage(message);
            return message;
        }
        public async Task<object> Invoke(MethodInfo methodInfo, InvokeMethodRequest request, IGrainMethodInvoker invoker)
        {
            if (methodInfo.Name == "One" && methodInfo.GetParameters().Length == 0)
            {
                return "intercepted one with no args";
            }

            var result = await invoker.Invoke(this, request);

            // To prove that the MethodInfo is from the implementation and not the interface,
            // we check for this attribute which is only present on the implementation. This could be
            // done in a simpler fashion, but this demonstrates a potential usage scenario.
            var shouldMessWithResult = methodInfo.GetCustomAttribute<MessWithResultAttribute>();
            var resultString = result as string;
            if (shouldMessWithResult != null && resultString !=null)
            {
                result = string.Concat(resultString.Reverse());
            }

            return result;
        }
示例#9
0
 public void SendRequest(GrainReference target, InvokeMethodRequest request, TaskCompletionSource<object> context, Action<Message, TaskCompletionSource<object>> callback, string debugContext = null, InvokeMethodOptions options = InvokeMethodOptions.None, string genericArguments = null)
 {
     var message = Message.CreateMessage(request, options);
     SendRequestMessage(target, message, context, callback, debugContext, options, genericArguments);
 }
示例#10
0
            /// <summary>
            /// Invokes the appropriate grain or extension method for the request interface ID and method ID.
            /// First each extension invoker is tried; if no extension handles the request, then the base
            /// invoker is used to handle the request.
            /// The base invoker will throw an appropriate exception if the request is not recognized.
            /// </summary>
            /// <param name="grain"></param>
            /// <param name="request"></param>
            /// <returns></returns>
            public Task<object> Invoke(IAddressable grain, InvokeMethodRequest request)
            {
                if (extensionMap == null || !extensionMap.ContainsKey(request.InterfaceId))
                    throw new InvalidOperationException(
                        String.Format("Extension invoker invoked with an unknown inteface ID:{0}.", request.InterfaceId));

                var invoker = extensionMap[request.InterfaceId].Item2;
                var extension = extensionMap[request.InterfaceId].Item1;
                return invoker.Invoke(extension, request);
            }
示例#11
0
        public void OnInvoke(InvokeMethodRequest request, IGrain grain)
        {
            // (NOT YET AVAILABLE) Interface name is available from: <c>grainReference.InterfaceName</c>
            // (NOT YET AVAILABLE) Method name is available from: <c>grainReference.GetMethodName(request.InterfaceId, request.MethodId)</c>
            // GrainId is available from: <c>grainReference.GrainId</c>
            // PrimaryKey is availabe from: <c>grainReference.GrainId.GetPrimaryKeyLong()</c> or <c>grainReference.GrainId.GetPrimaryKey()</c> depending on key type.
            // Call arguments are available from: <c>request.Arguments</c> array

            TotalCalls++;

            Console.WriteLine("OnInvoke TotalCalls={0}", TotalCalls);

            try
            {
                Console.WriteLine("OnInvoke called for Grain={0} PrimaryKey={1} GrainId={2} with {3} arguments",
                    grain.GetType().FullName,
                    ((GrainReference) grain).GrainId.GetPrimaryKeyLong(),
                    ((GrainReference) grain).GrainId,
                    request.Arguments != null ? request.Arguments.Length : 0);
            }
            catch (Exception exc)
            {
                Console.WriteLine("**** Error OnInvoke for Grain={0} GrainId={1} with {2} arguments. Exception = {3}",
                    grain.GetType().FullName,
                    ((GrainReference)grain).GrainId,
                    request.Arguments != null ? request.Arguments.Length : 0,
                    exc);
            }

            if (setActivityId != Guid.Empty)
            {
                Trace.CorrelationManager.ActivityId = setActivityId;
                Console.WriteLine("OnInvoke Set ActivityId={0}", setActivityId);
            }
            Console.WriteLine("OnInvoke Current ActivityId={0}", Trace.CorrelationManager.ActivityId);
        }
示例#12
0
        internal static Message CreateMessage(InvokeMethodRequest request, InvokeMethodOptions options)
        {
            var message = new Message(
                Categories.Application,
                (options & InvokeMethodOptions.OneWay) != 0 ? Directions.OneWay : Directions.Request)
            {
                Id = CorrelationId.GetNext(),
                IsReadOnly = (options & InvokeMethodOptions.ReadOnly) != 0,
                IsUnordered = (options & InvokeMethodOptions.Unordered) != 0,
                BodyObject = request
            };

            if ((options & InvokeMethodOptions.AlwaysInterleave) != 0)
                message.IsAlwaysInterleave = true;

            var contextData = RequestContext.Export();
            if (contextData != null)
            {
                message.RequestContextData = contextData;
            }
            return message;
        }
示例#13
0
        private void RunTest(int numItems)
        {
            InvokeMethodRequest request = new InvokeMethodRequest(0, 0, null);
            Message resp = Message.CreateMessage(request, InvokeMethodOptions.None);
            resp.Id = new CorrelationId();
            resp.SendingSilo = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 200), 0);
            resp.TargetSilo = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 300), 0);
            resp.SendingGrain = GrainId.NewId();
            resp.TargetGrain = GrainId.NewId();
            resp.IsAlwaysInterleave = true;

            List<object> requestBody = new List<object>();
            for (int k = 0; k < numItems; k++)
            {
                requestBody.Add(k + ": test line");
            }

            resp.BodyObject = requestBody;

            string s = resp.ToString();
            output.WriteLine(s);

            int dummy = 0;
            var serialized = resp.Serialize(out dummy);
            int length = serialized.Sum<ArraySegment<byte>>(x => x.Count);
            byte[] data = new byte[length];
            int n = 0;
            foreach (var buffer in serialized)
            {
                Array.Copy(buffer.Array, buffer.Offset, data, n, buffer.Count);
                n += buffer.Count;
            }
            resp.ReleaseBodyAndHeaderBuffers();

            int headerLength = BitConverter.ToInt32(data, 0);
            int bodyLength = BitConverter.ToInt32(data, 4);
            Assert.Equal<int>(length, headerLength + bodyLength + 8); //Serialized lengths are incorrect
            byte[] header = new byte[headerLength];
            Array.Copy(data, 8, header, 0, headerLength);
            byte[] body = new byte[bodyLength];
            Array.Copy(data, 8 + headerLength, body, 0, bodyLength);
            var headerList = new List<ArraySegment<byte>>();
            headerList.Add(new ArraySegment<byte>(header));
            var bodyList = new List<ArraySegment<byte>>();
            bodyList.Add(new ArraySegment<byte>(body));
            var resp1 = new Message(headerList, bodyList);

            //byte[] serialized = resp.FormatForSending();
            //Message resp1 = new Message(serialized, serialized.Length);
            Assert.Equal(resp.Category, resp1.Category); //Category is incorrect"
            Assert.Equal(resp.Direction, resp1.Direction); //Direction is incorrect
            Assert.Equal(resp.Id, resp1.Id); //Correlation ID is incorrect
            Assert.Equal(resp.IsAlwaysInterleave, resp1.IsAlwaysInterleave); //Foo Boolean is incorrect
            Assert.Equal(resp.CacheInvalidationHeader, resp1.CacheInvalidationHeader); //Bar string is incorrect
            Assert.True(resp.TargetSilo.Equals(resp1.TargetSilo));
            Assert.True(resp.TargetGrain.Equals(resp1.TargetGrain));
            Assert.True(resp.SendingGrain.Equals(resp1.SendingGrain));
            Assert.True(resp.SendingSilo.Equals(resp1.SendingSilo)); //SendingSilo is incorrect
            List<object> responseList = Assert.IsAssignableFrom<List<object>>(resp1.BodyObject);
            Assert.Equal<int>(numItems, responseList.Count); //Body list has wrong number of entries
            for (int k = 0; k < numItems; k++)
            {
                Assert.IsAssignableFrom<string>(responseList[k]); //Body list item " + k + " has wrong type
                Assert.Equal<string>((string)(requestBody[k]), (string)(responseList[k])); //Body list item " + k + " is incorrect
            }
        }
示例#14
0
        private Task<object> InvokeWithInterceptors(IAddressable target, InvokeMethodRequest request, IGrainMethodInvoker invoker)
        {
            // If the target has a grain-level interceptor or there is a silo-level interceptor, intercept the
            // call.
            var siloWideInterceptor = SiloProviderRuntime.Instance.GetInvokeInterceptor();
            var grainWithInterceptor = target as IGrainInvokeInterceptor;
            
            // Silo-wide interceptors do not operate on system targets.
            var hasSiloWideInterceptor = siloWideInterceptor != null && target is IGrain;
            var hasGrainLevelInterceptor = grainWithInterceptor != null;
            
            if (!hasGrainLevelInterceptor && !hasSiloWideInterceptor)
            {
                // The call is not intercepted at either the silo or the grain level, so call the invoker
                // directly.
                return invoker.Invoke(target, request);
            }

            // Get an invoker which delegates to the grain's IGrainInvocationInterceptor implementation.
            // If the grain does not implement IGrainInvocationInterceptor, then the invoker simply delegates
            // calls to the provided invoker.
            var interceptedMethodInvoker = interceptedMethodInvokerCache.GetOrCreate(
                target.GetType(),
                request.InterfaceId,
                invoker);
            var methodInfo = interceptedMethodInvoker.GetMethodInfo(request.MethodId);
            if (hasSiloWideInterceptor)
            {
                // There is a silo-level interceptor and possibly a grain-level interceptor.
                // As a minor optimization, only pass the intercepted invoker if there is a grain-level
                // interceptor.
                return siloWideInterceptor(
                    methodInfo,
                    request,
                    (IGrain)target,
                    hasGrainLevelInterceptor ? interceptedMethodInvoker : invoker);
            }

            // The grain has an invoke method, but there is no silo-wide interceptor.
            return grainWithInterceptor.Invoke(methodInfo, request, invoker);
        }
示例#15
0
        private static void RunTest(int numItems)
        {
            InvokeMethodRequest request = new InvokeMethodRequest(0, 0, null);
            Message resp = Message.CreateMessage(request, InvokeMethodOptions.None);
            resp.Id = new CorrelationId();
            resp.SendingSilo = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 200), 0);
            resp.TargetSilo = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 300), 0);
            resp.SendingGrain = GrainId.NewId();
            resp.TargetGrain = GrainId.NewId();
            resp.SetHeader(Message.Header.ALWAYS_INTERLEAVE, true);
            resp.SetHeader(Message.Header.CACHE_INVALIDATION_HEADER, "TestBar");
            //resp.SetStringBody("This is test data");

            List<object> requestBody = new List<object>();
            for (int k = 0; k < numItems; k++)
            {
                requestBody.Add(k + ": test line");
            }

            resp.BodyObject = requestBody;

            string s = resp.ToString();
            Console.WriteLine(s);

            var serialized = resp.Serialize();
            int length = serialized.Sum<ArraySegment<byte>>(x => x.Count);
            byte[] data = new byte[length];
            int n = 0;
            foreach (var buffer in serialized)
            {
                Array.Copy(buffer.Array, buffer.Offset, data, n, buffer.Count);
                n += buffer.Count;
            }
            resp.ReleaseBodyAndHeaderBuffers();

            int headerLength = BitConverter.ToInt32(data, 0);
            int bodyLength = BitConverter.ToInt32(data, 4);
            Assert.AreEqual<int>(length, headerLength + bodyLength + 8, "Serialized lengths are incorrect");
            byte[] header = new byte[headerLength];
            Array.Copy(data, 8, header, 0, headerLength);
            byte[] body = new byte[bodyLength];
            Array.Copy(data, 8 + headerLength, body, 0, bodyLength);
            var headerList = new List<ArraySegment<byte>>();
            headerList.Add(new ArraySegment<byte>(header));
            var bodyList = new List<ArraySegment<byte>>();
            bodyList.Add(new ArraySegment<byte>(body));
            var resp1 = new Message(headerList, bodyList);

            //byte[] serialized = resp.FormatForSending();
            //Message resp1 = new Message(serialized, serialized.Length);
            Assert.AreEqual<Message.Categories>(resp.Category, resp1.Category, "Category is incorrect");
            Assert.AreEqual<Message.Directions>(resp.Direction, resp1.Direction, "Direction is incorrect");
            Assert.AreEqual<CorrelationId>(resp.Id, resp1.Id, "Correlation ID is incorrect");
            Assert.AreEqual<bool>((bool)resp.GetHeader(Message.Header.ALWAYS_INTERLEAVE), (bool)resp1.GetHeader(Message.Header.ALWAYS_INTERLEAVE), "Foo Boolean is incorrect");
            Assert.AreEqual<string>((string)resp.GetHeader(Message.Header.CACHE_INVALIDATION_HEADER), (string)resp1.GetHeader(Message.Header.CACHE_INVALIDATION_HEADER), "Bar string is incorrect");
            Assert.IsTrue(resp.TargetSilo.Equals(resp1.TargetSilo), "TargetSilo is incorrect");
            Assert.IsTrue(resp.SendingSilo.Equals(resp1.SendingSilo), "SendingSilo is incorrect");
            Assert.IsInstanceOfType(resp1.BodyObject, typeof(List<object>), "Body object is wrong type");
            List<object> responseList = resp1.BodyObject as List<object>;
            Assert.AreEqual<int>(numItems, responseList.Count, "Body list has wrong number of entries");
            for (int k = 0; k < numItems; k++)
            {
                Assert.IsInstanceOfType(responseList[k], typeof(string), "Body list item " + k + " has wrong type");
                Assert.AreEqual<string>((string)(requestBody[k]), (string)(responseList[k]), "Body list item " + k + " is incorrect");
            }
        }
        // capture stats
        async Task<object> InvokeInterceptor(MethodInfo targetMethod, InvokeMethodRequest request, IGrain grain, IGrainMethodInvoker invoker)
        {
            var grainName = grain.GetType().FullName;
            var stopwatch = Stopwatch.StartNew();

            // invoke grain
            object result = null;
            var isException = false;

            try
            {
                if (this.innerInterceptor != null)
                {
                    result = await this.innerInterceptor(targetMethod, request, grain, invoker);
                }
                else
                {
                    result = await invoker.Invoke(grain, request);
                }
            }
            catch (Exception ex)
            {
                isException = true;
                throw;
            }
            finally
            {

                try
                {
                    stopwatch.Stop();

                    var elapsedMs = (double)stopwatch.ElapsedTicks / TimeSpan.TicksPerMillisecond;

                    var key = string.Format("{0}.{1}", grainName, targetMethod?.Name ?? "Unknown");

                    grainTrace.AddOrUpdate(key, _ =>
                    {
                        return new GrainTraceEntry
                        {
                            Count = 1,
                            ExceptionCount = (isException ? 1 : 0),
                            SiloAddress = siloAddress,
                            ElapsedTime = elapsedMs,
                            Grain = grainName ,
                            Method = targetMethod?.Name ?? "Unknown",
                            Period = DateTime.UtcNow
                        };
                    },
                    (_, last) =>
                    {
                        last.Count += 1;
                        last.ElapsedTime += elapsedMs;
                        if (isException) last.ExceptionCount += 1;
                        return last;
                    });
                }
                catch (Exception ex)
                {
                    this.Logger.Error(100002, "error recording results for grain", ex);
                }
            }

            return result;
        }