package topology import ( "code.google.com/p/weed-fs/go/storage" "code.google.com/p/weed-fs/go/glog" "math/rand" ) type NodeList struct { nodes map[NodeId]Node except map[string]Node } func NewNodeList(nodes map[NodeId]Node, except map[string]Node) *NodeList { m := make(map[NodeId]Node, len(nodes)-len(except)) for _, n := range nodes { if except[n.String()] == nil { m[n.Id()] = n } } nl := &NodeList{nodes: m} return nl } func (nl *NodeList) FreeSpace() int { freeSpace := 0 for _, n := range nl.nodes { freeSpace += n.FreeSpace() } return freeSpace } func (nl *NodeList) RandomlyPickN(count int, minSpace int, firstNodeName string) ([]Node, bool) { var list []Node var preferredNode *Node if firstNodeName != "" { for _, n := range nl.nodes { if n.Id() == NodeId(firstNodeName) && n.FreeSpace() >= minSpace { preferredNode = &n break } } if preferredNode == nil { return list, false } } for _, n := range nl.nodes { if n.FreeSpace() >= minSpace && n.Id() != NodeId(firstNodeName) { list = append(list, n) } } if count > len(list) || count == len(list) && firstNodeName != "" { return nil, false } for i := len(list); i > 0; i-- { r := rand.Intn(i) list[r], list[i-1] = list[i-1], list[r] } if firstNodeName != "" { list[0] = *preferredNode } return list[:count], true } func (nl *NodeList) ReserveOneVolume(randomVolumeIndex int, vid storage.VolumeId) (bool, *DataNode) { for _, node := range nl.nodes { freeSpace := node.FreeSpace() if randomVolumeIndex >= freeSpace { randomVolumeIndex -= freeSpace } else { if node.IsDataNode() && node.FreeSpace() > 0 { glog.V(0).Infoln("vid =", vid, " assigned to node =", node, ", freeSpace =", node.FreeSpace()) return true, node.(*DataNode) } children := node.Children() newNodeList := NewNodeList(children, nl.except) return newNodeList.ReserveOneVolume(randomVolumeIndex, vid) } } return false, nil }