github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/errors" 11 "github.com/juju/utils/clock" 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 // TODO(fwereade): 2016-03-17 lp:1558657 38 return s.time.After(s.items[0].t.Sub(s.time.Now())) 39 } 40 return nil 41 } 42 43 // Ready returns the parameters for items that are scheduled at or before 44 // "now", and removes them from the schedule. The resulting slices are in 45 // order of time; items scheduled for the same time have no defined relative 46 // order. 47 func (s *Schedule) Ready(now time.Time) []interface{} { 48 var ready []interface{} 49 for len(s.items) > 0 && !s.items[0].t.After(now) { 50 item := heap.Pop(&s.items).(*scheduleItem) 51 delete(s.m, item.key) 52 ready = append(ready, item.value) 53 } 54 return ready 55 } 56 57 // Add adds an item with the specified value, with the corresponding key 58 // and time to the schedule. Add will panic if there already exists an item 59 // with the same key. 60 func (s *Schedule) Add(key, value interface{}, t time.Time) { 61 if _, ok := s.m[key]; ok { 62 panic(errors.Errorf("duplicate key %v", key)) 63 } 64 item := &scheduleItem{key: key, value: value, t: t} 65 s.m[key] = item 66 heap.Push(&s.items, item) 67 } 68 69 // Remove removes the item corresponding to the specified key from the 70 // schedule. If no item with the specified key exists, this is a no-op. 71 func (s *Schedule) Remove(key interface{}) { 72 if item, ok := s.m[key]; ok { 73 heap.Remove(&s.items, item.i) 74 delete(s.m, key) 75 } 76 } 77 78 type scheduleItems []*scheduleItem 79 80 type scheduleItem struct { 81 i int 82 key interface{} 83 value interface{} 84 t time.Time 85 } 86 87 func (s scheduleItems) Len() int { 88 return len(s) 89 } 90 91 func (s scheduleItems) Less(i, j int) bool { 92 return s[i].t.Before(s[j].t) 93 } 94 95 func (s scheduleItems) Swap(i, j int) { 96 s[i], s[j] = s[j], s[i] 97 s[i].i = i 98 s[j].i = j 99 } 100 101 func (s *scheduleItems) Push(x interface{}) { 102 item := x.(*scheduleItem) 103 item.i = len(*s) 104 *s = append(*s, item) 105 } 106 107 func (s *scheduleItems) Pop() interface{} { 108 n := len(*s) - 1 109 x := (*s)[n] 110 *s = (*s)[:n] 111 return x 112 }