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);
}
}
}