示例#1
0
 public ActivationAddress AddSingleActivation(GrainId grain, ActivationId act, SiloAddress silo)
 {
     SingleInstance = true;
     if (Instances.Count > 0)
     {
         var item = Instances.First();
         return(ActivationAddress.GetAddress(item.Value.SiloAddress, grain, item.Key));
     }
     else
     {
         Instances.Add(act, new ActivationInfo(silo));
         VersionTag = rand.Next();
         return(ActivationAddress.GetAddress(silo, grain, act));
     }
 }
        public Dictionary <SiloAddress, List <ActivationAddress> > Merge(GrainId grain, IGrainInfo other)
        {
            bool modified = false;

            foreach (var pair in other.Instances)
            {
                if (Instances.ContainsKey(pair.Key))
                {
                    continue;
                }

                Instances[pair.Key] = new ActivationInfo(pair.Value.SiloAddress, pair.Value.RegistrationStatus);
                modified            = true;
            }

            if (modified)
            {
                VersionTag = rand.Next();
            }

            if (SingleInstance && (Instances.Count > 0))
            {
                // Grain is supposed to be in single activation mode, but we have two activations!!
                // Eventually we should somehow delegate handling this to the silo, but for now, we'll arbitrarily pick one value.
                var orderedActivations = Instances.OrderBy(pair => pair.Key);
                var activationToKeep   = orderedActivations.First();
                var activationsToDrop  = orderedActivations.Skip(1);
                Instances.Clear();
                Instances.Add(activationToKeep.Key, activationToKeep.Value);
                var mapping = new Dictionary <SiloAddress, List <ActivationAddress> >();
                foreach (var activationPair in activationsToDrop)
                {
                    var activation = ActivationAddress.GetAddress(activationPair.Value.SiloAddress, grain, activationPair.Key);

                    List <ActivationAddress> activationsToRemoveOnSilo;
                    if (!mapping.TryGetValue(activation.Silo, out activationsToRemoveOnSilo))
                    {
                        activationsToRemoveOnSilo = mapping[activation.Silo] = new List <ActivationAddress>(1);
                    }

                    activationsToRemoveOnSilo.Add(activation);
                }

                return(mapping);
            }

            return(null);
        }
示例#3
0
        public void Serialize_ActivationAddress()
        {
            GrainId grain        = LegacyGrainId.NewId();
            var     addr         = ActivationAddress.GetAddress(null, grain, default);
            object  deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, addr, false);

            Assert.IsAssignableFrom <ActivationAddress>(deserialized);
            Assert.True(((ActivationAddress)deserialized).Activation.IsDefault); //Activation no longer null after copy
            Assert.Null(((ActivationAddress)deserialized).Silo);                 //Silo no longer null after copy
            Assert.Equal(grain, ((ActivationAddress)deserialized).Grain);        //Grain different after copy
            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, addr);
            Assert.IsAssignableFrom <ActivationAddress>(deserialized);           //ActivationAddress full serialization loop as wrong type
            Assert.True(((ActivationAddress)deserialized).Activation.IsDefault); //Activation no longer null after full serialization loop
            Assert.Null(((ActivationAddress)deserialized).Silo);                 //Silo no longer null after full serialization loop
            Assert.Equal(grain, ((ActivationAddress)deserialized).Grain);        //Grain different after copy
        }
        /// <summary> Read an <c>ActivationAddress</c> value from the stream. </summary>
        /// <returns>Data from current position in stream, converted to the appropriate output type.</returns>
        internal ActivationAddress ReadActivationAddress()
        {
            var silo  = ReadSiloAddress();
            var grain = ReadGrainId();
            var act   = ReadActivationId();

            if (silo.Equals(SiloAddress.Zero))
            {
                silo = null;
            }

            if (act.Equals(ActivationId.Zero))
            {
                act = null;
            }

            return(ActivationAddress.GetAddress(silo, grain, act));
        }
示例#5
0
        /// <summary> Read an <c>ActivationAddress</c> value from the stream. </summary>
        /// <returns>Data from current position in stream, converted to the appropriate output type.</returns>
        internal static ActivationAddress ReadActivationAddress <TReader>(this TReader @this) where TReader : IBinaryTokenStreamReader
        {
            var silo  = @this.ReadSiloAddress();
            var grain = @this.ReadGrainId();
            var act   = @this.ReadActivationId();

            if (silo.Equals(SiloAddress.Zero))
            {
                silo = null;
            }

            if (act.Equals(ActivationId.Zero))
            {
                act = null;
            }

            return(ActivationAddress.GetAddress(silo, grain, act));
        }
