refactoring: UpdateBarPriority with lazy flag
Vladimir Bauer
2 years ago
| 337 | 337 | // priority, i.e. bar will be on top. If you don't need to set priority |
| 338 | 338 | // dynamically, better use BarPriority option. |
| 339 | 339 | func (b *Bar) SetPriority(priority int) { |
| 340 | b.container.UpdateBarPriority(b, priority) | |
| 340 | b.container.UpdateBarPriority(b, priority, false) | |
| 341 | 341 | } |
| 342 | 342 | |
| 343 | 343 | // Abort interrupts bar's running goroutine. Abort won't be engaged |
| 35 | 35 | type fixData struct { |
| 36 | 36 | bar *Bar |
| 37 | 37 | priority int |
| 38 | lazy bool | |
| 38 | 39 | } |
| 39 | 40 | |
| 40 | 41 | func (m heapManager) run() { |
| 95 | 96 | close(data.iter) |
| 96 | 97 | case h_fix: |
| 97 | 98 | data := req.data.(fixData) |
| 98 | bar, priority := data.bar, data.priority | |
| 99 | if bar.index < 0 { | |
| 99 | if data.bar.index < 0 { | |
| 100 | 100 | break |
| 101 | 101 | } |
| 102 | bar.priority = priority | |
| 103 | heap.Fix(&bHeap, bar.index) | |
| 102 | data.bar.priority = data.priority | |
| 103 | if !data.lazy { | |
| 104 | heap.Fix(&bHeap, data.bar.index) | |
| 105 | } | |
| 104 | 106 | case h_state: |
| 105 | 107 | ch := req.data.(chan<- bool) |
| 106 | 108 | ch <- sync || l != bHeap.Len() |
| 135 | 137 | m <- heapRequest{cmd: h_drain, data: data} |
| 136 | 138 | } |
| 137 | 139 | |
| 138 | func (m heapManager) fix(b *Bar, priority int) { | |
| 139 | data := fixData{b, priority} | |
| 140 | func (m heapManager) fix(b *Bar, priority int, lazy bool) { | |
| 141 | data := fixData{b, priority, lazy} | |
| 140 | 142 | m <- heapRequest{cmd: h_fix, data: data} |
| 141 | 143 | } |
| 142 | 144 | |
| 200 | 200 | } |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | // UpdateBarPriority same as *Bar.SetPriority(int). | |
| 204 | func (p *Progress) UpdateBarPriority(b *Bar, priority int) { | |
| 203 | // UpdateBarPriority either immediately or lazy. | |
| 204 | // With lazy flag order is updated after the next refresh cycle. | |
| 205 | // If you don't care about laziness just use *Bar.SetPriority(int). | |
| 206 | func (p *Progress) UpdateBarPriority(b *Bar, priority int, lazy bool) { | |
| 207 | if b == nil { | |
| 208 | return | |
| 209 | } | |
| 205 | 210 | select { |
| 206 | case p.operateState <- func(s *pState) { s.hm.fix(b, priority) }: | |
| 211 | case p.operateState <- func(s *pState) { s.hm.fix(b, priority, lazy) }: | |
| 207 | 212 | case <-p.done: |
| 208 | 213 | } |
| 209 | 214 | } |
| 207 | 207 | shutdown := make(chan interface{}) |
| 208 | 208 | ctx, cancel := context.WithCancel(context.Background()) |
| 209 | 209 | p := mpb.NewWithContext(ctx, |
| 210 | mpb.WithOutput(io.Discard), | |
| 210 | mpb.WithOutput(io.Discard), // auto refresh is disabled because of io.Discard | |
| 211 | 211 | mpb.WithShutdownNotifier(shutdown), |
| 212 | 212 | ) |
| 213 | 213 | a := p.AddBar(100, mpb.BarPriority(1)) |
| 220 | 220 | c: "c", |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | p.UpdateBarPriority(c, 2) | |
| 224 | p.UpdateBarPriority(b, 3) | |
| 225 | ||
| 226 | cancel() | |
| 223 | p.UpdateBarPriority(c, 2, false) | |
| 224 | p.UpdateBarPriority(b, 3, false) | |
| 225 | ||
| 226 | go cancel() | |
| 227 | ||
| 228 | bars := (<-shutdown).([]*mpb.Bar) | |
| 229 | if l := len(bars); l != 3 { | |
| 230 | t.Errorf("Expected len of bars: %d, got: %d", 3, l) | |
| 231 | } | |
| 232 | ||
| 233 | p.Wait() | |
| 234 | pq := mpb.PriorityQueue(bars) | |
| 235 | ||
| 236 | if bar := heap.Pop(&pq).(*mpb.Bar); bar != b { | |
| 237 | t.Errorf("Expected bar b, got: %s", identity[bar]) | |
| 238 | } | |
| 239 | if bar := heap.Pop(&pq).(*mpb.Bar); bar != c { | |
| 240 | t.Errorf("Expected bar c, got: %s", identity[bar]) | |
| 241 | } | |
| 242 | if bar := heap.Pop(&pq).(*mpb.Bar); bar != a { | |
| 243 | t.Errorf("Expected bar a, got: %s", identity[bar]) | |
| 244 | } | |
| 245 | } | |
| 246 | ||
| 247 | func TestUpdateBarPriorityLazy(t *testing.T) { | |
| 248 | shutdown := make(chan interface{}) | |
| 249 | refreshCh := make(chan interface{}) | |
| 250 | ctx, cancel := context.WithCancel(context.Background()) | |
| 251 | p := mpb.NewWithContext(ctx, | |
| 252 | mpb.WithOutput(io.Discard), | |
| 253 | mpb.WithManualRefresh(refreshCh), | |
| 254 | mpb.WithShutdownNotifier(shutdown), | |
| 255 | ) | |
| 256 | a := p.AddBar(100, mpb.BarPriority(1)) | |
| 257 | b := p.AddBar(100, mpb.BarPriority(2)) | |
| 258 | c := p.AddBar(100, mpb.BarPriority(3)) | |
| 259 | ||
| 260 | identity := map[*mpb.Bar]string{ | |
| 261 | a: "a", | |
| 262 | b: "b", | |
| 263 | c: "c", | |
| 264 | } | |
| 265 | ||
| 266 | // UpdateBarPriority with lazy flat needs at least one refresh cycle to | |
| 267 | // update order inside underlying binary heap | |
| 268 | p.UpdateBarPriority(c, 2, true) | |
| 269 | p.UpdateBarPriority(b, 3, true) | |
| 270 | ||
| 271 | // ommiting following line will fail the test which proves correct lazy behavior | |
| 272 | refreshCh <- time.Now() | |
| 273 | ||
| 274 | go cancel() | |
| 227 | 275 | |
| 228 | 276 | bars := (<-shutdown).([]*mpb.Bar) |
| 229 | 277 | if l := len(bars); l != 3 { |