|
|
@ -62,56 +62,64 @@ type NodeImpl struct { |
|
|
|
} |
|
|
|
|
|
|
|
// the first node must satisfy filterFirstNodeFn(), the rest nodes must have one free slot
|
|
|
|
func (n *NodeImpl) RandomlyPickNodes(numberOfNodes int, filterFirstNodeFn func(dn Node) error) (firstNode Node, restNodes []Node, err error) { |
|
|
|
candidates := make([]Node, 0, len(n.children)) |
|
|
|
func (n *NodeImpl) PickNodesByWeight(numberOfNodes int, filterFirstNodeFn func(dn Node) error) (firstNode Node, restNodes []Node, err error) { |
|
|
|
var totalWeights int64 |
|
|
|
var errs []string |
|
|
|
n.RLock() |
|
|
|
candidates := make([]Node, 0, len(n.children)) |
|
|
|
candidatesWeights := make([]int64, 0, len(n.children)) |
|
|
|
//pick nodes which has enough free volumes as candidates, and use free volumes number as node weight.
|
|
|
|
for _, node := range n.children { |
|
|
|
if err := filterFirstNodeFn(node); err == nil { |
|
|
|
candidates = append(candidates, node) |
|
|
|
} else { |
|
|
|
errs = append(errs, string(node.Id())+":"+err.Error()) |
|
|
|
if node.FreeSpace() <= 0 { |
|
|
|
continue |
|
|
|
} |
|
|
|
totalWeights += node.FreeSpace() |
|
|
|
candidates = append(candidates, node) |
|
|
|
candidatesWeights = append(candidatesWeights, node.FreeSpace()) |
|
|
|
} |
|
|
|
n.RUnlock() |
|
|
|
if len(candidates) == 0 { |
|
|
|
return nil, nil, errors.New("No matching data node found! \n" + strings.Join(errs, "\n")) |
|
|
|
if len(candidates) < numberOfNodes { |
|
|
|
glog.V(2).Infoln(n.Id(), "failed to pick", numberOfNodes, "from ", len(candidates), "node candidates") |
|
|
|
return nil, nil, errors.New("No enough data node found!") |
|
|
|
} |
|
|
|
firstNode = candidates[rand.Intn(len(candidates))] |
|
|
|
glog.V(2).Infoln(n.Id(), "picked main node:", firstNode.Id()) |
|
|
|
|
|
|
|
restNodes = make([]Node, numberOfNodes-1) |
|
|
|
candidates = candidates[:0] |
|
|
|
n.RLock() |
|
|
|
for _, node := range n.children { |
|
|
|
if node.Id() == firstNode.Id() { |
|
|
|
continue |
|
|
|
} |
|
|
|
if node.FreeSpace() <= 0 { |
|
|
|
continue |
|
|
|
//pick nodes randomly by weights, the node picked earlier has higher final weights
|
|
|
|
sortedCandidates := make([]Node, 0, len(candidates)) |
|
|
|
for i:=0; i<len(candidates); i++ { |
|
|
|
weightsInterval := rand.Int63n(totalWeights) |
|
|
|
lastWeights := int64(0) |
|
|
|
for k, weights := range candidatesWeights { |
|
|
|
if (weightsInterval>=lastWeights) && (weightsInterval<lastWeights + weights) { |
|
|
|
sortedCandidates = append(sortedCandidates, candidates[k]) |
|
|
|
candidatesWeights[k] = 0 |
|
|
|
totalWeights -= weights |
|
|
|
break |
|
|
|
} |
|
|
|
lastWeights += weights |
|
|
|
} |
|
|
|
glog.V(2).Infoln("select rest node candidate:", node.Id()) |
|
|
|
candidates = append(candidates, node) |
|
|
|
} |
|
|
|
n.RUnlock() |
|
|
|
glog.V(2).Infoln(n.Id(), "picking", numberOfNodes-1, "from rest", len(candidates), "node candidates") |
|
|
|
ret := len(restNodes) == 0 |
|
|
|
for k, node := range candidates { |
|
|
|
if k < len(restNodes) { |
|
|
|
restNodes[k] = node |
|
|
|
if k == len(restNodes)-1 { |
|
|
|
ret = true |
|
|
|
|
|
|
|
restNodes = make([]Node, 0, numberOfNodes-1) |
|
|
|
ret := false |
|
|
|
n.RLock() |
|
|
|
for k, node := range sortedCandidates { |
|
|
|
if err := filterFirstNodeFn(node); err == nil { |
|
|
|
firstNode = node |
|
|
|
if k >= numberOfNodes-1 { |
|
|
|
restNodes = sortedCandidates[:numberOfNodes-1] |
|
|
|
} else { |
|
|
|
restNodes = append(restNodes, sortedCandidates[:k]...) |
|
|
|
restNodes = append(restNodes, sortedCandidates[k+1:numberOfNodes]...) |
|
|
|
} |
|
|
|
ret = true |
|
|
|
break |
|
|
|
} else { |
|
|
|
r := rand.Intn(k + 1) |
|
|
|
if r < len(restNodes) { |
|
|
|
restNodes[r] = node |
|
|
|
} |
|
|
|
errs = append(errs, string(node.Id())+":"+err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
n.RUnlock() |
|
|
|
if !ret { |
|
|
|
glog.V(2).Infoln(n.Id(), "failed to pick", numberOfNodes-1, "from rest", len(candidates), "node candidates") |
|
|
|
err = errors.New("No enough data node found!") |
|
|
|
return nil, nil, errors.New("No matching data node found! \n" + strings.Join(errs, "\n")) |
|
|
|
} |
|
|
|
return |
|
|
|
} |
|
|
|