示例#6
0
        private PlacementResult SelectActivationCore(PlacementStrategy strategy, GrainId target, IPlacementRuntime context)
        {
            if (target.IsClient())
            {
                throw new InvalidOperationException("Cannot use StatelessWorkerStrategy to route messages to client grains.");
            }

            // If there are available (not busy with a request) activations, it returns the first one.
            // If all are busy and the number of local activations reached or exceeded MaxLocal, it randomly returns one of them.
            // Otherwise, it requests creation of a new activation.
            List <ActivationData> local;

            if (context.LocalSiloStatus.IsTerminating())
            {
                return(null);
            }

            if (!context.LocalLookup(target, out local) || local.Count == 0)
            {
                return(null);
            }

            var placement = (StatelessWorkerPlacement)strategy;

            foreach (var activation in local)
            {
                ActivationData info;
                if (!context.TryGetActivationData(activation.ActivationId, out info) ||
                    info.State != ActivationState.Valid || !info.IsInactive)
                {
                    continue;
                }

                return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, activation.ActivationId)));
            }

            if (local.Count >= placement.MaxLocal)
            {
                var id = local[local.Count == 1 ? 0 : random.Next(local.Count)].ActivationId;
                return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, id)));
            }

            return(null);
        }
示例#7
0
        private async Task RunBatchedValidation(SiloAddress silo, List <KeyValuePair <GrainId, IGrainInfo> > list)
        {
            var    multiClusterConfig = this.multiClusterOracle.GetMultiClusterConfiguration();
            string clusterId          = null;

            // If this silo is a part of a multi-cluster, try to find out which cluster the target silo belongs to.
            // The check here is a simple ping used to check if the remote silo is available and, if so, which cluster
            // it belongs to.
            // This is a used to determine whether or not the local silo should invalidate directory cache entries
            // pointing to the remote silo.
            // A preferable approach would be to flow cluster membership or grain directory information from the remote
            // cluster to the local one. That would avoid heuristic checks such as this. Additionally, information
            // about which cluster a particular silo belongs (or belonged) to could be maintained. That would allow
            // us to skip this first step.
            if (multiClusterConfig != null)
            {
                try
                {
                    var validator = this.grainFactory.GetSystemTarget <IClusterGrainDirectory>(
                        Constants.ClusterDirectoryServiceId,
                        silo);
                    clusterId = await validator.Ping();
                }
                catch (Exception exception)
                {
                    // A failure here may indicate a transient error, but for simplicity we will continue as though
                    // the remote silo is no longer a part of the multi-cluster.
                    this.logger.LogWarning("Failed to ping remote silo {Silo}: {Exception}", silo, exception);
                }
            }

            // if the silo could not be contacted or is not part of the multicluster, unregister
            if (clusterId == null || !multiClusterConfig.Clusters.Contains(clusterId))
            {
                this.logger.Debug("GSIP:M removing {Count} cache entries pointing to {Silo}", list.Count, silo);

                var registrar = this.registrarManager.GetRegistrar(GlobalSingleInstanceRegistration.Singleton);

                foreach (var kvp in list)
                {
                    registrar.InvalidateCache(ActivationAddress.GetAddress(silo, kvp.Key, kvp.Value.Instances.FirstOrDefault().Key));
                }
            }
        }
        /// <summary>
        /// Returns a list of activations (along with the version number of the list) for the given grain.
        /// If the grain is not found, null is returned.
        /// </summary>
        /// <param name="grain"></param>
        /// <returns></returns>
        internal AddressesAndTag LookUpGrain(GrainId grain)
        {
            var result = new AddressesAndTag();

            lock (lockable)
            {
                if (partitionData.ContainsKey(grain))
                {
                    result.Addresses  = new List <ActivationAddress>();
                    result.VersionTag = partitionData[grain].VersionTag;

                    foreach (var route in partitionData[grain].Instances.Where(route => IsValidSilo(route.Value.SiloAddress)))
                    {
                        result.Addresses.Add(ActivationAddress.GetAddress(route.Value.SiloAddress, grain, route.Key, route.Value.RegistrationStatus));
                    }
                }
            }
            return(result);
        }
