private Task ApplyIndexUpdatesEagerly(Type iGrainType,
                                              IIndexableGrain updatedGrain,
                                              IDictionary <string, IMemberUpdate> updates,
                                              UpdateIndexType updateIndexTypes,
                                              bool updateIndexesTentatively)
        {
            IList <Task <bool> > updateIndexTasks = new List <Task <bool> >();

            foreach (KeyValuePair <string, IMemberUpdate> updt in updates.Where(updt => updt.Value.OperationType != IndexOperationType.None))
            {
                var idxInfo = this._grainIndexes[updt.Key];

                if (updateIndexTypes.HasFlag(idxInfo.MetaData.IsUniqueIndex ? UpdateIndexType.Unique : UpdateIndexType.NonUnique))
                {
                    // If the caller asks for the update to be tentative, then it will be wrapped inside a MemberUpdateTentative
                    IMemberUpdate updateToIndex = updateIndexesTentatively ? new MemberUpdateTentative(updt.Value) : updt.Value;

                    // The update task is added to the list of update tasks
                    updateIndexTasks.Add(idxInfo.IndexInterface.ApplyIndexUpdate(this.SiloIndexManager,
                                                                                 updatedGrain, updateToIndex.AsImmutable(), idxInfo.MetaData, BaseSiloAddress));
                }
            }

            // At the end, because the index update should be eager, we wait for all index update tasks to finish
            return(Task.WhenAll(updateIndexTasks));
        }
 private void ApplyIndexUpdatesLazilyWithoutWait(IDictionary <string, IMemberUpdate> updates,
                                                 IList <Type> iGrainTypes,
                                                 IIndexableGrain thisGrain,
                                                 Guid workflowID)
 {
     ApplyIndexUpdatesLazily(updates, iGrainTypes, thisGrain, workflowID).Ignore();
 }
