| 351 | } |
| 352 | |
| 353 | func (*replicatedProgressUpdater) tasksBySlot(tasks []swarm.Task, activeNodes map[string]struct{}) map[int]swarm.Task { |
| 354 | // If there are multiple tasks with the same slot number, favor the one |
| 355 | // with the *lowest* desired state. This can happen in restart |
| 356 | // scenarios. |
| 357 | tasksBySlot := make(map[int]swarm.Task) |
| 358 | for _, task := range tasks { |
| 359 | if numberedStates[task.DesiredState] == 0 || numberedStates[task.Status.State] == 0 { |
| 360 | continue |
| 361 | } |
| 362 | if existingTask, ok := tasksBySlot[task.Slot]; ok { |
| 363 | if numberedStates[existingTask.DesiredState] < numberedStates[task.DesiredState] { |
| 364 | continue |
| 365 | } |
| 366 | // If the desired states match, observed state breaks |
| 367 | // ties. This can happen with the "start first" service |
| 368 | // update mode. |
| 369 | if numberedStates[existingTask.DesiredState] == numberedStates[task.DesiredState] && |
| 370 | numberedStates[existingTask.Status.State] <= numberedStates[task.Status.State] { |
| 371 | continue |
| 372 | } |
| 373 | } |
| 374 | if task.NodeID != "" { |
| 375 | if _, nodeActive := activeNodes[task.NodeID]; !nodeActive { |
| 376 | continue |
| 377 | } |
| 378 | } |
| 379 | tasksBySlot[task.Slot] = task |
| 380 | } |
| 381 | |
| 382 | return tasksBySlot |
| 383 | } |
| 384 | |
| 385 | func (u *replicatedProgressUpdater) writeTaskProgress(task swarm.Task, mappedSlot int, replicas uint64) { |
| 386 | if u.done || replicas > maxProgressBars || uint64(mappedSlot) > replicas { |