示例#9
0
        public bool Merge(GrainId grain, IGrainInfo other)
        {
            bool modified = false;

            foreach (var pair in other.Instances)
            {
                if (Instances.ContainsKey(pair.Key))
                {
                    continue;
                }

                Instances[pair.Key] = new ActivationInfo(pair.Value.SiloAddress);
                modified            = true;
            }

            if (modified)
            {
                VersionTag = rand.Next();
            }

            if (SingleInstance && (Instances.Count > 0))
            {
                // Grain is supposed to be in single activation mode, but we have two activations!!
                // Eventually we should somehow delegate handling this to the silo, but for now, we'll arbitrarily pick one value.
                var orderedActivations = Instances.OrderBy(pair => pair.Key);
                var activationToKeep   = orderedActivations.First();
                var activationsToDrop  = orderedActivations.Skip(1);
                Instances.Clear();
                Instances.Add(activationToKeep.Key, activationToKeep.Value);
                var list = new List <ActivationAddress>(1);
                foreach (var activation in activationsToDrop.Select(keyValuePair => ActivationAddress.GetAddress(keyValuePair.Value.SiloAddress, grain, keyValuePair.Key)))
                {
                    list.Add(activation);
                    CatalogFactory.GetSystemTarget(Constants.CatalogId, activation.Silo).
                    DeleteActivations(list).Ignore();

                    list.Clear();
                }
                return(true);
            }
            return(false);
        }
示例#10
0
        public bool TryLocalLookup(GrainId grainId, out List <ActivationAddress> addresses)
        {
            if (grainId.IsClient)
            {
                return(this.inClusterGrainLocator.TryLocalLookup(grainId, out addresses));
            }

            if (this.cache.LookUp(grainId, out var results))
            {
                // IGrainDirectory only supports single activation
                var result = results[0];
                addresses = new List <ActivationAddress>()
                {
                    ActivationAddress.GetAddress(result.Item1, grainId, result.Item2)
                };
                return(true);
            }

            addresses = null;
            return(false);
        }
示例#11
0
        /// <summary>
        /// Returns the activation of a single-activation grain, if present.
        /// </summary>
        internal GrainDirectoryEntryStatus TryGetActivation(GrainId grain, out ActivationAddress address, out int version)
        {
            lock (lockable)
            {
                IGrainInfo graininfo;
                if (partitionData.TryGetValue(grain, out graininfo))
                {
                    var first = graininfo.Instances.FirstOrDefault();

                    if (first.Value != null)
                    {
                        address = ActivationAddress.GetAddress(first.Value.SiloAddress, grain, first.Key);
                        version = graininfo.VersionTag;
                        return(first.Value.RegistrationStatus);
                    }
                }
            }
            address = null;
            version = 0;
            return(GrainDirectoryEntryStatus.Invalid);
        }
        private void HandleMessage(Message message)
        {
            // when we receive the first message, we update the
            // clientId for this client because it may have been modified to
            // include the cluster name
            if (!firstMessageReceived)
            {
                firstMessageReceived = true;
                if (!handshakeClientId.Equals(message.TargetGrain))
                {
                    clientId = message.TargetGrain;
                    transport.UpdateClientId(clientId);
                    CurrentActivationAddress = ActivationAddress.GetAddress(transport.MyAddress, clientId, CurrentActivationAddress.Activation);
                }
                else
                {
                    clientId = handshakeClientId;
                }
            }

            switch (message.Direction)
            {
            case Message.Directions.Response:
            {
                ReceiveResponse(message);
                break;
            }

            case Message.Directions.OneWay:
            case Message.Directions.Request:
            {
                this.localObjects.Dispatch(message);
                break;
            }

            default:
                logger.Error(ErrorCode.Runtime_Error_100327, $"Message not supported: {message}.");
                break;
            }
        }
示例#13
0
        /// <summary>
        /// Returns a list of activations (along with the version number of the list) for the given grain.
        /// If the grain is not found, null is returned.
        /// </summary>
        /// <param name="grain"></param>
        /// <returns></returns>
        internal AddressesAndTag LookUpActivations(GrainId grain)
        {
            var result = new AddressesAndTag();

            lock (lockable)
            {
                IGrainInfo graininfo;
                if (partitionData.TryGetValue(grain, out graininfo))
                {
                    result.Addresses  = new List <ActivationAddress>();
                    result.VersionTag = partitionData[grain].VersionTag;

                    foreach (var route in partitionData[grain].Instances)
                    {
                        if (IsValidSilo(route.Value.SiloAddress))
                        {
                            result.Addresses.Add(ActivationAddress.GetAddress(route.Value.SiloAddress, grain, route.Key));
                        }
                    }
                }
            }
            return(result);
        }
示例#14
0
        internal List <ActivationAddress> ToListOfActivations(bool singleActivation)
        {
            var result = new List <ActivationAddress>();

            lock (lockable)
            {
                foreach (var pair in partitionData)
                {
                    var grain = pair.Key;
                    if (pair.Value.SingleInstance == singleActivation)
                    {
                        result.AddRange(pair.Value.Instances.Select(activationPair => ActivationAddress.GetAddress(activationPair.Value.SiloAddress, grain, activationPair.Key))
                                        .Where(addr => IsValidSilo(addr.Silo)));
                    }
                }
            }

            return(result);
        }
