github.com/turingchain2020/turingchain@v1.1.21/blockchain/task.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package blockchain 6 7 import ( 8 "errors" 9 "sync" 10 "time" 11 12 "github.com/turingchain2020/turingchain/types" 13 ) 14 15 //Task 任务 16 type Task struct { 17 sync.Mutex 18 cond *sync.Cond 19 start int64 20 end int64 21 isruning bool 22 ticker *time.Timer 23 timeout time.Duration 24 cb func() 25 donelist map[int64]struct{} 26 timeoutcb func(height int64) 27 } 28 29 func newTask(timeout time.Duration) *Task { 30 t := &Task{} 31 t.timeout = timeout 32 t.ticker = time.NewTimer(t.timeout) 33 t.cond = sync.NewCond(t) 34 go t.tick() 35 return t 36 } 37 38 func (t *Task) tick() { 39 for { 40 t.cond.L.Lock() 41 for !t.isruning { 42 t.cond.Wait() 43 } 44 t.cond.L.Unlock() 45 _, ok := <-t.ticker.C 46 if !ok { 47 chainlog.Error("task is done", "timer ticker is stop", t.start) 48 continue 49 } 50 t.Lock() 51 if err := t.stop(false); err == nil { 52 if t.timeoutcb != nil { 53 go t.timeoutcb(t.start) 54 } 55 chainlog.Debug("task is done", "timer timeout is stop", t.start) 56 } 57 t.Unlock() 58 } 59 } 60 61 //InProgress 是否在执行 62 func (t *Task) InProgress() bool { 63 t.Lock() 64 defer t.Unlock() 65 return t.isruning 66 } 67 68 //TimerReset 计时器重置 69 func (t *Task) TimerReset(timeout time.Duration) { 70 t.TimerStop() 71 t.ticker.Reset(timeout) 72 } 73 74 //TimerStop 计时器停止 75 func (t *Task) TimerStop() { 76 if !t.ticker.Stop() { 77 select { 78 case <-t.ticker.C: 79 default: 80 } 81 } 82 } 83 84 //Start 计时器启动 85 func (t *Task) Start(start, end int64, cb func(), timeoutcb func(height int64)) error { 86 t.Lock() 87 defer t.Unlock() 88 if t.isruning { 89 return errors.New("task is running") 90 } 91 if start > end { 92 return types.ErrStartBigThanEnd 93 } 94 chainlog.Debug("task start:", "start", start, "end", end) 95 t.isruning = true 96 t.TimerReset(t.timeout) 97 t.start = start 98 t.end = end 99 t.cb = cb 100 t.timeoutcb = timeoutcb 101 t.donelist = make(map[int64]struct{}) 102 t.cond.Signal() 103 return nil 104 } 105 106 //Done 任务完成 107 func (t *Task) Done(height int64) { 108 t.Lock() 109 defer t.Unlock() 110 if !t.isruning { 111 return 112 } 113 if height >= t.start && height <= t.end { 114 chainlog.Debug("done", "height", height) 115 t.done(height) 116 t.TimerReset(t.timeout) 117 } 118 } 119 120 func (t *Task) stop(runcb bool) error { 121 if !t.isruning { 122 return errors.New("not running") 123 } 124 t.isruning = false 125 if t.cb != nil && runcb { 126 go t.cb() 127 } 128 t.TimerStop() 129 return nil 130 } 131 132 //Cancel 任务取消 133 func (t *Task) Cancel() error { 134 t.Lock() 135 defer t.Unlock() 136 chainlog.Warn("----task is cancel----") 137 return t.stop(false) 138 } 139 140 func (t *Task) done(height int64) { 141 if height == t.start { 142 t.start = t.start + 1 143 for i := t.start; i <= t.end; i++ { 144 _, ok := t.donelist[i] 145 if !ok { 146 break 147 } 148 delete(t.donelist, i) 149 t.start = i + 1 150 //任务完成 151 } 152 if t.start > t.end { 153 chainlog.Debug("----task is done----") 154 err := t.stop(true) 155 if err != nil { 156 chainlog.Debug("----task stop error ----", "err", err) 157 } 158 } 159 } 160 t.donelist[height] = struct{}{} 161 }