using System.Linq; using System.Threading.Tasks; namespace Orleans.Runtime.Placement { /// /// PreferLocalPlacementDirector is a single activation placement. /// It is similar to RandomPlacementDirector except for how new activations are placed. /// When activation is requested (OnSelectActivation), it uses the same algorithm as RandomPlacementDirector to pick one if one already exists. /// That is, it checks with the Distributed Directory. /// If none exits, it prefers to place a new one in the local silo. If there are no races (only one silo at a time tries to activate this grain), /// the local silo wins. In the case of concurrent activations of the first activation of this grain, only one silo wins. /// internal class PreferLocalPlacementDirector : RandomPlacementDirector, IPlacementDirector { private Task? _cachedLocalSilo; public override Task OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context) { var compatibleSilos = context.GetCompatibleSilos(target); // If a valid placement hint was specified, use it. if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint) { return Task.FromResult(placementHint); } // if local silo is not active or does not support this type of grain, revert to random placement if (context.LocalSiloStatus != SiloStatus.Active || !compatibleSilos.Contains(context.LocalSilo)) { return base.OnAddActivation(strategy, target, context); } return _cachedLocalSilo ??= Task.FromResult(context.LocalSilo); } } }