示例#15
0
        private void RunClientMessagePump(CancellationToken ct)
        {
            if (StatisticsCollector.CollectThreadTimeTrackingStats)
            {
                incomingMessagesThreadTimeTracking.OnStartExecution();
            }
            while (listenForMessages)
            {
                var message = transport.WaitMessage(Message.Categories.Application, ct);

                if (message == null) // if wait was cancelled
                {
                    break;
                }
#if TRACK_DETAILED_STATS
                if (StatisticsCollector.CollectThreadTimeTrackingStats)
                {
                    incomingMessagesThreadTimeTracking.OnStartProcessing();
                }
#endif

                // when we receive the first message, we update the
                // clientId for this client because it may have been modified to
                // include the cluster name
                if (!firstMessageReceived)
                {
                    firstMessageReceived = true;
                    if (!handshakeClientId.Equals(message.TargetGrain))
                    {
                        clientId = message.TargetGrain;
                        transport.UpdateClientId(clientId);
                        CurrentActivationAddress = ActivationAddress.GetAddress(transport.MyAddress, clientId, CurrentActivationAddress.Activation);
                    }
                    else
                    {
                        clientId = handshakeClientId;
                    }
                }

                switch (message.Direction)
                {
                case Message.Directions.Response:
                {
                    ReceiveResponse(message);
                    break;
                }

                case Message.Directions.OneWay:
                case Message.Directions.Request:
                {
                    this.DispatchToLocalObject(message);
                    break;
                }

                default:
                    logger.Error(ErrorCode.Runtime_Error_100327, String.Format("Message not supported: {0}.", message));
                    break;
                }
#if TRACK_DETAILED_STATS
                if (StatisticsCollector.CollectThreadTimeTrackingStats)
                {
                    incomingMessagesThreadTimeTracking.OnStopProcessing();
                    incomingMessagesThreadTimeTracking.IncrementNumberOfProcessed();
                }
#endif
            }
            if (StatisticsCollector.CollectThreadTimeTrackingStats)
            {
                incomingMessagesThreadTimeTracking.OnStopExecution();
            }
        }
示例#16
0
        public async Task <List <ActivationAddress> > FullLookup(GrainId grain)
        {
            fullLookups.Increment();

            SiloAddress silo = CalculateTargetSilo(grain, false);

            // No need to check that silo != null since we're passing excludeThisSiloIfStopping = false

            if (log.IsVerbose)
            {
                log.Verbose("Silo {0} fully lookups for {1}-->{2} ({3}-->{4})", MyAddress, grain, silo, grain.GetUniformHashCode(), silo.GetConsistentHashCode());
            }

            // We assyme that getting here means the grain was not found locally (i.e., in TryFullLookup()).
            // We still check if we own the grain locally to avoid races between the time TryFullLookup() and FullLookup() were called.
            if (silo.Equals(MyAddress))
            {
                LocalDirectoryLookups.Increment();
                var localResult = DirectoryPartition.LookUpGrain(grain);
                if (localResult == null)
                {
                    // it can happen that we cannot find the grain in our partition if there were
                    // some recent changes in the membership
                    if (log.IsVerbose2)
                    {
                        log.Verbose2("FullLookup mine {0}=none", grain);
                    }
                    return(new List <ActivationAddress>());
                }
                var a = localResult.Item1.Select(t => ActivationAddress.GetAddress(t.Item1, grain, t.Item2)).Where(addr => IsValidSilo(addr.Silo)).ToList();
                if (log.IsVerbose2)
                {
                    log.Verbose2("FullLookup mine {0}={1}", grain, a.ToStrings());
                }
                LocalDirectorySuccesses.Increment();
                return(a);
            }

            // Just a optimization. Why sending a message to someone we know is not valid.
            if (!IsValidSilo(silo))
            {
                throw new OrleansException(String.Format("Current directory at {0} is not stable to perform the lookup for grain {1} (it maps to {2}, which is not a valid silo). Retry later.", MyAddress, grain, silo));
            }

            RemoteLookupsSent.Increment();
            Tuple <List <Tuple <SiloAddress, ActivationId> >, int> result = await GetDirectoryReference(silo).LookUp(grain, NUM_RETRIES);

            // update the cache
            List <Tuple <SiloAddress, ActivationId> > entries = result.Item1.Where(t => IsValidSilo(t.Item1)).ToList();
            List <ActivationAddress> addresses = entries.Select(t => ActivationAddress.GetAddress(t.Item1, grain, t.Item2)).ToList();

            if (log.IsVerbose2)
            {
                log.Verbose2("FullLookup remote {0}={1}", grain, addresses.ToStrings());
            }

            if (entries.Count > 0)
            {
                DirectoryCache.AddOrUpdate(grain, entries, result.Item2);
            }

            return(addresses);
        }