Пример #3
0
        private Dictionary <string, IDictionary <IIndexableGrain, IList <IMemberUpdate> > > PopulateUpdatesToIndexes(
            IndexWorkflowRecordNode currentWorkflow, Dictionary <IIndexableGrain, HashSet <Guid> > grainsToActiveWorkflows)
        {
            var  updatesToIndexes = new Dictionary <string, IDictionary <IIndexableGrain, IList <IMemberUpdate> > >();
            bool faultTolerant    = IsFaultTolerant;

            for (; !currentWorkflow.IsPunctuation; currentWorkflow = currentWorkflow.Next)
            {
                IndexWorkflowRecord workflowRec = currentWorkflow.WorkflowRecord;
                IIndexableGrain     g           = workflowRec.Grain;
                bool existsInActiveWorkflows    = faultTolerant && grainsToActiveWorkflows.TryGetValue(g, out HashSet <Guid> activeWorkflowRecs) &&
                                                  activeWorkflowRecs.Contains(workflowRec.WorkflowId);

                foreach (var(indexName, updt) in currentWorkflow.WorkflowRecord.MemberUpdates.Where(kvp => kvp.Value.OperationType != IndexOperationType.None))
                {
                    var updatesByGrain  = updatesToIndexes.GetOrAdd(indexName, () => new Dictionary <IIndexableGrain, IList <IMemberUpdate> >());
                    var updatesForGrain = updatesByGrain.GetOrAdd(g, () => new List <IMemberUpdate>());

                    if (!faultTolerant || existsInActiveWorkflows)
                    {
                        updatesForGrain.Add(updt);
                    }
                    else if (GrainIndexes[indexName].MetaData.IsUniqueIndex)
                    {
                        // If the workflow record does not exist in the set of active workflows and the index is fault-tolerant,
                        // enqueue a reversal (undo) to any possible remaining tentative updates to unique indexes.
                        updatesForGrain.Add(new MemberUpdateReverseTentative(updt));
                    }
                }
            }
            return(updatesToIndexes);
        }
        private async Task DirectApplyIndexUpdateNonPersistent(IIndexableGrain g, IMemberUpdate updt, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            //this variable determines whether index was still unavailable
            //when we received a delete operation
            bool fixIndexUnavailableOnDelete = false;

            //the target grain that is updated
            V updatedGrain = g.AsReference <V>(GrainFactory);

            K befImg;
            HashIndexSingleBucketEntry <V> befEntry;

            //Updates the index bucket synchronously
            //(note that no other thread can run concurrently
            //before we reach an await operation, so no concurrency
            //control mechanism (e.g., locking) is required)
            if (!HashIndexBucketUtils.UpdateBucket(updatedGrain, updt, State, isUniqueIndex, idxMetaData, out befImg, out befEntry, out fixIndexUnavailableOnDelete))
            {
                await(await GetNextBucketAndPersist()).DirectApplyIndexUpdate(g, updt.AsImmutable(), isUniqueIndex, idxMetaData, siloAddress);
            }

            //if the index was still unavailable
            //when we received a delete operation
            //if (fixIndexUnavailableOnDelete)
            //{
            //    //create tombstone
            //}
        }
        private Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, IMemberUpdate updt, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            V updatedGrain = g;

            HashIndexBucketUtils.UpdateBucket(updatedGrain, updt, state, isUniqueIndex, idxMetaData);
            return(Task.FromResult(true));
        }
 private async Task DirectApplyIndexUpdates(IIndexableGrain g, IList <IMemberUpdate> updates, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 {
     foreach (IMemberUpdate updt in updates)
     {
         await DirectApplyIndexUpdate(g, updt, isUniqueIndex, idxMetaData, siloAddress);
     }
 }
Пример #7
0
        private async Task <Dictionary <IIndexableGrain, HashSet <Guid> > > GetActiveWorkflowsListsFromGrains(IndexWorkflowRecordNode currentWorkflow)
        {
            var result = new Dictionary <IIndexableGrain, HashSet <Guid> >();
            var grains = new List <IIndexableGrain>();
            var activeWorkflowsSetsTasks = new List <Task <Immutable <HashSet <Guid> > > >();

            while (!currentWorkflow.IsPunctuation())
            {
                IIndexableGrain g = currentWorkflow.WorkflowRecord.Grain;
                foreach (var updates in currentWorkflow.WorkflowRecord.MemberUpdates)
                {
                    IMemberUpdate updt = updates.Value;
                    if (updt.GetOperationType() != IndexOperationType.None && !result.ContainsKey(g))
                    {
                        result.Add(g, EMPTY_HASHSET);
                        grains.Add(g);
                        activeWorkflowsSetsTasks.Add(g.AsReference <IIndexableGrain>(InsideRuntimeClient.Current.ConcreteGrainFactory, _iGrainType).GetActiveWorkflowIdsList());
                    }
                }
                currentWorkflow = currentWorkflow.Next;
            }

            if (activeWorkflowsSetsTasks.Count() > 0)
            {
                Immutable <HashSet <Guid> >[] activeWorkflowsSets = await Task.WhenAll(activeWorkflowsSetsTasks);

                for (int i = 0; i < activeWorkflowsSets.Length; ++i)
                {
                    result[grains[i]] = activeWorkflowsSets[i].Value;
                }
            }

            return(result);
        }
Пример #8
0
        private protected async Task PreActivate(Grain grain, Func <Task <IndexedGrainStateWrapper <TGrainState> > > readGrainStateFunc, Func <Task> writeGrainStateFunc)
        {
            if (this.grain != null) // Already called
            {
                return;
            }
            this.grain               = grain;
            this.iIndexableGrain     = this.grain.AsReference <IIndexableGrain>(this.SiloIndexManager);
            this.readGrainStateFunc  = readGrainStateFunc;
            this.writeGrainStateFunc = writeGrainStateFunc;

            await this.ReadAsync();

            if (!GrainIndexes.CreateInstance(this.SiloIndexManager.IndexRegistry, this.grain.GetType(), out this._grainIndexes) ||
                !this._grainIndexes.HasAnyIndexes)
            {
                throw new InvalidOperationException("IndexedState should not be used for a Grain class with no indexes");
            }

            if (!this.wrappedState.AreNullValuesInitialized)
            {
                IndexUtils.SetNullValues(this.wrappedState.UserState, this._grainIndexes.PropertyNullValues);
                this.wrappedState.AreNullValuesInitialized = true;
            }

            this._hasAnyUniqueIndex = this._grainIndexes.HasAnyUniqueIndex;
            this._grainIndexes.AddMissingBeforeImages(this.wrappedState.UserState);
        }
Пример #9
0
        private async Task <Dictionary <IIndexableGrain, HashSet <Guid> > > FtGetActiveWorkflowSetsFromGrains(IndexWorkflowRecordNode currentWorkflow)
        {
            var activeWorkflowSetTasksByGrain = new Dictionary <IIndexableGrain, Task <Immutable <HashSet <Guid> > > >();
            var currentWorkflowIds            = new HashSet <Guid>();

            for (; !currentWorkflow.IsPunctuation; currentWorkflow = currentWorkflow.Next)
            {
                var record = currentWorkflow.WorkflowRecord;
                currentWorkflowIds.Add(record.WorkflowId);
                IIndexableGrain g = record.Grain;
                if (!activeWorkflowSetTasksByGrain.ContainsKey(g) && record.MemberUpdates.Where(ups => ups.Value.OperationType != IndexOperationType.None).Any())
                {
                    activeWorkflowSetTasksByGrain[g] = g.AsReference <IIndexableGrain>(this._siloIndexManager, this._grainInterfaceType).GetActiveWorkflowIdsSet();
                }
            }

            if (activeWorkflowSetTasksByGrain.Count > 0)
            {
                await Task.WhenAll(activeWorkflowSetTasksByGrain.Values);

                // Intersect so we do not include workflowIds that are not in our work queue.
                return(activeWorkflowSetTasksByGrain.ToDictionary(kvp => kvp.Key,
                                                                  kvp => new HashSet <Guid>(kvp.Value.Result.Value.Intersect(currentWorkflowIds))));
            }

            return(new Dictionary <IIndexableGrain, HashSet <Guid> >());
        }
        /// <summary>
        /// This method applies a given update to the current index.
        /// </summary>
        /// <param name="updatedGrain">the grain that issued the update</param>
        /// <param name="iUpdate">contains the data for the update</param>
        /// <param name="isUnique">whether this is a unique index that we are updating</param>
        /// <param name="op">the actual type of the operation, which override the operation-type in iUpdate</param>
        /// <returns>true, if the index update was successful, otherwise false</returns>
        public async Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            await DirectApplyIndexUpdateNonPersistent(g, iUpdate.Value, isUniqueIndex, idxMetaData, siloAddress);
            await PersistIndex();

            return(true);
        }
        private Task DirectApplyIndexUpdatesNonPersistent(IIndexableGrain g, IList <IMemberUpdate> updates, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            Task[] updateTasks = new Task[updates.Count()];
            int    i           = 0;

            foreach (IMemberUpdate updt in updates)
            {
                updateTasks[i++] = DirectApplyIndexUpdateNonPersistent(g, updt, isUniqueIndex, idxMetaData, siloAddress);
            }
            return(Task.WhenAll(updateTasks));
        }
        public async Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates, bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
        {
            logger.Trace($"Started calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {isUnique}, siloAddress = {siloAddress}," +
                         $" iUpdates = {MemberUpdate.UpdatesToString(iUpdates.Value)}");

            IDictionary <IIndexableGrain, IList <IMemberUpdate> > updates = iUpdates.Value;
            IDictionary <int, IDictionary <IIndexableGrain, IList <IMemberUpdate> > > bucketUpdates = new Dictionary <int, IDictionary <IIndexableGrain, IList <IMemberUpdate> > >();

            foreach (var kv in updates)
            {
                IIndexableGrain       g        = kv.Key;
                IList <IMemberUpdate> gUpdates = kv.Value;
                foreach (IMemberUpdate update in gUpdates)
                {
                    IndexOperationType opType = update.OperationType;
                    if (opType == IndexOperationType.Update)
                    {
                        int befImgHash = GetBucketIndexFromHashCode(update.GetBeforeImage());
                        int aftImgHash = GetBucketIndexFromHashCode(update.GetAfterImage());

                        if (befImgHash == aftImgHash)
                        {
                            AddUpdateToBucket(bucketUpdates, g, befImgHash, update);
                        }
                        else
                        {
                            AddUpdateToBucket(bucketUpdates, g, befImgHash, new MemberUpdateOverridenOperation(update, IndexOperationType.Delete));
                            AddUpdateToBucket(bucketUpdates, g, aftImgHash, new MemberUpdateOverridenOperation(update, IndexOperationType.Insert));
                        }
                    }
                    else if (opType == IndexOperationType.Insert)
                    {
                        int aftImgHash = GetBucketIndexFromHashCode(update.GetAfterImage());
                        AddUpdateToBucket(bucketUpdates, g, aftImgHash, update);
                    }
                    else if (opType == IndexOperationType.Delete)
                    {
                        int befImgHash = GetBucketIndexFromHashCode(update.GetBeforeImage());
                        AddUpdateToBucket(bucketUpdates, g, befImgHash, update);
                    }
                }
            }

            var results = await Task.WhenAll(bucketUpdates.Select(kv =>
            {
                BucketT bucket = GetGrain(IndexUtils.GetIndexGrainPrimaryKey(typeof(V), this._indexName) + "_" + kv.Key);
                return(bucket.DirectApplyIndexUpdateBatch(kv.Value.AsImmutable(), isUnique, idxMetaData, siloAddress));
            }));

            logger.Trace($"Finished calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {isUnique}, siloAddress = {siloAddress}," +
                         $" iUpdates = {MemberUpdate.UpdatesToString(iUpdates.Value)}, results = '{string.Join(", ", results)}'");

            return(true);
        }
        protected Task ApplyIndexUpdatesLazily(IDictionary <string, IMemberUpdate> updates,
                                               IList <Type> iGrainTypes,
                                               IIndexableGrain thisGrain,
                                               Guid workflowID)
        {
            Task addToQueue(Type iGrainType) => GetWorkflowQueue(iGrainType).AddToQueue(new IndexWorkflowRecord(workflowID, thisGrain, updates).AsImmutable());

            return(iGrainTypes.Count() == 1
                ? addToQueue(iGrainTypes[0])
                : Task.WhenAll(iGrainTypes.Select(iGrainType => addToQueue(iGrainType))));
        }
        protected async Task ApplyIndexUpdatesEagerly(IList <Type> iGrainTypes,
                                                      IIndexableGrain updatedGrain,
                                                      IDictionary <string, IMemberUpdate> updates,
                                                      UpdateIndexType updateIndexTypes,
                                                      bool updateIndexesTentatively = false)
        {
            Task applyUpdate(Type iGrainType) => ApplyIndexUpdatesEagerly(iGrainType, updatedGrain, updates, updateIndexTypes, updateIndexesTentatively);

            await(iGrainTypes.Count() == 1
                ? applyUpdate(iGrainTypes[0])
                : Task.WhenAll(iGrainTypes.Select(iGrainType => applyUpdate(iGrainType))));
        }
