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); }
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); }
internal static string ToString(IMemberUpdate update) { switch (update.OperationType) { case IndexOperationType.None: return(update.GetType().Name + ": No operation"); case IndexOperationType.Insert: return(update.GetType().Name + ": Inserted " + update.GetAfterImage()); case IndexOperationType.Delete: return(update.GetType().Name + ": Deleted " + update.GetBeforeImage()); case IndexOperationType.Update: return(update.GetType().Name + ": Updated " + update.GetBeforeImage() + " into " + update.GetAfterImage()); default: return(update.GetType().Name + ": Unsupported operation"); } }
/// <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); }
/// <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); }
public object GetBeforeImage() { return(_update.GetAfterImage()); }
public object GetAfterImage() { return((_opType == IndexOperationType.Update || _opType == IndexOperationType.Insert) ? _update.GetAfterImage() : null); }