Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/derive/rackLayout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ describe('three-rack', () => {
expect([left.usedU, mid.usedU, right.usedU]).toEqual([15, 15, 15])
})

it('spreads a storage group across the racks even when workers fill them unevenly', () => {
const plan = createEmptyPlan()
const rack = plan.partitions[0].racks[0]
rack.kind = 'three-rack'
// 13 worker chassis x 3U pack to 15/15/12U; without the per-group spread
// the emptiest rack would then take two of the three 2U storage systems.
rack.servers[0].count = 13 * 8
rack.servers.push({
id: 'storage',
role: 'storage',
modelId: 'server-superserver-tn12',
count: 3,
uplink: '2x25G',
})
const layout = deriveRackLayout(plan)[0]
for (const physical of layout.racks.slice(1)) {
expect(physical.slots.filter((s) => s.kind === 'storage')).toHaveLength(1)
}
})

it('flags overflow when the three racks are full', () => {
const plan = createEmptyPlan()
const rack = plan.partitions[0].racks[0]
Expand Down
15 changes: 11 additions & 4 deletions src/derive/rackLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ interface Item {
/** One physical rack of a plan rack: a single rack has one (no position);
* a three-rack has left/mid/right, with the switches in the middle and
* chassis distributed evenly by used height (each chassis goes to the
* physical rack with the fewest used units; ties favor mid, then left,
* then right). A chassis that fits nowhere lands in the least-used rack,
* where the height check flags it. */
* physical rack holding the fewest chassis of its group, the least-used
* one among those; ties favor mid, then left, then right). Spreading each
* group first keeps e.g. storage systems across the racks even when the
* worker chassis fill them unevenly. A chassis that fits nowhere lands in
* the chosen rack, where the height check flags it. */
export interface PhysicalRack {
position?: RackPosition
name: string
Expand Down Expand Up @@ -109,8 +111,13 @@ export function physicalRacks(rack: Rack, fabric: FabricConfig): PhysicalRack[]
const mid = { items: [] as Item[], used: switches.reduce((u, i) => u + i.units, 0) }
const left = { items: [] as Item[], used: 0 }
const right = { items: [] as Item[], used: 0 }
const chassisOfGroup = (bin: { items: Item[] }, groupId?: string) =>
bin.items.filter((item) => item.groupId === groupId).length
for (const c of chassis) {
const target = [mid, left, right].reduce((best, r) => (r.used < best.used ? r : best))
const target = [mid, left, right].reduce((best, r) => {
const spread = chassisOfGroup(r, c.groupId) - chassisOfGroup(best, c.groupId)
return spread < 0 || (spread === 0 && r.used < best.used) ? r : best
})
target.items.push(c)
target.used += c.units
}
Expand Down
Loading