/// <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); }
// 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; }
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; }
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); }
/// <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); }
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); }
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; }
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 } }
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); }
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; }