/// <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));
 }
        private IDictionary <string, IMemberUpdate> GeneratMemberUpdates(TProperties indexableProperties, bool isOnActivate, bool onlyUpdateActiveIndexes, out bool updateIndexesEagerly, ref bool onlyUniqueIndexesWereUpdated, out int numberOfUniqueIndexesUpdated)
        {
            updateIndexesEagerly         = false;
            numberOfUniqueIndexesUpdated = 0;

            IDictionary <string, IMemberUpdate> updates = new Dictionary <string, IMemberUpdate>();
            IDictionary <string, Tuple <object, object, object> > iUpdateGens = _iUpdateGens;

            {
                IDictionary <string, object> befImgs = _beforeImages.Value;
                foreach (KeyValuePair <string, Tuple <object, object, object> > kvp in iUpdateGens)
                {
                    var idxInfo = kvp.Value;
                    if (!onlyUpdateActiveIndexes || !(idxInfo.Item1 is TotalIndex))
                    {
                        IMemberUpdate mu = isOnActivate ? ((IIndexUpdateGenerator)idxInfo.Item3).CreateMemberUpdate(befImgs[kvp.Key])
                                                        : ((IIndexUpdateGenerator)idxInfo.Item3).CreateMemberUpdate(indexableProperties, befImgs[kvp.Key]);
                        if (mu.GetOperationType() != IndexOperationType.None)
                        {
                            updates.Add(kvp.Key, mu);
                            IndexMetaData indexMetaData = (IndexMetaData)kvp.Value.Item2;

                            //this flag should be the same for all indexes defined
                            //on a grain and that's why we do not accumulate the
                            //changes from different indexes
                            updateIndexesEagerly = indexMetaData.IsEager();

                            //update unique index related output flags and counters
                            bool isUniqueIndex = indexMetaData.IsUniqueIndex();
                            onlyUniqueIndexesWereUpdated = onlyUniqueIndexesWereUpdated && isUniqueIndex;
                            if (isUniqueIndex)
                            {
                                ++numberOfUniqueIndexesUpdated;
                            }
                        }
                    }
                }
            }

            return(updates);
        }
 public Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates,
                                                bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
 => Task.FromResult(true);       // The index is maintained by the underlying _grainStorage, when the grain's WriteStateAsync is called
