diff --git a/pkg/scheduler/core/generic_scheduler.go b/pkg/scheduler/core/generic_scheduler.go index 9d5b846f57..db72c0a9b1 100644 --- a/pkg/scheduler/core/generic_scheduler.go +++ b/pkg/scheduler/core/generic_scheduler.go @@ -182,7 +182,7 @@ func newSchedResultByCtx(u *Unit, count int64, c Candidater) *SchedResultItem { Count: count, Capacity: u.GetCapacity(id), Name: c.Getter().Name(), - Score: u.GetScore(id).String(), + Score: u.GetScore(id), Data: u.GetFiltedData(id, count), Candidater: c, AllocatedResource: u.GetAllocatedResource(id), @@ -244,7 +244,7 @@ type SchedResultItem struct { Count int64 `json:"count"` Data map[string]interface{} `json:"data"` Capacity int64 `json:"capacity"` - Score string `json:"score"` + Score Score `json:"score"` CapacityDetails map[string]int64 `json:"capacity_details"` ScoreDetails string `json:"score_details"` diff --git a/pkg/scheduler/manager/instancegroup_select.go b/pkg/scheduler/manager/instancegroup_select.go index 02d2af72b6..932bb4cc76 100644 --- a/pkg/scheduler/manager/instancegroup_select.go +++ b/pkg/scheduler/manager/instancegroup_select.go @@ -28,6 +28,7 @@ import ( "yunion.io/x/onecloud/pkg/scheduler/api" "yunion.io/x/onecloud/pkg/scheduler/cache/candidate" "yunion.io/x/onecloud/pkg/scheduler/core" + "yunion.io/x/onecloud/pkg/scheduler/core/score" ) func transToInstanceGroupSchedResult(result *core.SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput { @@ -55,6 +56,19 @@ type sSchedResultItem struct { backupCount int64 } +func (item *sSchedResultItem) minInstanceGroupCapacity(groupSet map[string]*models.SGroup) int64 { + var mincapa int64 = -1 + for id, capa := range item.instanceGroupCapacity { + if _, ok := groupSet[id]; !ok { + continue + } + if mincapa == -1 || capa < mincapa { + mincapa = capa + } + } + return mincapa +} + func buildHosts(result *core.SchedResultItemList, groups map[string]*models.SGroup) []*sSchedResultItem { hosts := make([]*sSchedResultItem, result.Data.Len()) for i := 0; i < len(result.Data); i++ { @@ -78,30 +92,52 @@ func buildHosts(result *core.SchedResultItemList, groups map[string]*models.SGro instanceGroupCapacity: igCapacity, } } - sortHosts(hosts, nil) return hosts } // sortHost sorts the host for guest that is the backup one of the high-availability guest // if isBackup is true and the master one if isBackup is false. -func sortHosts(hosts []*sSchedResultItem, isBackup *bool) { +func sortHosts(hosts []*sSchedResultItem, guestInfo *sGuestInfo, isBackup *bool) { + sortIndexi, sortIndexj := make([]int64, 4), make([]int64, 4) sort.Slice(hosts, func(i, j int) bool { - var counti, countj int64 switch { case isBackup == nil: - counti, countj = hosts[i].Count, hosts[j].Count + sortIndexi[0], sortIndexj[0] = hosts[i].Count, hosts[j].Count case *isBackup: - counti, countj = hosts[i].backupCount, hosts[j].backupCount + sortIndexi[0], sortIndexj[0] = hosts[i].backupCount, hosts[j].backupCount default: - counti, countj = hosts[i].masterCount, hosts[j].masterCount + sortIndexi[0], sortIndexj[0] = hosts[i].masterCount, hosts[j].masterCount } - if counti == countj { - return hosts[i].Capacity > hosts[j].Capacity + sortIndexi[1], sortIndexj[1] = hosts[i].Count, hosts[j].Count + sortIndexi[2], sortIndexj[2] = -(hosts[i].minInstanceGroupCapacity(guestInfo.instanceGroupsDetail)), -(hosts[j].minInstanceGroupCapacity(guestInfo.instanceGroupsDetail)) + sortIndexi[3], sortIndexj[3] = scoreNormalization(hosts[i].Score, hosts[j].Score) + sortIndexi[4], sortIndexj[4] = -(hosts[i].Capacity), -(hosts[j].Capacity) + for i := 0; i < 5; i++ { + if sortIndexi[i] == sortIndexj[i] { + continue + } + return sortIndexi[i] < sortIndexj[i] } - return counti < countj + return true }) } +// scoreNormalization compare the value of s1 and s2. +// If s1 is less than s2, return 1, 0 which means s2 is better than s1. +func scoreNormalization(s1, s2 core.Score) (int64, int64) { + sb1, sb2 := s1.ScoreBucket, s2.ScoreBucket + preferLess := score.PreferLess(sb1, sb2) + avoidLess := score.AvoidLess(sb1, sb2) + normalLess := score.AvoidLess(sb1, sb2) + if preferLess || normalLess { + return 1, 0 + } + if avoidLess { + return 0, 1 + } + return 0, 0 +} + // buildWireHosts classify hosts according to their wire func buildWireHosts(hosts []*sSchedResultItem) map[string][]*sSchedResultItem { wireHostMap := make(map[string][]*sSchedResultItem) @@ -288,7 +324,7 @@ func unMarkHostUsed(host *sSchedResultItem, guestInfo sGuestInfo, isBackup *bool // If forced is true, all instanceGroups will be forced. // Otherwise, the instanceGroups with ForceDispersion 'false' will be unforced. func selectHost(hosts []*sSchedResultItem, guestInfo sGuestInfo, isBackup *bool, forced bool) *sSchedResultItem { - sortHosts(hosts, isBackup) + sortHosts(hosts, &guestInfo, isBackup) var idx = -1 if len(guestInfo.preferHost) > 0 { if idx = hostsIndex(guestInfo.preferHost, hosts); idx < 0 {