func reportProgress(r *rebalance.Rebalancer) error { var firstError error var lastEmit string maxNodeLen := 0 maxPIndexLen := 0 seenNodes := map[string]bool{} seenNodesSorted := []string(nil) // Map of pindex -> (source) partition -> node -> *ProgressEntry progressEntries := map[string]map[string]map[string]*ProgressEntry{} seenPIndexes := map[string]bool{} seenPIndexesSorted := []string(nil) updateProgressEntry := func(pindex, sourcePartition, node string, cb func(*ProgressEntry)) { if !seenNodes[node] { seenNodes[node] = true seenNodesSorted = append(seenNodesSorted, node) sort.Strings(seenNodesSorted) if maxNodeLen < len(node) { maxNodeLen = len(node) } } if maxPIndexLen < len(pindex) { maxPIndexLen = len(pindex) } sourcePartitions, exists := progressEntries[pindex] if !exists || sourcePartitions == nil { sourcePartitions = map[string]map[string]*ProgressEntry{} progressEntries[pindex] = sourcePartitions } nodes, exists := sourcePartitions[sourcePartition] if !exists || nodes == nil { nodes = map[string]*ProgressEntry{} sourcePartitions[sourcePartition] = nodes } progressEntry, exists := nodes[node] if !exists || progressEntry == nil { progressEntry = &ProgressEntry{ pindex: pindex, sourcePartition: sourcePartition, node: node, move: -1, } nodes[node] = progressEntry } cb(progressEntry) // TODO: Check UUID matches, too. if !seenPIndexes[pindex] { seenPIndexes[pindex] = true seenPIndexesSorted = append(seenPIndexesSorted, pindex) sort.Strings(seenPIndexesSorted) } } for progress := range r.ProgressCh() { if progress.Error != nil { r.Log("main: error, progress: %+v", progress) if firstError == nil { firstError = progress.Error } r.Stop() continue } updateProgressEntries(r, updateProgressEntry) var b bytes.Buffer writeProgressTable(&b, maxNodeLen, maxPIndexLen, seenNodes, seenNodesSorted, seenPIndexes, seenPIndexesSorted, progressEntries) currEmit := b.String() if currEmit != lastEmit { r.Log("%s", currEmit) } lastEmit = currEmit } return firstError }