Beispiel #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);
        }
Beispiel #2
0
        private static void ValidateSingleIndex(IndexAttribute indexAttr, Type grainInterfaceType, Type grainClassType, Type propertiesArgType,
                                                PropertyInfo propInfo, bool?grainIndexesAreEager, ConsistencyScheme consistencyScheme, bool isEager, bool isUnique)
        {
            var indexType               = (Type)indexTypeProperty.GetValue(indexAttr);
            var isTotalIndex            = indexType.IsTotalIndex();
            var isPerSiloIndex          = indexType.IsPartitionedPerSiloIndex();
            var isFaultTolerantWorkflow = consistencyScheme == ConsistencyScheme.FaultTolerantWorkflow;
            var isTransactional         = consistencyScheme == ConsistencyScheme.Transactional;

            if (indexAttr is ActiveIndexAttribute && isUnique)
            {
                // See comments in ActiveIndexAttribute for details of why this is disallowed.
                throw new InvalidOperationException($"An active Index cannot be configured to be unique, because multiple activations, persisting, and deactivations can create duplicates." +
                                                    $" Active Index of type {IndexUtils.GetFullTypeName(indexType)} is defined to be unique on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on the {IndexUtils.GetFullTypeName(grainInterfaceType)} grain interface.");
            }
            if (isPerSiloIndex && isUnique)
            {
                throw new InvalidOperationException($"Unique indexes cannot be partitioned per silo because uniqueness across silos is currently not enforced." +
                                                    $" Partitioned Per Silo Index of type {IndexUtils.GetFullTypeName(indexType)} is defined to be unique on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on the {IndexUtils.GetFullTypeName(grainInterfaceType)} grain interface.");
            }
            if (isFaultTolerantWorkflow && isEager)
            {
                throw new InvalidOperationException($"A workflow-fault-tolerant consistency scheme cannot be configured to eagerly update its indexes." +
                                                    $" The only option for updating the indexes of a fault-tolerant indexable grain is lazy updating." +
                                                    $" The index of type {IndexUtils.GetFullTypeName(indexType)} is defined to be updated eagerly on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on the {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class.");
            }
            if (isFaultTolerantWorkflow && indexType.IsActiveIndex())
            {
                throw new InvalidOperationException($"A workflow-fault-tolerant consistency scheme cannot be used with an Active index, because it will continually be reactivated as part of the fault-tolerant workflow." +
                                                    $" An Active index of type {IndexUtils.GetFullTypeName(indexType)} is defined on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on the {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class" +
                                                    $" which uses workflow-fault-tolerant indexing.");
            }
            if (isTransactional && !isEager)
            {
                throw new InvalidOperationException($"A transactional consistency scheme must be configured to eagerly update its indexes." +
                                                    $" The index of type {IndexUtils.GetFullTypeName(indexType)} is defined to be updated eagerly on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class.");
            }
            if (isTransactional && indexType.IsActiveIndex())
            {
                throw new InvalidOperationException($"A transactional consistency scheme cannot be used with an Active index, because activation and deactivation do not always run in a transactional context." +
                                                    $" An Active index of type {IndexUtils.GetFullTypeName(indexType)} is defined on property {propInfo.Name}" +
                                                    $" of class {IndexUtils.GetFullTypeName(propertiesArgType)} on the {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class" +
                                                    $" which uses transactional indexing.");
            }
            if (grainIndexesAreEager.HasValue && grainIndexesAreEager.Value != isEager)
            {
                throw new InvalidOperationException($"Some indexes on {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class are defined as eager while others are lazy." +
                                                    $" The index of type {IndexUtils.GetFullTypeName(indexType)} is defined to be updated {(isEager ? "eagerly" : "lazily")} on property { propInfo.Name}" +
                                                    $" of property class {IndexUtils.GetFullTypeName(propertiesArgType)} on {IndexUtils.GetFullTypeName(grainInterfaceType)} grain interface," +
                                                    $" while previous indexes have been configured to be updated {(isEager ? "lazily" : "eagerly")}." +
                                                    $" You must fix this by configuring all indexes to be updated lazily or eagerly." +
                                                    $" Note: If you have at least one Total Index among your indexes, this must be lazy, and thus all other indexes must be lazy also.");
            }
            if (!VerifyNullValue(propInfo, isUnique, out string convertErrMsg))
            {
                throw new InvalidOperationException($"The index of type {IndexUtils.GetFullTypeName(indexType)} on {IndexUtils.GetFullTypeName(grainClassType)} grain implementation class" +
                                                    $" failed verification. " + convertErrMsg);
            }
        }