public void CodeGen_EncounteredFullySpecifiedInterfacesAreEncodedDistinctly() { var id1 = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IFullySpecified <int>)); var id2 = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IFullySpecified <long>)); Assert.NotEqual(id1, id2); }
public void TypeCodesMatch() { var wellKnownTypes = WellKnownTypes.FromCompilation(this.compilation); foreach (var(type, symbol) in GetTypeSymbolPairs(nameof(Grains))) { this.output.WriteLine($"Type: {RuntimeTypeNameFormatter.Format(type)}"); { // First check Type.FullName matches. var expected = type.FullName; var actual = RoslynTypeNameFormatter.Format(symbol, RoslynTypeNameFormatter.Style.FullName); this.output.WriteLine($"Expected FullName: {expected}\nActual FullName: {actual}"); Assert.Equal(expected, actual); } { var expected = TypeUtils.GetTemplatedName( TypeUtils.GetFullName(type), type, type.GetGenericArguments(), t => false); var named = Assert.IsAssignableFrom <INamedTypeSymbol>(symbol); var actual = OrleansLegacyCompat.FormatTypeForIdComputation(named); this.output.WriteLine($"Expected format: {expected}\nActual format: {actual}"); Assert.Equal(expected, actual); } { var expected = GrainInterfaceUtils.GetGrainInterfaceId(type); var named = Assert.IsAssignableFrom <INamedTypeSymbol>(symbol); var actual = wellKnownTypes.GetTypeId(named); this.output.WriteLine($"Expected Id: 0x{expected:X}\nActual Id: 0x{actual:X}"); Assert.Equal(expected, actual); } } }
private GrainInterfaceData GetOrAddGrainInterfaceData(Type iface, bool isGenericGrainClass) { var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(iface); // If already exist GrainInterfaceData grainInterfaceData; if (table.TryGetValue(interfaceId, out grainInterfaceData)) { return(grainInterfaceData); } // If not create new entry var interfaceName = TypeUtils.GetRawClassName(TypeUtils.GetFullName(iface)); grainInterfaceData = new GrainInterfaceData(interfaceId, iface, interfaceName); table[interfaceId] = grainInterfaceData; // Add entry to mapping iface string -> data var interfaceTypeKey = GetTypeKey(iface, isGenericGrainClass); typeToInterfaceData[interfaceTypeKey] = grainInterfaceData; // If we are adding a concrete implementation of a generic interface // add also the latter to the map: GrainReference and InvokeMethodRequest // always use the id of the generic one if (iface.IsConstructedGenericType) { GetOrAddGrainInterfaceData(iface.GetGenericTypeDefinition(), true); } return(grainInterfaceData); }
public void Generic_InterfaceId_Test() { var expected = GrainInterfaceUtils.GetGrainInterfaceId(typeof(ISimpleGenericGrain <>)); IDictionary <int, Type> actual = GrainInterfaceUtils.GetRemoteInterfaces(typeof(SimpleGenericGrain <>)); Assert.Contains(expected, actual); }
/// <summary> /// Registers a grain extension implementation for the specified interface. /// </summary> /// <typeparam name="TExtensionInterface">The <see cref="IGrainExtension"/> interface being registered.</typeparam> /// <typeparam name="TExtension">The implementation of <typeparamref name="TExtensionInterface"/>.</typeparam> public static ISiloBuilder AddGrainExtension <TExtensionInterface, TExtension>(this ISiloBuilder builder) where TExtensionInterface : class, IGrainExtension where TExtension : class, TExtensionInterface { int interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(typeof(TExtensionInterface)); return(builder.ConfigureServices(services => services.AddTransientKeyedService <int, IGrainExtension, TExtension>(interfaceId))); }
public void Generic_InterfaceId_Test() { var expected = GrainInterfaceUtils.GetGrainInterfaceId(typeof(ISimpleGenericGrain <>)); var actual = GrainInterfaceUtils.GetRemoteInterfaces(typeof(SimpleGenericGrain <>)); Assert.Single(actual); Assert.Equal(expected, GrainInterfaceUtils.GetGrainInterfaceId(actual[0])); }
public void Override_InterfaceId_Test() { var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IMethodInterceptionGrain)); Assert.Equal(6548972, interfaceId); interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IOutgoingMethodInterceptionGrain)); Assert.Equal(-6548972, interfaceId); }
/// <summary> /// Creates and returns a map from interface id to map of method id to method info for the provided non-generic type. /// </summary> /// <param name="implementationType">The implementation type.</param> /// <returns>A map from interface id to map of method id to method info for the provided type.</returns> private static Dictionary <int, Dictionary <int, Entry> > CreateMapForNonGeneric(Type implementationType) { if (implementationType.IsConstructedGenericType) { throw new InvalidOperationException( $"Type {implementationType} passed to {nameof(CreateMapForNonGeneric)} is a constructed generic type."); } var implementationTypeInfo = implementationType.GetTypeInfo(); var interfaces = implementationType.GetInterfaces(); // Create an invoker for every interface on the provided type. var result = new Dictionary <int, Dictionary <int, Entry> >(interfaces.Length); foreach (var iface in interfaces) { var methods = GrainInterfaceUtils.GetMethods(iface); // Map every method on this interface from the definition interface onto the implementation class. var methodMap = new Dictionary <int, Entry>(methods.Length); var mapping = default(InterfaceMapping); foreach (var method in methods) { // If this method is not from the expected interface (eg, because it's from a parent interface), then // get the mapping for the interface which it does belong to. if (mapping.InterfaceType != method.DeclaringType) { mapping = implementationTypeInfo.GetRuntimeInterfaceMap(method.DeclaringType); } // Find the index of the interface method and then get the implementation method at that position. for (var k = 0; k < mapping.InterfaceMethods.Length; k++) { if (mapping.InterfaceMethods[k] != method) { continue; } methodMap[GrainInterfaceUtils.ComputeMethodId(method)] = new Entry(mapping.TargetMethods[k], method); break; } } // Add the resulting map of methodId -> method to the interface map. var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(iface); result[interfaceId] = methodMap; } return(result); }
private IGrainExtensionMethodInvoker TryGetExtensionInvoker(Type handlerType) { var interfaces = GrainInterfaceUtils.GetRemoteInterfaces(handlerType).Values; if (interfaces.Count != 1) throw new InvalidOperationException($"Extension type {handlerType.FullName} implements more than one grain interface."); var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(interfaces.First()); var invoker = typeManager.GetInvoker(interfaceId); if (invoker != null) return (IGrainExtensionMethodInvoker)invoker; throw new ArgumentException( $"Provider extension handler type {handlerType} was not found in the type manager", nameof(handlerType)); }
public async Task ChangeCompatibilityStrategy() { var ifaceId = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IVersionUpgradeTestGrain)); await DeployCluster(); var grainV1 = Client.GetGrain <IVersionUpgradeTestGrain>(0); Assert.Equal(1, await grainV1.GetVersion()); await StartSiloV2(); var grainV2 = Client.GetGrain <IVersionUpgradeTestGrain>(1); Assert.Equal(2, await grainV2.GetVersion()); // Current policy "AllVersionsCompatible" -> no downgrade Assert.Equal(2, await grainV1.ProxyGetVersion(grainV2)); Assert.Equal(2, await grainV2.GetVersion()); Assert.Equal(1, await grainV1.GetVersion()); await ManagementGrain.SetCompatibilityStrategy(ifaceId, StrictVersionCompatible.Singleton); // Current policy "StrictVersionCompatible" -> Downgrade mandatory Assert.Equal(1, await grainV1.ProxyGetVersion(grainV2)); Assert.Equal(1, await grainV2.GetVersion()); Assert.Equal(1, await grainV1.GetVersion()); // Since this client is V1, only V1 should be activated, even with the "LatestVersion" rule for (var i = 2; i < 102; i++) { var grain = Client.GetGrain <IVersionUpgradeTestGrain>(i); Assert.Equal(1, await grain.GetVersion()); } // Fallback to AllVersionsCompatible await ManagementGrain.SetCompatibilityStrategy(ifaceId, null); // Now we should activate only v2 for (var i = 102; i < 202; i++) { var grain = Client.GetGrain <IVersionUpgradeTestGrain>(i); Assert.Equal(2, await grain.GetVersion()); } }
public async Task ChangeVersionSelectorStrategy() { var ifaceId = GrainInterfaceUtils.GetGrainInterfaceId(typeof(IVersionUpgradeTestGrain)); await DeployCluster(); // Only V1 exists var grainV1 = Client.GetGrain <IVersionUpgradeTestGrain>(0); Assert.Equal(1, await grainV1.GetVersion()); await StartSiloV2(); // Don't touch to V1 Assert.Equal(1, await grainV1.GetVersion()); // But only activate V2 for (int i = 1; i < 101; i++) { var grain = Client.GetGrain <IVersionUpgradeTestGrain>(i); Assert.Equal(2, await grain.GetVersion()); } await ManagementGrain.SetSelectorStrategy(ifaceId, MinimumVersion.Singleton); // Don't touch to existing activation Assert.Equal(1, await grainV1.GetVersion()); for (int i = 1; i < 101; i++) { var grain = Client.GetGrain <IVersionUpgradeTestGrain>(i); Assert.Equal(2, await grain.GetVersion()); } // But only activate V1 for (int i = 101; i < 201; i++) { var grain = Client.GetGrain <IVersionUpgradeTestGrain>(i); Assert.Equal(1, await grain.GetVersion()); } }
private void AddToGrainInterfaceToClassMap(Type grainClass, IEnumerable <Type> grainInterfaces, bool isUnordered) { var grainTypeInfo = grainClass.GetTypeInfo(); var grainClassCompleteName = TypeUtils.GetFullName(grainTypeInfo); var isGenericGrainClass = grainTypeInfo.ContainsGenericParameters; var grainClassTypeCode = GrainInterfaceUtils.GetGrainClassTypeCode(grainClass); var placement = GrainTypeData.GetPlacementStrategy(grainClass, this.defaultPlacementStrategy); var registrationStrategy = GrainTypeData.GetMultiClusterRegistrationStrategy(grainClass); foreach (var iface in grainInterfaces) { var ifaceCompleteName = TypeUtils.GetFullName(iface); var ifaceName = TypeUtils.GetRawClassName(ifaceCompleteName); var isPrimaryImplementor = IsPrimaryImplementor(grainClass, iface); var ifaceId = GrainInterfaceUtils.GetGrainInterfaceId(iface); grainInterfaceMap.AddEntry(ifaceId, iface, grainClassTypeCode, ifaceName, grainClassCompleteName, grainTypeInfo.Assembly.CodeBase, isGenericGrainClass, placement, registrationStrategy, isPrimaryImplementor); } if (isUnordered) { grainInterfaceMap.AddToUnorderedList(grainClassTypeCode); } }
/// <summary> /// Creates and returns a map from interface id to map of method id to method info for the provided constructed generic type. /// </summary> /// <param name="implementationType">The implementation type.</param> /// <returns>A map from interface id to map of method id to method info for the provided type.</returns> private static Dictionary <int, Dictionary <int, Entry> > CreateMapForConstructedGeneric(Type implementationType) { // It is important to note that the interfaceId and methodId are computed based upon the non-concrete // version of the implementation type. During code generation, the concrete type would not be available // and therefore the generic type definition is used. if (!implementationType.IsConstructedGenericType) { throw new InvalidOperationException( $"Type {implementationType} passed to {nameof(CreateMapForConstructedGeneric)} is not a constructed generic type"); } var genericClass = implementationType.GetGenericTypeDefinition(); var genericInterfaces = genericClass.GetInterfaces(); var concreteInterfaces = implementationType.GetInterfaces(); // Create an invoker for every interface on the provided type. var result = new Dictionary <int, Dictionary <int, Entry> >(genericInterfaces.Length); for (var i = 0; i < genericInterfaces.Length; i++) { // Because these methods are identical except for type parameters, their methods should also be identical except // for type parameters, including identical ordering. That is the assumption. var genericMethods = GrainInterfaceUtils.GetMethods(genericInterfaces[i]); var concreteInterfaceMethods = GrainInterfaceUtils.GetMethods(concreteInterfaces[i]); // Map every method on this interface from the definition interface onto the implementation class. var methodMap = new Dictionary <int, Entry>(genericMethods.Length); var genericMap = default(InterfaceMapping); var concreteMap = default(InterfaceMapping); for (var j = 0; j < genericMethods.Length; j++) { // If this method is not from the expected interface (eg, because it's from a parent interface), then // get the mapping for the interface which it does belong to. var genericInterfaceMethod = genericMethods[j]; if (genericMap.InterfaceType != genericInterfaceMethod.DeclaringType) { genericMap = genericClass.GetTypeInfo().GetRuntimeInterfaceMap(genericInterfaceMethod.DeclaringType); concreteMap = implementationType.GetTypeInfo().GetRuntimeInterfaceMap(concreteInterfaceMethods[j].DeclaringType); } // Determine the position in the definition's map which the target method belongs to and take the implementation // from the same position on the implementation's map. for (var k = 0; k < genericMap.InterfaceMethods.Length; k++) { if (genericMap.InterfaceMethods[k] != genericInterfaceMethod) { continue; } methodMap[GrainInterfaceUtils.ComputeMethodId(genericInterfaceMethod)] = new Entry(concreteMap.TargetMethods[k], concreteMap.InterfaceMethods[k]); break; } } // Add the resulting map of methodId -> method to the interface map. var interfaceId = GrainInterfaceUtils.GetGrainInterfaceId(genericInterfaces[i]); result[interfaceId] = methodMap; } return(result); }
/// <summary> /// Generates switch cases for the provided grain type. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="methodIdArgument"> /// The method id argument, which is used to select the correct switch label. /// </param> /// <param name="generateMethodHandler"> /// The function used to generate switch block statements for each method. /// </param> /// <returns> /// The switch cases for the provided grain type. /// </returns> public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch( Type grainType, ExpressionSyntax methodIdArgument, Func <MethodInfo, StatementSyntax[]> generateMethodHandler) { var interfaces = GrainInterfaceUtils.GetRemoteInterfaces(grainType); interfaces[GrainInterfaceUtils.GetGrainInterfaceId(grainType)] = grainType; // Switch on interface id. var interfaceCases = new List <SwitchSectionSyntax>(); foreach (var @interface in interfaces) { var interfaceType = @interface.Value; var interfaceId = @interface.Key; var methods = GrainInterfaceUtils.GetMethods(interfaceType); var methodCases = new List <SwitchSectionSyntax>(); // Switch on method id. foreach (var method in methods) { // Generate switch case. var methodId = GrainInterfaceUtils.ComputeMethodId(method); var methodType = method; // Generate the switch label for this interface id. var methodIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Generate the switch body. var methodInvokeStatement = generateMethodHandler(methodType); methodCases.Add( SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement)); } // Generate the switch label for this interface id. var interfaceIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), SF.BinaryExpression( SyntaxKind.AddExpression, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)), SF.BinaryExpression( SyntaxKind.AddExpression, ",methodId=".GetLiteralExpression(), methodIdArgument))); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); // Generate switch statements for the methods in this interface. var methodSwitchStatements = SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase); // Generate the switch section for this interface. interfaceCases.Add( SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements)); } return(interfaceCases.ToArray()); }