volcano.sh/volcano@v1.9.0/pkg/scheduler/framework/session_plugins.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package framework
    18  
    19  import (
    20  	k8sframework "k8s.io/kubernetes/pkg/scheduler/framework"
    21  
    22  	"volcano.sh/apis/pkg/apis/scheduling"
    23  	"volcano.sh/volcano/pkg/controllers/job/helpers"
    24  	"volcano.sh/volcano/pkg/scheduler/api"
    25  	"volcano.sh/volcano/pkg/scheduler/util"
    26  )
    27  
    28  // AddJobOrderFn add job order function
    29  func (ssn *Session) AddJobOrderFn(name string, cf api.CompareFn) {
    30  	ssn.jobOrderFns[name] = cf
    31  }
    32  
    33  // AddQueueOrderFn add queue order function
    34  func (ssn *Session) AddQueueOrderFn(name string, qf api.CompareFn) {
    35  	ssn.queueOrderFns[name] = qf
    36  }
    37  
    38  // AddClusterOrderFn add queue order function
    39  func (ssn *Session) AddClusterOrderFn(name string, qf api.CompareFn) {
    40  	ssn.clusterOrderFns[name] = qf
    41  }
    42  
    43  // AddTaskOrderFn add task order function
    44  func (ssn *Session) AddTaskOrderFn(name string, cf api.CompareFn) {
    45  	ssn.taskOrderFns[name] = cf
    46  }
    47  
    48  // AddPreemptableFn add preemptable function
    49  func (ssn *Session) AddPreemptableFn(name string, cf api.EvictableFn) {
    50  	ssn.preemptableFns[name] = cf
    51  }
    52  
    53  // AddReclaimableFn add Reclaimable function
    54  func (ssn *Session) AddReclaimableFn(name string, rf api.EvictableFn) {
    55  	ssn.reclaimableFns[name] = rf
    56  }
    57  
    58  // AddJobReadyFn add JobReady function
    59  func (ssn *Session) AddJobReadyFn(name string, vf api.ValidateFn) {
    60  	ssn.jobReadyFns[name] = vf
    61  }
    62  
    63  // AddJobPipelinedFn add pipelined function
    64  func (ssn *Session) AddJobPipelinedFn(name string, vf api.VoteFn) {
    65  	ssn.jobPipelinedFns[name] = vf
    66  }
    67  
    68  // AddPredicateFn add Predicate function
    69  func (ssn *Session) AddPredicateFn(name string, pf api.PredicateFn) {
    70  	ssn.predicateFns[name] = pf
    71  }
    72  
    73  // AddPrePredicateFn add PrePredicate function
    74  func (ssn *Session) AddPrePredicateFn(name string, pf api.PrePredicateFn) {
    75  	ssn.prePredicateFns[name] = pf
    76  }
    77  
    78  // AddBestNodeFn add BestNode function
    79  func (ssn *Session) AddBestNodeFn(name string, pf api.BestNodeFn) {
    80  	ssn.bestNodeFns[name] = pf
    81  }
    82  
    83  // AddNodeOrderFn add Node order function
    84  func (ssn *Session) AddNodeOrderFn(name string, pf api.NodeOrderFn) {
    85  	ssn.nodeOrderFns[name] = pf
    86  }
    87  
    88  // AddBatchNodeOrderFn add Batch Node order function
    89  func (ssn *Session) AddBatchNodeOrderFn(name string, pf api.BatchNodeOrderFn) {
    90  	ssn.batchNodeOrderFns[name] = pf
    91  }
    92  
    93  // AddNodeMapFn add Node map function
    94  func (ssn *Session) AddNodeMapFn(name string, pf api.NodeMapFn) {
    95  	ssn.nodeMapFns[name] = pf
    96  }
    97  
    98  // AddNodeReduceFn add Node reduce function
    99  func (ssn *Session) AddNodeReduceFn(name string, pf api.NodeReduceFn) {
   100  	ssn.nodeReduceFns[name] = pf
   101  }
   102  
   103  // AddOverusedFn add overused function
   104  func (ssn *Session) AddOverusedFn(name string, fn api.ValidateFn) {
   105  	ssn.overusedFns[name] = fn
   106  }
   107  
   108  // AddPreemptiveFn add preemptive function
   109  func (ssn *Session) AddPreemptiveFn(name string, fn api.ValidateFn) {
   110  	ssn.preemptiveFns[name] = fn
   111  }
   112  
   113  // AddAllocatableFn add allocatable function
   114  func (ssn *Session) AddAllocatableFn(name string, fn api.AllocatableFn) {
   115  	ssn.allocatableFns[name] = fn
   116  }
   117  
   118  // AddJobValidFn add jobvalid function
   119  func (ssn *Session) AddJobValidFn(name string, fn api.ValidateExFn) {
   120  	ssn.jobValidFns[name] = fn
   121  }
   122  
   123  // AddJobEnqueueableFn add jobenqueueable function
   124  func (ssn *Session) AddJobEnqueueableFn(name string, fn api.VoteFn) {
   125  	ssn.jobEnqueueableFns[name] = fn
   126  }
   127  
   128  // AddJobEnqueuedFn add jobEnqueued function
   129  func (ssn *Session) AddJobEnqueuedFn(name string, fn api.JobEnqueuedFn) {
   130  	ssn.jobEnqueuedFns[name] = fn
   131  }
   132  
   133  // AddTargetJobFn add targetjob function
   134  func (ssn *Session) AddTargetJobFn(name string, fn api.TargetJobFn) {
   135  	ssn.targetJobFns[name] = fn
   136  }
   137  
   138  // AddReservedNodesFn add reservedNodesFn function
   139  func (ssn *Session) AddReservedNodesFn(name string, fn api.ReservedNodesFn) {
   140  	ssn.reservedNodesFns[name] = fn
   141  }
   142  
   143  // AddVictimTasksFns add victimTasksFns function
   144  func (ssn *Session) AddVictimTasksFns(name string, fns []api.VictimTasksFn) {
   145  	ssn.victimTasksFns[name] = fns
   146  }
   147  
   148  // AddJobStarvingFns add jobStarvingFns function
   149  func (ssn *Session) AddJobStarvingFns(name string, fn api.ValidateFn) {
   150  	ssn.jobStarvingFns[name] = fn
   151  }
   152  
   153  // Reclaimable invoke reclaimable function of the plugins
   154  func (ssn *Session) Reclaimable(reclaimer *api.TaskInfo, reclaimees []*api.TaskInfo) []*api.TaskInfo {
   155  	var victims []*api.TaskInfo
   156  	var init bool
   157  
   158  	for _, tier := range ssn.Tiers {
   159  		for _, plugin := range tier.Plugins {
   160  			if !isEnabled(plugin.EnabledReclaimable) {
   161  				continue
   162  			}
   163  			rf, found := ssn.reclaimableFns[plugin.Name]
   164  			if !found {
   165  				continue
   166  			}
   167  
   168  			candidates, abstain := rf(reclaimer, reclaimees)
   169  			if abstain == 0 {
   170  				continue
   171  			}
   172  			if len(candidates) == 0 {
   173  				victims = nil
   174  				break
   175  			}
   176  			if !init {
   177  				victims = candidates
   178  				init = true
   179  			} else {
   180  				var intersection []*api.TaskInfo
   181  				// Get intersection of victims and candidates.
   182  				for _, v := range victims {
   183  					for _, c := range candidates {
   184  						if v.UID == c.UID {
   185  							intersection = append(intersection, v)
   186  						}
   187  					}
   188  				}
   189  
   190  				// Update victims to intersection
   191  				victims = intersection
   192  			}
   193  		}
   194  		// Plugins in this tier made decision if victims is not nil
   195  		if victims != nil {
   196  			return victims
   197  		}
   198  	}
   199  
   200  	return victims
   201  }
   202  
   203  // Preemptable invoke preemptable function of the plugins
   204  func (ssn *Session) Preemptable(preemptor *api.TaskInfo, preemptees []*api.TaskInfo) []*api.TaskInfo {
   205  	var victims []*api.TaskInfo
   206  	var init bool
   207  
   208  	for _, tier := range ssn.Tiers {
   209  		for _, plugin := range tier.Plugins {
   210  			if !isEnabled(plugin.EnabledPreemptable) {
   211  				continue
   212  			}
   213  
   214  			pf, found := ssn.preemptableFns[plugin.Name]
   215  			if !found {
   216  				continue
   217  			}
   218  			candidates, abstain := pf(preemptor, preemptees)
   219  			if abstain == 0 {
   220  				continue
   221  			}
   222  			// intersection will be nil if length is 0, don't need to do any more check
   223  			if len(candidates) == 0 {
   224  				victims = nil
   225  				break
   226  			}
   227  
   228  			if !init {
   229  				victims = candidates
   230  				init = true
   231  			} else {
   232  				var intersection []*api.TaskInfo
   233  				// Get intersection of victims and candidates.
   234  				for _, v := range victims {
   235  					for _, c := range candidates {
   236  						if v.UID == c.UID {
   237  							intersection = append(intersection, v)
   238  						}
   239  					}
   240  				}
   241  
   242  				// Update victims to intersection
   243  				victims = intersection
   244  			}
   245  		}
   246  		// Plugins in this tier made decision if victims is not nil
   247  		if victims != nil {
   248  			return victims
   249  		}
   250  	}
   251  
   252  	return victims
   253  }
   254  
   255  // Overused invoke overused function of the plugins
   256  func (ssn *Session) Overused(queue *api.QueueInfo) bool {
   257  	for _, tier := range ssn.Tiers {
   258  		for _, plugin := range tier.Plugins {
   259  			if !isEnabled(plugin.EnabledOverused) {
   260  				continue
   261  			}
   262  			of, found := ssn.overusedFns[plugin.Name]
   263  			if !found {
   264  				continue
   265  			}
   266  			if of(queue) {
   267  				return true
   268  			}
   269  		}
   270  	}
   271  
   272  	return false
   273  }
   274  
   275  // Preemptive invoke can preemptive function of the plugins
   276  func (ssn *Session) Preemptive(queue *api.QueueInfo) bool {
   277  	for _, tier := range ssn.Tiers {
   278  		for _, plugin := range tier.Plugins {
   279  			of, found := ssn.preemptiveFns[plugin.Name]
   280  			if !isEnabled(plugin.EnablePreemptive) {
   281  				continue
   282  			}
   283  			if !found {
   284  				continue
   285  			}
   286  			if !of(queue) {
   287  				return false
   288  			}
   289  		}
   290  	}
   291  
   292  	return true
   293  }
   294  
   295  // Allocatable invoke allocatable function of the plugins
   296  func (ssn *Session) Allocatable(queue *api.QueueInfo, candidate *api.TaskInfo) bool {
   297  	for _, tier := range ssn.Tiers {
   298  		for _, plugin := range tier.Plugins {
   299  			if !isEnabled(plugin.EnabledAllocatable) {
   300  				continue
   301  			}
   302  			af, found := ssn.allocatableFns[plugin.Name]
   303  			if !found {
   304  				continue
   305  			}
   306  			if !af(queue, candidate) {
   307  				return false
   308  			}
   309  		}
   310  	}
   311  
   312  	return true
   313  }
   314  
   315  // JobReady invoke jobready function of the plugins
   316  func (ssn *Session) JobReady(obj interface{}) bool {
   317  	for _, tier := range ssn.Tiers {
   318  		for _, plugin := range tier.Plugins {
   319  			if !isEnabled(plugin.EnabledJobReady) {
   320  				continue
   321  			}
   322  			jrf, found := ssn.jobReadyFns[plugin.Name]
   323  			if !found {
   324  				continue
   325  			}
   326  
   327  			if !jrf(obj) {
   328  				return false
   329  			}
   330  		}
   331  	}
   332  
   333  	return true
   334  }
   335  
   336  // JobPipelined invoke pipelined function of the plugins
   337  // Check if job has get enough resource to run
   338  func (ssn *Session) JobPipelined(obj interface{}) bool {
   339  	var hasFound bool
   340  	for _, tier := range ssn.Tiers {
   341  		for _, plugin := range tier.Plugins {
   342  			if !isEnabled(plugin.EnabledJobPipelined) {
   343  				continue
   344  			}
   345  			jrf, found := ssn.jobPipelinedFns[plugin.Name]
   346  			if !found {
   347  				continue
   348  			}
   349  
   350  			res := jrf(obj)
   351  			if res < 0 {
   352  				return false
   353  			}
   354  			if res > 0 {
   355  				hasFound = true
   356  			}
   357  		}
   358  		// if plugin exists that votes permit, meanwhile other plugin votes abstention,
   359  		// permit job to be pipelined, do not check next tier
   360  		if hasFound {
   361  			return true
   362  		}
   363  	}
   364  
   365  	return true
   366  }
   367  
   368  // JobStarving invoke jobStarving function of the plugins
   369  // Check if job still need more resource
   370  func (ssn *Session) JobStarving(obj interface{}) bool {
   371  	var hasFound bool
   372  	for _, tier := range ssn.Tiers {
   373  		for _, plugin := range tier.Plugins {
   374  			if !isEnabled(plugin.EnabledJobStarving) {
   375  				continue
   376  			}
   377  			jrf, found := ssn.jobStarvingFns[plugin.Name]
   378  			if !found {
   379  				continue
   380  			}
   381  			hasFound = true
   382  
   383  			if !jrf(obj) {
   384  				return false
   385  			}
   386  		}
   387  		// this tier registered function
   388  		if hasFound {
   389  			return true
   390  		}
   391  	}
   392  
   393  	return false
   394  }
   395  
   396  // JobValid invoke jobvalid function of the plugins
   397  func (ssn *Session) JobValid(obj interface{}) *api.ValidateResult {
   398  	for _, tier := range ssn.Tiers {
   399  		for _, plugin := range tier.Plugins {
   400  			jrf, found := ssn.jobValidFns[plugin.Name]
   401  			if !found {
   402  				continue
   403  			}
   404  
   405  			if vr := jrf(obj); vr != nil && !vr.Pass {
   406  				return vr
   407  			}
   408  		}
   409  	}
   410  
   411  	return nil
   412  }
   413  
   414  // JobEnqueueable invoke jobEnqueueableFns function of the plugins
   415  func (ssn *Session) JobEnqueueable(obj interface{}) bool {
   416  	var hasFound bool
   417  	for _, tier := range ssn.Tiers {
   418  		for _, plugin := range tier.Plugins {
   419  			if !isEnabled(plugin.EnabledJobEnqueued) {
   420  				continue
   421  			}
   422  			fn, found := ssn.jobEnqueueableFns[plugin.Name]
   423  			if !found {
   424  				continue
   425  			}
   426  
   427  			res := fn(obj)
   428  			if res < 0 {
   429  				return false
   430  			}
   431  			if res > 0 {
   432  				hasFound = true
   433  			}
   434  		}
   435  		// if plugin exists that votes permit, meanwhile other plugin votes abstention,
   436  		// permit job to be enqueueable, do not check next tier
   437  		if hasFound {
   438  			return true
   439  		}
   440  	}
   441  
   442  	return true
   443  }
   444  
   445  // JobEnqueued invoke jobEnqueuedFns function of the plugins
   446  func (ssn *Session) JobEnqueued(obj interface{}) {
   447  	for _, tier := range ssn.Tiers {
   448  		for _, plugin := range tier.Plugins {
   449  			if !isEnabled(plugin.EnabledJobEnqueued) {
   450  				continue
   451  			}
   452  			fn, found := ssn.jobEnqueuedFns[plugin.Name]
   453  			if !found {
   454  				continue
   455  			}
   456  
   457  			fn(obj)
   458  		}
   459  	}
   460  }
   461  
   462  // TargetJob invoke targetJobFns function of the plugins
   463  func (ssn *Session) TargetJob(jobs []*api.JobInfo) *api.JobInfo {
   464  	for _, tier := range ssn.Tiers {
   465  		for _, plugin := range tier.Plugins {
   466  			if !isEnabled(plugin.EnabledTargetJob) {
   467  				continue
   468  			}
   469  			fn, found := ssn.targetJobFns[plugin.Name]
   470  			if !found {
   471  				continue
   472  			}
   473  			return fn(jobs)
   474  		}
   475  	}
   476  	return nil
   477  }
   478  
   479  // VictimTasks returns the victims selected
   480  func (ssn *Session) VictimTasks(tasks []*api.TaskInfo) map[*api.TaskInfo]bool {
   481  	// different filters may add the same task to victims, so use a map to remove duplicate tasks.
   482  	victimSet := make(map[*api.TaskInfo]bool)
   483  	for _, tier := range ssn.Tiers {
   484  		for _, plugin := range tier.Plugins {
   485  			if !isEnabled(plugin.EnabledVictim) {
   486  				continue
   487  			}
   488  			fns, found := ssn.victimTasksFns[plugin.Name]
   489  			if !found {
   490  				continue
   491  			}
   492  			for _, fn := range fns {
   493  				victimTasks := fn(tasks)
   494  				for _, victim := range victimTasks {
   495  					victimSet[victim] = true
   496  				}
   497  			}
   498  		}
   499  		if len(victimSet) > 0 {
   500  			return victimSet
   501  		}
   502  	}
   503  	return victimSet
   504  }
   505  
   506  // ReservedNodes invoke ReservedNodes function of the plugins
   507  func (ssn *Session) ReservedNodes() {
   508  	for _, tier := range ssn.Tiers {
   509  		for _, plugin := range tier.Plugins {
   510  			if !isEnabled(plugin.EnabledReservedNodes) {
   511  				continue
   512  			}
   513  			fn, found := ssn.reservedNodesFns[plugin.Name]
   514  			if !found {
   515  				continue
   516  			}
   517  			fn()
   518  		}
   519  	}
   520  }
   521  
   522  // JobOrderFn invoke joborder function of the plugins
   523  func (ssn *Session) JobOrderFn(l, r interface{}) bool {
   524  	for _, tier := range ssn.Tiers {
   525  		for _, plugin := range tier.Plugins {
   526  			if !isEnabled(plugin.EnabledJobOrder) {
   527  				continue
   528  			}
   529  			jof, found := ssn.jobOrderFns[plugin.Name]
   530  			if !found {
   531  				continue
   532  			}
   533  			if j := jof(l, r); j != 0 {
   534  				return j < 0
   535  			}
   536  		}
   537  	}
   538  
   539  	// If no job order funcs, order job by CreationTimestamp first, then by UID.
   540  	lv := l.(*api.JobInfo)
   541  	rv := r.(*api.JobInfo)
   542  	if lv.CreationTimestamp.Equal(&rv.CreationTimestamp) {
   543  		return lv.UID < rv.UID
   544  	}
   545  	return lv.CreationTimestamp.Before(&rv.CreationTimestamp)
   546  }
   547  
   548  // ClusterOrderFn invoke ClusterOrderFn function of the plugins
   549  func (ssn *Session) ClusterOrderFn(l, r interface{}) bool {
   550  	for _, tier := range ssn.Tiers {
   551  		for _, plugin := range tier.Plugins {
   552  			if !isEnabled(plugin.EnabledClusterOrder) {
   553  				continue
   554  			}
   555  			cof, found := ssn.clusterOrderFns[plugin.Name]
   556  			if !found {
   557  				continue
   558  			}
   559  			if j := cof(l, r); j != 0 {
   560  				return j < 0
   561  			}
   562  		}
   563  	}
   564  
   565  	// If no cluster order funcs, order cluster by ClusterID
   566  	lv := l.(*scheduling.Cluster)
   567  	rv := r.(*scheduling.Cluster)
   568  	return lv.Name < rv.Name
   569  }
   570  
   571  // QueueOrderFn invoke queueorder function of the plugins
   572  func (ssn *Session) QueueOrderFn(l, r interface{}) bool {
   573  	for _, tier := range ssn.Tiers {
   574  		for _, plugin := range tier.Plugins {
   575  			if !isEnabled(plugin.EnabledQueueOrder) {
   576  				continue
   577  			}
   578  			qof, found := ssn.queueOrderFns[plugin.Name]
   579  			if !found {
   580  				continue
   581  			}
   582  			if j := qof(l, r); j != 0 {
   583  				return j < 0
   584  			}
   585  		}
   586  	}
   587  
   588  	// If no queue order funcs, order queue by CreationTimestamp first, then by UID.
   589  	lv := l.(*api.QueueInfo)
   590  	rv := r.(*api.QueueInfo)
   591  	if lv.Queue.CreationTimestamp.Equal(&rv.Queue.CreationTimestamp) {
   592  		return lv.UID < rv.UID
   593  	}
   594  	return lv.Queue.CreationTimestamp.Before(&rv.Queue.CreationTimestamp)
   595  }
   596  
   597  // TaskCompareFns invoke taskorder function of the plugins
   598  func (ssn *Session) TaskCompareFns(l, r interface{}) int {
   599  	for _, tier := range ssn.Tiers {
   600  		for _, plugin := range tier.Plugins {
   601  			if !isEnabled(plugin.EnabledTaskOrder) {
   602  				continue
   603  			}
   604  			tof, found := ssn.taskOrderFns[plugin.Name]
   605  			if !found {
   606  				continue
   607  			}
   608  			if j := tof(l, r); j != 0 {
   609  				return j
   610  			}
   611  		}
   612  	}
   613  
   614  	return 0
   615  }
   616  
   617  // TaskOrderFn invoke taskorder function of the plugins
   618  func (ssn *Session) TaskOrderFn(l, r interface{}) bool {
   619  	if res := ssn.TaskCompareFns(l, r); res != 0 {
   620  		return res < 0
   621  	}
   622  
   623  	// If no task order funcs, order task by default func.
   624  	lv := l.(*api.TaskInfo)
   625  	rv := r.(*api.TaskInfo)
   626  	return helpers.CompareTask(lv, rv)
   627  }
   628  
   629  // PredicateFn invoke predicate function of the plugins
   630  func (ssn *Session) PredicateFn(task *api.TaskInfo, node *api.NodeInfo) ([]*api.Status, error) {
   631  	predicateStatus := make([]*api.Status, 0)
   632  	for _, tier := range ssn.Tiers {
   633  		for _, plugin := range tier.Plugins {
   634  			if !isEnabled(plugin.EnabledPredicate) {
   635  				continue
   636  			}
   637  			pfn, found := ssn.predicateFns[plugin.Name]
   638  			if !found {
   639  				continue
   640  			}
   641  			status, err := pfn(task, node)
   642  			predicateStatus = append(predicateStatus, status...)
   643  			if err != nil {
   644  				return predicateStatus, err
   645  			}
   646  		}
   647  	}
   648  	return predicateStatus, nil
   649  }
   650  
   651  // PrePredicateFn invoke predicate function of the plugins
   652  func (ssn *Session) PrePredicateFn(task *api.TaskInfo) error {
   653  	for _, tier := range ssn.Tiers {
   654  		for _, plugin := range tier.Plugins {
   655  			// we use same option as predicates for they are
   656  			if !isEnabled(plugin.EnabledPredicate) {
   657  				continue
   658  			}
   659  			pfn, found := ssn.prePredicateFns[plugin.Name]
   660  			if !found {
   661  				continue
   662  			}
   663  			err := pfn(task)
   664  			if err != nil {
   665  				return err
   666  			}
   667  		}
   668  	}
   669  	return nil
   670  }
   671  
   672  // BestNodeFn invoke bestNode function of the plugins
   673  func (ssn *Session) BestNodeFn(task *api.TaskInfo, nodeScores map[float64][]*api.NodeInfo) *api.NodeInfo {
   674  	for _, tier := range ssn.Tiers {
   675  		for _, plugin := range tier.Plugins {
   676  			if !isEnabled(plugin.EnabledBestNode) {
   677  				continue
   678  			}
   679  			pfn, found := ssn.bestNodeFns[plugin.Name]
   680  			if !found {
   681  				continue
   682  			}
   683  			// Only the first plugin that enables and realizes bestNodeFn is allowed to choose best node for task
   684  			if bestNode := pfn(task, nodeScores); bestNode != nil {
   685  				return bestNode
   686  			}
   687  		}
   688  	}
   689  	return nil
   690  }
   691  
   692  // NodeOrderFn invoke node order function of the plugins
   693  func (ssn *Session) NodeOrderFn(task *api.TaskInfo, node *api.NodeInfo) (float64, error) {
   694  	priorityScore := 0.0
   695  	for _, tier := range ssn.Tiers {
   696  		for _, plugin := range tier.Plugins {
   697  			if !isEnabled(plugin.EnabledNodeOrder) {
   698  				continue
   699  			}
   700  			pfn, found := ssn.nodeOrderFns[plugin.Name]
   701  			if !found {
   702  				continue
   703  			}
   704  			score, err := pfn(task, node)
   705  			if err != nil {
   706  				return 0, err
   707  			}
   708  			priorityScore += score
   709  		}
   710  	}
   711  	return priorityScore, nil
   712  }
   713  
   714  // BatchNodeOrderFn invoke node order function of the plugins
   715  func (ssn *Session) BatchNodeOrderFn(task *api.TaskInfo, nodes []*api.NodeInfo) (map[string]float64, error) {
   716  	priorityScore := make(map[string]float64, len(nodes))
   717  	for _, tier := range ssn.Tiers {
   718  		for _, plugin := range tier.Plugins {
   719  			if !isEnabled(plugin.EnabledNodeOrder) {
   720  				continue
   721  			}
   722  			pfn, found := ssn.batchNodeOrderFns[plugin.Name]
   723  			if !found {
   724  				continue
   725  			}
   726  			score, err := pfn(task, nodes)
   727  			if err != nil {
   728  				return nil, err
   729  			}
   730  			for nodeName, score := range score {
   731  				priorityScore[nodeName] += score
   732  			}
   733  		}
   734  	}
   735  	return priorityScore, nil
   736  }
   737  
   738  func isEnabled(enabled *bool) bool {
   739  	return enabled != nil && *enabled
   740  }
   741  
   742  // NodeOrderMapFn invoke node order function of the plugins
   743  func (ssn *Session) NodeOrderMapFn(task *api.TaskInfo, node *api.NodeInfo) (map[string]float64, float64, error) {
   744  	nodeScoreMap := map[string]float64{}
   745  	var priorityScore float64
   746  	for _, tier := range ssn.Tiers {
   747  		for _, plugin := range tier.Plugins {
   748  			if !isEnabled(plugin.EnabledNodeOrder) {
   749  				continue
   750  			}
   751  			if pfn, found := ssn.nodeOrderFns[plugin.Name]; found {
   752  				score, err := pfn(task, node)
   753  				if err != nil {
   754  					return nodeScoreMap, priorityScore, err
   755  				}
   756  				priorityScore += score
   757  			}
   758  			if pfn, found := ssn.nodeMapFns[plugin.Name]; found {
   759  				score, err := pfn(task, node)
   760  				if err != nil {
   761  					return nodeScoreMap, priorityScore, err
   762  				}
   763  				nodeScoreMap[plugin.Name] = score
   764  			}
   765  		}
   766  	}
   767  	return nodeScoreMap, priorityScore, nil
   768  }
   769  
   770  // NodeOrderReduceFn invoke node order function of the plugins
   771  func (ssn *Session) NodeOrderReduceFn(task *api.TaskInfo, pluginNodeScoreMap map[string]k8sframework.NodeScoreList) (map[string]float64, error) {
   772  	nodeScoreMap := map[string]float64{}
   773  	for _, tier := range ssn.Tiers {
   774  		for _, plugin := range tier.Plugins {
   775  			if !isEnabled(plugin.EnabledNodeOrder) {
   776  				continue
   777  			}
   778  			pfn, found := ssn.nodeReduceFns[plugin.Name]
   779  			if !found {
   780  				continue
   781  			}
   782  			if err := pfn(task, pluginNodeScoreMap[plugin.Name]); err != nil {
   783  				return nodeScoreMap, err
   784  			}
   785  			for _, hp := range pluginNodeScoreMap[plugin.Name] {
   786  				nodeScoreMap[hp.Name] += float64(hp.Score)
   787  			}
   788  		}
   789  	}
   790  	return nodeScoreMap, nil
   791  }
   792  
   793  // BuildVictimsPriorityQueue returns a priority queue with victims sorted by:
   794  // if victims has same job id, sorted by !ssn.TaskOrderFn
   795  // if victims has different job id, sorted by !ssn.JobOrderFn
   796  func (ssn *Session) BuildVictimsPriorityQueue(victims []*api.TaskInfo) *util.PriorityQueue {
   797  	victimsQueue := util.NewPriorityQueue(func(l, r interface{}) bool {
   798  		lv := l.(*api.TaskInfo)
   799  		rv := r.(*api.TaskInfo)
   800  		if lv.Job == rv.Job {
   801  			return !ssn.TaskOrderFn(l, r)
   802  		}
   803  		return !ssn.JobOrderFn(ssn.Jobs[lv.Job], ssn.Jobs[rv.Job])
   804  	})
   805  	for _, victim := range victims {
   806  		victimsQueue.Push(victim)
   807  	}
   808  	return victimsQueue
   809  }