@@ -68,6 +68,22 @@ func (ssn *Session) AddJobOrderFn(jof common_info.CompareFn) {
6868 ssn .JobOrderFns = append (ssn .JobOrderFns , jof )
6969}
7070
71+ // AddVictimOrderFn registers a comparator used only to rank candidate
72+ // eviction victims, without affecting pending-job allocation order.
73+ //
74+ // The registered JobOrderFns chain is always checked first (inverted,
75+ // matching existing allocation-order semantics); comparators registered
76+ // here apply only as a tiebreak, when every JobOrderFn treats l and r as
77+ // equal. This ensures job-level protections (e.g. elastic at-min/above-min
78+ // status) take precedence over any victim-specific comparator.
79+ //
80+ // Sign convention: vof(l, r) < 0 means l should be evicted before r. This
81+ // is the direct, non-inverted sense -- unlike the JobOrderFn chain, which
82+ // VictimOrderFn inverts internally when using it for the eviction path.
83+ func (ssn * Session ) AddVictimOrderFn (vof common_info.CompareFn ) {
84+ ssn .VictimOrderFns = append (ssn .VictimOrderFns , vof )
85+ }
86+
7187func (ssn * Session ) AddTaskOrderFn (tof common_info.CompareFn ) {
7288 ssn .TaskOrderFns = append (ssn .TaskOrderFns , tof )
7389}
@@ -268,21 +284,42 @@ func (ssn *Session) QueueAllocatedResources(queue *queue_info.QueueInfo) *resour
268284 return nil
269285}
270286
287+ func jobOrderCreationFallback (l , r interface {}) bool {
288+ lv := l .(* podgroup_info.PodGroupInfo )
289+ rv := r .(* podgroup_info.PodGroupInfo )
290+ if lv .CreationTimestamp .Equal (& rv .CreationTimestamp ) {
291+ return lv .UID < rv .UID
292+ }
293+ return lv .CreationTimestamp .Before (& rv .CreationTimestamp )
294+ }
295+
271296func (ssn * Session ) JobOrderFn (l , r interface {}) bool {
272297 for _ , jof := range ssn .JobOrderFns {
273298 if j := jof (l , r ); j != 0 {
274299 return j < 0
275300 }
276301 }
302+ return jobOrderCreationFallback (l , r )
303+ }
277304
278- // If no job order funcs, order job by CreationTimestamp first, then by UID.
279- lv := l .(* podgroup_info.PodGroupInfo )
280- rv := r .(* podgroup_info.PodGroupInfo )
281- if lv .CreationTimestamp .Equal (& rv .CreationTimestamp ) {
282- return lv .UID < rv .UID
283- } else {
284- return lv .CreationTimestamp .Before (& rv .CreationTimestamp )
305+ // VictimOrderFn reports whether l should be evicted before r.
306+ //
307+ // The JobOrderFns chain is consulted first, inverted; VictimOrderFns
308+ // registered via AddVictimOrderFn apply only when every JobOrderFn treats
309+ // l and r as equal. With no VictimOrderFns registered, this reduces to
310+ // the original !JobOrderFn(l, r) behavior.
311+ func (ssn * Session ) VictimOrderFn (l , r interface {}) bool {
312+ for _ , jof := range ssn .JobOrderFns {
313+ if j := jof (l , r ); j != 0 {
314+ return j > 0
315+ }
316+ }
317+ for _ , vof := range ssn .VictimOrderFns {
318+ if v := vof (l , r ); v != 0 {
319+ return v < 0
320+ }
285321 }
322+ return ! jobOrderCreationFallback (l , r )
286323}
287324
288325func (ssn * Session ) TaskOrderFn (l , r interface {}) bool {
0 commit comments