protected object CreateInstance(IComparable instanceId, object[] initializationParameters)
        {
            Requires.Argument("instanceId", instanceId).NotNull();

            StatefulProgramInstance instance = this.GetOrCreateInstance(instanceId, typeof(TInstance), initializationParameters);

            return(instance != null ? instance.Instance : null);
        }
        private bool DeleteInstanceInternal(IComparable instanceId, bool replicate, long evictionVersion)
        {
            Requires.Argument("instanceId", instanceId).NotNull();

            StatefulServiceExecutionContext executionContext = StatefulServiceExecutionContext.Current as StatefulServiceExecutionContext;

            if (executionContext == null || executionContext.Partition == null)
            {
                throw new InvalidOperationException("Program instance cannot be obtained outside context of a partition. Please ensure that StatefulServiceReplicaT.Invoke is called.");
            }

            StatefulProgramInstance instance = null;
            ItemCollection <IComparable, StatefulProgramInstance> instances;

            using (this.instanceManager.GetInstances(LockPermission.Write, out instances))
            {
                if (instances.Contains(instanceId))
                {
                    instance = (StatefulProgramInstance)instances[instanceId];
                    if (evictionVersion != -2 && !instance.CanEvict(evictionVersion))
                    {
                        return(false);
                    }

                    instances.Remove(instanceId);
                    ((IDisposable)instance).Dispose();
                }
            }

            if (instance != null)
            {
                if (replicate)
                {
                    Replicable <StatefulProgramInstance> replicable = new Replicable <StatefulProgramInstance>(instance.Id.ToString(), instance);
                    ReplicationScope replicationScope = new ReplicationScope(new Replicable[] { replicable }, ReplicationOperationType.Evict);
                    replicationScope.ReplicateAsync().ContinueWith(
                        task =>
                    {
                        ReplicationResult result = task.IsFaulted ? ReplicationResult.Failed : task.Result;
                        if (result != ReplicationResult.Success)
                        {
                            AppTrace.TraceMsg(TraceLogEventType.Warning, "StatefulServiceReplicaT.DeleteInstanceInternal", "Replication call to dispose the instance with id {0} failed.", instance.Id);
                        }
                    },
                        TaskContinuationOptions.ExecuteSynchronously);
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        protected Task <Tuple <object, object[]> > InvokeAsync(IComparable instanceId, MethodInfo replicationMethod, object[] inputParameters)
        {
            Requires.Argument("instanceId", instanceId).NotNull();
            Requires.Argument("replicationMethod", replicationMethod).NotNull();

            StatefulProgramInstance instance = this.instanceManager.GetInstance(instanceId);

            if (instance == null)
            {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "No instance was found with InstanceId: '{0}'", instanceId), "instanceId");
            }

            return(instance.InvokeAsync(replicationMethod, inputParameters));
        }
Exemple #4
0
        public static void ClassInitialize(TestContext context)
        {
            TestStatefulServiceReplica   service                  = new TestStatefulServiceReplica();
            StatefulServiceReplicaBroker broker                   = new StatefulServiceReplicaBroker(service, ReplicationWithLockingTests.DefaultInitializationParameters, ReplicationWithLockingTests.DefaultReplicaId);
            TestNativePartition          nativePartition          = new TestNativePartition();
            StatefulServicePartition     statefulServicePartition = new StatefulServicePartition(nativePartition, ServicePartitionInformation.CreateFromNative(nativePartition.PartitionInfo));

            //((IServiceCatalog)ServiceCatalog.Current).AddService(service.Name, statefulServicePartition.Id, service);
            ((IStatefulServiceReplica)service).OpenAsync(statefulServicePartition);
            ((IStatefulServiceReplica)service).ChangeRoleAsync(ReplicaRole.Primary).Wait();
            ReplicationWithLockingTests.Context = new StatefulServiceExecutionContext(
                service,
                new Dictionary <string, object>
            {
                { System.Fabric.Common.Constants.PropertyNames.Service, service.Name },
                { System.Fabric.Common.Constants.PropertyNames.PartitionId, service.Partition.Id }
            });
            ReplicationWithLockingTests.TypeInfo        = ReplicableTypeInfo.GenerateReplicableTypeInfo(typeof(SampleService));
            ReplicationWithLockingTests.ProgramInstance = new StatefulProgramInstance(service, Guid.NewGuid(), TypeInfo, new SampleService());
            ReplicationWithLockingTests.StateReplicator = nativePartition.StateReplicator;
        }
        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);
        }
        bool ISupportEvictableProgramInstances.CanEvict(IComparable instanceId)
        {
            StatefulProgramInstance instance = this.instanceManager.GetInstance(instanceId);

            return(instance == null || instance.TypeInfo.CanEvict);
        }
        long ISupportEvictableProgramInstances.GetVersion(IComparable instanceId)
        {
            StatefulProgramInstance instance = this.instanceManager.GetInstance(instanceId);

            return(instance != null ? instance.Version : -1);
        }
        private void InvokeProcessRequestAsync <TRequestType, TResult>(TaskCompletionSource <TResult> taskProducer, StatefulServiceExecutionContext executionContext, string methodName, Tuple <Type, Type[], object[]> methodParams)
        {
            Exception exception = null;

            try
            {
                if (!typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType)) &&
                    !typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType)))
                {
                    taskProducer.SetException(new NotSupportedException("Method not supported by the server"));
                    return;
                }

                // Get Session Information
                StatefulProgramInstance instance = null;
                DateTime            expiryTime;
                IComparable         sessionId;
                object              sessionObj          = null;
                HttpListenerContext httpListenerContext = methodParams.Item3[methodParams.Item3.Length - 1] as HttpListenerContext;
                if (httpListenerContext != null)
                {
                    sessionObj = httpListenerContext.Request;
                }
                else
                {
                    // For TCP we smuggle the headers in IDictionary<string, string> passed via asyncState
                    StreamWrapper streamWrapper = methodParams.Item3[methodParams.Item3.Length - 1] as StreamWrapper;
                    sessionObj = streamWrapper != null ? streamWrapper.UserData : null;
                }

                if (!StatefulServiceReplica <TInstance> .GetSessionInformation(sessionObj, out sessionId, out expiryTime))
                {
                    // TODO: We do not support session expiry currently
                    sessionId  = Helpers.GenerateUniqueId();
                    expiryTime = DateTime.UtcNow.AddYears(100);
                }
                else
                {
                    instance = this.instanceManager.GetInstance(sessionId);
                }

                // Create a new instance if necessary
                bool setSessionInformation = false;
                bool isExpired             = sessionId != null && DateTime.UtcNow > expiryTime;
                if (instance == null)
                {
                    this.CreateInstance(sessionId, null);
                    instance = this.instanceManager.GetInstance(sessionId);
                    setSessionInformation = true;
                }

                Action <Task> processRequestContinuation = delegate(Task task)
                {
                    this.Invoke <StatefulServiceExecutionContext>(
                        (cec) =>
                    {
                        Exception exception1 = null;
                        try
                        {
                            if (setSessionInformation)
                            {
                                if (httpListenerContext != null)
                                {
                                    sessionObj = httpListenerContext.Response;
                                }
                                else
                                {
                                    // For TCP we smuggle the headers in asyncObject
                                    sessionObj = (IDictionary <string, string>)methodParams.Item3[methodParams.Item3.Length - 1];
                                }

                                StatefulServiceReplica <TInstance> .SetSessionInformation(sessionObj, sessionId, expiryTime);
                            }

                            if (!task.IsFaulted)
                            {
                                // Get the result from either the http task or task returned by Replicable method invocation.
                                object result = null;
                                if (typeof(IProcessTcpRequest).IsAssignableFrom(typeof(TRequestType)))
                                {
                                    Task <Stream> tcpResponseTask = task as Task <Stream>;
                                    if (tcpResponseTask != null)
                                    {
                                        result = tcpResponseTask.Result;
                                    }
                                    else
                                    {
                                        Task <object> taskWithObj = task as Task <object>;
                                        result = (Stream)taskWithObj.Result;
                                    }
                                }

                                taskProducer.SetResult((TResult)result);
                            }
                            else
                            {
                                exception1 = task.Exception.InnerException ?? task.Exception;
                            }

                            if (isExpired)
                            {
                                this.DeleteInstance(sessionId);
                            }
                        }
                        catch (Exception e)
                        {
                            AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync");
                            exception1 = e;
                        }
                        finally
                        {
                            if (exception1 != null)
                            {
                                taskProducer.SetException(exception1);
                            }
                        }
                    });
                };

                if (instance != null && !isExpired)
                {
                    IEnumerable <ReplicableMethodInfo> matchingMethods = null;
                    instance.TypeInfo.TryGetMatchingMethod("ProcessRequestAsync", methodParams.Item1, methodParams.Item2, out matchingMethods);
                    int matchingMethodCount = matchingMethods != null?matchingMethods.Count() : 0;

                    if (matchingMethodCount == 1 && matchingMethods.First().Type == ReplicableMethodInfo.MethodType.AsyncTask)
                    {
                        ReplicableMethodInfo             methodInfo          = matchingMethods.First();
                        Task <Tuple <object, object[]> > asyncInvocationTask = instance.InvokeAsync(methodInfo.Methods[0], methodParams.Item3);
                        asyncInvocationTask.Wait();
                        Task task = (Task)asyncInvocationTask.Result.Item1;
                        task.ContinueWith(processRequestContinuation);
                    }
                    else if (matchingMethodCount > 1)
                    {
                        exception = new AmbiguousMatchException(String.Format(CultureInfo.InvariantCulture, "Multiple methods with name '{0}' matching similar parameters were found", "ProcessRequestAsync"));
                    }
                    else if (typeof(IProcessHttpRequest).IsAssignableFrom(typeof(TRequestType)))
                    {
                        ((IProcessHttpRequest)instance.Instance).ProcessRequestAsync((HttpListenerContext)methodParams.Item3[0])
                        .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously);
                    }
                    else
                    {
                        ((IProcessTcpRequest)instance.Instance).ProcessRequestAsync((Stream)methodParams.Item3[0])
                        .ContinueWith(task => { processRequestContinuation(task); }, TaskContinuationOptions.ExecuteSynchronously);
                    }
                }
                else
                {
                    AppTrace.TraceMsg(TraceLogEventType.Warning, "StatefulServiceReplicaT.InvokeProcessRequestAsync", "Instance cannot be created for expired session cookie with session id '{0}'.", sessionId);
                    taskProducer.SetException(new InvalidOperationException("Instance expired. Service cannot process request"));
                }
            }
            catch (Exception e)
            {
                AppTrace.TraceException(e, "StatefulServiceReplicaT.InvokeProcessRequestAsync");
                exception = e;
            }
            finally
            {
                if (exception != null)
                {
                    taskProducer.SetException(exception);
                }
            }
        }
        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));
        }
        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);
        }
        protected internal sealed override ReplicationOperation PrepareReplicationOperation(StatefulServiceExecutionContext executionContext, ReplicationOperationType type, IEnumerable <Replicable> replicables, IDictionary <string, string> operationMetadata)
        {
            if (this.IsDisposed)
            {
                AppTrace.TraceMsg(TraceLogEventType.Information, "StatefulServiceReplicaT.PrepareReplicationOperation", "PrepareReplicationOperation called after service was disposed");
                return(null);
            }

            ReplicationOperation replicationOperation = null;

            if (type == ReplicationOperationType.Replicate)
            {
                StatefulProgramInstance instance = this.instanceManager.GetInstance(StatefulProgramInstance.CurrentInstanceId);
                if (instance == null)
                {
                    AppTrace.TraceMsg(TraceLogEventType.Error, "StatefulServiceReplicaT.PrepareReplicationOperation", "Could not find StatefulProgramInstance with id '{0}'", StatefulProgramInstance.CurrentInstanceId);
                    throw new InvalidOperationException("Replication needs to be triggered in context of a program instance.");
                }

                IEnumerable <Replicable> attributedReplicables = instance.CollectAttributedReplicableMembers(replicables);
                if (attributedReplicables != null)
                {
                    replicables = Enumerable.Concat(replicables, attributedReplicables);
                }

                instance.SetContextInstanceId(replicables);

                IEnumerable <Replicable> invalidReplicables;
                if (!instance.ValidateReplicablesMapToTypeMembers(replicables, out invalidReplicables))
                {
                    string        missingReplicables = StatefulProgramInstance.GetReplicablesString(invalidReplicables);
                    StringBuilder error = new StringBuilder();
                    error.AppendFormat("Replication cannot be triggered as following members were not found in instance of type '{0}'.", instance.TypeInfo.ReplicableType.FullName);
                    error.AppendLine(missingReplicables.ToString());
                    AppTrace.TraceMsg(TraceLogEventType.Information, "StatefulServiceReplicaT.PrepareReplicationOperation", error.ToString());
                    throw new InvalidOperationException(error.ToString());
                }

                // TODO: When we make Replicable name to be IComparable, we can remove the ToString call from here.
                replicationOperation = new ReplicationOperation(
                    type,
                    new List <Replicable>()
                {
                    new Replicable <StatefulProgramInstance>(instance.Id.ToString(), new StatefulProgramInstance(this, instance.Id, instance.TypeInfo.ReplicableType, instance.InitializationParams, replicables, instance.Singleton))
                },
                    operationMetadata);
            }
            else if (type == ReplicationOperationType.Copy)
            {
                ItemCollection <IComparable, StatefulProgramInstance> instances;
                using (this.instanceManager.GetInstances(LockPermission.Read, out instances))
                {
                    List <Replicable <StatefulProgramInstance> > replicablesToCopy = new List <Replicable <StatefulProgramInstance> >();
                    foreach (StatefulProgramInstance instance in instances)
                    {
                        // TODO: When we make Replicable name to be IComparable, we can remove the ToString call from here.
                        replicablesToCopy.Add(new Replicable <StatefulProgramInstance>(instance.Id.ToString(), instance));
                    }

                    replicationOperation = new ReplicationOperation(
                        type,
                        replicablesToCopy,
                        operationMetadata);
                }
            }

            if (replicationOperation == null)
            {
                replicationOperation = new ReplicationOperation(type, replicables, operationMetadata);
            }

            return(replicationOperation);
        }