/// <summary>
        /// Called by MultiClusterOracle when there is a configuration change.
        /// </summary>
        /// <returns></returns>
        public async Task OnMultiClusterConfigurationChange(MultiCluster.MultiClusterConfiguration newConfig)
        {
            Debug.Assert(newConfig != null);

            var oldConfig = Configuration;

            // process only if newer than what we already have
            if (!MultiClusterConfiguration.OlderThan(oldConfig, newConfig))
            {
                return;
            }

            Services.Log(LogLevel.Debug, "Processing Configuration {0}", newConfig);

            await this.OnConfigurationChange(newConfig); // updates Configuration and does any work required

            var added = oldConfig == null ? newConfig.Clusters : newConfig.Clusters.Except(oldConfig.Clusters);

            // if the multi-cluster is operated correctly, this grain should not be active before we are joined to the multicluster
            // but if we detect that anyway here, enforce a refresh to reduce risk of missed notifications
            if (!needInitialRead && added.Contains(Services.MyClusterId))
            {
                needRefresh = true;
                Services.Log(LogLevel.Debug, "Refresh Because of Join");
                worker.Notify();
            }

            if (notificationTracker != null)
            {
                var remoteInstances = Services.RegistrationStrategy.GetRemoteInstances(newConfig.Clusters, Services.MyClusterId).ToList();
                notificationTracker.UpdateNotificationTargets(remoteInstances);
            }
        }
Пример #2
0
        public async Task <MultiClusterConfiguration> InjectMultiClusterConfiguration(IEnumerable <string> clusters, string comment = "", bool checkForLaggingSilosFirst = true)
        {
            var multiClusterOracle = GetMultiClusterOracle();

            var configuration = new MultiClusterConfiguration(DateTime.UtcNow, clusters.ToList(), comment);

            if (!MultiClusterConfiguration.OlderThan(multiClusterOracle.GetMultiClusterConfiguration(), configuration))
            {
                throw new OrleansException("Could not inject multi-cluster configuration: current configuration is newer than clock");
            }

            if (checkForLaggingSilosFirst)
            {
                try
                {
                    var laggingSilos = await multiClusterOracle.FindLaggingSilos(multiClusterOracle.GetMultiClusterConfiguration());

                    if (laggingSilos.Count > 0)
                    {
                        var msg = string.Format("Found unstable silos {0}", string.Join(",", laggingSilos));
                        throw new OrleansException(msg);
                    }
                }
                catch (Exception e)
                {
                    throw new OrleansException("Could not inject multi-cluster configuration: stability check failed", e);
                }
            }

            await multiClusterOracle.InjectMultiClusterConfiguration(configuration);

            return(configuration);
        }
Пример #3
0
        /// <summary>
        ///  incorporate source, producing new result, and report delta.
        ///  Ignores expired entries in source, and removes expired entries from this.
        /// </summary>
        /// <param name="source">The source data to apply to the data in this object</param>
        /// <param name="delta">A delta of what changes were actually applied, used for change listeners</param>
        /// <returns>The updated data</returns>
        public MultiClusterData Merge(MultiClusterData source, out MultiClusterData delta)
        {
            //--  configuration
            var sourceConf = source.Configuration;
            var thisConf   = this.Configuration;
            MultiClusterConfiguration resultConf;
            MultiClusterConfiguration deltaConf = null;

            if (MultiClusterConfiguration.OlderThan(thisConf, sourceConf))
            {
                resultConf = sourceConf;
                deltaConf  = sourceConf;
            }
            else
            {
                resultConf = thisConf;
            }

            //--  gateways
            var sourceList = source.Gateways;
            var thisList   = this.Gateways;
            var resultList = new Dictionary <SiloAddress, GatewayEntry>();
            var deltaList  = new Dictionary <SiloAddress, GatewayEntry>();

            foreach (var key in sourceList.Keys.Union(thisList.Keys).Distinct())
            {
                GatewayEntry thisEntry;
                GatewayEntry sourceEntry;
                thisList.TryGetValue(key, out thisEntry);
                sourceList.TryGetValue(key, out sourceEntry);

                if (sourceEntry != null && !sourceEntry.Expired &&
                    (thisEntry == null || thisEntry.HeartbeatTimestamp < sourceEntry.HeartbeatTimestamp))
                {
                    resultList.Add(key, sourceEntry);
                    deltaList.Add(key, sourceEntry);
                }
                else if (thisEntry != null)
                {
                    if (!thisEntry.Expired)
                    {
                        resultList.Add(key, thisEntry);
                    }
                    else
                    {
                        deltaList.Add(key, thisEntry);
                    }
                }
            }

            delta = new MultiClusterData(deltaList, deltaConf);
            return(new MultiClusterData(resultList, resultConf));
        }