Exemplo n.º 1
0
        /// <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));
        }
Exemplo n.º 2
0
 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
         });
     }
 }
Exemplo n.º 3
0
 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
         });
     }
 }
Exemplo n.º 4
0
        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);
        }