protected sealed override IEnumerable <Replicable> OnApplyReplicationOperation(StatefulServiceExecutionContext executionContext, ReplicationOperation replicationOperation) { if (this.IsDisposed) { AppTrace.TraceMsg(TraceLogEventType.Information, "StatefulServiceReplicaT.OnApplyReplicationOperation", "OnApplyReplicationOperation called after service was disposed"); return(Enumerable.Empty <Replicable>()); } if (replicationOperation.Type == ReplicationOperationType.Replicate || replicationOperation.Type == ReplicationOperationType.Copy) { List <Replicable> replicablesToCommit = new List <Replicable>(); ItemCollection <IComparable, StatefulProgramInstance> instances; using (this.instanceManager.GetInstances(LockPermission.Write, out instances)) { if (replicationOperation.Type == ReplicationOperationType.Copy) { instances.Clear(); } int count = replicationOperation.Replicables.Count(); //// Bug#221476 //// Debug.Assert(count <= 1, string.Format(CultureInfo.InvariantCulture, "Unexpected number of replicables {0}", count)); Replicable <StatefulProgramInstance> replicableToApply = (Replicable <StatefulProgramInstance>)replicationOperation.Replicables.FirstOrDefault(); if (replicableToApply == null) { return(replicablesToCommit); } StatefulProgramInstance instance = (StatefulProgramInstance)this.GetOrCreateInstance(replicableToApply.Value.Id, Type.GetType(replicableToApply.Value.TypeName), replicableToApply.Value.InitializationParams); if (instance != null) { instance.SetContextInstanceId(); ItemCollection <string, Replicable> replicables; using (instance.GetReplicables(LockPermission.Write, out replicables)) { if (replicationOperation.Type == ReplicationOperationType.Copy) { // Overwrite the existing replicables replicables.Fill(replicableToApply.Value.DataContractReplicables); replicablesToCommit.AddRange(replicables); } else if (replicableToApply.IsDisposed) { /// If this ProgramInstance was disposed, then dispose all associated Replicables and add them /// to replicablesToCommit so that the persistence logic can pick it up and delete from the store /// if required. ItemCollection <string, Replicable> instanceReplicables; using (instance.GetReplicables(LockPermission.Read, out instanceReplicables)) { foreach (Replicable replicable in instanceReplicables) { replicable.Dispose(); replicablesToCommit.Add(replicable); } } this.DeleteInstanceInternal(instance.Id, false, -2); } else { foreach (Replicable replicable in replicableToApply.Value.DataContractReplicables) { if (!replicable.IsDisposed) { if (replicables.Contains(replicable.Name)) { // TODO: Need setitem support on ItemCollection Replicable existingReplicable = replicables[replicable.Name]; if (existingReplicable.SequenceNumber <= replicable.SequenceNumber) { replicables.Remove(replicable.Name); replicables.Add(replicable); } } else { replicables.Add(replicable); } replicablesToCommit.Add(replicable); } else { replicables.Remove(replicable.Name); } } } } instance.SetContextInstanceId(replicablesToCommit); } } return(replicablesToCommit); } else if (replicationOperation.Type == ReplicationOperationType.Evict) { int count = replicationOperation.Replicables.Count(); Debug.Assert(count <= 1, string.Format(CultureInfo.InvariantCulture, "Unexpected number of replicables {0}", count)); Replicable <StatefulProgramInstance> replicable = (Replicable <StatefulProgramInstance>)replicationOperation.Replicables.FirstOrDefault(); if (replicable != null) { ItemCollection <IComparable, StatefulProgramInstance> instances; using (this.instanceManager.GetInstances(LockPermission.Write, out instances)) { foreach (Replicable <StatefulProgramInstance> instance in replicationOperation.Replicables) { this.DeleteInstanceInternal(instance.Value.Id, false, -2); } } } return(replicationOperation.Replicables); } return(base.OnApplyReplicationOperation(executionContext, replicationOperation)); }
private StatefulProgramInstance GetOrCreateInstance(IComparable instanceId, Type instanceType, object[] initializationParameters) { Requires.Argument("instanceId", instanceId).NotNull(); Requires.Argument("instanceType", instanceType).NotNull(); StatefulServiceExecutionContext executionContext = StatefulServiceExecutionContext.Current as StatefulServiceExecutionContext; if (executionContext == null || executionContext.Partition == null) { throw new InvalidOperationException("Program instance cannot be created in context of a partition. Please ensure that StatefulServiceReplica.Invoke is called."); } ReplicableTypeInfo replicableTypeInfo = null; Dictionary <Type, ReplicableTypeInfo> replicableTypeInfos; using (ReplicableTypeInfo.GetReplicableTypeInfos(LockPermission.Read, out replicableTypeInfos)) { replicableTypeInfos.TryGetValue(instanceType, out replicableTypeInfo); if (replicableTypeInfo == null) { return(null); } } StatefulProgramInstance instance = null; ItemCollection <IComparable, StatefulProgramInstance> instances; using (this.instanceManager.GetInstances(LockPermission.Write, out instances)) { if (instances.Contains(instanceId)) { instance = instances[instanceId]; } else if (this.ReplicaRole != Fabric.ReplicaRole.Primary) { /// Since we are the secondary, create a new instance. Resurrection will only happen on the primary which /// will then replicate the state to all secondaries. instance = new StatefulProgramInstance(this, instanceId, replicableTypeInfo, initializationParameters, instanceId.CompareTo(StatefulServiceReplica <TInstance> .SingletonSessionId) == 0); instances.Add(instance); } } if (instance == null) { /// TODO: Make this async. The asynchrony needs to be plumbed all the way through. WCF interfaces don't support /// asynchrony when obtaining service instances, so we will need to live with this there but can do better for the /// rest. StatefulComponentStateManager stateManager = (StatefulComponentStateManager)this.StateManager; Task <IEnumerable <Replicable> > task = stateManager.ResurrectProgramInstanceAsync(executionContext, instanceId); Task.WaitAll(task); IEnumerable <Replicable> replicables = !task.IsFaulted ? task.Result : Enumerable.Empty <Replicable>(); using (this.instanceManager.GetInstances(LockPermission.Write, out instances)) { if (instances.Contains(instanceId)) { instance = instances[instanceId]; } else { StatefulProgramInstance statefulProgramInstance = new StatefulProgramInstance(this, instanceId, replicableTypeInfo, initializationParameters, instanceId.CompareTo(StatefulServiceReplica <TInstance> .SingletonSessionId) == 0); instance = statefulProgramInstance; instances.Add(instance); ItemCollection <string, Replicable> typeReplicables; using (statefulProgramInstance.GetReplicables(LockPermission.Write, out typeReplicables)) { foreach (Replicable replicable in replicables) { typeReplicables.Remove(replicable); typeReplicables.Add(replicable); } } } } } return(instance); }
protected internal sealed override IEnumerable <Replicable> ReplicationOperationComplete(StatefulServiceExecutionContext executionContext, ReplicationResult result, ReplicationOperation replicationOperation) { if (this.IsDisposed) { AppTrace.TraceMsg(TraceLogEventType.Information, "StatefulServiceReplicaT.ReplicationOperationComplete", "ReplicationOperationComplete called after service was disposed"); return(Enumerable.Empty <Replicable>()); } StatefulProgramInstance instance = null; Replicable <StatefulProgramInstance> replicableToCommit = replicationOperation.Replicables.FirstOrDefault() as Replicable <StatefulProgramInstance>; if (replicableToCommit != null) { instance = this.instanceManager.GetInstance(replicableToCommit.Value.Id) as StatefulProgramInstance; if (instance != null) { instance.SetContextInstanceId(); } else if (replicableToCommit.Value != null) { Debug.Assert(replicationOperation.Type == ReplicationOperationType.Evict, "Unexpected operation type"); replicableToCommit.Value.SetContextInstanceId(); } else { Debug.Assert(false, "replicableToCommit.Value is null"); } } AppTrace.TraceMsg( TraceLogEventType.Information, "StatefulComponent.ReplicationOperationComplete", "replicationOperation.Type={0}, result={1}, replicables.Count={2}, replicableToCommit={3}, programInstance={4}", replicationOperation.Type, result, replicationOperation.Replicables.Count(), replicableToCommit != null ? replicableToCommit.Name : "Null", instance != null ? instance.Id : "Null"); IEnumerable <Replicable> replicablesToCommit = null; if (replicationOperation.Type == ReplicationOperationType.Replicate) { if (result == ReplicationResult.Success) { List <Replicable> changes = new List <Replicable>(); if (replicableToCommit.IsDisposed) { foreach (Replicable replicable in replicableToCommit.Value.DataContractReplicables) { changes.Add(replicable); } } else { ItemCollection <string, Replicable> replicables; using (instance.GetReplicables(LockPermission.Write, out replicables)) { foreach (Replicable replicable in replicableToCommit.Value.DataContractReplicables) { if (replicables.Contains(replicable.Name)) { replicables.Remove(replicable.Name); replicables.Add(replicable); } else { replicables.Add(replicable); } changes.Add(replicable); } } } replicablesToCommit = changes; } else { if (instance != null) { AppTrace.TraceMsg(TraceLogEventType.Error, "StatefulServiceReplicaT.ReplicationOperationComplete", "Recycling StatefulProgramInstance with id '{0}'", instance.Id); instance.RecycleInstance(); } replicablesToCommit = base.ReplicationOperationComplete(executionContext, result, replicationOperation); } } if (replicablesToCommit == null) { replicablesToCommit = base.ReplicationOperationComplete(executionContext, result, replicationOperation); } return(replicablesToCommit); }