nodeset.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package scheduler
  2. import (
  3. "container/heap"
  4. "errors"
  5. "strings"
  6. "time"
  7. "github.com/docker/swarmkit/api"
  8. "github.com/docker/swarmkit/manager/constraint"
  9. )
  10. var errNodeNotFound = errors.New("node not found in scheduler dataset")
  11. type nodeSet struct {
  12. nodes map[string]NodeInfo // map from node id to node info
  13. }
  14. func (ns *nodeSet) alloc(n int) {
  15. ns.nodes = make(map[string]NodeInfo, n)
  16. }
  17. // nodeInfo returns the NodeInfo struct for a given node identified by its ID.
  18. func (ns *nodeSet) nodeInfo(nodeID string) (NodeInfo, error) {
  19. node, ok := ns.nodes[nodeID]
  20. if ok {
  21. return node, nil
  22. }
  23. return NodeInfo{}, errNodeNotFound
  24. }
  25. // addOrUpdateNode sets the number of tasks for a given node. It adds the node
  26. // to the set if it wasn't already tracked.
  27. func (ns *nodeSet) addOrUpdateNode(n NodeInfo) {
  28. if n.Tasks == nil {
  29. n.Tasks = make(map[string]*api.Task)
  30. }
  31. if n.ActiveTasksCountByService == nil {
  32. n.ActiveTasksCountByService = make(map[string]int)
  33. }
  34. if n.recentFailures == nil {
  35. n.recentFailures = make(map[string][]time.Time)
  36. }
  37. ns.nodes[n.ID] = n
  38. }
  39. // updateNode sets the number of tasks for a given node. It ignores the update
  40. // if the node isn't already tracked in the set.
  41. func (ns *nodeSet) updateNode(n NodeInfo) {
  42. _, ok := ns.nodes[n.ID]
  43. if ok {
  44. ns.nodes[n.ID] = n
  45. }
  46. }
  47. func (ns *nodeSet) remove(nodeID string) {
  48. delete(ns.nodes, nodeID)
  49. }
  50. func (ns *nodeSet) tree(serviceID string, preferences []*api.PlacementPreference, maxAssignments int, meetsConstraints func(*NodeInfo) bool, nodeLess func(*NodeInfo, *NodeInfo) bool) decisionTree {
  51. var root decisionTree
  52. if maxAssignments == 0 {
  53. return root
  54. }
  55. for _, node := range ns.nodes {
  56. tree := &root
  57. for _, pref := range preferences {
  58. // Only spread is supported so far
  59. spread := pref.GetSpread()
  60. if spread == nil {
  61. continue
  62. }
  63. descriptor := spread.SpreadDescriptor
  64. var value string
  65. switch {
  66. case len(descriptor) > len(constraint.NodeLabelPrefix) && strings.EqualFold(descriptor[:len(constraint.NodeLabelPrefix)], constraint.NodeLabelPrefix):
  67. if node.Spec.Annotations.Labels != nil {
  68. value = node.Spec.Annotations.Labels[descriptor[len(constraint.NodeLabelPrefix):]]
  69. }
  70. case len(descriptor) > len(constraint.EngineLabelPrefix) && strings.EqualFold(descriptor[:len(constraint.EngineLabelPrefix)], constraint.EngineLabelPrefix):
  71. if node.Description != nil && node.Description.Engine != nil && node.Description.Engine.Labels != nil {
  72. value = node.Description.Engine.Labels[descriptor[len(constraint.EngineLabelPrefix):]]
  73. }
  74. // TODO(aaronl): Support other items from constraint
  75. // syntax like node ID, hostname, os/arch, etc?
  76. default:
  77. continue
  78. }
  79. // If value is still uninitialized, the value used for
  80. // the node at this level of the tree is "". This makes
  81. // sure that the tree structure is not affected by
  82. // which properties nodes have and don't have.
  83. if node.ActiveTasksCountByService != nil {
  84. tree.tasks += node.ActiveTasksCountByService[serviceID]
  85. }
  86. if tree.next == nil {
  87. tree.next = make(map[string]*decisionTree)
  88. }
  89. next := tree.next[value]
  90. if next == nil {
  91. next = &decisionTree{}
  92. tree.next[value] = next
  93. }
  94. tree = next
  95. }
  96. if node.ActiveTasksCountByService != nil {
  97. tree.tasks += node.ActiveTasksCountByService[serviceID]
  98. }
  99. if tree.nodeHeap.lessFunc == nil {
  100. tree.nodeHeap.lessFunc = nodeLess
  101. }
  102. if tree.nodeHeap.Len() < maxAssignments {
  103. if meetsConstraints(&node) {
  104. heap.Push(&tree.nodeHeap, node)
  105. }
  106. } else if nodeLess(&node, &tree.nodeHeap.nodes[0]) {
  107. if meetsConstraints(&node) {
  108. tree.nodeHeap.nodes[0] = node
  109. heap.Fix(&tree.nodeHeap, 0)
  110. }
  111. }
  112. }
  113. return root
  114. }