// WaitForWantedNodes blocks until the nodeDefsWanted in the cfg is // equal to or a superset of the provided wantedNodes, and returns the // "nodes to remove" (actualWantedNodes SET-DIFFERENCE wantedNodes). func WaitForWantedNodes(cfg cbgt.Cfg, wantedNodes []string, cancelCh <-chan struct{}, secs int) ( []string, error) { var nodeDefWantedUUIDs []string for i := 0; i < secs; i++ { select { case <-cancelCh: return nil, ErrCtlCanceled default: } nodeDefsWanted, _, err := cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED) if err != nil { return nil, err } nodeDefWantedUUIDs = nil for _, nodeDef := range nodeDefsWanted.NodeDefs { nodeDefWantedUUIDs = append(nodeDefWantedUUIDs, nodeDef.UUID) } if len(cbgt.StringsRemoveStrings(wantedNodes, nodeDefWantedUUIDs)) <= 0 { return cbgt.StringsRemoveStrings(nodeDefWantedUUIDs, wantedNodes), nil } time.Sleep(1 * time.Second) } return nil, fmt.Errorf("ctl: WaitForWantedNodes"+ " could not attain wantedNodes: %#v,"+ " only reached nodeDefWantedUUIDs: %#v", wantedNodes, nodeDefWantedUUIDs) }
// StartRebalance begins a concurrent, cluster-wide rebalancing of all // the indexes (and their index partitions) on a cluster of cbgt // nodes. StartRebalance utilizes the blance library for calculating // and orchestrating partition reassignments and the cbgt/rest/monitor // library to watch for progress and errors. func StartRebalance(version string, cfg cbgt.Cfg, server string, nodesToRemoveParam []string, options RebalanceOptions) ( *Rebalancer, error) { // TODO: Need timeouts on moves. // uuid := "" // We don't have a uuid, as we're not a node. begIndexDefs, begNodeDefs, begPlanPIndexes, begPlanPIndexesCAS, err := cbgt.PlannerGetPlan(cfg, version, uuid) if err != nil { return nil, err } nodesAll, nodesToAdd, nodesToRemove, nodeWeights, nodeHierarchy := cbgt.CalcNodesLayout(begIndexDefs, begNodeDefs, begPlanPIndexes) nodesUnknown := cbgt.StringsRemoveStrings(nodesToRemoveParam, nodesAll) if len(nodesUnknown) > 0 { return nil, fmt.Errorf("rebalance:"+ " unknown nodes in nodesToRemoveParam: %#v", nodesUnknown) } nodesToRemove = append(nodesToRemove, nodesToRemoveParam...) nodesToRemove = cbgt.StringsIntersectStrings(nodesToRemove, nodesToRemove) nodesToAdd = cbgt.StringsRemoveStrings(nodesToAdd, nodesToRemove) // -------------------------------------------------------- urlUUIDs := monitor.NodeDefsUrlUUIDs(begNodeDefs) monitorSampleCh := make(chan monitor.MonitorSample) monitorOptions := monitor.MonitorNodesOptions{ DiagSampleDisable: true, HttpGet: options.HttpGet, } monitorInst, err := monitor.StartMonitorNodes(urlUUIDs, monitorSampleCh, monitorOptions) if err != nil { return nil, err } // -------------------------------------------------------- stopCh := make(chan struct{}) r := &Rebalancer{ version: version, cfg: cfg, server: server, options: options, progressCh: make(chan RebalanceProgress), monitor: monitorInst, monitorDoneCh: make(chan struct{}), monitorSampleCh: monitorSampleCh, monitorSampleWantCh: make(chan chan monitor.MonitorSample), nodesAll: nodesAll, nodesToAdd: nodesToAdd, nodesToRemove: nodesToRemove, nodeWeights: nodeWeights, nodeHierarchy: nodeHierarchy, begIndexDefs: begIndexDefs, begNodeDefs: begNodeDefs, begPlanPIndexes: begPlanPIndexes, begPlanPIndexesCAS: begPlanPIndexesCAS, endPlanPIndexes: cbgt.NewPlanPIndexes(version), currStates: map[string]map[string]map[string]StateOp{}, currSeqs: map[string]map[string]map[string]cbgt.UUIDSeq{}, wantSeqs: map[string]map[string]map[string]cbgt.UUIDSeq{}, stopCh: stopCh, } r.Logf("rebalance: nodesAll: %#v", nodesAll) r.Logf("rebalance: nodesToAdd: %#v", nodesToAdd) r.Logf("rebalance: nodesToRemove: %#v", nodesToRemove) r.Logf("rebalance: nodeWeights: %#v", nodeWeights) r.Logf("rebalance: nodeHierarchy: %#v", nodeHierarchy) // r.Logf("rebalance: begIndexDefs: %#v", begIndexDefs) // r.Logf("rebalance: begNodeDefs: %#v", begNodeDefs) r.Logf("rebalance: monitor urlUUIDs: %#v", urlUUIDs) // begPlanPIndexesJSON, _ := json.Marshal(begPlanPIndexes) // // r.Logf("rebalance: begPlanPIndexes: %s, cas: %v", // begPlanPIndexesJSON, begPlanPIndexesCAS) // TODO: Prepopulate currStates so that we can double-check that // our state transitions in assignPartition are valid. go r.runMonitor(stopCh) go r.runRebalanceIndexes(stopCh) return r, nil }