Exemple #1
0
 internal static bool CreateInstance(IndexRegistry registry, Type grainType, out GrainIndexes grainIndexes)
 {
     grainIndexes = registry.TryGetGrainIndexedInterfaces(grainType, out Type[] indexedInterfaces)
                     ? new GrainIndexes(registry, indexedInterfaces, registry.GetNullPropertyValuesForGrain(grainType))
                     : null;
     return(grainIndexes != null);
 }
Exemple #2
0
        internal static IndexRegistry GetIndexRegistry(ApplicationPartsIndexableGrainLoader loader, IEnumerable <Type> grainClassTypes)
        {
            var registry = new IndexRegistry();

            foreach (var grainClassType in grainClassTypes)
            {
                if (registry.ContainsGrainType(grainClassType))
                {
                    throw new InvalidOperationException($"Precondition violated: GetIndexRegistry should not encounter a duplicate grain class type ({IndexUtils.GetFullTypeName(grainClassType)})");
                }
                GetIndexesForASingleGrainType(loader, registry, grainClassType);
            }
            return(registry);
        }
Exemple #3
0
        internal async static Task <IndexRegistry> GetIndexRegistry(ApplicationPartsIndexableGrainLoader loader, Type[] grainTypes)
        {
            var registry = new IndexRegistry();

            foreach (var grainType in grainTypes)
            {
                if (registry.ContainsKey(grainType))
                {
                    throw new InvalidOperationException($"Precondition violated: GetGrainClassIndexes should not encounter a duplicate type ({IndexUtils.GetFullTypeName(grainType)})");
                }
                await GetIndexesForASingleGrainType(loader, registry, grainType);
            }
            return(registry);
        }
Exemple #4
0
 private GrainIndexes(IndexRegistry registry, IEnumerable <Type> indexedInterfaceTypes, IReadOnlyDictionary <string, object> propertyNullValues)
 {
     this.indexRegistry       = registry;
     this.PropertyNullValues  = propertyNullValues;
     this.interfaceToIndexMap = indexedInterfaceTypes.ToDictionary(itf => itf, itf => new InterfaceIndexes(registry[itf]));
 }
Exemple #5
0
        private async static Task <bool?> CreateIndexesForASingleInterface(ApplicationPartsIndexableGrainLoader loader, IndexRegistry registry, Type propertiesArgType,
                                                                           Type userDefinedIGrain, Type userDefinedGrainImpl, 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.
            NamedIndexMap indexesOnGrain        = new NamedIndexMap();
            var           interfaceHasLazyIndex = false; // Use a separate value from grainIndexesAreEager in case we change to allow mixing eager and lazy on a single grain.

            foreach (PropertyInfo propInfo in propertiesArgType.GetProperties())
            {
                var indexAttrs = propInfo.GetCustomAttributes <IndexAttribute>(inherit: false);
                foreach (var indexAttr in indexAttrs)
                {
                    string indexName = "__" + propInfo.Name;
                    if (indexesOnGrain.ContainsKey(indexName))
                    {
                        throw new InvalidOperationException($"An index named {indexName} already exists for user-defined grain interface {userDefinedIGrain.Name}");
                    }

                    Type indexType = (Type)indexTypeProperty.GetValue(indexAttr);
                    if (indexType.IsGenericTypeDefinition)
                    {
                        indexType = indexType.MakeGenericType(propInfo.PropertyType, userDefinedIGrain);
                    }

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

                    ValidateSingleIndex(indexAttr, userDefinedIGrain, userDefinedGrainImpl, propertiesArgType, propInfo, grainIndexesAreEager, isEager, isUnique);

                    int maxEntriesPerBucket = (int)maxEntriesPerBucketProperty.GetValue(indexAttr);
                    if (loader != null)
                    {
                        await loader.CreateIndex(propertiesArgType, userDefinedIGrain, indexesOnGrain, propInfo, indexName, indexType, isEager, isUnique, maxEntriesPerBucket);
                    }
                }
            }
            registry[userDefinedIGrain] = indexesOnGrain;
            if (interfaceHasLazyIndex && loader != null)
            {
                await loader.RegisterWorkflowQueues(userDefinedIGrain, userDefinedGrainImpl);
            }
            return(grainIndexesAreEager);
        }
