private InterfaceToUpdatesMap GenerateMemberUpdates(IndexUpdateReason updateReason, bool onlyUpdateActiveIndexes, out bool updateIndexesEagerly, ref bool onlyUniqueIndexesWereUpdated, out int numberOfUniqueIndexesUpdated) { (string prevIndexName, var prevIndexIsEager) = (null, false); var numUniqueIndexes = 0; // Local vars due to restrictions on local functions accessing ref/out params var onlyUniqueIndexes = true; IEnumerable <(string indexName, IMemberUpdate mu)> generateNamedMemberUpdates(Type interfaceType, InterfaceIndexes indexes) { var befImgs = indexes.BeforeImages.Value; foreach ((var indexName, var indexInfo) in indexes.NamedIndexes .Where(kvp => !onlyUpdateActiveIndexes || !kvp.Value.IndexInterface.IsTotalIndex()) .Select(kvp => (kvp.Key, kvp.Value))) { var mu = updateReason == IndexUpdateReason.OnActivate ? indexInfo.UpdateGenerator.CreateMemberUpdate(befImgs[indexName]) : indexInfo.UpdateGenerator.CreateMemberUpdate( updateReason == IndexUpdateReason.OnDeactivate ? null : indexes.Properties, befImgs[indexName]); if (mu.OperationType != IndexOperationType.None) { if (prevIndexName != null && prevIndexIsEager != indexInfo.MetaData.IsEager) { throw new InvalidOperationException($"Inconsistent index eagerness specification on grain implementation {this.GetType().Name}," + $" interface {interfaceType.Name}, properties {indexes.PropertiesType.FullName}." + $" Prior indexes (most recently {prevIndexName}) specified {prevIndexIsEager} while" + $" index {indexName} specified {indexInfo.MetaData.IsEager}. This misconfiguration should have been detected on silo startup."); } (prevIndexName, prevIndexIsEager) = (indexName, indexInfo.MetaData.IsEager); if (indexInfo.MetaData.IsUniqueIndex) { // An update is a delete plus insert, so count it as two. numUniqueIndexes += (mu.OperationType == IndexOperationType.Update) ? 2 : 1; } else { onlyUniqueIndexes = false; } yield return(indexName, mu); } } } var interfaceToUpdatesMap = new InterfaceToUpdatesMap(updateReason, this.getWorkflowIdFunc, this._grainIndexes.Select(kvp => (kvp.Key, generateNamedMemberUpdates(kvp.Key, kvp.Value)))); updateIndexesEagerly = prevIndexName != null ? prevIndexIsEager : false; numberOfUniqueIndexesUpdated = numUniqueIndexes; onlyUniqueIndexesWereUpdated = onlyUniqueIndexes; return(interfaceToUpdatesMap); }
/// <summary> /// After some changes were made to the grain, and the grain is in a consistent state, this method is called to update the /// indexes defined on this grain type. /// </summary> /// <remarks> /// A call to this method first creates the member updates, and then sends them to ApplyIndexUpdates of the index handler. /// /// The only reason that this method can receive a negative result from a call to ApplyIndexUpdates is that the list of indexes /// might have changed. In this case, it updates the list of member update and tries again. In the case of a positive result /// from ApplyIndexUpdates, the list of before-images is replaced by the list of after-images. /// </remarks> /// <param name="updateReason">Determines whether this method is called upon activation, deactivation, or still-active state of this grain</param> /// <param name="onlyUpdateActiveIndexes">whether only active indexes should be updated</param> /// <param name="writeStateIfConstraintsAreNotViolated">whether to write back the state to the storage if no constraint is violated</param> private protected Task UpdateIndexes(IndexUpdateReason updateReason, bool onlyUpdateActiveIndexes, bool writeStateIfConstraintsAreNotViolated) { // A flag to determine whether only unique indexes were updated var onlyUniqueIndexesWereUpdated = this._hasAnyUniqueIndex; // Gather the dictionary of indexes to their corresponding updates, grouped by interface var interfaceToUpdatesMap = this.GenerateMemberUpdates(updateReason, onlyUpdateActiveIndexes, out var updateIndexesEagerly, ref onlyUniqueIndexesWereUpdated, out var numberOfUniqueIndexesUpdated); // Apply the updates to the indexes defined on this grain return(this.ApplyIndexUpdates(interfaceToUpdatesMap, updateIndexesEagerly, onlyUniqueIndexesWereUpdated, numberOfUniqueIndexesUpdated, writeStateIfConstraintsAreNotViolated)); }
internal InterfaceToUpdatesMap(IndexUpdateReason updateReason, Func <Guid> getWorkflowIdFunc, IEnumerable <(Type interfaceType, IEnumerable <(string indexName, IMemberUpdate mu)> namedUpdates)> updateEnumerator)