示例#1
0
        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);
                }
            }
        }
示例#3
0
        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);
        }
示例#4
0
        public void Generic_InterfaceId_Test()
        {
            var expected = GrainInterfaceUtils.GetGrainInterfaceId(typeof(ISimpleGenericGrain <>));
            IDictionary <int, Type> actual = GrainInterfaceUtils.GetRemoteInterfaces(typeof(SimpleGenericGrain <>));

            Assert.Contains(expected, actual);
        }
示例#5
0
        /// <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)));
        }
示例#6
0
        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]));
        }
示例#7
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);
        }
示例#8
0
        /// <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);
        }
示例#9
0
        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));
        }
示例#10
0
        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());
            }
        }
示例#11
0
        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());
            }
        }
示例#12
0
        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);
            }
        }
示例#13
0
        /// <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());
        }