Пример #15
0
 /// <summary>
 /// An extension method to intercept the calls to DirectApplyIndexUpdate
 /// on an Index
 /// </summary>
 internal static Task <bool> ApplyIndexUpdate(this IndexInterface index, IIndexableGrain updatedGrain, Immutable <IMemberUpdate> update, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
 {
     if (index is ActiveHashIndexPartitionedPerSilo)
     {
         ActiveHashIndexPartitionedPerSiloBucket bucketInCurrentSilo = InsideRuntimeClient.Current.InternalGrainFactory.GetSystemTarget <ActiveHashIndexPartitionedPerSiloBucket>(
             GetAHashIndexPartitionedPerSiloGrainID(IndexUtils.GetIndexNameFromIndexGrain((IAddressable )index), index.GetType().GetGenericArguments()[1]),
             siloAddress
             );
         return(bucketInCurrentSilo.DirectApplyIndexUpdate(updatedGrain, update, isUniqueIndex, idxMetaData /*, siloAddress*/));
     }
     return(index.DirectApplyIndexUpdate(updatedGrain, update, isUniqueIndex, idxMetaData, siloAddress));
 }
Пример #16
0
        private void PopulateUpdatesToIndexes(IndexWorkflowRecordNode currentWorkflow, Dictionary <string, IDictionary <IIndexableGrain, IList <IMemberUpdate> > > updatesToIndexes, Dictionary <IIndexableGrain, HashSet <Guid> > grainsToActiveWorkflows)
        {
            bool faultTolerant = IsFaultTolerant;

            while (!currentWorkflow.IsPunctuation())
            {
                IndexWorkflowRecord workflowRec = currentWorkflow.WorkflowRecord;
                IIndexableGrain     g           = workflowRec.Grain;
                bool existsInActiveWorkflows    = false;
                if (faultTolerant)
                {
                    HashSet <Guid> activeWorkflowRecs = null;
                    if (grainsToActiveWorkflows.TryGetValue(g, out activeWorkflowRecs))
                    {
                        if (activeWorkflowRecs.Contains(workflowRec.WorkflowId))
                        {
                            existsInActiveWorkflows = true;
                        }
                    }
                }

                foreach (var updates in currentWorkflow.WorkflowRecord.MemberUpdates)
                {
                    IMemberUpdate updt = updates.Value;
                    if (updt.GetOperationType() != IndexOperationType.None)
                    {
                        string index          = updates.Key;
                        var    updatesToIndex = updatesToIndexes[index];
                        IList <IMemberUpdate> updatesList;
                        if (!updatesToIndex.TryGetValue(g, out updatesList))
                        {
                            updatesList = new List <IMemberUpdate>();
                            updatesToIndex.Add(g, updatesList);
                        }

                        if (!faultTolerant || existsInActiveWorkflows)
                        {
                            updatesList.Add(updt);
                        }
                        //if the workflow record does not exist in the list of active work-flows
                        //and the index is fault-tolerant, we should make sure that tentative updates
                        //to unique indexes are undone
                        else if (((IndexMetaData)Indexes[index].Item2).IsUniqueIndex())
                        {
                            //reverse a possible remaining tentative record from the index
                            updatesList.Add(new MemberUpdateReverseTentative(updt));
                        }
                    }
                }
                currentWorkflow = currentWorkflow.Next;
            }
        }
 /// <summary>
 /// An extension method to intercept the calls to DirectApplyIndexUpdate on an Index,
 /// so that for a PerSilo index, it can obtain the GrainService of that index on the silo of the indexed grain.
 /// </summary>
 internal static Task <bool> ApplyIndexUpdate(this IIndexInterface index, SiloIndexManager siloIndexManager,
                                              IIndexableGrain updatedGrain, Immutable <IMemberUpdate> update,
                                              IndexMetaData idxMetaData, SiloAddress siloAddress = null)
 {
     if (index is IActiveHashIndexPartitionedPerSilo)
     {
         var bucketInCurrentSilo = siloIndexManager.GetGrainService <IActiveHashIndexPartitionedPerSiloBucket>(
             GetAHashIndexPartitionedPerSiloGrainReference(siloIndexManager,
                                                           IndexUtils.GetIndexNameFromIndexGrain((IAddressable)index), index.GetType().GetGenericArguments()[1],
                                                           siloAddress
                                                           ));
         return(bucketInCurrentSilo.DirectApplyIndexUpdate(updatedGrain, update, idxMetaData.IsUniqueIndex, idxMetaData /*, siloAddress*/));
     }
     return(index.DirectApplyIndexUpdate(updatedGrain, update, idxMetaData.IsUniqueIndex, idxMetaData, siloAddress));
 }
Пример #18
0
        private Task Initialize(Grain grain)
        {
            if (this.grain == null) // If not already called
            {
                this.grain           = grain;
                this.iIndexableGrain = this.grain.AsReference <IIndexableGrain>(this.SiloIndexManager);

                if (!GrainIndexes.CreateInstance(this.SiloIndexManager.IndexRegistry, this.grain.GetType(), out this._grainIndexes) ||
                    !this._grainIndexes.HasAnyIndexes)
                {
                    throw new InvalidOperationException("IndexedState should not be used for a Grain class with no indexes");
                }
                this._hasAnyUniqueIndex = this._grainIndexes.HasAnyUniqueIndex;
            }
            return(Task.CompletedTask);
        }
        public async Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            IMemberUpdate      update = iUpdate.Value;
            IndexOperationType opType = update.GetOperationType();

            if (opType == IndexOperationType.Update)
            {
                int     befImgHash   = update.GetBeforeImage().GetHashCode();
                int     aftImgHash   = update.GetAfterImage().GetHashCode();
                BucketT befImgBucket = InsideRuntimeClient.Current.InternalGrainFactory.GetGrain <BucketT>(
                    IndexUtils.GetIndexGrainID(typeof(V), _indexName) + "_" + befImgHash
                    );
                if (befImgHash == aftImgHash)
                {
                    return(await befImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
                }
                else
                {
                    BucketT aftImgBucket = InsideRuntimeClient.Current.InternalGrainFactory.GetGrain <BucketT>(
                        IndexUtils.GetIndexGrainID(typeof(V), _indexName) + "_" + befImgHash
                        );
                    var    befTask = befImgBucket.DirectApplyIndexUpdate(g, new MemberUpdateOverridenOperation(iUpdate.Value, IndexOperationType.Delete).AsImmutable <IMemberUpdate>(), isUniqueIndex, idxMetaData);
                    var    aftTask = aftImgBucket.DirectApplyIndexUpdate(g, new MemberUpdateOverridenOperation(iUpdate.Value, IndexOperationType.Insert).AsImmutable <IMemberUpdate>(), isUniqueIndex, idxMetaData);
                    bool[] results = await Task.WhenAll(befTask, aftTask);

                    return(results[0] && results[1]);
                }
            }
            else if (opType == IndexOperationType.Insert)
            {
                int     aftImgHash   = update.GetAfterImage().GetHashCode();
                BucketT aftImgBucket = InsideRuntimeClient.Current.InternalGrainFactory.GetGrain <BucketT>(
                    IndexUtils.GetIndexGrainID(typeof(V), _indexName) + "_" + aftImgHash
                    );
                return(await aftImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
            }
            else if (opType == IndexOperationType.Delete)
            {
                int     befImgHash   = update.GetBeforeImage().GetHashCode();
                BucketT befImgBucket = InsideRuntimeClient.Current.InternalGrainFactory.GetGrain <BucketT>(
                    IndexUtils.GetIndexGrainID(typeof(V), _indexName) + "_" + befImgHash
                    );
                return(await befImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
            }
            return(true);
        }
Пример #20
0
        private async Task DirectApplyIndexUpdateNonPersistent(IIndexableGrain g, IMemberUpdate updt, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            // The target grain that is updated
            V updatedGrain = g.AsReference <V>(this.SiloIndexManager);

            // Updates the index bucket synchronously (note that no other thread can run concurrently before we reach an await operation,
            // when execution is yielded back to the Orleans scheduler, so no concurrency control mechanism (e.g., locking) is required).
            // 'fixIndexUnavailableOnDelete' indicates whether the index was still unavailable when we received a delete operation.
            if (!HashIndexBucketUtils.UpdateBucketState(updatedGrain, updt, this.State, isUniqueIndex, idxMetaData, out K befImg, out HashIndexSingleBucketEntry <V> befEntry, out bool fixIndexUnavailableOnDelete))
            {
                await(await GetNextBucketAndPersist()).DirectApplyIndexUpdate(g, updt.AsImmutable(), isUniqueIndex, idxMetaData, siloAddress);
            }

            // TODO if the index was still unavailable when we received a delete operation
            //if (fixIndexUnavailableOnDelete)
            //{
            //    //create tombstone
            //}
        }
        private Task ApplyIndexUpdatesEagerly(Type iGrainType,
                                              IIndexableGrain updatedGrain,
                                              IDictionary <string, IMemberUpdate> updates,
                                              bool onlyUpdateUniqueIndexes,
                                              bool onlyUpdateNonUniqueIndexes,
                                              bool updateIndexesTentatively)
        {
            IList <Task <bool> > updateIndexTasks = new List <Task <bool> >();

            foreach (KeyValuePair <string, IMemberUpdate> updt in updates)
            {
                //if the update is not a no-operation
                if (updt.Value.GetOperationType() != IndexOperationType.None)
                {
                    var idxInfo       = _iUpdateGens[updt.Key];
                    var isUniqueIndex = ((IndexMetaData)idxInfo.Item2).IsUniqueIndex();

                    //the actual update happens if either the corresponding index is not a unique index
                    //and the caller asks for only updating non-unique indexes, or the corresponding
                    //index is a unique index and the caller asks for only updating unqiue indexes.
                    if ((onlyUpdateNonUniqueIndexes && !isUniqueIndex) || (onlyUpdateUniqueIndexes && isUniqueIndex))
                    {
                        IMemberUpdate updateToIndex = updt.Value;
                        //if the caller asks for the update to be tentative, then
                        //it will be wrapped inside a MemberUpdateTentative
                        if (updateIndexesTentatively)
                        {
                            updateToIndex = new MemberUpdateTentative(updateToIndex);
                        }

                        //the update task is added to the list of update tasks
                        updateIndexTasks.Add(((IndexInterface)idxInfo.Item1).ApplyIndexUpdate(updatedGrain, updateToIndex.AsImmutable(), isUniqueIndex, (IndexMetaData)idxInfo.Item2, RuntimeAddress));
                    }
                }
            }

            //at the end, because the index update should be eager, we wait for
            //all index update tasks to finish
            return(Task.WhenAll(updateIndexTasks));
        }
 protected async Task ApplyIndexUpdatesEagerly(IList <Type> iGrainTypes,
                                               IIndexableGrain updatedGrain,
                                               IDictionary <string, IMemberUpdate> updates,
                                               bool onlyUpdateUniqueIndexes,
                                               bool onlyUpdateNonUniqueIndexes,
                                               bool updateIndexesTentatively = false)
 {
     if (iGrainTypes.Count() == 1)
     {
         await ApplyIndexUpdatesEagerly(iGrainTypes[0], updatedGrain, updates, onlyUpdateUniqueIndexes, onlyUpdateNonUniqueIndexes, updateIndexesTentatively);
     }
     else
     {
         Task[] updateTasks = new Task[iGrainTypes.Count()];
         int    i           = 0;
         foreach (Type iGrainType in iGrainTypes)
         {
             updateTasks[i++] = ApplyIndexUpdatesEagerly(iGrainType, updatedGrain, updates, onlyUpdateUniqueIndexes, onlyUpdateNonUniqueIndexes, updateIndexesTentatively);
         }
         await Task.WhenAll(updateTasks);
     }
 }
 protected Task ApplyIndexUpdatesLazily(IDictionary <string, IMemberUpdate> updates,
                                        IList <Type> iGrainTypes,
                                        IIndexableGrain thisGrain,
                                        Guid workflowID)
 {
     if (iGrainTypes.Count() == 1)
     {
         IIndexWorkflowQueue workflowQ = GetWorkflowQueue(iGrainTypes[0]);
         return(workflowQ.AddToQueue(new IndexWorkflowRecord(workflowID, thisGrain, updates).AsImmutable()));
     }
     else
     {
         Task[] tasks = new Task[iGrainTypes.Count];
         int    i     = 0;
         foreach (Type iGrainType in iGrainTypes)
         {
             tasks[i++] = GetWorkflowQueue(iGrainType).AddToQueue(
                 new IndexWorkflowRecord(workflowID, thisGrain, updates).AsImmutable()
                 );
         }
         return(Task.WhenAll(tasks));
     }
 }
Пример #24
0
        private async Task <Dictionary <IIndexableGrain, HashSet <Guid> > > GetActiveWorkflowsListsFromGrains(IndexWorkflowRecordNode currentWorkflow)
        {
            var result = new Dictionary <IIndexableGrain, HashSet <Guid> >();
            var grains = new List <IIndexableGrain>();
            var activeWorkflowsSetsTasks = new List <Task <Immutable <HashSet <Guid> > > >();
            var workflowIds = new HashSet <Guid>();

            while (!currentWorkflow.IsPunctuation())
            {
                workflowIds.Add(currentWorkflow.WorkflowRecord.WorkflowId);
                IIndexableGrain g = currentWorkflow.WorkflowRecord.Grain;
                foreach (var updates in currentWorkflow.WorkflowRecord.MemberUpdates)
                {
                    IMemberUpdate updt = updates.Value;
                    if (updt.OperationType != IndexOperationType.None && !result.ContainsKey(g))
                    {
                        result.Add(g, emptyHashset);
                        grains.Add(g);
                        activeWorkflowsSetsTasks.Add(g.AsReference <IIndexableGrain>(_siloIndexManager, _iGrainType).GetActiveWorkflowIdsList());
                    }
                }
                currentWorkflow = currentWorkflow.Next;
            }

            if (activeWorkflowsSetsTasks.Count() > 0)
            {
                Immutable <HashSet <Guid> >[] activeWorkflowsSets = await Task.WhenAll(activeWorkflowsSetsTasks);

                for (int i = 0; i < activeWorkflowsSets.Length; ++i)
                {
                    // Do not include workflowIds that are not in our work queue.
                    result[grains[i]] = new HashSet <Guid>(activeWorkflowsSets[i].Value.Intersect(workflowIds));
                }
            }

            return(result);
        }
        public async Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
        {
            IMemberUpdate      update = iUpdate.Value;
            IndexOperationType opType = update.OperationType;

            if (opType == IndexOperationType.Update)
            {
                int     befImgHash   = GetBucketIndexFromHashCode(update.GetBeforeImage());
                int     aftImgHash   = GetBucketIndexFromHashCode(update.GetAfterImage());
                BucketT befImgBucket = this.GetBucketGrain(befImgHash);
                if (befImgHash == aftImgHash)
                {
                    return(await befImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
                }

                BucketT aftImgBucket = this.GetBucketGrain(aftImgHash);
                var     befTask      = befImgBucket.DirectApplyIndexUpdate(g, new MemberUpdateOverriddenOperation(iUpdate.Value, IndexOperationType.Delete).AsImmutable <IMemberUpdate>(), isUniqueIndex, idxMetaData);
                var     aftTask      = aftImgBucket.DirectApplyIndexUpdate(g, new MemberUpdateOverriddenOperation(iUpdate.Value, IndexOperationType.Insert).AsImmutable <IMemberUpdate>(), isUniqueIndex, idxMetaData);
                bool[]  results      = await Task.WhenAll(befTask, aftTask);

                return(results[0] && results[1]);
            }
            else if (opType == IndexOperationType.Insert)
            {
                int     aftImgHash   = GetBucketIndexFromHashCode(update.GetAfterImage());
                BucketT aftImgBucket = this.GetBucketGrain(aftImgHash);
                return(await aftImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
            }
            else if (opType == IndexOperationType.Delete)
            {
                int     befImgHash   = GetBucketIndexFromHashCode(update.GetBeforeImage());
                BucketT befImgBucket = this.GetBucketGrain(befImgHash);
                return(await befImgBucket.DirectApplyIndexUpdate(g, iUpdate, isUniqueIndex, idxMetaData));
            }
            return(true);
        }
 /// <summary>
 /// DirectApplyIndexUpdate is not supported on ActiveHashIndexPartitionedPerSiloImpl, because it will be skipped
 /// via IndexExtensions.ApplyIndexUpdate which goes directly to the IActiveHashIndexPartitionedPerSiloBucket grain service
 /// </summary>
 public Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 => throw new NotSupportedException();
 public Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 => DirectApplyIndexUpdate(g, iUpdate.Value, isUniqueIndex, idxMetaData, siloAddress);
        /// <summary>
        /// Applies a set of updates to the indexes defined on the grain
        /// </summary>
        /// <param name="updates">the dictionary of indexes to their corresponding updates</param>
        /// <param name="updateIndexesEagerly">whether indexes should be
        /// updated eagerly or lazily</param>
        /// <param name="onlyUniqueIndexesWereUpdated">a flag to determine whether
        /// only unique indexes were updated</param>
        /// <param name="numberOfUniqueIndexesUpdated">determine the number of
        /// updated unique indexes</param>
        /// <param name="writeStateIfConstraintsAreNotViolated">whether writing back
        /// the state to the storage should be done if no constraint is violated</param>
        protected virtual async Task ApplyIndexUpdates(IDictionary <string, IMemberUpdate> updates,
                                                       bool updateIndexesEagerly,
                                                       bool onlyUniqueIndexesWereUpdated,
                                                       int numberOfUniqueIndexesUpdated,
                                                       bool writeStateIfConstraintsAreNotViolated)
        {
            //if there is any update to the indexes
            //we go ahead and updates the indexes
            if (updates.Count() > 0)
            {
                IList <Type>    iGrainTypes = GetIIndexableGrainTypes();
                IIndexableGrain thisGrain   = this.AsReference <IIndexableGrain>(GrainFactory);

                bool isThereAtMostOneUniqueIndex = numberOfUniqueIndexesUpdated <= 1;

                //if any unique index is defined on this grain and at least one of them is updated
                if (numberOfUniqueIndexesUpdated > 0)
                {
                    try
                    {
                        //update the unique indexes eagerly
                        //if there were more than one unique index, the updates to
                        //the unique indexes should be tentative in order not to
                        //become visible to readers before making sure that all
                        //uniqueness constraints are satisfied
                        await ApplyIndexUpdatesEagerly(iGrainTypes, thisGrain, updates, true, false, !isThereAtMostOneUniqueIndex);
                    }
                    catch (UniquenessConstraintViolatedException ex)
                    {
                        //if any uniqueness constraint is violated and we have
                        //more than one unique index defined, then all tentative
                        //updates should be undone
                        if (!isThereAtMostOneUniqueIndex)
                        {
                            await UndoTentativeChangesToUniqueIndexesEagerly(iGrainTypes, thisGrain, updates);
                        }
                        //then, the exception is thrown back to the user code.
                        throw ex;
                    }
                }

                //if indexes are updated eagerly
                if (updateIndexesEagerly)
                {
                    //Case 1: if only unique indexes were updated, then their update
                    //is already processed before and the only thing remaining is to
                    //save the grain state if requested
                    if (onlyUniqueIndexesWereUpdated && writeStateIfConstraintsAreNotViolated)
                    {
                        await WriteBaseStateAsync();
                    }
                    //Case 2: if there were some non-unique indexes updates and
                    //writing the state back to the storage is requested, then we
                    //do these two tasks concurrently
                    else if (writeStateIfConstraintsAreNotViolated)
                    {
                        await Task.WhenAll(
                            WriteBaseStateAsync(),
                            ApplyIndexUpdatesEagerly(iGrainTypes, thisGrain, updates, false, isThereAtMostOneUniqueIndex)
                            );
                    }
                    //Case 3: if there were some non-unique indexes updates, but
                    //writing the state back to the storage is not requested, then
                    //the only thing left is updating the remaining non-unique indexes
                    else
                    {
                        await ApplyIndexUpdatesEagerly(iGrainTypes, thisGrain, updates, false, isThereAtMostOneUniqueIndex);
                    }
                }
                //Otherwise, if indexes are updated lazily
                else
                {
                    //update the indexes lazily
                    ApplyIndexUpdatesLazilyWithoutWait(updates, iGrainTypes, thisGrain, Guid.NewGuid());

                    //final, the grain state is persisted if requested
                    if (writeStateIfConstraintsAreNotViolated)
                    {
                        await WriteBaseStateAsync();
                    }
                }
                //if everything was successful, the before images are updated
                UpdateBeforeImages(updates);
            }
            //otherwise if there is no update to the indexes, we should
            //write back the state of the grain if requested
            else if (writeStateIfConstraintsAreNotViolated)
            {
                await WriteBaseStateAsync();
            }
        }
 private Task UndoTentativeChangesToUniqueIndexesEagerly(IList <Type> iGrainTypes,
                                                         IIndexableGrain thisGrain,
                                                         IDictionary <string, IMemberUpdate> updates)
 {
     return(ApplyIndexUpdatesEagerly(iGrainTypes, thisGrain, MemberUpdateReverseTentative.Reverse(updates), true, false, false));
 }
        => Task.FromResult(true);       // The index is maintained by the underlying _grainStorage, when the grain's WriteStateAsync is called

        public Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex,
                                                  IndexMetaData idxMetaData, SiloAddress siloAddress)
        => Task.FromResult(true);       // The index is maintained by the underlying _grainStorage, when the grain's WriteStateAsync is called