From 15d0b5ac028de1cd233af7bc09953c8b1df87891 Mon Sep 17 00:00:00 2001 From: ShiboSoftwareDev Date: Tue, 14 Jul 2026 12:16:09 +0200 Subject: [PATCH] Prevent selective rerip route starvation --- ...selective-rerip-tiny-hyper-graph-solver.ts | 28 +++++++++++++------ ...tive-rerip-tiny-hyper-graph-solver.test.ts | 15 +++++++++- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/selective-rerip-tiny-hyper-graph-solver.ts b/lib/selective-rerip-tiny-hyper-graph-solver.ts index e25e62c..64a7f2c 100644 --- a/lib/selective-rerip-tiny-hyper-graph-solver.ts +++ b/lib/selective-rerip-tiny-hyper-graph-solver.ts @@ -125,6 +125,22 @@ export function selectOwnerRouteIdsToRip(params: { return rippedRouteIds } +export function orderRoutesAfterSelectiveRerip(params: { + failedRouteId: RouteId + pendingRouteIds: readonly RouteId[] + rippedRouteIds: ReadonlySet +}): RouteId[] { + const pendingRouteIds = params.pendingRouteIds.filter( + (routeId) => + routeId !== params.failedRouteId && !params.rippedRouteIds.has(routeId), + ) + const rippedRouteIds = [...params.rippedRouteIds].filter( + (routeId) => routeId !== params.failedRouteId, + ) + + return [params.failedRouteId, ...pendingRouteIds, ...rippedRouteIds] +} + /** * Keeps the normal tiny-hypergraph route acceptance policy while replacing a * full rerip with a minimal, explicit rerip when the exhausted route has a @@ -245,10 +261,6 @@ export class SelectiveReripTinyHyperGraphSolver extends DistanceAwareTinyHyperGr const alternateOnlyOwnerRouteIds = (alternateOwnerRouteIds ?? []).filter( (ownerRouteId) => !directPath.owners.has(ownerRouteId), ) - const remainingRouteIds = this.state.unroutedRoutes.filter( - (routeId) => routeId !== failedRouteId && !rippedRouteIds.has(routeId), - ) - if ( this.selectiveReripCongestionUpdateCount < MAX_SELECTIVE_RERIP_CONGESTION_UPDATES @@ -260,11 +272,11 @@ export class SelectiveReripTinyHyperGraphSolver extends DistanceAwareTinyHyperGr this.state.ripCount += 1 this.state.currentRouteId = undefined this.state.currentRouteNetId = undefined - this.state.unroutedRoutes = [ + this.state.unroutedRoutes = orderRoutesAfterSelectiveRerip({ failedRouteId, - ...rippedRouteIds, - ...remainingRouteIds, - ] + pendingRouteIds: this.state.unroutedRoutes, + rippedRouteIds, + }) this.state.candidateQueue.clear() this.resetCandidateBestCosts() this.state.goalPortId = -1 diff --git a/tests/selective-rerip-tiny-hyper-graph-solver.test.ts b/tests/selective-rerip-tiny-hyper-graph-solver.test.ts index e62d21d..86cf46d 100644 --- a/tests/selective-rerip-tiny-hyper-graph-solver.test.ts +++ b/tests/selective-rerip-tiny-hyper-graph-solver.test.ts @@ -1,5 +1,8 @@ import { expect, test } from "bun:test" -import { selectOwnerRouteIdsToRip } from "lib/selective-rerip-tiny-hyper-graph-solver" +import { + orderRoutesAfterSelectiveRerip, + selectOwnerRouteIdsToRip, +} from "lib/selective-rerip-tiny-hyper-graph-solver" test("selects alternate owners and rejects a failed route as its only blocker", () => { expect([ @@ -19,3 +22,13 @@ test("selects alternate owners and rejects a failed route as its only blocker", "SelectiveReripTinyHyperGraphSolver: route 1 has blocker resources but no distinct committed owner can be reripped", ) }) + +test("keeps pending routes ahead of newly ripped routes", () => { + expect( + orderRoutesAfterSelectiveRerip({ + failedRouteId: 7, + pendingRouteIds: [3, 4, 8, 7, 9], + rippedRouteIds: new Set([4, 2, 7]), + }), + ).toEqual([7, 3, 8, 9, 4, 2]) +})