private static GlobalSingleInstanceResponseOutcome?GetOutcome(ICollection <RemoteClusterActivationResponse> responses, GrainId grainId, ILogger 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 occurred. 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); }
private RemoteClusterActivationResponse ProcessRequestLocal(GrainId grain, string requestClusterId) { RemoteClusterActivationResponse response; //This function will be called only on the Owner silo. try { ActivationAddress address; int version; GrainDirectoryEntryStatus existingActivationStatus = router.DirectoryPartition.TryGetActivation(grain, out address, out version); //Return appropriate protocol response, given current mc status switch (existingActivationStatus) { case GrainDirectoryEntryStatus.Invalid: response = RemoteClusterActivationResponse.Pass; break; case GrainDirectoryEntryStatus.Owned: response = new RemoteClusterActivationResponse(ActivationResponseStatus.Failed) { ExistingActivationAddress = new AddressAndTag() { Address = address, VersionTag = version }, ClusterId = clusterId, Owned = true }; break; case GrainDirectoryEntryStatus.Cached: case GrainDirectoryEntryStatus.RaceLoser: response = RemoteClusterActivationResponse.Pass; break; case GrainDirectoryEntryStatus.RequestedOwnership: case GrainDirectoryEntryStatus.Doubtful: var iWin = MultiClusterUtils.ActivationPrecedenceFunc(grain, clusterId, requestClusterId); if (iWin) { response = new RemoteClusterActivationResponse(ActivationResponseStatus.Failed) { ExistingActivationAddress = new AddressAndTag() { Address = address, VersionTag = version }, ClusterId = clusterId, Owned = false }; } else { response = RemoteClusterActivationResponse.Pass; //update own activation status to race loser. if (existingActivationStatus == GrainDirectoryEntryStatus.RequestedOwnership) { logger.Trace("GSIP:Rsp {0} Origin={1} RaceLoser", grain.ToString(), requestClusterId); var success = router.DirectoryPartition.UpdateClusterRegistrationStatus(grain, address.Activation, GrainDirectoryEntryStatus.RaceLoser, GrainDirectoryEntryStatus.RequestedOwnership); if (!success) { // there was a race. retry. logger.Trace("GSIP:Rsp {0} Origin={1} Retry", grain.ToString(), requestClusterId); return(ProcessRequestLocal(grain, requestClusterId)); } } } break; default: throw new InvalidOperationException("Invalid MultiClusterStatus value"); } } catch (Exception ex) { //LOG exception response = new RemoteClusterActivationResponse(ActivationResponseStatus.Faulted) { ResponseException = ex }; } if (logger.IsEnabled(LogLevel.Debug)) { logger.Debug("GSIP:Rsp {0} Origin={1} Result={2}", grain.ToString(), requestClusterId, response); } return(response); }