/// <summary> /// Registers a new activation, in single activation mode, with the directory service. /// If there is already an activation registered for this grain, then the new activation will /// not be registered and the address of the existing activation will be returned. /// Otherwise, the passed-in address will be returned. /// <para>This method must be called from a scheduler thread.</para> /// </summary> /// <param name="address">The address of the potential new activation.</param> /// <param name="retries"></param> /// <returns>The address registered for the grain's single activation.</returns> public async Task <Tuple <ActivationAddress, int> > RegisterSingleActivation(ActivationAddress address, int retries) { router.RegistrationsSingleActRemoteReceived.Increment(); if (logger.IsVerbose2) { logger.Verbose2("Trying to register activation for grain. GrainId: {0}. ActivationId: {1}.", address.Grain, address.Activation); } // validate that this grain should be stored in our partition SiloAddress owner = router.CalculateTargetSilo(address.Grain); if (owner == null) { // We don't know about any other silos, and we're stopping, so throw throw new InvalidOperationException("Grain directory is stopping"); } if (router.MyAddress.Equals(owner)) { router.RegistrationsSingleActLocal.Increment(); return(partition.AddSingleActivation(address.Grain, address.Activation, address.Silo)); } if (retries <= 0) { throw new OrleansException("Silo " + router.MyAddress + " is not the owner of the grain " + address.Grain + " Owner=" + owner); } if (logger.IsVerbose2) { logger.Verbose2("Retry {0} RemoteGrainDirectory.RegisterSingleActivation for address={1} at Owner={2}", retries, address, owner); } PrepareForRetry(retries); await Task.Delay(RETRY_DELAY); SiloAddress o = router.CalculateTargetSilo(address.Grain); if (o == null) { // We don't know about any other silos, and we're stopping, so throw throw new InvalidOperationException("Grain directory is stopping"); } if (o.Equals(router.MyAddress)) { router.RegistrationsSingleActLocal.Increment(); return(partition.AddSingleActivation(address.Grain, address.Activation, address.Silo)); } router.RegistrationsSingleActRemoteSent.Increment(); return(await GetDirectoryReference(o).RegisterSingleActivation(address, retries - 1)); }
public AddressAndTag Register(ActivationAddress address, bool singleActivation) { if (singleActivation) { var result = directoryPartition.AddSingleActivation(address.Grain, address.Activation, address.Silo, GrainDirectoryEntryStatus.ClusterLocal); return(result); } else { var tag = directoryPartition.AddActivation(address.Grain, address.Activation, address.Silo); return(new AddressAndTag() { Address = address, VersionTag = tag }); } }
public virtual AddressAndTag Register(ActivationAddress address, bool singleActivation) { if (singleActivation) { var result = DirectoryPartition.AddSingleActivation(address.Grain, address.Activation, address.Silo); return(result); } else { var tag = DirectoryPartition.AddActivation(address.Grain, address.Activation, address.Silo); return(new AddressAndTag() { Address = address, VersionTag = tag }); } }
public async Task <AddressAndTag> RegisterAsync(ActivationAddress address, bool singleActivation) { if (!singleActivation) { throw new OrleansException("global single instance protocol is incompatible with using multiple activations"); } var myClusterId = Silo.CurrentSilo.ClusterId; if (myClusterId == null) { // no multicluster network. Go to owned state directly. return(directoryPartition.AddSingleActivation(address.Grain, address.Activation, address.Silo, GrainDirectoryEntryStatus.Owned)); } // examine the multicluster configuration var config = Silo.CurrentSilo.LocalMultiClusterOracle.GetMultiClusterConfiguration(); if (config == null || !config.Clusters.Contains(myClusterId)) { // we are not joined to the cluster yet/anymore. Go to doubtful state directly. gsiActivationMaintainer.TrackDoubtfulGrain(address.Grain); return(directoryPartition.AddSingleActivation(address.Grain, address.Activation, address.Silo, GrainDirectoryEntryStatus.Doubtful)); } var remoteClusters = config.Clusters.Where(id => id != myClusterId).ToList(); // Try to go into REQUESTED_OWNERSHIP state var myActivation = directoryPartition.AddSingleActivation(address.Grain, address.Activation, address.Silo, GrainDirectoryEntryStatus.RequestedOwnership); if (!myActivation.Address.Equals(address)) { //This implies that the registration already existed in some state? return the existing activation. return(myActivation); } // Do request rounds until successful or we run out of retries int retries = numRetries; while (retries-- > 0) { if (logger.IsVerbose) { logger.Verbose("GSIP:Req {0} Round={1} Act={2}", address.Grain.ToString(), numRetries - retries, myActivation.Address.ToString()); } var outcome = await SendRequestRound(address, remoteClusters); if (logger.IsVerbose) { logger.Verbose("GSIP:End {0} Round={1} Outcome={2}", address.Grain.ToString(), numRetries - retries, outcome); } switch (outcome.State) { case OutcomeState.RemoteOwner: case OutcomeState.RemoteOwnerLikely: { directoryPartition.CacheOrUpdateRemoteClusterRegistration(address.Grain, address.Activation, outcome.RemoteOwnerAddress.Address); return(outcome.RemoteOwnerAddress); } case OutcomeState.Succeed: { if (directoryPartition.UpdateClusterRegistrationStatus(address.Grain, address.Activation, GrainDirectoryEntryStatus.Owned, GrainDirectoryEntryStatus.RequestedOwnership)) { return(myActivation); } else { break; // concurrently moved to RACE_LOSER } } case OutcomeState.Inconclusive: { break; } } // we were not successful, reread state to determine what is going on int version; var mcstatus = directoryPartition.TryGetActivation(address.Grain, out address, out version); if (mcstatus == GrainDirectoryEntryStatus.RequestedOwnership) { // we failed because of inconclusive answers. Stay in this state for retry. } else if (mcstatus == GrainDirectoryEntryStatus.RaceLoser) { // we failed because an external request moved us to RACE_LOSER. Go back to REQUESTED_OWNERSHIP for retry var success = directoryPartition.UpdateClusterRegistrationStatus(address.Grain, address.Activation, GrainDirectoryEntryStatus.RequestedOwnership, GrainDirectoryEntryStatus.RaceLoser); if (!success) { ProtocolError(address, "unable to transition from RACE_LOSER to REQUESTED_OWNERSHIP"); } // do not wait before retrying because there is a dominant remote request active so we can probably complete quickly } else { ProtocolError(address, "unhandled protocol state"); } } // we are done with the quick retries. Now we go into doubtful state, which means slower retries. var ok = directoryPartition.UpdateClusterRegistrationStatus(address.Grain, address.Activation, GrainDirectoryEntryStatus.Doubtful, GrainDirectoryEntryStatus.RequestedOwnership); if (!ok) { ProtocolError(address, "unable to transition into doubtful"); } this.gsiActivationMaintainer.TrackDoubtfulGrain(address.Grain); return(myActivation); }