From fa0450b4540e970071ee8d3919b494e376683728 Mon Sep 17 00:00:00 2001 From: rainzm Date: Tue, 21 Jul 2020 20:29:47 +0800 Subject: [PATCH] feat(scheduler): Change the action for guests with backup and instanceGroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 对于主机组的打散功能,放在调度的最后单独处理。 2. 主备机的调度,通过在主机和备机之间设置一个粒度为1的主机组来实现。 3. 虚拟机的调度默认打散,在打散的基础上,选择容量大的宿主机。 3. 主备机中,主机和备机的默认打散流程分散开,互不影响。 --- .../predicates/instance_group_predicate.go | 156 --------- pkg/scheduler/algorithmprovider/defaults.go | 2 - pkg/scheduler/cache/candidate/base.go | 4 +- pkg/scheduler/core/generic_scheduler.go | 8 - pkg/scheduler/manager/instancegroup_select.go | 323 ++++++++++++++++++ pkg/scheduler/manager/result_helper.go | 170 +-------- 6 files changed, 328 insertions(+), 335 deletions(-) delete mode 100644 pkg/scheduler/algorithm/predicates/instance_group_predicate.go create mode 100644 pkg/scheduler/manager/instancegroup_select.go diff --git a/pkg/scheduler/algorithm/predicates/instance_group_predicate.go b/pkg/scheduler/algorithm/predicates/instance_group_predicate.go deleted file mode 100644 index dbb5494421..0000000000 --- a/pkg/scheduler/algorithm/predicates/instance_group_predicate.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package predicates - -import ( - "fmt" - "math" - - "yunion.io/x/onecloud/pkg/scheduler/core" -) - -type InstanceGroupPredicate struct { - BasePredicate -} - -func (p *InstanceGroupPredicate) Name() string { - return "instance_group" -} - -func (p *InstanceGroupPredicate) Clone() core.FitPredicate { - return &InstanceGroupPredicate{} -} - -func (p *InstanceGroupPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, error) { - schedDate := u.SchedData() - if schedDate.InstanceGroupIds == nil || len(schedDate.InstanceGroupIds) == 0 { - return false, nil - } - return true, nil -} - -func (p *InstanceGroupPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) { - return true, nil, nil -} - -type SForcedGroupPredicate struct { - InstanceGroupPredicate -} - -func (p *SForcedGroupPredicate) Name() string { - return "forced_instance_group" -} - -func (p *SForcedGroupPredicate) Clone() core.FitPredicate { - return &SForcedGroupPredicate{} -} - -// SForcedGroupPredicate make sure that there is no more guest with same group whose IsForcedSpe is ture in a host -// for all forced groups in u.SchedData.InstanceGroupIds, so that the capacity is the min value of the FreeGroupCounts -func (p *SForcedGroupPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) { - h := NewPredicateHelper(p, u, c) - schedDate := u.SchedData() - - instanceGroups := c.Getter().InstanceGroups() - minFree := math.MaxInt32 - for _, id := range schedDate.InstanceGroupIds { - detail := schedDate.InstanceGroupsDetail[id] - // SForcedGroupPredicate only deal with group whose ForceDispersion is ture - if detail.ForceDispersion.IsFalse() { - continue - } - var free int - if _, ok := instanceGroups[id]; ok { - free, _ = c.Getter().GetFreeGroupCount(id) - if free < 1 { - h.AppendPredicateFailMsg(fmt.Sprintf( - "the number of guests with same instance group '%s' in this host has reached the upper limit", - instanceGroups[id].GetName())) - minFree = 0 - break - } - } else { - free = detail.Granularity - } - if free < minFree { - minFree = free - } - } - // chose the min capacity of groups - h.SetCapacity(int64(minFree)) - return h.GetResult() -} - -type SUnForcedGroupPredicate struct { - InstanceGroupPredicate -} - -func (p *SUnForcedGroupPredicate) Name() string { - return "unforced_instance_group" -} - -func (p *SUnForcedGroupPredicate) Clone() core.FitPredicate { - return &SUnForcedGroupPredicate{} -} - -func (p *SUnForcedGroupPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, error) { - ret, err := p.InstanceGroupPredicate.PreExecute(u, cs) - if err != nil || !ret { - return ret, err - } - u.RegisterSelectPriorityUpdater(p.Name(), func(u *core.Unit, origin core.SSelectPriorityValue, - hostID string) core.SSelectPriorityValue { - - return origin.SubOne() - }) - return ret, err -} - -// SUnForcedGroupPredicate make sure that the guests are assigned to these hosts who has enough FreeGroupCount of -// unforced groups, so that it will improve the priority of these hosts meet the conditions and the priority should -// be the max value of the FreeGroupCounts -func (p *SUnForcedGroupPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, - error) { - - h := NewPredicateHelper(p, u, c) - schedDate := u.SchedData() - - instanceGroups := c.Getter().InstanceGroups() - maxPriority := 0 - for _, id := range schedDate.InstanceGroupIds { - detail := schedDate.InstanceGroupsDetail[id] - // SUnForcedGroupPredicate only deal with group whose ForceDispersion is false - if detail.ForceDispersion.IsTrue() { - continue - } - var priority int - if _, ok := instanceGroups[id]; ok { - free, _ := c.Getter().GetFreeGroupCount(id) - if free < 1 { - priority = 0 - } - priority = free - } else { - priority = detail.Granularity - } - if priority > maxPriority { - maxPriority = priority - } - } - - // set priority - h.SetSelectPriority(maxPriority) - return h.GetResult() -} diff --git a/pkg/scheduler/algorithmprovider/defaults.go b/pkg/scheduler/algorithmprovider/defaults.go index 3ec00a7eb0..c0111d00a8 100644 --- a/pkg/scheduler/algorithmprovider/defaults.go +++ b/pkg/scheduler/algorithmprovider/defaults.go @@ -45,8 +45,6 @@ func defaultPredicates() sets.String { factory.RegisterFitPredicate("m-GuestDiskschedtagFilter", &predicates.DiskSchedtagPredicate{}), factory.RegisterFitPredicate("n-ServerSkuFilter", &predicates.InstanceTypePredicate{}), factory.RegisterFitPredicate("o-GuestNetschedtagFilter", &predicates.NetworkSchedtagPredicate{}), - factory.RegisterFitPredicate("p-GuestForcedDispersionFilter", &predicates.SForcedGroupPredicate{}), - factory.RegisterFitPredicate("p-GuestUnForcedDispersionFilter", &predicates.SUnForcedGroupPredicate{}), factory.RegisterFitPredicate("z-QuotaFilter", &predicates.SQuotaPredicate{}), ) } diff --git a/pkg/scheduler/cache/candidate/base.go b/pkg/scheduler/cache/candidate/base.go index 4ac4d583be..f252743cf7 100644 --- a/pkg/scheduler/cache/candidate/base.go +++ b/pkg/scheduler/cache/candidate/base.go @@ -31,6 +31,8 @@ import ( schedmodels "yunion.io/x/onecloud/pkg/scheduler/models" ) +var ErrInstanceGroupNotFound = errors.Error("InstanceGroupNotFound") + type BaseHostDesc struct { *computemodels.SHost Region *computemodels.SCloudregion `json:"region"` @@ -128,7 +130,7 @@ func (b baseHostGetter) GetFreeGroupCount(groupId string) (int, error) { // Must Be scg, ok := b.h.InstanceGroups[groupId] if !ok { - return 0, fmt.Errorf("No such Group id") + return 0, errors.Wrap(ErrInstanceGroupNotFound, groupId) } free := scg.Granularity - scg.ReferCount if free < 1 { diff --git a/pkg/scheduler/core/generic_scheduler.go b/pkg/scheduler/core/generic_scheduler.go index 2b8f28bb86..9d5b846f57 100644 --- a/pkg/scheduler/core/generic_scheduler.go +++ b/pkg/scheduler/core/generic_scheduler.go @@ -450,17 +450,12 @@ func SelectHosts(unit *Unit, priorityList HostPriorityList) ([]*SelectedCandidat completed: for len(priorityList) > 0 { log.V(10).Debugf("PriorityList: %#v", priorityList) - currentPriority := unit.GetMaxSelectPriority() priorityList0 := HostPriorityList{} for _, it := range priorityList { if count <= 0 { break completed } hostID := it.Host - if !currentPriority.IsEmpty() && unit.GetSelectPriority(hostID).Less(currentPriority) { - priorityList0 = append(priorityList0, it) - continue - } var ( selectedItem *SelectedCandidate ok bool @@ -479,9 +474,6 @@ completed: priorityList0 = append(priorityList0, it) } } - if !currentPriority.IsEmpty() { - unit.UpdateSelectPriority() - } // sort by score priorityList = priorityList0 //sort.Sort(sort.Reverse(priorityList)) diff --git a/pkg/scheduler/manager/instancegroup_select.go b/pkg/scheduler/manager/instancegroup_select.go new file mode 100644 index 0000000000..02d2af72b6 --- /dev/null +++ b/pkg/scheduler/manager/instancegroup_select.go @@ -0,0 +1,323 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package manager + +import ( + "fmt" + "sort" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/tristate" + "yunion.io/x/pkg/util/sets" + + schedapi "yunion.io/x/onecloud/pkg/apis/scheduler" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/scheduler/api" + "yunion.io/x/onecloud/pkg/scheduler/cache/candidate" + "yunion.io/x/onecloud/pkg/scheduler/core" +) + +func transToInstanceGroupSchedResult(result *core.SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput { + for _, item := range result.Data { + item.Count = 0 + } + guestInfos, backGuestInfos, groups := generateGuestInfo(schedInfo) + hosts := buildHosts(result, groups) + if len(backGuestInfos) > 0 { + return getBackupSchedResult(hosts, guestInfos, backGuestInfos, schedInfo.SessionId) + } + return getSchedResult(hosts, guestInfos, schedInfo.SessionId) +} + +type sGuestInfo struct { + schedInfo *api.SchedInfo + instanceGroupsDetail map[string]*models.SGroup + preferHost string +} + +type sSchedResultItem struct { + *core.SchedResultItem + instanceGroupCapacity map[string]int64 + masterCount int64 + backupCount int64 +} + +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++ { + getter := result.Data[i].Candidater.Getter() + igCapacity := make(map[string]int64) + for id, group := range groups { + c, err := getter.GetFreeGroupCount(id) + if err != nil { + if errors.Cause(err) == candidate.ErrInstanceGroupNotFound { + igCapacity[id] = int64(group.Granularity) + } else { + igCapacity[id] = 0 + log.Errorf("GetFreeGroupCount: %s", err.Error()) + } + } else { + igCapacity[id] = int64(c) + } + } + hosts[i] = &sSchedResultItem{ + SchedResultItem: result.Data[i], + 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) { + sort.Slice(hosts, func(i, j int) bool { + var counti, countj int64 + switch { + case isBackup == nil: + counti, countj = hosts[i].Count, hosts[j].Count + case *isBackup: + counti, countj = hosts[i].backupCount, hosts[j].backupCount + default: + counti, countj = hosts[i].masterCount, hosts[j].masterCount + } + if counti == countj { + return hosts[i].Capacity > hosts[j].Capacity + } + return counti < countj + }) +} + +// buildWireHosts classify hosts according to their wire +func buildWireHosts(hosts []*sSchedResultItem) map[string][]*sSchedResultItem { + wireHostMap := make(map[string][]*sSchedResultItem) + for _, host := range hosts { + networks := host.Candidater.Getter().Networks() + for j := 0; j < len(networks); j++ { + if hosts, ok := wireHostMap[networks[j].WireId]; ok { + if hostsIndex(host.ID, hosts) < 0 { + wireHostMap[networks[j].WireId] = append(hosts, host) + } + } else { + wireHostMap[networks[j].WireId] = []*sSchedResultItem{host} + } + } + } + return wireHostMap +} + +// generateGuestInfo return guestInfos, backupGuestInfos and all instanceGroups +func generateGuestInfo(schedInfo *api.SchedInfo) ([]sGuestInfo, []sGuestInfo, map[string]*models.SGroup) { + infos := make([]sGuestInfo, 0, schedInfo.Count) + infobs := make([]sGuestInfo, 0, schedInfo.Count) + groups := make(map[string]*models.SGroup) + name := schedInfo.Name + if len(name) == 0 { + name = "default" + } + for id, group := range schedInfo.InstanceGroupsDetail { + groups[id] = group + } + for i := 0; i < schedInfo.Count; i++ { + info := sGuestInfo{ + schedInfo: schedInfo, + instanceGroupsDetail: make(map[string]*models.SGroup), + preferHost: schedInfo.PreferHost, + } + for id, group := range schedInfo.InstanceGroupsDetail { + info.instanceGroupsDetail[id] = group + } + infos = append(infos, info) + if !schedInfo.Backup { + continue + } + infob := sGuestInfo{ + schedInfo: schedInfo, + preferHost: schedInfo.PreferBackupHost, + instanceGroupsDetail: make(map[string]*models.SGroup), + } + infobs = append(infobs, infob) + // Virtual an instanceGroup + group := models.SGroup{ + Granularity: 1, + ForceDispersion: tristate.True, + } + groupid := fmt.Sprintf("virtual-%s-%d", name, i) + group.Id = groupid + infos[i].instanceGroupsDetail[groupid] = &group + infobs[i].instanceGroupsDetail[groupid] = &group + groups[groupid] = &group + } + return infos, infobs, groups +} + +func hostsIndex(hostId string, hosts []*sSchedResultItem) int { + for i := 0; i < len(hosts); i++ { + if hosts[i].ID == hostId { + return i + } + } + return -1 +} + +// getBackupSchedResult return the ScheduleOutput for guest without backup +func getSchedResult(hosts []*sSchedResultItem, guestInfos []sGuestInfo, sid string) *schedapi.ScheduleOutput { + apiResults := make([]*schedapi.CandidateResource, 0) + storageUsed := core.NewStorageUsed() + var i int = 0 + for ; i < len(guestInfos); i++ { + host := selectHost(hosts, guestInfos[i], nil, true) + if host == nil { + host = selectHost(hosts, guestInfos[i], nil, false) + if host == nil { + er := &schedapi.CandidateResource{Error: fmt.Sprintf("no suitable Host for No.%d Guest", i+1)} + apiResults = append(apiResults, er) + break + } + } + markHostUsed(host, guestInfos[i], nil) + tr := host.ToCandidateResource(storageUsed) + tr.SessionId = sid + apiResults = append(apiResults, tr) + } + for ; i < len(guestInfos); i++ { + er := &schedapi.CandidateResource{Error: fmt.Sprintf("no suitable Host for No.%d Guest", i+1)} + apiResults = append(apiResults, er) + } + ret := new(schedapi.ScheduleOutput) + ret.Candidates = apiResults + return ret +} + +// getBackupSchedResult return the ScheduleOutput for guest with backup +func getBackupSchedResult(hosts []*sSchedResultItem, guestInfos, backGuestInfos []sGuestInfo, sid string) *schedapi.ScheduleOutput { + wireHostMap := buildWireHosts(hosts) + apiResults := make([]*schedapi.CandidateResource, 0, len(guestInfos)) + nowireIds := sets.NewString() + storageUsed := core.NewStorageUsed() + isBackup := true + isMaster := false + for i := 0; i < len(guestInfos); i++ { + for wireid, hosts := range wireHostMap { + if nowireIds.Has(wireid) { + continue + } + masterItem := selectHost(hosts, guestInfos[i], &isMaster, true) + if masterItem == nil { + masterItem = selectHost(hosts, guestInfos[i], &isMaster, false) + if masterItem == nil { + nowireIds.Insert(wireid) + continue + } + } + // mark master used for now + markHostUsed(masterItem, guestInfos[i], &isMaster) + backupItem := selectHost(hosts, backGuestInfos[i], &isBackup, false) + if backupItem == nil { + nowireIds.Insert(wireid) + unMarkHostUsed(masterItem, guestInfos[i], &isMaster) + continue + } + markHostUsed(backupItem, backGuestInfos[i], &isBackup) + canRe := masterItem.ToCandidateResource(storageUsed) + canRe.BackupCandidate = backupItem.ToCandidateResource(storageUsed) + canRe.SessionId = sid + canRe.BackupCandidate.SessionId = sid + apiResults = append(apiResults, canRe) + break + } + if len(apiResults) == i+1 { + continue + } + er := &schedapi.CandidateResource{Error: fmt.Sprintf("no suitable Host for No.%d Highly available Guest", i+1)} + apiResults = append(apiResults, er) + } + ret := new(schedapi.ScheduleOutput) + ret.Candidates = apiResults + return ret +} + +func markHostUsed(host *sSchedResultItem, guestInfo sGuestInfo, isBackup *bool) { + for gid := range guestInfo.instanceGroupsDetail { + host.instanceGroupCapacity[gid] = host.instanceGroupCapacity[gid] - 1 + } + host.Capacity-- + host.Count++ + if isBackup == nil { + return + } + if *isBackup { + host.backupCount++ + } else { + host.masterCount++ + } +} + +// unMarkHostUsed is the reverse operation of markHostUsed +func unMarkHostUsed(host *sSchedResultItem, guestInfo sGuestInfo, isBackup *bool) { + for gid := range guestInfo.instanceGroupsDetail { + host.instanceGroupCapacity[gid] = host.instanceGroupCapacity[gid] + 1 + } + host.Capacity++ + host.Count-- + if isBackup == nil { + return + } + if *isBackup { + host.backupCount-- + } else { + host.masterCount-- + } +} + +// selectHost select host from hosts for guest described by guestInfo. +// 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) + var idx = -1 + if len(guestInfo.preferHost) > 0 { + if idx = hostsIndex(guestInfo.preferHost, hosts); idx < 0 { + return nil + } + } + var choosed bool +Loop: + for i, host := range hosts { + if idx >= 0 && idx != i { + continue + } + if host.Capacity <= 0 { + continue + } + // check forced instanceGroup + for id, group := range guestInfo.instanceGroupsDetail { + capacity := host.instanceGroupCapacity[id] + checkCapacity := forced || group.ForceDispersion.IsTrue() + if checkCapacity && capacity <= 0 { + continue Loop + } + } + idx = i + choosed = true + break + } + if choosed { + return hosts[idx] + } + return nil +} diff --git a/pkg/scheduler/manager/result_helper.go b/pkg/scheduler/manager/result_helper.go index 2a8bbcf70c..8ded1924ff 100644 --- a/pkg/scheduler/manager/result_helper.go +++ b/pkg/scheduler/manager/result_helper.go @@ -16,7 +16,6 @@ package manager import ( "fmt" - "sort" "yunion.io/x/log" @@ -28,9 +27,8 @@ import ( ) func transToSchedResult(result *core.SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput { - if schedInfo.Backup { - return transToBackupSchedResult(result, - schedInfo.PreferHost, schedInfo.PreferBackupHost, int64(schedInfo.Count), schedInfo.SessionId) + if schedInfo.Backup || len(schedInfo.InstanceGroupsDetail) > 0 { + return transToInstanceGroupSchedResult(result, schedInfo) } else { return transToRegionSchedResult(result.Data, int64(schedInfo.Count), schedInfo.SessionId) } @@ -81,101 +79,6 @@ func transToRegionSchedResult(result core.SchedResultItems, count int64, sid str } } -func transToBackupSchedResult( - result *core.SchedResultItemList, preferMasterHost, preferBackupHost string, count int64, sid string, -) *schedapi.ScheduleOutput { - // clean each result sched result item's count - for _, item := range result.Data { - item.Count = 0 - } - - apiResults := newBackupSchedResult(result, preferMasterHost, preferBackupHost, count, sid) - return apiResults -} - -func newBackupSchedResult( - result *core.SchedResultItemList, - preferMasterHost, preferBackupHost string, - count int64, - sid string, -) *schedapi.ScheduleOutput { - ret := new(schedapi.ScheduleOutput) - apiResults := make([]*schedapi.CandidateResource, 0) - storageUsed := core.NewStorageUsed() - var wireHostMap map[string]core.SchedResultItems - for i := 0; i < int(count); i++ { - log.V(10).Debugf("Select backup host from result: %s", result) - target, err := getSchedBackupResult(result, preferMasterHost, preferBackupHost, sid, wireHostMap, storageUsed) - if err != nil { - er := &schedapi.CandidateResource{Error: err.Error()} - apiResults = append(apiResults, er) - continue - } - apiResults = append(apiResults, target) - } - ret.Candidates = apiResults - return ret -} - -func getSchedBackupResult( - result *core.SchedResultItemList, - preferMasterHost, preferBackupHost string, - sid string, wireHostMap map[string]core.SchedResultItems, - storageUsed *core.StorageUsed, -) (*schedapi.CandidateResource, error) { - if wireHostMap == nil { - wireHostMap = buildWireHostMap(result) - } else { - reviseWireHostMap(wireHostMap) - } - - masterHost, backupHost := selectHosts(wireHostMap, preferMasterHost, preferBackupHost) - if masterHost == nil { - return nil, fmt.Errorf("Can't find master host %q", preferMasterHost) - } - if backupHost == nil { - return nil, fmt.Errorf("Can't find backup host %q by master %q", preferBackupHost, masterHost.ID) - } - - markHostUsed(masterHost) - markHostUsed(backupHost) - - ret := masterHost.ToCandidateResource(storageUsed) - ret.BackupCandidate = backupHost.ToCandidateResource(storageUsed) - ret.SessionId = sid - ret.BackupCandidate.SessionId = sid - return ret, nil -} - -func buildWireHostMap(result *core.SchedResultItemList) map[string]core.SchedResultItems { - sort.Sort(sort.Reverse(result.Data)) - wireHostMap := make(map[string]core.SchedResultItems) - for i := 0; i < len(result.Data); i++ { - networks := result.Data[i].Candidater.Getter().Networks() - for j := 0; j < len(networks); j++ { - if hosts, ok := wireHostMap[networks[j].WireId]; ok { - if hostInResultItemsIndex(result.Data[i].ID, hosts) < 0 { - wireHostMap[networks[j].WireId] = append(hosts, result.Data[i]) - } - } else { - wireHostMap[networks[j].WireId] = core.SchedResultItems{result.Data[i]} - } - } - } - return wireHostMap -} - -func reviseWireHostMap(wireHostMap map[string]core.SchedResultItems) { - for _, hosts := range wireHostMap { - sort.Sort(sort.Reverse(hosts)) - } -} - -func markHostUsed(host *core.SchedResultItem) { - host.Count++ - host.Capacity-- -} - func hostInResultItemsIndex(hostId string, hosts core.SchedResultItems) int { for i := 0; i < len(hosts); i++ { if hosts[i].ID == hostId { @@ -185,75 +88,6 @@ func hostInResultItemsIndex(hostId string, hosts core.SchedResultItems) int { return -1 } -func selectHosts( - wireHostMap map[string]core.SchedResultItems, preferMasterHost, preferBackupHost string, -) (*core.SchedResultItem, *core.SchedResultItem) { - var scroe int64 - var masterIdx, backupIdx int - var selectedWireId string - for wireId, hosts := range wireHostMap { - masterIdx, backupIdx = -1, -1 - if len(hosts) < 2 { - continue - } - if len(preferMasterHost) > 0 { - if masterIdx = hostInResultItemsIndex(preferMasterHost, hosts); masterIdx < 0 { - continue - } - } - if len(preferBackupHost) > 0 { - if backupIdx = hostInResultItemsIndex(preferBackupHost, hosts); backupIdx < 0 { - continue - } - } - - // select master host index - if masterIdx < 0 { - for i := 0; i < len(hosts); i++ { - if hosts[i].ID != preferBackupHost { - masterIdx = i - } - } - } - if hosts[masterIdx].Capacity <= 0 { - if len(preferMasterHost) > 0 { - // in case prefer master host capacity isn't enough - break - } else { - continue - } - } - - // select backup host index - if backupIdx < 0 { - for i := 0; i < len(hosts); i++ { - if i != masterIdx { - backupIdx = i - } - } - } - if hosts[backupIdx].Capacity <= 0 { - if len(preferBackupHost) > 0 { - // in case perfer backup host capacity isn't enough - break - } else { - continue - } - } - - // the highest total score wins - curScore := hosts[masterIdx].Capacity + hosts[backupIdx].Capacity - if curScore > scroe { - selectedWireId = wireId - scroe = curScore - } - } - if len(selectedWireId) == 0 { - return nil, nil - } - return wireHostMap[selectedWireId][masterIdx], wireHostMap[selectedWireId][backupIdx] -} - func transToSchedTestResult(result *core.SchedResultItemList, limit int64) interface{} { return &api.SchedTestResult{ Data: result.Data,