Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
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);
                    }
                }
            }
        }
Ejemplo n.º 3
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());
            }
        }
        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());
        }