predicates.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Licensed under the Apache License, Version 2.0 (the "License");
  15. // you may not use this file except in compliance with the License.
  16. // You may obtain a copy of the License at
  17. //
  18. // http://www.apache.org/licenses/LICENSE-2.0
  19. //
  20. // Unless required by applicable law or agreed to in writing, software
  21. // distributed under the License is distributed on an "AS IS" BASIS,
  22. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  23. // See the License for the specific language governing permissions and
  24. // limitations under the License.
  25. package predicates
  26. import (
  27. "context"
  28. "fmt"
  29. "sort"
  30. "strings"
  31. "sync"
  32. "golang.org/x/sync/errgroup"
  33. "yunion.io/x/jsonutils"
  34. "yunion.io/x/log"
  35. "yunion.io/x/pkg/gotypes"
  36. "yunion.io/x/pkg/util/errors"
  37. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  38. "yunion.io/x/onecloud/pkg/compute/models"
  39. "yunion.io/x/onecloud/pkg/scheduler/algorithm/plugin"
  40. "yunion.io/x/onecloud/pkg/scheduler/api"
  41. "yunion.io/x/onecloud/pkg/scheduler/core"
  42. "yunion.io/x/onecloud/pkg/scheduler/core/score"
  43. "yunion.io/x/onecloud/pkg/scheduler/data_manager/schedtag"
  44. )
  45. // BasePredicate is a default struct for all the predicates that will
  46. // include it and implement it's Name() and PreExecute() methods.
  47. type BasePredicate struct{}
  48. func (b *BasePredicate) Name() string {
  49. return "base_predicate_should_not_be_called"
  50. }
  51. func (b *BasePredicate) PreExecute(ctx context.Context, unit *core.Unit, candis []core.Candidater) (bool, error) {
  52. return true, nil
  53. }
  54. func (b *BasePredicate) GetHypervisorDriver(u *core.Unit) models.IGuestDriver {
  55. hypervisor := u.GetHypervisor()
  56. driver, _ := models.GetDriver(hypervisor, u.SchedInfo.Provider)
  57. return driver
  58. }
  59. type PredicateHelper struct {
  60. predicate core.FitPredicate
  61. predicateFails []core.PredicateFailureReason
  62. capacity int64
  63. Unit *core.Unit
  64. Candidate core.Candidater
  65. }
  66. func (h *PredicateHelper) getResult() (bool, []core.PredicateFailureReason, error) {
  67. if len(h.predicateFails) > 0 {
  68. return false, h.predicateFails, nil
  69. }
  70. if h.capacity == 0 {
  71. return false, []core.PredicateFailureReason{}, nil
  72. }
  73. return true, nil, nil
  74. }
  75. func (h *PredicateHelper) GetResult() (bool, []core.PredicateFailureReason, error) {
  76. ok, reasons, err := h.getResult()
  77. if !ok {
  78. log.Warningf("[Filter Result] candidate: %q, filter: %q, is_ok: %v, reason: %q, error: %v\n",
  79. h.Candidate.IndexKey(), h.predicate.Name(), ok, getReasonsString(reasons), err)
  80. }
  81. return ok, reasons, err
  82. }
  83. func getReasonsString(reasons []core.PredicateFailureReason) string {
  84. if len(reasons) == 0 {
  85. return ""
  86. }
  87. ss := make([]string, 0, len(reasons))
  88. for _, reason := range reasons {
  89. ss = append(ss, reason.GetReason())
  90. }
  91. return strings.Join(ss, ", ")
  92. }
  93. func NewPredicateHelper(pre core.FitPredicate, unit *core.Unit, candi core.Candidater) *PredicateHelper {
  94. h := &PredicateHelper{
  95. predicate: pre,
  96. capacity: core.EmptyCapacity,
  97. predicateFails: []core.PredicateFailureReason{},
  98. Unit: unit,
  99. Candidate: candi,
  100. }
  101. return h
  102. }
  103. func (h *PredicateHelper) GetFailedResult(err error) (bool, []core.PredicateFailureReason, error) {
  104. return false, nil, err
  105. }
  106. func (h *PredicateHelper) AppendPredicateFail(reason core.PredicateFailureReason) {
  107. h.predicateFails = append(h.predicateFails, reason)
  108. }
  109. type predicateFailure struct {
  110. err core.PredicateFailureError
  111. eType string
  112. }
  113. func (f predicateFailure) GetReason() string {
  114. return f.err.GetReason()
  115. }
  116. func (f predicateFailure) GetType() string {
  117. return f.eType
  118. }
  119. func (h *PredicateHelper) AppendPredicateFailMsg(reason string) {
  120. h.AppendPredicateFailMsgWithType(reason, h.predicate.Name())
  121. }
  122. func (h *PredicateHelper) AppendPredicateFailMsgWithType(reason string, eType string) {
  123. err := NewUnexceptedResourceError(reason)
  124. h.AppendPredicateFail(&predicateFailure{err: err, eType: eType})
  125. }
  126. func (h *PredicateHelper) AppendInsufficientResourceError(req, total, free int64) {
  127. h.AppendPredicateFail(
  128. &predicateFailure{
  129. err: NewInsufficientResourceError(h.Candidate.Getter().Name(), req, total, free),
  130. eType: h.predicate.Name(),
  131. })
  132. }
  133. // SetCapacity returns the current resource capacity calculated by a filter.
  134. // And 'capacity' default is -1.
  135. func (h *PredicateHelper) SetCapacity(capacity int64) {
  136. if capacity < 0 {
  137. capacity = 0
  138. }
  139. h.SetCapacityCounter(core.NewNormalCounter(capacity))
  140. }
  141. func (h *PredicateHelper) SetCapacityCounter(counter core.Counter) {
  142. capacity := counter.GetCount()
  143. if capacity < core.EmptyCapacity {
  144. capacity = core.EmptyCapacity
  145. }
  146. h.capacity = capacity
  147. h.Unit.SetCapacity(h.Candidate.IndexKey(), h.predicate.Name(), counter)
  148. }
  149. func (h *PredicateHelper) SetSelectPriority(sp int) {
  150. if sp < 0 {
  151. sp = 0
  152. }
  153. h.Unit.SetSelectPriorityWithLock(h.Candidate.IndexKey(), h.predicate.Name(), core.SSelectPriorityValue(sp))
  154. }
  155. func (h *PredicateHelper) Exclude(reason string) {
  156. h.SetCapacity(0)
  157. h.AppendPredicateFailMsg(reason)
  158. }
  159. func (h *PredicateHelper) ExcludeByErrors(errs []core.PredicateFailureReason) {
  160. h.SetCapacity(0)
  161. for _, err := range errs {
  162. h.AppendPredicateFail(err)
  163. }
  164. }
  165. func (h *PredicateHelper) Exclude2(predicateName string, current, expected interface{}) {
  166. h.Exclude(fmt.Sprintf("%s is '%v', expected '%v'", predicateName, current, expected))
  167. }
  168. // UseReserved check whether the unit can use guest reserved resource
  169. func (h *PredicateHelper) UseReserved() bool {
  170. usable := false
  171. data := h.Unit.SchedData()
  172. isoDevs := data.IsolatedDevices
  173. if len(isoDevs) > 0 || (data.ChangeConfig && data.HasIsolatedDevice) {
  174. usable = true
  175. }
  176. return usable
  177. }
  178. type PredicatedSchedtagResource struct {
  179. ISchedtagCandidateResource
  180. PreferTags []computeapi.SchedtagConfig
  181. AvoidTags []computeapi.SchedtagConfig
  182. }
  183. type SchedtagInputResourcesMap map[int][]*PredicatedSchedtagResource
  184. func (m SchedtagInputResourcesMap) getAllTags(isPrefer bool) []computeapi.SchedtagConfig {
  185. ret := make([]computeapi.SchedtagConfig, 0)
  186. for _, ss := range m {
  187. for _, s := range ss {
  188. var tags []computeapi.SchedtagConfig
  189. if isPrefer {
  190. tags = s.PreferTags
  191. } else {
  192. tags = s.AvoidTags
  193. }
  194. ret = append(ret, tags...)
  195. }
  196. }
  197. return ret
  198. }
  199. func (m SchedtagInputResourcesMap) GetPreferTags() []computeapi.SchedtagConfig {
  200. return m.getAllTags(true)
  201. }
  202. func (m SchedtagInputResourcesMap) GetAvoidTags() []computeapi.SchedtagConfig {
  203. return m.getAllTags(false)
  204. }
  205. type CandidateInputResourcesMap struct {
  206. *sync.Map // map[string]SchedtagInputResourcesMap
  207. }
  208. type ISchedtagCandidateResource interface {
  209. GetName() string
  210. GetId() string
  211. Keyword() string
  212. // GetSchedtags() []models.SSchedtag
  213. GetSchedtagJointManager() models.ISchedtagJointManager
  214. GetDynamicConditionInput() *jsonutils.JSONDict
  215. }
  216. type ISchedtagPredicateInstance interface {
  217. core.FitPredicate
  218. OnPriorityEnd(u *core.Unit, c core.Candidater)
  219. OnSelectEnd(u *core.Unit, c core.Candidater, count int64)
  220. GetInputs(u *core.Unit) []ISchedtagCustomer
  221. GetResources(c core.Candidater) []ISchedtagCandidateResource
  222. IsResourceMatchInput(ctx context.Context, input ISchedtagCustomer, res ISchedtagCandidateResource) bool
  223. IsResourceFitInput(ctx context.Context, unit *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) core.PredicateFailureReason
  224. DoSelect(c core.Candidater, input ISchedtagCustomer, res []ISchedtagCandidateResource) []ISchedtagCandidateResource
  225. AddSelectResult(index int, input ISchedtagCustomer, selectRes []ISchedtagCandidateResource, output *core.AllocatedResource)
  226. GetCandidateResourceSortScore(candidate ISchedtagCandidateResource) int64
  227. }
  228. // Schedtag Description
  229. // require: Must be scheduled to the specified tag resource
  230. // prefer: Priority to the specified resource
  231. // avoid: Try to avoid scheduling to the specified resource
  232. // exclude: Do not allow scheduling on the specified resource
  233. type BaseSchedtagPredicate struct {
  234. BasePredicate
  235. plugin.BasePlugin
  236. CandidateInputResources *CandidateInputResourcesMap
  237. Hypervisor string
  238. Provider string
  239. }
  240. func NewBaseSchedtagPredicate() *BaseSchedtagPredicate {
  241. return &BaseSchedtagPredicate{
  242. CandidateInputResources: &CandidateInputResourcesMap{Map: new(sync.Map)}, // make(map[string]SchedtagInputResourcesMap),
  243. }
  244. }
  245. func (p *PredicatedSchedtagResource) isNoTag() bool {
  246. return len(p.PreferTags) == 0 && len(p.AvoidTags) == 0
  247. }
  248. func (p *PredicatedSchedtagResource) hasPreferTags() bool {
  249. return len(p.PreferTags) != 0
  250. }
  251. func (p *PredicatedSchedtagResource) hasAvoidTags() bool {
  252. return len(p.AvoidTags) != 0
  253. }
  254. type ISchedtagCustomer interface {
  255. // JSON(interface{}) *jsonutils.JSONDict
  256. GetDynamicConditionInput() *jsonutils.JSONDict
  257. Keyword() string
  258. IsSpecifyResource() bool
  259. GetSchedtags() []*computeapi.SchedtagConfig
  260. ResourceKeyword() string
  261. }
  262. type SchedtagResourceW struct {
  263. candidater ISchedtagCandidateResource
  264. input ISchedtagCustomer
  265. }
  266. func (w SchedtagResourceW) GetId() string {
  267. return w.candidater.GetId()
  268. }
  269. func (w SchedtagResourceW) IndexKey() string {
  270. return fmt.Sprintf("%s:%s", w.candidater.GetName(), w.candidater.GetId())
  271. }
  272. func (w SchedtagResourceW) ResourceType() string {
  273. return getSchedtagResourceType(w.candidater)
  274. }
  275. func getSchedtagResourceType(candidater ISchedtagCandidateResource) string {
  276. return candidater.GetSchedtagJointManager().GetMasterManager().KeywordPlural()
  277. }
  278. func (w SchedtagResourceW) GetSchedtags() []schedtag.ISchedtag {
  279. return schedtag.GetCandidateSchedtags(w.ResourceType(), w.candidater.GetId())
  280. }
  281. func (w SchedtagResourceW) GetDynamicSchedDesc() *jsonutils.JSONDict {
  282. ret := jsonutils.NewDict()
  283. resSchedDesc := w.candidater.GetDynamicConditionInput()
  284. inputSchedDesc := w.input.GetDynamicConditionInput()
  285. ret.Add(resSchedDesc, w.candidater.Keyword())
  286. ret.Add(inputSchedDesc, w.input.Keyword())
  287. return ret
  288. }
  289. func (p *BaseSchedtagPredicate) GetHypervisorDriver() models.IGuestDriver {
  290. hypervisor := p.Hypervisor
  291. if hypervisor == api.HostHypervisorForKvm {
  292. hypervisor = api.SchedTypeKvm
  293. }
  294. driver, _ := models.GetDriver(hypervisor, p.Provider)
  295. return driver
  296. }
  297. func (p *BaseSchedtagPredicate) check(input ISchedtagCustomer, candidate ISchedtagCandidateResource, u *core.Unit, c core.Candidater, allTags []schedtag.ISchedtag) (*PredicatedSchedtagResource, error) {
  298. // allTags, err := GetAllSchedtags(getSchedtagResourceType(candidate))
  299. // sMan, err := schedtag.GetSessionManager(u.SessionID())
  300. // if err != nil {
  301. // return nil, err
  302. // }
  303. tagPredicate := NewSchedtagPredicate(input.GetSchedtags(), allTags)
  304. res := &PredicatedSchedtagResource{
  305. ISchedtagCandidateResource: candidate,
  306. }
  307. if !input.IsSpecifyResource() {
  308. if err := tagPredicate.Check(
  309. SchedtagResourceW{
  310. candidater: candidate,
  311. input: input,
  312. },
  313. ); err != nil {
  314. return nil, err
  315. }
  316. res.PreferTags = tagPredicate.GetPreferTags()
  317. res.AvoidTags = tagPredicate.GetAvoidTags()
  318. }
  319. return res, nil
  320. }
  321. func (p *BaseSchedtagPredicate) checkResources(input ISchedtagCustomer, ress []ISchedtagCandidateResource, u *core.Unit, c core.Candidater, allTags []schedtag.ISchedtag) ([]*PredicatedSchedtagResource, error) {
  322. errs := make([]error, len(ress))
  323. ret := make([]*PredicatedSchedtagResource, len(ress))
  324. errGrp := errgroup.Group{}
  325. for i := range ress {
  326. res := ress[i]
  327. errGrp.Go(func() error {
  328. ps, err := p.check(input, res, u, c, allTags)
  329. if err != nil {
  330. // append err, resource not suit input customer
  331. errs[i] = err
  332. } else {
  333. ret[i] = ps
  334. }
  335. return nil
  336. })
  337. }
  338. if err := errGrp.Wait(); err != nil {
  339. return nil, fmt.Errorf("errGrp.Wait: %v", err)
  340. }
  341. newRet := make([]*PredicatedSchedtagResource, 0)
  342. newErrs := make([]error, 0)
  343. for i := range ress {
  344. if ps := ret[i]; ps != nil {
  345. newRet = append(newRet, ps)
  346. } else {
  347. newErrs = append(newErrs, errs[i])
  348. }
  349. }
  350. if len(newRet) == 0 {
  351. return nil, errors.NewAggregate(newErrs)
  352. }
  353. return newRet, nil
  354. }
  355. func (p *BaseSchedtagPredicate) GetInputResourcesMap(candidateId string) SchedtagInputResourcesMap {
  356. ret, ok := p.CandidateInputResources.Load(candidateId)
  357. if !ok {
  358. ret = make(map[int][]*PredicatedSchedtagResource)
  359. p.CandidateInputResources.Store(candidateId, ret)
  360. }
  361. return ret.(map[int][]*PredicatedSchedtagResource)
  362. }
  363. func (p *BaseSchedtagPredicate) PreExecute(ctx context.Context, sp ISchedtagPredicateInstance, u *core.Unit, cs []core.Candidater) (bool, error) {
  364. input := sp.GetInputs(u)
  365. if len(input) == 0 {
  366. return false, nil
  367. }
  368. if u.SchedData().ResetCpuNumaPin {
  369. return false, nil
  370. }
  371. p.Hypervisor = u.GetHypervisor()
  372. p.Provider = u.SchedInfo.Provider
  373. // always do select step
  374. u.AppendSelectPlugin(sp)
  375. return true, nil
  376. }
  377. func (p *BaseSchedtagPredicate) Execute(
  378. ctx context.Context,
  379. sp ISchedtagPredicateInstance,
  380. u *core.Unit,
  381. c core.Candidater,
  382. ) (bool, []core.PredicateFailureReason, error) {
  383. //inputTime := time.Now()
  384. inputs := sp.GetInputs(u)
  385. resources := sp.GetResources(c)
  386. //log.Infof("=======%s get input time: %s, inputs: %s", sp.Name(), time.Since(inputTime), jsonutils.Marshal(inputs))
  387. h := NewPredicateHelper(sp, u, c)
  388. inputRes := p.GetInputResourcesMap(c.IndexKey())
  389. filterErrs := make([]core.PredicateFailureReason, 0)
  390. for idx, input := range inputs {
  391. fitResources := make([]ISchedtagCandidateResource, 0)
  392. errs := make([]core.PredicateFailureReason, 0)
  393. matchedRes := make([]ISchedtagCandidateResource, 0)
  394. for _, r := range resources {
  395. if sp.IsResourceMatchInput(ctx, input, r) {
  396. matchedRes = append(matchedRes, r)
  397. }
  398. }
  399. if len(matchedRes) == 0 {
  400. errs = append(errs, &FailReason{
  401. Reason: fmt.Sprintf("Not found matched %s, candidate: %s, %s: %s", input.ResourceKeyword(), c.Getter().Name(), input.Keyword(), input.GetDynamicConditionInput()),
  402. Type: fmt.Sprintf("%s_match", input.ResourceKeyword()),
  403. })
  404. }
  405. for _, res := range matchedRes {
  406. if err := sp.IsResourceFitInput(ctx, u, c, res, input); err == nil {
  407. fitResources = append(fitResources, res)
  408. } else {
  409. errs = append(errs, err)
  410. }
  411. }
  412. if len(fitResources) == 0 {
  413. h.ExcludeByErrors(errs)
  414. break
  415. }
  416. if len(errs) > 0 {
  417. filterErrs = append(filterErrs, errs...)
  418. }
  419. allTags, err := schedtag.GetAllSchedtags(getSchedtagResourceType(fitResources[0]))
  420. if err != nil {
  421. h.Exclude(fmt.Sprintf("get all schedtags"))
  422. break
  423. }
  424. //checkTime := time.Now()
  425. matchedResources, err := p.checkResources(input, fitResources, u, c, allTags)
  426. //log.Infof("---%s checkResources time: %s", sp.Name(), time.Since(checkTime))
  427. if err != nil {
  428. if len(filterErrs) > 0 {
  429. h.ExcludeByErrors(filterErrs)
  430. }
  431. errMsg := fmt.Sprintf("schedtag: %v", err.Error())
  432. h.Exclude(errMsg)
  433. }
  434. inputRes[idx] = matchedResources
  435. }
  436. //log.Infof("=======%s get execute time: %s", sp.Name(), time.Since(inputTime))
  437. return h.GetResult()
  438. }
  439. func SetCandidateScoreBySchedtag(u *core.Unit, c core.Candidater, aggCountMap map[string]int, prefer bool) {
  440. stepScore := core.PriorityStep
  441. doSet := u.SetPreferScore
  442. if !prefer {
  443. doSet = u.SetAvoidScore
  444. }
  445. for n, count := range aggCountMap {
  446. doSet(c.IndexKey(), score.NewScore(score.TScore(count*stepScore), n))
  447. }
  448. }
  449. func (p *BaseSchedtagPredicate) OnPriorityEnd(sp ISchedtagPredicateInstance, u *core.Unit, c core.Candidater) {
  450. resTags := []schedtag.ISchedtag{}
  451. // sessionMan, err := schedtag.GetSessionManager(u.SessionID())
  452. // if err != nil {
  453. // // should not happended
  454. // panic(fmt.Sprintf("GetSessionManager(%q) error: %v", u.SessionID(), err))
  455. // }
  456. for _, res := range sp.GetResources(c) {
  457. resType := getSchedtagResourceType(res)
  458. tags := schedtag.GetCandidateSchedtags(resType, res.GetId())
  459. resTags = append(resTags, tags...)
  460. }
  461. inputRes := p.GetInputResourcesMap(c.IndexKey())
  462. avoidTags := inputRes.GetAvoidTags()
  463. preferTags := inputRes.GetPreferTags()
  464. avoidCountMap := GetSchedtagCount(avoidTags, resTags, api.AggregateStrategyAvoid)
  465. preferCountMap := GetSchedtagCount(preferTags, resTags, api.AggregateStrategyPrefer)
  466. setScore := SetCandidateScoreBySchedtag
  467. setScore(u, c, preferCountMap, true)
  468. setScore(u, c, avoidCountMap, false)
  469. }
  470. func (p *BaseSchedtagPredicate) OnSelectEnd(sp ISchedtagPredicateInstance, u *core.Unit, c core.Candidater, count int64) {
  471. inputRes := p.GetInputResourcesMap(c.IndexKey())
  472. output := u.GetAllocatedResource(c.IndexKey())
  473. inputs := sp.GetInputs(u)
  474. idxKeys := []int{}
  475. // inputRes is unorder map, sorted it
  476. for idx := range inputRes {
  477. idxKeys = append(idxKeys, idx)
  478. }
  479. sort.Ints(idxKeys)
  480. for idx := range idxKeys {
  481. res := inputRes[idx]
  482. selRes := p.selectResource(sp, c, inputs[idx], res)
  483. sortRes := newSortCandidateResource(sp, selRes)
  484. sort.Sort(sortRes)
  485. sp.AddSelectResult(idx, inputs[idx], sortRes.res, output)
  486. }
  487. }
  488. type sortCandidateResource struct {
  489. predicate ISchedtagPredicateInstance
  490. res []ISchedtagCandidateResource
  491. }
  492. func newSortCandidateResource(predicate ISchedtagPredicateInstance, res []ISchedtagCandidateResource) *sortCandidateResource {
  493. return &sortCandidateResource{
  494. predicate: predicate,
  495. res: res,
  496. }
  497. }
  498. func (s *sortCandidateResource) Len() int {
  499. return len(s.res)
  500. }
  501. func (s *sortCandidateResource) DebugString() string {
  502. var debugStr string
  503. for _, i := range s.res {
  504. debugStr = fmt.Sprintf("%s %d", debugStr, s.predicate.GetCandidateResourceSortScore(i))
  505. }
  506. return debugStr
  507. }
  508. // desc order
  509. func (s *sortCandidateResource) Less(i, j int) bool {
  510. res1, res2 := s.res[i], s.res[j]
  511. v1 := s.predicate.GetCandidateResourceSortScore(res1)
  512. v2 := s.predicate.GetCandidateResourceSortScore(res2)
  513. return v1 > v2
  514. }
  515. func (s *sortCandidateResource) Swap(i, j int) {
  516. s.res[i], s.res[j] = s.res[j], s.res[i]
  517. }
  518. func (p *BaseSchedtagPredicate) selectResource(
  519. sp ISchedtagPredicateInstance,
  520. c core.Candidater,
  521. input ISchedtagCustomer,
  522. ress []*PredicatedSchedtagResource,
  523. ) []ISchedtagCandidateResource {
  524. preferRes := make([]ISchedtagCandidateResource, 0)
  525. noTagRes := make([]ISchedtagCandidateResource, 0)
  526. avoidRes := make([]ISchedtagCandidateResource, 0)
  527. for _, res := range ress {
  528. if res.isNoTag() {
  529. noTagRes = append(noTagRes, res.ISchedtagCandidateResource)
  530. } else if res.hasPreferTags() {
  531. preferRes = append(preferRes, res.ISchedtagCandidateResource)
  532. } else if res.hasAvoidTags() {
  533. avoidRes = append(avoidRes, res.ISchedtagCandidateResource)
  534. }
  535. }
  536. for _, ress := range [][]ISchedtagCandidateResource{
  537. preferRes,
  538. noTagRes,
  539. avoidRes,
  540. } {
  541. if len(ress) == 0 {
  542. continue
  543. }
  544. if ret := sp.DoSelect(c, input, ress); ret != nil {
  545. return ret
  546. }
  547. }
  548. return nil
  549. }
  550. type iServerBaseSchedtagPredicate interface {
  551. ISchedtagPredicateInstance
  552. GetCandidateResource(core.Candidater) ISchedtagCandidateResource
  553. }
  554. type ServerBaseSchedtagPredicate struct {
  555. *BaseSchedtagPredicate
  556. filter iServerBaseSchedtagPredicate
  557. }
  558. func NewServerBaseSchedtagPredicate(filter iServerBaseSchedtagPredicate) *ServerBaseSchedtagPredicate {
  559. return &ServerBaseSchedtagPredicate{
  560. BaseSchedtagPredicate: NewBaseSchedtagPredicate(),
  561. filter: filter,
  562. }
  563. }
  564. func (p *ServerBaseSchedtagPredicate) PreExecute(ctx context.Context, u *core.Unit, cs []core.Candidater) (bool, error) {
  565. return p.BaseSchedtagPredicate.PreExecute(ctx, p.filter, u, cs)
  566. }
  567. func (p *ServerBaseSchedtagPredicate) Execute(ctx context.Context, u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
  568. return p.BaseSchedtagPredicate.Execute(ctx, p.filter, u, c)
  569. }
  570. func (p *ServerBaseSchedtagPredicate) GetResources(c core.Candidater) []ISchedtagCandidateResource {
  571. res := p.filter.GetCandidateResource(c)
  572. if res == nil || gotypes.IsNil(res) {
  573. return nil
  574. }
  575. return []ISchedtagCandidateResource{
  576. res,
  577. }
  578. }
  579. func (p *ServerBaseSchedtagPredicate) IsResourceMatchInput(ctx context.Context, input ISchedtagCustomer, res ISchedtagCandidateResource) bool {
  580. return true
  581. }
  582. func (p *ServerBaseSchedtagPredicate) IsResourceFitInput(ctx context.Context, u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) core.PredicateFailureReason {
  583. return nil
  584. }
  585. func (p *ServerBaseSchedtagPredicate) DoSelect(
  586. c core.Candidater,
  587. input ISchedtagCustomer,
  588. res []ISchedtagCandidateResource,
  589. ) []ISchedtagCandidateResource {
  590. return res
  591. }
  592. func (p *ServerBaseSchedtagPredicate) AddSelectResult(index int, input ISchedtagCustomer, selectRes []ISchedtagCandidateResource, output *core.AllocatedResource) {
  593. // resource is host, do nothing
  594. }
  595. func (p *ServerBaseSchedtagPredicate) GetCandidateResourceSortScore(selectRes ISchedtagCandidateResource) int64 {
  596. // TODO
  597. return 1
  598. }
  599. func (p *ServerBaseSchedtagPredicate) OnPriorityEnd(u *core.Unit, c core.Candidater) {
  600. p.BaseSchedtagPredicate.OnPriorityEnd(p.filter, u, c)
  601. }
  602. func (p *ServerBaseSchedtagPredicate) OnSelectEnd(u *core.Unit, c core.Candidater, count int64) {
  603. p.BaseSchedtagPredicate.OnSelectEnd(p.filter, u, c, count)
  604. }