github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/storageprovisioner/internal/schedule/schedule.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package schedule 5 6 import ( 7 "container/heap" 8 "time" 9 10 "github.com/juju/clock" 11 "github.com/juju/errors" 12 ) 13 14 // Schedule provides a schedule for storage operations, with the following 15 // properties: 16 // - fast to add and remove items by key: O(log(n)); n is the total number of items 17 // - fast to identify/remove the next scheduled item: O(log(n)) 18 type Schedule struct { 19 time clock.Clock 20 items scheduleItems 21 m map[interface{}]*scheduleItem 22 } 23 24 // NewSchedule constructs a new schedule, using the given Clock for the Next 25 // method. 26 func NewSchedule(clock clock.Clock) *Schedule { 27 return &Schedule{ 28 time: clock, 29 m: make(map[interface{}]*scheduleItem), 30 } 31 } 32 33 // Next returns a channel which will send after the next scheduled item's time 34 // has been reached. If there are no scheduled items, nil is returned. 35 func (s *Schedule) Next() <-chan time.Time { 36 if len(s.items) > 0 { 37 return s.time.After(s.items[0].t.Sub(s.time.Now())) 38 } 39 return nil 40 } 41 42 // Ready returns the parameters for items that are scheduled at or before 43 // "now", and removes them from the schedule. The resulting slices are in 44 // order of time; items scheduled for the same time have no defined relative 45 // order. 46 func (s *Schedule) Ready(now time.Time) []interface{} { 47 var ready []interface{} 48 for len(s.items) > 0 && !s.items[0].t.After(now) { 49 item := heap.Pop(&s.items).(*scheduleItem) 50 delete(s.m, item.key) 51 ready = append(ready, item.value) 52 } 53 return ready 54 } 55 56 // Add adds an item with the specified value, with the corresponding key 57 // and time to the schedule. Add will panic if there already exists an item 58 // with the same key. 59 func (s *Schedule) Add(key, value interface{}, t time.Time) { 60 if _, ok := s.m[key]; ok { 61 panic(errors.Errorf("duplicate key %v", key)) 62 } 63 item := &scheduleItem{key: key, value: value, t: t} 64 s.m[key] = item 65 heap.Push(&s.items, item) 66 } 67 68 // Remove removes the item corresponding to the specified key from the 69 // schedule. If no item with the specified key exists, this is a no-op. 70 func (s *Schedule) Remove(key interface{}) { 71 if item, ok := s.m[key]; ok { 72 heap.Remove(&s.items, item.i) 73 delete(s.m, key) 74 } 75 } 76 77 type scheduleItems []*scheduleItem 78 79 type scheduleItem struct { 80 i int 81 key interface{} 82 value interface{} 83 t time.Time 84 } 85 86 func (s scheduleItems) Len() int { 87 return len(s) 88 } 89 90 func (s scheduleItems) Less(i, j int) bool { 91 return s[i].t.Before(s[j].t) 92 } 93 94 func (s scheduleItems) Swap(i, j int) { 95 s[i], s[j] = s[j], s[i] 96 s[i].i = i 97 s[j].i = j 98 } 99 100 func (s *scheduleItems) Push(x interface{}) { 101 item := x.(*scheduleItem) 102 item.i = len(*s) 103 *s = append(*s, item) 104 } 105 106 func (s *scheduleItems) Pop() interface{} { 107 n := len(*s) - 1 108 x := (*s)[n] 109 *s = (*s)[:n] 110 return x 111 }