context.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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. package core
  15. import (
  16. "fmt"
  17. "sort"
  18. "strings"
  19. "sync"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/tristate"
  22. "yunion.io/x/onecloud/pkg/compute/models"
  23. "yunion.io/x/onecloud/pkg/scheduler/api"
  24. "yunion.io/x/onecloud/pkg/scheduler/core/score"
  25. )
  26. const (
  27. EmptyCapacity int64 = -1
  28. MaxCapacity int64 = 0x7FFFFFFFFFFFFFFF
  29. )
  30. var (
  31. EmptyCapacities = make(map[string]Counter)
  32. EmptySelectPriorityValue = SSelectPriorityValue(0)
  33. )
  34. type SharedResourceManager struct {
  35. resourceMap map[string]Counter
  36. lock sync.Mutex
  37. }
  38. func NewSharedResourceManager() *SharedResourceManager {
  39. return &SharedResourceManager{
  40. lock: sync.Mutex{},
  41. resourceMap: make(map[string]Counter),
  42. }
  43. }
  44. func (m *SharedResourceManager) Add(resourceKey string, capacity Counter) {
  45. m.lock.Lock()
  46. defer m.lock.Unlock()
  47. m.resourceMap[resourceKey] = capacity
  48. }
  49. type CounterManager struct {
  50. Counters map[string]Counter
  51. lock sync.Mutex
  52. }
  53. func NewCounterManager() *CounterManager {
  54. return &CounterManager{
  55. Counters: make(map[string]Counter),
  56. lock: sync.Mutex{},
  57. }
  58. }
  59. func (m *CounterManager) Get(key string) Counter {
  60. m.lock.Lock()
  61. defer m.lock.Unlock()
  62. if counter, ok := m.Counters[key]; ok {
  63. return counter
  64. }
  65. return nil
  66. }
  67. func (m *CounterManager) GetOrCreate(key string, creator func() Counter) Counter {
  68. m.lock.Lock()
  69. defer m.lock.Unlock()
  70. if counter, ok := m.Counters[key]; ok {
  71. return counter
  72. }
  73. counter := creator()
  74. if counter == nil {
  75. return nil
  76. }
  77. m.Counters[key] = counter
  78. return counter
  79. }
  80. type Counter interface {
  81. GetCount() int64
  82. }
  83. type MultiCounter interface {
  84. Counter
  85. Add(counter Counter)
  86. }
  87. type NormalCounter struct {
  88. Value int64
  89. }
  90. func NewNormalCounter(value int64) *NormalCounter {
  91. return &NormalCounter{
  92. Value: value,
  93. }
  94. }
  95. func (c *NormalCounter) GetCount() int64 {
  96. return c.Value
  97. }
  98. type Counters struct {
  99. counters []Counter
  100. lock sync.Mutex
  101. sum int64
  102. }
  103. func NewCounters() *Counters {
  104. return &Counters{
  105. sum: EmptyCapacity,
  106. lock: sync.Mutex{},
  107. }
  108. }
  109. func (c *Counters) Add(cnt Counter) {
  110. c.lock.Lock()
  111. defer c.lock.Unlock()
  112. c.counters = append(c.counters, cnt)
  113. c.sum = EmptyCapacity
  114. }
  115. func (c *Counters) GetCount() int64 {
  116. if c.sum == EmptyCapacity {
  117. c.sum = c.calculateCount()
  118. }
  119. return c.sum
  120. }
  121. func (c *Counters) calculateCount() int64 {
  122. if len(c.counters) == 0 {
  123. return 0
  124. }
  125. c.lock.Lock()
  126. defer c.lock.Unlock()
  127. value := int64(0)
  128. for _, c := range c.counters {
  129. count := c.GetCount()
  130. if count != EmptyCapacity {
  131. value += c.GetCount()
  132. }
  133. }
  134. return value
  135. }
  136. type MinCounters struct {
  137. counters []Counter
  138. }
  139. func NewMinCounters() *MinCounters {
  140. return &MinCounters{}
  141. }
  142. func (c *MinCounters) Add(counter Counter) {
  143. c.counters = append(c.counters, counter)
  144. }
  145. func (c *MinCounters) GetCount() int64 {
  146. if len(c.counters) == 0 {
  147. return EmptyCapacity
  148. }
  149. minCount := c.counters[0].GetCount()
  150. if len(c.counters) == 1 {
  151. return minCount
  152. }
  153. for _, c0 := range c.counters[1:] {
  154. count := c0.GetCount()
  155. if count < minCount {
  156. minCount = count
  157. }
  158. }
  159. return minCount
  160. }
  161. type Capacity struct {
  162. Values map[string]Counter
  163. MinValue int64
  164. }
  165. type Score struct {
  166. *score.ScoreBucket
  167. }
  168. func newScore() *Score {
  169. return &Score{
  170. ScoreBucket: score.NewScoreBuckets(),
  171. }
  172. }
  173. func newZeroScore() Score {
  174. s := newScore()
  175. s.SetScore(score.NewZeroScore(), tristate.None)
  176. return *s
  177. }
  178. type SchedContextDataItem struct {
  179. Networks *sync.Map
  180. Data map[string]interface{}
  181. }
  182. type LogMessage struct {
  183. Type string
  184. Info string
  185. }
  186. type LogMessages []*LogMessage
  187. func (ms LogMessages) String() string {
  188. ss := make([]string, 0)
  189. for _, s := range ms {
  190. ss = append(ss, fmt.Sprintf("%s: %s", s.Type, s.Info))
  191. }
  192. return strings.Join(ss, ",")
  193. }
  194. type SchedLog struct {
  195. Candidate string
  196. Action string
  197. Messages LogMessages
  198. IsFailed bool
  199. }
  200. func NewSchedLog(candidate, action string, messages LogMessages, isFailed bool) SchedLog {
  201. return SchedLog{candidate, action, messages, isFailed}
  202. }
  203. func (log *SchedLog) String() string {
  204. prefix := "Success"
  205. if log.IsFailed {
  206. prefix = "Failed"
  207. }
  208. return fmt.Sprintf("%s: %v [%v] %v", prefix, log.Candidate, log.Action, log.Messages.String())
  209. }
  210. type SchedLogList []SchedLog
  211. func (logList SchedLogList) Get(index string) *SchedLog {
  212. for _, l := range logList {
  213. if l.Candidate == index {
  214. return &l
  215. }
  216. }
  217. return nil
  218. }
  219. func (logList SchedLogList) Len() int {
  220. return len(logList)
  221. }
  222. func (logList SchedLogList) Less(i, j int) bool {
  223. r := strings.Compare(logList[i].Candidate, logList[j].Candidate)
  224. if r != 0 {
  225. return r < 0
  226. }
  227. r = strings.Compare(logList[i].Messages.String(), logList[j].Messages.String())
  228. if r != 0 {
  229. return r < 0
  230. }
  231. return strings.Compare(logList[i].Action, logList[j].Action) < 0
  232. }
  233. func (logList SchedLogList) Swap(i, j int) {
  234. logList[i], logList[j] = logList[j], logList[i]
  235. }
  236. type SchedLogManager struct {
  237. Logs SchedLogList
  238. lock sync.Mutex
  239. sorted bool
  240. }
  241. func NewSchedLogManager() *SchedLogManager {
  242. return &SchedLogManager{
  243. lock: sync.Mutex{},
  244. Logs: SchedLogList{},
  245. }
  246. }
  247. /*func (m *SchedLogManager) Append(candidate, action, message string, isFailed bool) {
  248. m.lock.Lock()
  249. defer m.lock.Unlock()
  250. m.Logs = append(m.Logs, NewSchedLog(candidate, action, message, isFailed))
  251. }*/
  252. func (m *SchedLogManager) Appends(logs []SchedLog) {
  253. m.lock.Lock()
  254. defer m.lock.Unlock()
  255. m.Logs = append(m.Logs, logs...)
  256. }
  257. func (m *SchedLogManager) FailedLogs() SchedLogList {
  258. var logs SchedLogList
  259. for _, l := range m.Logs {
  260. if l.IsFailed {
  261. logs = append(logs, l)
  262. }
  263. }
  264. return logs
  265. }
  266. func (m *SchedLogManager) Read() []string {
  267. rets := []string{}
  268. m.lock.Lock()
  269. defer m.lock.Unlock()
  270. if len(m.Logs) == 0 {
  271. return rets
  272. }
  273. if !m.sorted {
  274. sort.Sort(m.Logs)
  275. m.sorted = true
  276. }
  277. joinLogs := func(startIndex, endIndex int) string {
  278. if endIndex == startIndex+1 {
  279. return m.Logs[startIndex].String()
  280. }
  281. log := m.Logs[startIndex]
  282. actions := []string{}
  283. var isFailed bool
  284. for ; startIndex < endIndex; startIndex++ {
  285. actions = append(actions, m.Logs[startIndex].Action)
  286. if m.Logs[startIndex].IsFailed {
  287. isFailed = true
  288. }
  289. }
  290. newLog := NewSchedLog(log.Candidate, strings.Join(actions, ","), log.Messages, isFailed)
  291. return newLog.String()
  292. }
  293. startIndex := -1
  294. for index, len := 0, len(m.Logs); index < len; index++ {
  295. if startIndex < 0 {
  296. startIndex = index
  297. } else {
  298. log0, log := m.Logs[startIndex], m.Logs[index]
  299. if log0.Candidate != log.Candidate || log0.Messages.String() != log.Messages.String() {
  300. rets = append(rets, joinLogs(startIndex, index))
  301. startIndex = index
  302. }
  303. }
  304. }
  305. rets = append(rets, joinLogs(startIndex, len(m.Logs)))
  306. return rets
  307. }
  308. // Unit wraps sched input info and other log and record manager
  309. type Unit struct {
  310. SchedInfo *api.SchedInfo
  311. CapacityMap map[string]*Capacity
  312. ScoreMap map[string]Score
  313. DataMap map[string]*SchedContextDataItem
  314. SharedResourceManager *SharedResourceManager
  315. CounterManager *CounterManager
  316. capacityLock sync.Mutex
  317. scoreLock sync.Mutex
  318. FailedCandidateMap map[string]*FailedCandidates
  319. failedCandidateMapLock sync.Mutex
  320. //ScoreMap map[string]Score
  321. //LogManager *LogManager
  322. //ReservedPool *data_manager.ReservedPool
  323. SchedulerManager interface{}
  324. selectPlugins []SelectPlugin
  325. LogManager *SchedLogManager
  326. AllocatedResources map[string]*AllocatedResource
  327. SelectPriorityMap map[string]SSelectPriority
  328. SelectPriorityUpdaterMap map[string]SSelectPriorityUpdater
  329. SelectPriorityLock sync.Mutex
  330. }
  331. func NewScheduleUnit(info *api.SchedInfo, schedManager interface{}) *Unit {
  332. cmap := make(map[string]*Capacity) // candidate_id, Capacity
  333. smap := make(map[string]Score) // candidate_id, Score
  334. spmap := make(map[string]SSelectPriority)
  335. spumap := make(map[string]SSelectPriorityUpdater)
  336. unit := &Unit{
  337. SchedInfo: info,
  338. FailedCandidateMap: make(map[string]*FailedCandidates),
  339. failedCandidateMapLock: sync.Mutex{},
  340. CapacityMap: cmap,
  341. ScoreMap: smap,
  342. capacityLock: sync.Mutex{},
  343. scoreLock: sync.Mutex{},
  344. DataMap: make(map[string]*SchedContextDataItem),
  345. SharedResourceManager: NewSharedResourceManager(),
  346. CounterManager: NewCounterManager(),
  347. LogManager: NewSchedLogManager(),
  348. SchedulerManager: schedManager,
  349. AllocatedResources: make(map[string]*AllocatedResource),
  350. SelectPriorityMap: spmap,
  351. SelectPriorityUpdaterMap: spumap,
  352. }
  353. return unit
  354. }
  355. func (u *Unit) Info() string {
  356. return u.SchedInfo.JSON(u.SchedInfo).String()
  357. }
  358. func (u *Unit) SessionID() string {
  359. return u.SchedInfo.SessionId
  360. }
  361. func (u *Unit) SchedData() *api.SchedInfo {
  362. return u.SchedInfo
  363. }
  364. func (u *Unit) GetHypervisor() string {
  365. driver, _ := models.GetHostDriver(u.SchedInfo.Hypervisor, u.SchedInfo.Provider)
  366. if driver != nil {
  367. return driver.GetHypervisor()
  368. }
  369. return u.SchedData().Hypervisor
  370. }
  371. func (u *Unit) GetHypervisorDriver() models.IGuestDriver {
  372. hypervisor := u.GetHypervisor()
  373. driver, _ := models.GetDriver(hypervisor, u.SchedInfo.Provider)
  374. return driver
  375. }
  376. func (u *Unit) AppendFailedCandidates(fcs []FailedCandidate) {
  377. if len(fcs) == 0 {
  378. return
  379. }
  380. u.failedCandidateMapLock.Lock()
  381. defer u.failedCandidateMapLock.Unlock()
  382. for _, fc := range fcs {
  383. fcs, ok := u.FailedCandidateMap[fc.Stage]
  384. if !ok {
  385. fcs = &FailedCandidates{}
  386. u.FailedCandidateMap[fc.Stage] = fcs
  387. }
  388. fcs.Candidates = append(fcs.Candidates, fc)
  389. }
  390. }
  391. func (u *Unit) AppendSelectPlugin(p SelectPlugin) {
  392. u.selectPlugins = append(u.selectPlugins, p)
  393. }
  394. func (u *Unit) AllSelectPlugins() []SelectPlugin {
  395. return u.selectPlugins
  396. }
  397. func (u *Unit) GetCapacity(id string) int64 {
  398. var (
  399. capacityObj *Capacity
  400. ok bool
  401. )
  402. u.capacityLock.Lock()
  403. defer u.capacityLock.Unlock()
  404. if capacityObj, ok = u.CapacityMap[id]; !ok {
  405. return 0
  406. }
  407. if capacityObj.MinValue == EmptyCapacity {
  408. capacity := MaxCapacity
  409. for _, counter := range capacityObj.Values {
  410. count := counter.GetCount()
  411. if capacity > count {
  412. capacity = count
  413. }
  414. }
  415. capacityObj.MinValue = capacity
  416. }
  417. return capacityObj.MinValue
  418. }
  419. func (u *Unit) GetCapacityOfName(id string, name string) int64 {
  420. u.capacityLock.Lock()
  421. defer u.capacityLock.Unlock()
  422. if capacityObj, ok := u.CapacityMap[id]; ok {
  423. if counter, ok0 := capacityObj.Values[name]; ok0 {
  424. return counter.GetCount()
  425. }
  426. }
  427. return EmptyCapacity
  428. }
  429. func (u *Unit) GetCapacities(id string) map[string]Counter {
  430. if capacityObj, ok := u.CapacityMap[id]; ok {
  431. return capacityObj.Values
  432. }
  433. return EmptyCapacities
  434. }
  435. func (u *Unit) SetCapacity(id string, name string, capacity Counter) error {
  436. u.capacityLock.Lock()
  437. defer u.capacityLock.Unlock()
  438. // Capacity must >= -1
  439. if !validateCapacityInput(capacity) {
  440. err := fmt.Errorf("capacity counter %#v invalid %d", capacity, capacity.GetCount())
  441. log.Errorf("SetCapacity error: %v", err)
  442. return err
  443. }
  444. log.Debugf("%q setCapacity id: %s, capacity: %d", name, id, capacity.GetCount())
  445. var (
  446. capacityObj *Capacity
  447. ok bool
  448. )
  449. if capacityObj, ok = u.CapacityMap[id]; !ok {
  450. capacityObj = &Capacity{Values: make(map[string]Counter), MinValue: EmptyCapacity}
  451. u.CapacityMap[id] = capacityObj
  452. }
  453. capacityObj.Values[name] = capacity
  454. capacityObj.MinValue = EmptyCapacity
  455. return nil
  456. }
  457. func (u *Unit) GetSelectPriority(id string) SSelectPriorityValue {
  458. if sp, ok := u.SelectPriorityMap[id]; ok {
  459. return sp.Value()
  460. }
  461. return EmptySelectPriorityValue
  462. }
  463. func (u *Unit) SetSelectPriorityWithLock(id string, name string, spv SSelectPriorityValue) {
  464. u.SelectPriorityLock.Lock()
  465. defer u.SelectPriorityLock.Unlock()
  466. sp, ok := u.SelectPriorityMap[id]
  467. if !ok {
  468. sp = NewSSelctPriority()
  469. u.SelectPriorityMap[id] = sp
  470. }
  471. sp[name] = spv
  472. }
  473. func (u *Unit) UpdateSelectPriority() {
  474. for hostID, sp := range u.SelectPriorityMap {
  475. for name, spv := range sp {
  476. sp[name] = u.SelectPriorityUpdaterMap[name](u, spv, hostID)
  477. }
  478. }
  479. }
  480. func (u *Unit) GetMaxSelectPriority() (max SSelectPriorityValue) {
  481. max = EmptySelectPriorityValue
  482. for _, sp := range u.SelectPriorityMap {
  483. val := sp.Value()
  484. if max.Less(val) {
  485. max = val
  486. }
  487. }
  488. return
  489. }
  490. func (u *Unit) RegisterSelectPriorityUpdater(name string, f SSelectPriorityUpdater) {
  491. u.SelectPriorityLock.Lock()
  492. defer u.SelectPriorityLock.Unlock()
  493. u.SelectPriorityUpdaterMap[name] = f
  494. }
  495. func validateCapacityInput(c Counter) bool {
  496. if c != nil && c.GetCount() >= -1 {
  497. return true
  498. }
  499. return false
  500. }
  501. type ScoreValue struct {
  502. value score.TScore
  503. }
  504. func (u *Unit) setScore(id string, val score.SScore, prefer tristate.TriState) {
  505. u.scoreLock.Lock()
  506. defer u.scoreLock.Unlock()
  507. var (
  508. scoreObj Score
  509. ok bool
  510. )
  511. if scoreObj, ok = u.ScoreMap[id]; !ok {
  512. scoreObj = *newScore()
  513. u.ScoreMap[id] = scoreObj
  514. }
  515. scoreObj.ScoreBucket.SetScore(val, prefer)
  516. log.V(10).Infof("SetScore: %q -> %s, prefer: %s", id, val.String(), prefer)
  517. }
  518. func (u *Unit) SetScore(id string, val score.SScore) {
  519. u.setScore(id, val, tristate.None)
  520. }
  521. func (u *Unit) SetPreferScore(id string, val score.SScore) {
  522. u.setScore(id, val, tristate.True)
  523. }
  524. func (u *Unit) SetAvoidScore(id string, val score.SScore) {
  525. u.setScore(id, val, tristate.False)
  526. }
  527. func (u *Unit) GetScore(id string) Score {
  528. var (
  529. scoreObj Score
  530. ok bool
  531. )
  532. if scoreObj, ok = u.ScoreMap[id]; !ok {
  533. return *newScore()
  534. }
  535. return scoreObj
  536. }
  537. func (u *Unit) GetScoreDetails(id string) string {
  538. if score, ok := u.ScoreMap[id]; ok {
  539. return score.String()
  540. }
  541. return "EmptyScore"
  542. }
  543. func (u *Unit) SetFiltedData(id string, name string, data interface{}) error {
  544. u.scoreLock.Lock()
  545. defer u.scoreLock.Unlock()
  546. dataItem, ok := u.DataMap[id]
  547. if !ok {
  548. dataItem = &SchedContextDataItem{
  549. Data: make(map[string]interface{}),
  550. }
  551. u.DataMap[id] = dataItem
  552. }
  553. if name == "network" {
  554. dataItem.Networks = data.(*sync.Map)
  555. } else {
  556. if m, ok := data.(map[string]interface{}); ok {
  557. for key, value := range m {
  558. dataItem.Data[key] = value
  559. }
  560. }
  561. }
  562. return nil
  563. }
  564. func (u *Unit) GetFiltedData(id string, count int64) map[string]interface{} {
  565. schedContextData := make(map[string]interface{})
  566. if data, ok := u.DataMap[id]; ok {
  567. // deal networks
  568. networks := make(map[string]int64)
  569. if data.Networks != nil {
  570. data.Networks.Range(func(networkID, ipNumber interface{}) bool {
  571. networkIDString := networkID.(string)
  572. ipNumberInt64 := ipNumber.(int64)
  573. if count > ipNumberInt64 {
  574. networks[networkIDString] = ipNumberInt64
  575. count = count - ipNumberInt64
  576. return true
  577. } else if count <= ipNumberInt64 {
  578. networks[networkIDString] = count
  579. count = 0
  580. return false
  581. }
  582. return false
  583. })
  584. }
  585. schedContextData["networks"] = networks
  586. // others
  587. for key, value := range data.Data {
  588. schedContextData[key] = value
  589. }
  590. return schedContextData
  591. }
  592. return nil
  593. }
  594. func (u *Unit) GetAllocatedResource(candidateId string) *AllocatedResource {
  595. ret, ok := u.AllocatedResources[candidateId]
  596. if !ok {
  597. ret = NewAllocatedResource()
  598. u.AllocatedResources[candidateId] = ret
  599. }
  600. return ret
  601. }
  602. type SSelectPriority map[string]SSelectPriorityValue
  603. func (s SSelectPriority) Value() (val SSelectPriorityValue) {
  604. val = EmptySelectPriorityValue
  605. for _, v := range s {
  606. if v > val {
  607. val = v
  608. }
  609. }
  610. return
  611. }
  612. func NewSSelctPriority() SSelectPriority {
  613. return make(map[string]SSelectPriorityValue)
  614. }
  615. // SSelectPriorityUpdater will call to update the specified host after each round of selection
  616. type SSelectPriorityUpdater func(u *Unit, origin SSelectPriorityValue, hostID string) SSelectPriorityValue
  617. type SSelectPriorityValue int
  618. func (s SSelectPriorityValue) Less(sp SSelectPriorityValue) bool {
  619. return s < sp
  620. }
  621. func (s SSelectPriorityValue) Sub(sp SSelectPriorityValue) (ret SSelectPriorityValue) {
  622. ret = s - sp
  623. if ret.Less(EmptySelectPriorityValue) {
  624. ret = EmptySelectPriorityValue
  625. }
  626. return
  627. }
  628. func (s SSelectPriorityValue) SubOne() SSelectPriorityValue {
  629. return s.Sub(SSelectPriorityValue(1))
  630. }
  631. func (s SSelectPriorityValue) IsEmpty() bool {
  632. return s == EmptySelectPriorityValue
  633. }