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 }
func updateProgressEntries( r *rebalance.Rebalancer, updateProgressEntry func(pindex, sourcePartition, node string, cb func(*ProgressEntry)), ) { r.Visit(func( currStates rebalance.CurrStates, currSeqs rebalance.CurrSeqs, wantSeqs rebalance.WantSeqs, mapNextMoves map[string]*blance.NextMoves, ) { for _, pindexes := range currStates { for pindex, nodes := range pindexes { for node, stateOp := range nodes { updateProgressEntry(pindex, "", node, func(pe *ProgressEntry) { pe.stateOp = stateOp }) } } } for pindex, sourcePartitions := range currSeqs { for sourcePartition, nodes := range sourcePartitions { for node, currUUIDSeq := range nodes { updateProgressEntry(pindex, sourcePartition, node, func(pe *ProgressEntry) { pe.currUUIDSeq = currUUIDSeq if pe.initUUIDSeq.UUID == "" { pe.initUUIDSeq = currUUIDSeq } }) } } } for pindex, sourcePartitions := range wantSeqs { for sourcePartition, nodes := range sourcePartitions { for node, wantUUIDSeq := range nodes { updateProgressEntry(pindex, sourcePartition, node, func(pe *ProgressEntry) { pe.wantUUIDSeq = wantUUIDSeq }) } } } for pindex, nextMoves := range mapNextMoves { for i, nodeStateOp := range nextMoves.Moves { updateProgressEntry(pindex, "", nodeStateOp.Node, func(pe *ProgressEntry) { pe.move = i pe.done = i < nextMoves.Next }) } } }) }