示例#4
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));
 }
        /// <summary>
        /// This method contains the common functionality for updating the hash-index bucket.
        /// </summary>
        /// <typeparam name="K">key type</typeparam>
        /// <typeparam name="V">value type</typeparam>
        /// <param name="updatedGrain">the updated grain that is being indexed</param>
        /// <param name="update">the update information</param>
        /// <param name="state">the index bucket to be updated</param>
        /// <param name="isUniqueIndex">a flag to indicate whether the hash-index has a uniqueness constraint</param>
        /// <param name="idxMetaData">the index metadata</param>
        /// <param name="fixIndexUnavailableOnDelete">output parameter: this variable determines whether
        ///             the index was still unavailable when we received a delete operation</param>
        internal static bool UpdateBucketState <K, V>(V updatedGrain, IMemberUpdate update, HashIndexBucketState <K, V> state, bool isUniqueIndex,
                                                      IndexMetaData idxMetaData, out bool fixIndexUnavailableOnDelete) where V : IIndexableGrain
        {
            fixIndexUnavailableOnDelete = false;

            var indexUpdateMode = update.UpdateMode;
            var opType          = update.OperationType;
            HashIndexSingleBucketEntry <V> aftEntry;

            // Insert is done for both IndexOperationType.Update and IndexOperationType.Update, so use a local function.
            bool doInsert(K afterImage, out bool uniquenessViolation)
            {
                uniquenessViolation = false;
                if (state.IndexMap.TryGetValue(afterImage, out aftEntry))
                {
                    if (!aftEntry.Values.Contains(updatedGrain))
                    {
                        if (isUniqueIndex && aftEntry.Values.Count > 0)
                        {
                            uniquenessViolation = true;
                            return(false);
                        }
                        aftEntry.Add(updatedGrain, indexUpdateMode, isUniqueIndex);
                    }
                    else if (indexUpdateMode == IndexUpdateMode.Tentative)
                    {
                        aftEntry.SetTentativeInsert();
                    }
                    else
                    {
                        aftEntry.ClearTentativeFlag();
                    }
                    return(true);
                }

                // Add a new entry
                if (idxMetaData.IsCreatingANewBucketNecessary(state.IndexMap.Count))
                {
                    return(false);  // the bucket is full
                }

                aftEntry = new HashIndexSingleBucketEntry <V>();
                aftEntry.Add(updatedGrain, indexUpdateMode, isUniqueIndex);
                state.IndexMap.Add(afterImage, aftEntry);
                return(true);
            }

            if (opType == IndexOperationType.Update)
            {
                K   aftImg = (K)update.GetAfterImage();
                var befImg = (K)update.GetBeforeImage();
                if (state.IndexMap.TryGetValue(befImg, out var befEntry) && befEntry.Values.Contains(updatedGrain))
                {
                    // Delete and Insert
                    if (state.IndexMap.TryGetValue(aftImg, out aftEntry))
                    {
                        if (aftEntry.Values.Contains(updatedGrain))
                        {
                            if (indexUpdateMode == IndexUpdateMode.Tentative)
                            {
                                aftEntry.SetTentativeInsert();
                            }
                            else
                            {
                                aftEntry.ClearTentativeFlag();
                                befEntry.Remove(updatedGrain, indexUpdateMode, isUniqueIndex);
                            }
                        }
                        else
                        {
                            if (isUniqueIndex && aftEntry.Values.Count > 0)
                            {
                                throw new UniquenessConstraintViolatedException(
                                          $"The uniqueness property of index {idxMetaData.IndexName} is would be violated for an update operation" +
                                          $" for before-image = {befImg}, after-image = {aftImg} and grain = {updatedGrain.GetPrimaryKey()}");
                            }
                            befEntry.Remove(updatedGrain, indexUpdateMode, isUniqueIndex);
                            aftEntry.Add(updatedGrain, indexUpdateMode, isUniqueIndex);
                        }
                    }
                    else
                    {
                        aftEntry = new HashIndexSingleBucketEntry <V>();
                        befEntry.Remove(updatedGrain, indexUpdateMode, isUniqueIndex);
                        aftEntry.Add(updatedGrain, indexUpdateMode, isUniqueIndex);
                        state.IndexMap.Add(aftImg, aftEntry);
                    }
                }
                else
                {
                    // Insert-only, because Delete was not found. If there's a NextBucket so return false to search it;
                    // otherwise, the desired Delete result is met (the previous value is not present), so proceed to Insert.
                    if (idxMetaData.IsChainedBuckets && state.NextBucket != null)
                    {
                        return(false);
                    }

                    if (!doInsert(aftImg, out bool uniquenessViolation))
                    {
                        return(uniquenessViolation
                            ? throw new UniquenessConstraintViolatedException(
                                   $"The uniqueness property of index {idxMetaData.IndexName} would be violated for an update operation" +
                                   $" for (not found before-image = {befImg}), after-image = {aftImg} and grain = {updatedGrain.GetPrimaryKey()}")
                            : false);    // The bucket is full
                    }
                }
            }
            else if (opType == IndexOperationType.Insert)
            {
                if (!doInsert((K)update.GetAfterImage(), out bool uniquenessViolation))
                {
                    return(uniquenessViolation
                        ? throw new UniquenessConstraintViolatedException(
                               $"The uniqueness property of index {idxMetaData.IndexName} would be violated for an insert operation" +
                               $" for after-image = {(K)update.GetAfterImage()} and grain = {updatedGrain.GetPrimaryKey()}")
                        : false);
                }
            }
            else if (opType == IndexOperationType.Delete)
            {
                var befImg = (K)update.GetBeforeImage();

                if (state.IndexMap.TryGetValue(befImg, out var befEntry) && befEntry.Values.Contains(updatedGrain))
                {
                    befEntry.Remove(updatedGrain, indexUpdateMode, isUniqueIndex);
                    if (state.IndexStatus != IndexStatus.Available)
                    {
                        fixIndexUnavailableOnDelete = true;
                    }
                }
                else if (idxMetaData.IsChainedBuckets)
                {
                    // Not found in this bucket. If there's a NextBucket, return false to search it;
                    // otherwise, the desired Delete result is met (the value is not present), so return true.
                    return(state.NextBucket == null);
                }
            }
            return(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);
     }
 }
        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 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)
        {
            if (getLogger().IsVerbose)
            {
                getLogger().Verbose("Started calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {0}, siloAddress = {1}, iUpdates = {2}", isUnique, siloAddress, MemberUpdate.UpdatesToString(iUpdates.Value));
            }

            IDictionary <IIndexableGrain, IList <IMemberUpdate> > updates = iUpdates.Value;

            Task[] updateTasks = new Task[updates.Count()];
            int    i           = 0;

            foreach (var kv in updates)
            {
                updateTasks[i] = DirectApplyIndexUpdatesNonPersistent(kv.Key, kv.Value, isUnique, idxMetaData, siloAddress);
                ++i;
            }
            await Task.WhenAll(updateTasks);

            await PersistIndex();

            if (getLogger().IsVerbose)
            {
                getLogger().Verbose("Finished calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {0}, siloAddress = {1}, iUpdates = {2}", isUnique, siloAddress, MemberUpdate.UpdatesToString(iUpdates.Value));
            }

            return(true);
        }