Exemple #6
0
        private async static Task GetIndexesForASingleGrainType(ApplicationPartsIndexableGrainLoader loader, IndexRegistry registry, Type grainType)
        {
            Type[] interfaces           = grainType.GetInterfaces();
            bool?  grainIndexesAreEager = null;

            // If there is an interface that directly extends IIndexableGrain<TProperties>...
            Type iIndexableGrain = interfaces.Where(itf => itf.IsGenericType && itf.GetGenericTypeDefinition() == typeof(IIndexableGrain <>)).FirstOrDefault();

            if (iIndexableGrain != null)
            {
                // ... and its generic argument is a class (TProperties)...
                Type propertiesArgType = iIndexableGrain.GetGenericArguments()[0];
                if (propertiesArgType.GetTypeInfo().IsClass)
                {
                    // ... then add the indexes for all the descendant interfaces of IIndexableGrain<TProperties>; these interfaces are defined by end-users.
                    foreach (Type userDefinedIGrain in interfaces.Where(itf => iIndexableGrain != itf && iIndexableGrain.IsAssignableFrom(itf) && !registry.ContainsKey(itf)))
                    {
                        grainIndexesAreEager = await CreateIndexesForASingleInterface(loader, registry, propertiesArgType, userDefinedIGrain, grainType, grainIndexesAreEager);
                    }
                }
            }
        }
Exemple #7
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);
        }
Exemple #8
0
        private static void GetIndexesForASingleGrainType(ApplicationPartsIndexableGrainLoader loader, IndexRegistry registry, Type grainClassType)
        {
            // First see if any indexed interfaces on this grain were already encountered on another grain (unless we're
            // in validation mode, which doesn't create the indexes).
            var indexedInterfacesAndProperties = EnumerateIndexedInterfacesForAGrainClassType(grainClassType).ToList();
            var indexedInterfaces = loader != null
                    ? new HashSet <Type>(indexedInterfacesAndProperties.Select(tup => tup.interfaceType).Where(itfType => registry.ContainsKey(itfType)))
                    : new HashSet <Type>();

            var grainIndexesAreEager = indexedInterfaces.Count > 0 ? registry[indexedInterfaces.First()].HasAnyEagerIndex : default(bool?);
            var consistencyScheme    = grainClassType.GetConsistencyScheme();

            // Now find all indexed interfaces we're seeing for the first time (again, unless we're in validation mode).
            foreach (var(grainInterfaceType, propertiesClassType) in indexedInterfacesAndProperties)
            {
                if (!indexedInterfaces.Contains(grainInterfaceType))
                {
                    grainIndexesAreEager = CreateIndexesForASingleInterface(loader, registry, propertiesClassType, grainInterfaceType,
                                                                            grainClassType, consistencyScheme, grainIndexesAreEager);
                    indexedInterfaces.Add(grainInterfaceType);
                }
            }

            IReadOnlyDictionary <string, object> getNullValuesDictionary()
            {
                IEnumerable <(string propName, (string itfName, object nullValue))> getNullPropertyValuesForInterface(Type interfaceType)
                => registry[interfaceType].PropertiesClassType.GetProperties()
                .Select(info => (name: info.Name, nullSpec: (itfname: interfaceType.Name, nullValue: IndexUtils.GetNullValue(info))))
                .Where(p => p.nullSpec.nullValue != null);

                Dictionary <string, (string, object)> addToDict(Dictionary <string, (string, object)> dict, (string propName, (string itfName, object nullValue)nullSpec) current)
                {
                    bool isInDict(string propName)
                    {
                        return(dict.TryGetValue(propName, out (string itfName, object nullValue)prevNullSpec)
                            ? (prevNullSpec.nullValue.Equals(current.nullSpec.nullValue)
                                ? true
                                : throw new IndexConfigurationException($"Property {propName} has conflicting NullValues defined on interfaces {prevNullSpec.itfName} and {current.nullSpec.itfName}"))
                            : false);
                    }

                    if (!isInDict(current.propName))
                    {
                        dict[current.propName] = current.nullSpec;
                    }
                    return(dict);
                }

                return(indexedInterfaces.SelectMany(itf => getNullPropertyValuesForInterface(itf))
                       .Aggregate(new Dictionary <string, (string itfName, object nullValue)>(), (dict, pair) => addToDict(dict, pair))
                       .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.nullValue));
            }

            if (indexedInterfaces.Count > 0)
            {
                registry.SetGrainIndexes(grainClassType, indexedInterfaces.ToArray(), getNullValuesDictionary());
            }
        }
