예제 #1
0
        private static bool?CreateIndexesForASingleInterface(ApplicationPartsIndexableGrainLoader loader, IndexRegistry registry,
                                                             Type propertiesClassType, Type grainInterfaceType, Type grainClassType,
                                                             ConsistencyScheme consistencyScheme, bool?grainIndexesAreEager)
        {
            // All the properties in TProperties are scanned for Index annotation.
            // If found, the index is created using the information provided in the annotation.
            var indexesOnInterface = new NamedIndexMap(propertiesClassType);

            foreach (var propInfo in propertiesClassType.GetProperties())
            {
                var indexAttrs = propInfo.GetCustomAttributes <IndexAttribute>(inherit: false);
                foreach (var indexAttr in indexAttrs)
                {
                    var indexName = IndexUtils.PropertyNameToIndexName(propInfo.Name);
                    if (indexesOnInterface.ContainsKey(indexName))
                    {
                        throw new InvalidOperationException($"An index named {indexName} already exists for user-defined grain interface {grainInterfaceType.Name}");
                    }

                    var indexType = (Type)indexTypeProperty.GetValue(indexAttr);
                    if (consistencyScheme == ConsistencyScheme.Transactional)
                    {
                        var transactionalVariantAttr = indexType.GetCustomAttribute <TransactionalIndexVariantAttribute>();
                        if (transactionalVariantAttr != null)
                        {
                            indexType = transactionalVariantAttr.TransactionalIndexType;
                        }
                    }
                    if (indexType.IsGenericTypeDefinition)
                    {
                        // For the (Active|Total) constructors that take (Active|Total)IndexType parameters, leaving the indexType's key type and interface type
                        // generic arguments as "<,>", this fills them in.
                        indexType = indexType.MakeGenericType(propInfo.PropertyType, grainInterfaceType);
                    }

                    // If it's not eager, then it's configured to be lazily updated
                    var isEager = (bool)isEagerProperty.GetValue(indexAttr);
                    if (!grainIndexesAreEager.HasValue)
                    {
                        grainIndexesAreEager = isEager;
                    }
                    var isUnique = (bool)isUniqueProperty.GetValue(indexAttr);

                    ValidateSingleIndex(indexAttr, grainInterfaceType, grainClassType, propertiesClassType, propInfo, grainIndexesAreEager,
                                        consistencyScheme, isEager: isEager, isUnique: isUnique);   // Multiple bools, so use param names for safety

                    var maxEntriesPerBucket = (int)maxEntriesPerBucketProperty.GetValue(indexAttr);
                    if (loader != null)
                    {
                        loader.CreateIndex(propertiesClassType, grainInterfaceType, indexesOnInterface, propInfo, indexName, indexType, isEager, isUnique, maxEntriesPerBucket);
                    }
                    else
                    {
                        IndexFactory.ValidateIndexType(indexType, propInfo, out _, out _);
                    }
                }
            }
            registry[grainInterfaceType] = indexesOnInterface;
            return(grainIndexesAreEager);
        }
예제 #2
0
        /// <summary>
        /// This method crawls the assemblies and looks for the index definitions (determined by extending the <see cref="IIndexableGrain{TProperties}"/>
        /// interface and adding annotations to properties in TProperties), and registers the grain services needed for queues and PerSilo partitioning.
        /// </summary>
        /// <remarks>This two-step approach (RegisterGrainServices and then CreateIndexRegistry) is necessary because GrainServices should be
        /// registered to the IServiceCollection before Silo construction and the rest of Index creation requires the IServiceProvider which
        /// is created as part of Silo construction.</remarks>
        /// <returns>An index registry for the silo. </returns>
        internal static void RegisterGrainServices(HostBuilderContext context, IServiceCollection services, IndexingOptions indexingOptions)
        {
            var indexedClasses    = new HashSet <Type>();
            var indexedInterfaces = new HashSet <Type>();

            foreach (var grainClassType in GetIndexedConcreteGrainClasses(context.GetApplicationPartManager()))
            {
                var consistencyScheme = grainClassType.GetConsistencyScheme();
                if (consistencyScheme == ConsistencyScheme.Transactional)
                {
                    continue;
                }

                var indexedInterfacesAndProperties = EnumerateIndexedInterfacesForAGrainClassType(grainClassType).ToList();
                foreach (var(grainInterfaceType, propertiesClassType) in indexedInterfacesAndProperties)
                {
                    if (indexedInterfaces.Contains(grainInterfaceType))
                    {
                        continue;
                    }
                    indexedInterfaces.Add(grainInterfaceType);

                    var createQueues = consistencyScheme != ConsistencyScheme.Transactional;
                    foreach (var propInfo in propertiesClassType.GetProperties())
                    {
                        var indexName  = IndexUtils.PropertyNameToIndexName(propInfo.Name);
                        var indexAttrs = propInfo.GetCustomAttributes <IndexAttribute>(inherit: false);
                        foreach (var indexAttr in indexAttrs)
                        {
                            if (createQueues && !(bool)isEagerProperty.GetValue(indexAttr))
                            {
                                // Queues are per-interface, not per-index.
                                IndexFactory.RegisterIndexWorkflowQueueGrainServices(services, grainInterfaceType, indexingOptions,
                                                                                     consistencyScheme == ConsistencyScheme.FaultTolerantWorkflow);
                            }
                            createQueues = false;

                            var indexType = (Type)indexTypeProperty.GetValue(indexAttr);
                            var regMethod = indexType.GetCustomAttribute <PerSiloIndexGrainServiceClassAttribute>(inherit: false)
                                            ?.GrainServiceClassType
                                            ?.GetMethod("RegisterGrainService", BindingFlags.Static | BindingFlags.NonPublic);
                            if (regMethod != null)  // Static method so cannot use an interface
                            {
                                var regDelegate = (Action <IServiceCollection, Type, string>)Delegate.CreateDelegate(typeof(Action <IServiceCollection, Type, string>), regMethod);
                                regDelegate(services, grainInterfaceType, indexName);
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 /// This method tries to pull out the index name from a given field expression.
 /// </summary>
 /// <param name="exprTree">the original expression tree</param>
 /// <param name="fieldExpr">the field expression that should contain the indexed field</param>
 /// <param name="indexName">receives the index name, if <paramref name="fieldExpr"/> is a query property</param>
 /// <returns>A bool value indicating whether the index name was found</returns>
 private static bool GetIndexName(LambdaExpression exprTree, Expression fieldExpr, out string indexName)
 {
     if (fieldExpr is MemberExpression memberExpression)
     {
         ParameterExpression fieldParam     = exprTree.Parameters[0];
         Expression          innerFieldExpr = memberExpression.Expression;
         if ((innerFieldExpr.NodeType == ExpressionType.Parameter && innerFieldExpr.Equals(fieldParam)) ||
             (innerFieldExpr.NodeType == ExpressionType.Convert && innerFieldExpr is UnaryExpression ue && ue.Operand.Equals(fieldParam)))
         {
             indexName = IndexUtils.PropertyNameToIndexName(memberExpression.Member.Name);
             return(true);
         }
     }
     indexName = null;
     return(false);
 }