github.com/emate/nomad@v0.8.2-wo-binpacking/lib/delay_heap.go (about)

     1  package lib
     2  
     3  import (
     4  	"container/heap"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/nomad/structs"
     9  )
    10  
    11  // DelayHeap wraps a heap and gives operations other than Push/Pop.
    12  // The inner heap is sorted by the time in the WaitUntil field of delayHeapNode
    13  type DelayHeap struct {
    14  	index map[structs.NamespacedID]*delayHeapNode
    15  	heap  delayedHeapImp
    16  }
    17  
    18  // HeapNode is an interface type implemented by objects stored in the DelayHeap
    19  type HeapNode interface {
    20  	Data() interface{} // The data object
    21  	ID() string        // ID of the object, used in conjunction with namespace for deduplication
    22  	Namespace() string // Namespace of the object, can be empty
    23  }
    24  
    25  // delayHeapNode encapsulates the node stored in DelayHeap
    26  // WaitUntil is used as the sorting criteria
    27  type delayHeapNode struct {
    28  	// Node is the data object stored in the delay heap
    29  	Node HeapNode
    30  	// WaitUntil is the time delay associated with the node
    31  	// Objects in the heap are sorted by WaitUntil
    32  	WaitUntil time.Time
    33  
    34  	index int
    35  }
    36  
    37  type delayedHeapImp []*delayHeapNode
    38  
    39  func (h delayedHeapImp) Len() int {
    40  	return len(h)
    41  }
    42  
    43  func (h delayedHeapImp) Less(i, j int) bool {
    44  	// Two zero times should return false.
    45  	// Otherwise, zero is "greater" than any other time.
    46  	// (To sort it at the end of the list.)
    47  	// Sort such that zero times are at the end of the list.
    48  	iZero, jZero := h[i].WaitUntil.IsZero(), h[j].WaitUntil.IsZero()
    49  	if iZero && jZero {
    50  		return false
    51  	} else if iZero {
    52  		return false
    53  	} else if jZero {
    54  		return true
    55  	}
    56  
    57  	return h[i].WaitUntil.Before(h[j].WaitUntil)
    58  }
    59  
    60  func (h delayedHeapImp) Swap(i, j int) {
    61  	h[i], h[j] = h[j], h[i]
    62  	h[i].index = i
    63  	h[j].index = j
    64  }
    65  
    66  func (h *delayedHeapImp) Push(x interface{}) {
    67  	node := x.(*delayHeapNode)
    68  	n := len(*h)
    69  	node.index = n
    70  	*h = append(*h, node)
    71  }
    72  
    73  func (h *delayedHeapImp) Pop() interface{} {
    74  	old := *h
    75  	n := len(old)
    76  	node := old[n-1]
    77  	node.index = -1 // for safety
    78  	*h = old[0 : n-1]
    79  	return node
    80  }
    81  
    82  func NewDelayHeap() *DelayHeap {
    83  	return &DelayHeap{
    84  		index: make(map[structs.NamespacedID]*delayHeapNode),
    85  		heap:  make(delayedHeapImp, 0),
    86  	}
    87  }
    88  
    89  func (p *DelayHeap) Push(dataNode HeapNode, next time.Time) error {
    90  	tuple := structs.NamespacedID{
    91  		ID:        dataNode.ID(),
    92  		Namespace: dataNode.Namespace(),
    93  	}
    94  	if _, ok := p.index[tuple]; ok {
    95  		return fmt.Errorf("node %q (%s) already exists", dataNode.ID(), dataNode.Namespace())
    96  	}
    97  
    98  	delayHeapNode := &delayHeapNode{dataNode, next, 0}
    99  	p.index[tuple] = delayHeapNode
   100  	heap.Push(&p.heap, delayHeapNode)
   101  	return nil
   102  }
   103  
   104  func (p *DelayHeap) Pop() *delayHeapNode {
   105  	if len(p.heap) == 0 {
   106  		return nil
   107  	}
   108  
   109  	delayHeapNode := heap.Pop(&p.heap).(*delayHeapNode)
   110  	tuple := structs.NamespacedID{
   111  		ID:        delayHeapNode.Node.ID(),
   112  		Namespace: delayHeapNode.Node.Namespace(),
   113  	}
   114  	delete(p.index, tuple)
   115  	return delayHeapNode
   116  }
   117  
   118  func (p *DelayHeap) Peek() *delayHeapNode {
   119  	if len(p.heap) == 0 {
   120  		return nil
   121  	}
   122  
   123  	return p.heap[0]
   124  }
   125  
   126  func (p *DelayHeap) Contains(heapNode HeapNode) bool {
   127  	tuple := structs.NamespacedID{
   128  		ID:        heapNode.ID(),
   129  		Namespace: heapNode.Namespace(),
   130  	}
   131  	_, ok := p.index[tuple]
   132  	return ok
   133  }
   134  
   135  func (p *DelayHeap) Update(heapNode HeapNode, waitUntil time.Time) error {
   136  	tuple := structs.NamespacedID{
   137  		ID:        heapNode.ID(),
   138  		Namespace: heapNode.Namespace(),
   139  	}
   140  	if existingHeapNode, ok := p.index[tuple]; ok {
   141  		// Need to update the job as well because its spec can change.
   142  		existingHeapNode.Node = heapNode
   143  		existingHeapNode.WaitUntil = waitUntil
   144  		heap.Fix(&p.heap, existingHeapNode.index)
   145  		return nil
   146  	}
   147  
   148  	return fmt.Errorf("heap doesn't contain object with ID %q (%s)", heapNode.ID(), heapNode.Namespace())
   149  }
   150  
   151  func (p *DelayHeap) Remove(heapNode HeapNode) error {
   152  	tuple := structs.NamespacedID{
   153  		ID:        heapNode.ID(),
   154  		Namespace: heapNode.Namespace(),
   155  	}
   156  	if node, ok := p.index[tuple]; ok {
   157  		heap.Remove(&p.heap, node.index)
   158  		delete(p.index, tuple)
   159  		return nil
   160  	}
   161  
   162  	return fmt.Errorf("heap doesn't contain object with ID %q (%s)", heapNode.ID(), heapNode.Namespace())
   163  }
   164  
   165  func (p *DelayHeap) Length() int {
   166  	return len(p.heap)
   167  }