/// <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
/// <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); }
public Task <bool> DirectApplyIndexUpdate(V updatedGrain, Immutable <IMemberUpdate> iUpdate, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress) => this.DirectApplyIndexUpdate(updatedGrain, iUpdate.Value, isUniqueIndex, idxMetaData, siloAddress);
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); }
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 DirectApplyIndexUpdatesNonPersistent(IIndexableGrain g, IList <IMemberUpdate> updates, bool isUniqueIndex, IndexMetaData idxMetaData, SiloAddress siloAddress) => Task.WhenAll(updates.Select(updt => DirectApplyIndexUpdateNonPersistent(g, updt, isUniqueIndex, idxMetaData, siloAddress)));
/// <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); }
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 //} }
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); }