Exemple #9
0
 /// <summary>
 /// Provides the index information for a given grain interface type.
 /// </summary>
 /// <typeparam name="T">The target grain interface type</typeparam>
 /// <returns>the index information for the given grain type T.
 /// The index information is a dictionary from indexIDs defined
 /// on a grain interface to a triple. The triple consists of:
 /// 1) the index object that implements IndexInterface,
 /// 2) the IndexMetaData object for this index, and
 /// 3) the IndexUpdateGenerator instance for this index.
 /// This triple is untyped, because IndexInterface, IndexMetaData
 /// and IndexUpdateGenerator types are not visible in this project.
 ///
 /// This method returns an empty dictionary if the OrleansIndexing
 /// project is not available.</returns>
 internal static IDictionary <string, Tuple <object, object, object> > GetIndexes <T>() where T : IIndexableGrain
 {
     return(IndexRegistry.GetIndexes <T>());
 }
Exemple #10
0
 /// <summary>
 /// Provides the index information for a given grain interface type.
 /// </summary>
 /// <param name="iGrainType">The target grain interface type</param>
 /// <returns>the index information for the given grain type T.
 /// The index information is a dictionary from indexIDs defined
 /// on a grain interface to a triple. The triple consists of:
 /// 1) the index object (that implements IndexInterface,
 /// 2) the IndexMetaData object for this index, and
 /// 3) the IndexUpdateGenerator instance for this index.
 /// This triple is untyped, because IndexInterface, IndexMetaData
 /// and IndexUpdateGenerator types are not visible in this project.
 ///
 /// This method returns an empty dictionary if the OrleansIndexing
 /// project is not available.</returns>
 internal static IDictionary <string, Tuple <object, object, object> > GetIndexes(Type iGrainType)
 {
     return(IndexRegistry.GetIndexes(iGrainType));
 }
        private async static Task GetIndexesForASingleGrainType(ApplicationPartsIndexableGrainLoader loader, IndexRegistry registry, Type grainClassType)
        {
            if (!typeof(IIndexableGrain).IsAssignableFrom(grainClassType))
            {
                return;
            }

            if (registry.ContainsGrainType(grainClassType))
            {
                throw new InvalidOperationException($"Grain class type {grainClassType.Name} has already been added to the registry");
            }

            bool?grainIndexesAreEager = null;
            var  indexedInterfaces    = new List <Type>();
            var  consistencyScheme    = grainClassType.GetConsistencyScheme();

            foreach (var(grainInterfaceType, propertiesClassType) in EnumerateIndexedInterfacesForAGrainClassType(grainClassType).Where(tup => !registry.ContainsKey(tup.interfaceType)))
            {
                grainIndexesAreEager = await CreateIndexesForASingleInterface(loader, registry, propertiesClassType, grainInterfaceType,
                                                                              grainClassType, consistencyScheme, grainIndexesAreEager);

                indexedInterfaces.Add(grainInterfaceType);
            }

            IReadOnlyDictionary <string, object> getNullValuesDictionary()
            {
                IEnumerable <(string propName, (string itfName, object nullValue))> getNullPropertyValuesForInterface(Type interfaceType)
                => registry[interfaceType].PropertiesClassType.GetProperties()
                .Select(info => (name: info.Name, nullSpec: (itfname: interfaceType.Name, nullValue: IndexUtils.GetNullValue(info))))
                .Where(p => p.nullSpec.nullValue != null);

                Dictionary <string, (string, object)> addToDict(Dictionary <string, (string, object)> dict, (string propName, (string itfName, object nullValue)nullSpec) current)
                {
                    bool isInDict(string propName)
                    {
                        return(dict.TryGetValue(propName, out (string itfName, object nullValue)prevNullSpec)
                            ? (prevNullSpec.nullValue.Equals(current.nullSpec.nullValue)
                                ? true
                                : throw new IndexConfigurationException($"Property {propName} has conflicting NullValues defined on interfaces {prevNullSpec.itfName} and {current.nullSpec.itfName}"))
                            : false);
                    }

                    if (!isInDict(current.propName))
                    {
                        dict[current.propName] = current.nullSpec;
                    }
                    return(dict);
                }

                return(indexedInterfaces.SelectMany(itf => getNullPropertyValuesForInterface(itf))
                       .Aggregate(new Dictionary <string, (string itfName, object nullValue)>(), (dict, pair) => addToDict(dict, pair))
                       .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.nullValue));
            }

            registry.SetGrainIndexes(grainClassType, indexedInterfaces.ToArray(), getNullValuesDictionary());
        }