示例#10
0
 public Task <bool> DirectApplyIndexUpdate(V updatedGrain, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 => this.DirectApplyIndexUpdate(updatedGrain, iUpdate.Value, isUniqueIndex, idxMetaData, siloAddress);
示例#11
0
 private Task <bool> DirectApplyIndexUpdate(V updatedGrain, IMemberUpdate updt, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 // 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).
 => Task.FromResult(HashIndexBucketUtils.UpdateBucketState(updatedGrain, updt, state, isUniqueIndex, idxMetaData));
        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);
        }
        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> > >();

            void AddUpdateToBucket(IIndexableGrain g, int bucket, IMemberUpdate update)
            {
                var bucketUpdatesMap  = bucketUpdates.GetOrAdd(bucket, () => new Dictionary <IIndexableGrain, IList <IMemberUpdate> >());
                var bucketUpdatesList = bucketUpdatesMap.GetOrAdd(g, () => new List <IMemberUpdate>());

                bucketUpdatesList.Add(update);
            }

            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(g, befImgHash, update);
                        }
                        else
                        {
                            AddUpdateToBucket(g, befImgHash, new MemberUpdateOverriddenOperation(update, IndexOperationType.Delete));
                            AddUpdateToBucket(g, aftImgHash, new MemberUpdateOverriddenOperation(update, IndexOperationType.Insert));
                        }
                    }
                    else if (opType == IndexOperationType.Insert)
                    {
                        int aftImgHash = GetBucketIndexFromHashCode(update.GetAfterImage());
                        AddUpdateToBucket(g, aftImgHash, update);
                    }
                    else if (opType == IndexOperationType.Delete)
                    {
                        int befImgHash = GetBucketIndexFromHashCode(update.GetBeforeImage());
                        AddUpdateToBucket(g, befImgHash, update);
                    }
                }
            }

            var results = await Task.WhenAll(bucketUpdates.Select(kv =>
            {
                BucketT bucket = this.GetBucketGrain(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);
        }
示例#14
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
            //}
        }
示例#15
0
 private Task DirectApplyIndexUpdatesNonPersistent(IIndexableGrain g, IList <IMemberUpdate> updates, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress)
 => Task.WhenAll(updates.Select(updt => DirectApplyIndexUpdateNonPersistent(g, updt, isUniqueIndex, idxMetaData, siloAddress)));
示例#16
0
        /// <summary>
        /// This method contains the common functionality for updating
        /// hash-index bucket.
        /// </summary>
        /// <typeparam name="K">key type</typeparam>
        /// <typeparam name="V">value type</typeparam>
        /// <param name="updatedGrain">the updated grain that is being indexed</param>
        /// <param name="update">the update information</param>
        /// <param name="opType">the update operation type, which might be different
        /// from the update operation type inside the update parameter</param>
        /// <param name="State">the index bucket to be updated</param>
        /// <param name="isUniqueIndex">a flag to indicate whether the
        /// hash-index has a uniqueness constraint</param>
        /// <param name="befImg">output parameter: the before-image</param>
        /// <param name="befEntry">output parameter: the index entry containing the before-image</param>
        /// <param name="fixIndexUnavailableOnDelete">output parameter: this variable determines whether
        /// index was still unavailable when we received a delete operation</param>
        internal static bool UpdateBucket <K, V>(V updatedGrain, IMemberUpdate update, HashIndexBucketState <K, V> State, bool isUniqueIndex, IndexMetaData idxMetaData, out K befImg, out HashIndexSingleBucketEntry <V> befEntry, out bool fixIndexUnavailableOnDelete) where V : IIndexableGrain
        {
            fixIndexUnavailableOnDelete = false;
            befImg   = default(K);
            befEntry = null;

            bool isTentativeUpdate = isUniqueIndex && (update is MemberUpdateTentative);
            IndexOperationType             opType = update.GetOperationType();
            HashIndexSingleBucketEntry <V> aftEntry;

            if (opType == IndexOperationType.Update)
            {
                befImg = (K)update.GetBeforeImage();
                K aftImg = (K)update.GetAfterImage();
                if (State.IndexMap.TryGetValue(befImg, out befEntry) && befEntry.Values.Contains(updatedGrain))
                {   //Delete and Insert
                    if (State.IndexMap.TryGetValue(aftImg, out aftEntry))
                    {
                        if (aftEntry.Values.Contains(updatedGrain))
                        {
                            if (isTentativeUpdate)
                            {
                                aftEntry.setTentativeInsert();
                            }
                            else
                            {
                                aftEntry.clearTentativeFlag();
                                befEntry.Remove(updatedGrain, isTentativeUpdate, isUniqueIndex);
                            }
                        }
                        else
                        {
                            if (isUniqueIndex && aftEntry.Values.Count > 0)
                            {
                                throw new UniquenessConstraintViolatedException(string.Format("The uniqueness property of index is violated after an update operation for before-image = {0}, after-image = {1} and grain = {2}", befImg, aftImg, updatedGrain.GetPrimaryKey()));
                            }
                            befEntry.Remove(updatedGrain, isTentativeUpdate, isUniqueIndex);
                            aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                        }
                    }
                    else
                    {
                        aftEntry = new HashIndexSingleBucketEntry <V>();
                        befEntry.Remove(updatedGrain, isTentativeUpdate, isUniqueIndex);
                        aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                        State.IndexMap.Add(aftImg, aftEntry);
                    }
                }
                else
                {
                    if (idxMetaData.IsChainedBuckets())
                    {
                        return(false); //not found in this bucket
                    }
                    //Insert
                    if (State.IndexMap.TryGetValue(aftImg, out aftEntry))
                    {
                        if (!aftEntry.Values.Contains(updatedGrain))
                        {
                            if (isUniqueIndex && aftEntry.Values.Count > 0)
                            {
                                throw new UniquenessConstraintViolatedException(string.Format("The uniqueness property of index is violated after an update operation for (not found before-image = {0}), after-image = {1} and grain = {2}", befImg, aftImg, updatedGrain.GetPrimaryKey()));
                            }
                            aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                        }
                        else if (isTentativeUpdate)
                        {
                            aftEntry.setTentativeInsert();
                        }
                        else
                        {
                            aftEntry.clearTentativeFlag();
                        }
                    }
                    else
                    {
                        if (idxMetaData.IsCreatingANewBucketNecessary(State.IndexMap.Count()))
                        {
                            return(false);
                        }
                        aftEntry = new HashIndexSingleBucketEntry <V>();
                        aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                        State.IndexMap.Add(aftImg, aftEntry);
                    }
                }
            }
            else if (opType == IndexOperationType.Insert)
            { // Insert
                K aftImg = (K)update.GetAfterImage();
                if (State.IndexMap.TryGetValue(aftImg, out aftEntry))
                {
                    if (!aftEntry.Values.Contains(updatedGrain))
                    {
                        if (isUniqueIndex && aftEntry.Values.Count > 0)
                        {
                            throw new UniquenessConstraintViolatedException(string.Format("The uniqueness property of index is violated after an insert operation for after-image = {0} and grain = {1}", aftImg, updatedGrain.GetPrimaryKey()));
                        }
                        aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                    }
                    else if (isTentativeUpdate)
                    {
                        aftEntry.setTentativeInsert();
                    }
                    else
                    {
                        aftEntry.clearTentativeFlag();
                    }
                }
                else
                {
                    if (idxMetaData.IsCreatingANewBucketNecessary(State.IndexMap.Count()))
                    {
                        return(false);  //the bucket is full
                    }
                    aftEntry = new HashIndexSingleBucketEntry <V>();
                    aftEntry.Add(updatedGrain, isTentativeUpdate, isUniqueIndex);
                    State.IndexMap.Add(aftImg, aftEntry);
                }
            }
            else if (opType == IndexOperationType.Delete)
            { // Delete
                befImg = (K)update.GetBeforeImage();

                if (State.IndexMap.TryGetValue(befImg, out befEntry) && befEntry.Values.Contains(updatedGrain))
                {
                    befEntry.Remove(updatedGrain, isTentativeUpdate, isUniqueIndex);
                    if (State.IndexStatus != IndexStatus.Available)
                    {
                        fixIndexUnavailableOnDelete = true;
                    }
                }
                else if (idxMetaData.IsChainedBuckets())
                {
                    return(false); //not found in this bucket
                }
            }
            return(true);
        }
        => 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
 /// <summary>
 /// This method contains the common functionality for updating the hash-index bucket.
 /// </summary>
 /// <typeparam name="K">key type</typeparam>
 /// <typeparam name="V">value type</typeparam>
 /// <param name="updatedGrain">the updated grain that is being indexed</param>
 /// <param name="iUpdate">the update information</param>
 /// <param name="state">the index bucket to be updated</param>
 /// <param name="isUniqueIndex">a flag to indicate whether the hash-index has a uniqueness constraint</param>
 /// <param name="idxMetaData">the index metadata</param>
 internal static bool UpdateBucket <K, V>(V updatedGrain, IMemberUpdate iUpdate, HashIndexBucketState <K, V> state, bool isUniqueIndex, IndexMetaData idxMetaData) where V : IIndexableGrain
 => UpdateBucket(updatedGrain, iUpdate, state, isUniqueIndex, idxMetaData, out K befImg, out HashIndexSingleBucketEntry <V> befEntry, out bool fixIndexUnavailableOnDelete);
        /// <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);
        }
