86 lines
3.3 KiB
Java
86 lines
3.3 KiB
Java
package dev.ltms.bridged.placement;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Shared filtering and empty-set reporting used by the built-in placement policies.
|
|
*/
|
|
final class PlacementPolicyUtil {
|
|
|
|
private PlacementPolicyUtil() {
|
|
}
|
|
|
|
/**
|
|
* Candidates that are not weight-excluded (CB-554: explicit {@code weight <= 0}, checked
|
|
* first because it is a static config choice rather than transient state), not
|
|
* known-unreachable, not quarantined (CB-578 stage B), and have not reached their maxLoad.
|
|
* A {@code null} maxLoad means unlimited.
|
|
*/
|
|
static List<PlacementCandidate> available(PlacementContext ctx) {
|
|
List<PlacementCandidate> out = new ArrayList<>();
|
|
for (PlacementCandidate c : ctx.candidates()) {
|
|
if (c.excluded() || ctx.unreachable().contains(c.profile())
|
|
|| ctx.quarantined().contains(c.profile())) {
|
|
continue;
|
|
}
|
|
Integer cap = c.maxLoad();
|
|
if (cap != null) {
|
|
int live = ctx.liveCount().apply(c.profile());
|
|
if (live >= cap) {
|
|
continue;
|
|
}
|
|
}
|
|
out.add(c);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Build a clear exception describing why every candidate was dropped: all weight-0, all
|
|
* quarantined, all at capacity, all unreachable, or a mix. Each candidate is counted into
|
|
* exactly one bucket (weight-excluded takes priority) so a candidate excluded for more than
|
|
* one reason is never double-counted.
|
|
*/
|
|
static PlacementException emptyException(PlacementContext ctx) {
|
|
int weightExcluded = 0;
|
|
int atCap = 0;
|
|
int unreachable = 0;
|
|
int quarantined = 0;
|
|
for (PlacementCandidate c : ctx.candidates()) {
|
|
Integer cap = c.maxLoad();
|
|
if (c.excluded()) {
|
|
weightExcluded++;
|
|
} else if (ctx.quarantined().contains(c.profile())) {
|
|
quarantined++;
|
|
} else if (ctx.unreachable().contains(c.profile())) {
|
|
unreachable++;
|
|
} else if (cap != null && ctx.liveCount().apply(c.profile()) >= cap) {
|
|
atCap++;
|
|
}
|
|
}
|
|
|
|
int total = ctx.candidates().size();
|
|
if (total == 0) {
|
|
return new PlacementException("no worker profiles configured");
|
|
}
|
|
if (weightExcluded == total) {
|
|
return new PlacementException(
|
|
"all worker profiles have weight 0 (excluded from automatic selection)");
|
|
}
|
|
if (quarantined == total) {
|
|
return new PlacementException("all worker profiles are quarantined (backend exhausted)");
|
|
}
|
|
if (atCap == total) {
|
|
return new PlacementException("all worker profiles are at maxLoad");
|
|
}
|
|
if (unreachable == total) {
|
|
return new PlacementException("all worker profiles are unreachable");
|
|
}
|
|
return new PlacementException("no worker profile available: " + atCap + " at maxLoad, "
|
|
+ unreachable + " unreachable, " + quarantined + " quarantined, "
|
|
+ weightExcluded + " weight-0, "
|
|
+ (total - atCap - unreachable - quarantined - weightExcluded) + " remaining");
|
|
}
|
|
}
|