public GlobalSingleInstanceResponseOutcome(OutcomeState state, AddressAndTag remoteOwnerAddress, string remoteOwnerCluster)
 {
     this.State = state;
     this.RemoteOwnerAddress = remoteOwnerAddress;
     this.RemoteOwnerCluster = remoteOwnerCluster;
 }
        /// <summary>
        /// Adds a new activation to the directory partition
        /// </summary>
        /// <param name="grain"></param>
        /// <param name="activation"></param>
        /// <param name="silo"></param>
        /// <param name="registrationStatus"></param>
        /// <returns>The registered ActivationAddress and version associated with this directory mapping</returns>
        internal virtual AddressAndTag AddSingleActivation(GrainId grain, ActivationId activation, SiloAddress silo, GrainDirectoryEntryStatus registrationStatus)
        {
            if (log.IsVerbose3) log.Verbose3("Adding single activation for grain {0}{1}{2}", silo, grain, activation);

            AddressAndTag result = new AddressAndTag();

            if (!IsValidSilo(silo))
                return result;
            
            lock (lockable)
            {
                if (!partitionData.ContainsKey(grain))
                {
                    partitionData[grain] = new GrainInfo();
                }
                var grainInfo = partitionData[grain];
                result.Address = grainInfo.AddSingleActivation(grain, activation, silo, registrationStatus);
                result.VersionTag = grainInfo.VersionTag;
            }
            return result;
        }
        private static GlobalSingleInstanceResponseOutcome? GetOutcome(ICollection<RemoteClusterActivationResponse> responses, GrainId grainId, Logger logger, bool hasPendingResponses)
        {
            if (!hasPendingResponses && responses.All(res => res.ResponseStatus == ActivationResponseStatus.Pass))
            {
                // All passed, or no other clusters exist
                return GlobalSingleInstanceResponseOutcome.Succeed;
            }

            var ownerResponses = responses
                .Where(res => res.ResponseStatus == ActivationResponseStatus.Failed && res.Owned == true).ToList();

            if (ownerResponses.Count > 0)
            {
                if (ownerResponses.Count > 1)
                    logger.Warn((int)ErrorCode.GlobalSingleInstance_MultipleOwners, "GSIP:Req {0} Unexpected error occured. Multiple Owner Replies.", grainId);

                return new GlobalSingleInstanceResponseOutcome(OutcomeState.RemoteOwner, ownerResponses[0].ExistingActivationAddress, ownerResponses[0].ClusterId);
            }

            // are all responses here or have failed?
            if (!hasPendingResponses)
            {
                // determine best candidate
                var candidates = responses
                    .Where(res => res.ResponseStatus == ActivationResponseStatus.Failed && res.ExistingActivationAddress.Address != null)
                    .ToList();

                AddressAndTag remoteOwner = new AddressAndTag();
                string remoteOwnerCluster = null;
                foreach (var res in candidates)
                {
                    if (remoteOwner.Address == null ||
                        MultiClusterUtils.ActivationPrecedenceFunc(grainId, res.ClusterId, remoteOwnerCluster))
                    {
                        remoteOwner = res.ExistingActivationAddress;
                        remoteOwnerCluster = res.ClusterId;
                    }
                }

                var outcome = remoteOwner.Address != null ? OutcomeState.RemoteOwnerLikely : OutcomeState.Inconclusive;
                return new GlobalSingleInstanceResponseOutcome(outcome, remoteOwner, remoteOwnerCluster);
            }

            return null;
        }