示例#20
0
 public Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates,
                                                bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
 => Task.FromResult(true);
        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
            //}
        }
示例#22
0
 public Task <bool> DirectApplyIndexUpdate(IIndexableGrain g, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex,
                                           IndexMetaData idxMetaData, SiloAddress siloAddress)
 => Task.FromResult(true);
        public async Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates, bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
        {
            logger.Trace($"ParentIndex {_parentIndexName}: Started calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {isUnique}," +
                         $" siloAddress = {siloAddress}, iUpdates = {MemberUpdate.UpdatesToString(iUpdates.Value)}", isUnique, siloAddress);

            await Task.WhenAll(iUpdates.Value.Select(kvp => DirectApplyIndexUpdates(kvp.Key, kvp.Value, isUnique, idxMetaData, siloAddress)));

            logger.Trace($"Finished calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {isUnique}, siloAddress = {siloAddress}," +
                         $" iUpdates = {MemberUpdate.UpdatesToString(iUpdates.Value)}");
            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);
        public async Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates, bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
        {
            if (logger.IsVerbose)
            {
                logger.Verbose("Started calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {0}, siloAddress = {1}, iUpdates = {2}", isUnique, siloAddress, 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.GetOperationType();
                    if (opType == IndexOperationType.Update)
                    {
                        int befImgHash = update.GetBeforeImage().GetHashCode();
                        int aftImgHash = update.GetAfterImage().GetHashCode();

                        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 = update.GetAfterImage().GetHashCode();
                        AddUpdateToBucket(bucketUpdates, g, aftImgHash, update);
                    }
                    else if (opType == IndexOperationType.Delete)
                    {
                        int befImgHash = update.GetBeforeImage().GetHashCode();
                        AddUpdateToBucket(bucketUpdates, g, befImgHash, update);
                    }
                }
            }

            List <Task> updateTasks = new List <Task>();
            int         i           = 0;

            foreach (var kv in bucketUpdates)
            {
                BucketT bucket = InsideRuntimeClient.Current.InternalGrainFactory.GetGrain <BucketT>(
                    IndexUtils.GetIndexGrainID(typeof(V), _indexName) + "_" + kv.Key
                    );
                updateTasks.Add(bucket.DirectApplyIndexUpdateBatch(kv.Value.AsImmutable(), isUnique, idxMetaData, siloAddress));
                ++i;
            }
            await Task.WhenAll(updateTasks);

            if (logger.IsVerbose)
            {
                logger.Verbose("Finished calling DirectApplyIndexUpdateBatch with the following parameters: isUnique = {0}, siloAddress = {1}, iUpdates = {2}", isUnique, siloAddress, MemberUpdate.UpdatesToString(iUpdates.Value));
            }

            return(true);
        }
 /// <summary>
 /// DirectApplyIndexUpdateBatch is not supported on ActiveHashIndexPartitionedPerSiloImpl, because it will be skipped
 /// via IndexExtensions.ApplyIndexUpdateBatch which goes directly to the IActiveHashIndexPartitionedPerSiloBucket grain service
 /// </summary>
 public Task <bool> DirectApplyIndexUpdateBatch(Immutable <IDictionary <IIndexableGrain, IList <IMemberUpdate> > > iUpdates, bool isUnique, IndexMetaData idxMetaData, SiloAddress siloAddress = null)
 => throw new NotSupportedException();
 internal IndexInfo(IIndexInterface indexInterface, IndexMetaData metaData, IIndexUpdateGenerator updateGenerator)
 {
     this.IndexInterface  = indexInterface;
     this.MetaData        = metaData;
     this.UpdateGenerator = updateGenerator;
 }
 /// <summary>
 /// This method contains the common functionality for updating the hash-index bucket.
 /// </summary>
 /// <typeparam name="K">key type</typeparam>
 /// <typeparam name="V">value type</typeparam>
 /// <param name="updatedGrain">the updated grain that is being indexed</param>
 /// <param name="iUpdate">the update information</param>
 /// <param name="state">the index bucket to be updated</param>
 /// <param name="isUniqueIndex">a flag to indicate whether the hash-index has a uniqueness constraint</param>
 /// <param name="idxMetaData">the index metadata</param>
 internal static bool UpdateBucketState <K, V>(V updatedGrain, IMemberUpdate iUpdate, HashIndexBucketState <K, V> state, bool isUniqueIndex,
                                               IndexMetaData idxMetaData) where V : IIndexableGrain
 => UpdateBucketState(updatedGrain, iUpdate, state, isUniqueIndex, idxMetaData, out bool _);
        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);
        }