mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
volume layout for each replication level
This commit is contained in:
parent
8684b0999d
commit
6daf221937
|
@ -1,7 +0,0 @@
|
||||||
1. clients report its own server info, volumes info,
|
|
||||||
2. master collect all volumes, separated into readable volumes, writable volumes, volume2machine mapping
|
|
||||||
machines is an array of machine info
|
|
||||||
writable volumes is an array of vids
|
|
||||||
vid2machineId maps volume id to machineId, which is the index of machines array
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,50 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import ()
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
type VolumeInfo struct {
|
type VolumeInfo struct {
|
||||||
Id VolumeId
|
Id VolumeId
|
||||||
Size int64
|
Size int64
|
||||||
|
ReplicationType ReplicationType
|
||||||
|
}
|
||||||
|
type ReplicationType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Copy00 = ReplicationType(00) // single copy
|
||||||
|
Copy01 = ReplicationType(01) // 2 copies, each on different racks, same data center
|
||||||
|
Copy10 = ReplicationType(10) // 2 copies, each on different data center
|
||||||
|
Copy11 = ReplicationType(11) // 3 copies, 2 on different racks and local data center, 1 on different data center
|
||||||
|
Copy20 = ReplicationType(20) // 3 copies, each on dffereint data center
|
||||||
|
LengthRelicationType = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetReplicationLevelIndex(v *VolumeInfo) int {
|
||||||
|
switch v.ReplicationType {
|
||||||
|
case Copy00:
|
||||||
|
return 0
|
||||||
|
case Copy01:
|
||||||
|
return 1
|
||||||
|
case Copy10:
|
||||||
|
return 2
|
||||||
|
case Copy11:
|
||||||
|
return 3
|
||||||
|
case Copy20:
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
func GetCopyCount(v *VolumeInfo) int {
|
||||||
|
switch v.ReplicationType {
|
||||||
|
case Copy00:
|
||||||
|
return 1
|
||||||
|
case Copy01:
|
||||||
|
return 2
|
||||||
|
case Copy10:
|
||||||
|
return 2
|
||||||
|
case Copy11:
|
||||||
|
return 3
|
||||||
|
case Copy20:
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ import (
|
||||||
type DataNode struct {
|
type DataNode struct {
|
||||||
NodeImpl
|
NodeImpl
|
||||||
volumes map[storage.VolumeId]*storage.VolumeInfo
|
volumes map[storage.VolumeId]*storage.VolumeInfo
|
||||||
|
ip string
|
||||||
|
port int
|
||||||
|
publicUrl string
|
||||||
|
lastSeen int64 // unix time in seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDataNode(id string) *DataNode {
|
func NewDataNode(id string) *DataNode {
|
||||||
|
@ -17,12 +21,21 @@ func NewDataNode(id string) *DataNode {
|
||||||
s.volumes = make(map[storage.VolumeId]*storage.VolumeInfo)
|
s.volumes = make(map[storage.VolumeId]*storage.VolumeInfo)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
func (s *DataNode) CreateOneVolume(r int, vid storage.VolumeId) storage.VolumeId {
|
func (dn *DataNode) CreateOneVolume(r int, vid storage.VolumeId) storage.VolumeId {
|
||||||
s.AddVolume(&storage.VolumeInfo{Id: vid, Size: 32 * 1024 * 1024 * 1024})
|
dn.AddVolume(&storage.VolumeInfo{Id: vid, Size: 32 * 1024 * 1024 * 1024})
|
||||||
return vid
|
return vid
|
||||||
}
|
}
|
||||||
func (s *DataNode) AddVolume(v *storage.VolumeInfo) {
|
func (dn *DataNode) AddVolume(v *storage.VolumeInfo) {
|
||||||
s.volumes[v.Id] = v
|
dn.volumes[v.Id] = v
|
||||||
s.UpAdjustActiveVolumeCountDelta(1)
|
dn.UpAdjustActiveVolumeCountDelta(1)
|
||||||
s.UpAdjustMaxVolumeId(v.Id)
|
dn.UpAdjustMaxVolumeId(v.Id)
|
||||||
|
dn.GetTopology().RegisterVolume(v,dn)
|
||||||
|
}
|
||||||
|
func (dn *DataNode) GetTopology() *Topology {
|
||||||
|
p := dn.parent
|
||||||
|
for p.Parent()!=nil{
|
||||||
|
p = p.Parent()
|
||||||
|
}
|
||||||
|
t := p.(*Topology)
|
||||||
|
return t
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,11 @@ type Node interface {
|
||||||
setParent(Node)
|
setParent(Node)
|
||||||
LinkChildNode(node Node)
|
LinkChildNode(node Node)
|
||||||
UnlinkChildNode(nodeId NodeId)
|
UnlinkChildNode(nodeId NodeId)
|
||||||
|
CollectWritableVolumes(freshThreshHold int64, volumeSizeLimit uint64) []storage.VolumeId
|
||||||
|
|
||||||
IsDataNode() bool
|
IsDataNode() bool
|
||||||
Children() map[NodeId]Node
|
Children() map[NodeId]Node
|
||||||
Parent() Node
|
Parent() Node
|
||||||
}
|
}
|
||||||
type NodeImpl struct {
|
type NodeImpl struct {
|
||||||
id NodeId
|
id NodeId
|
||||||
|
@ -65,7 +66,7 @@ func (n *NodeImpl) Children() map[NodeId]Node {
|
||||||
return n.children
|
return n.children
|
||||||
}
|
}
|
||||||
func (n *NodeImpl) Parent() Node {
|
func (n *NodeImpl) Parent() Node {
|
||||||
return n.parent
|
return n.parent
|
||||||
}
|
}
|
||||||
func (n *NodeImpl) ReserveOneVolume(r int, vid storage.VolumeId) (bool, *DataNode) {
|
func (n *NodeImpl) ReserveOneVolume(r int, vid storage.VolumeId) (bool, *DataNode) {
|
||||||
ret := false
|
ret := false
|
||||||
|
@ -146,3 +147,26 @@ func (n *NodeImpl) UnlinkChildNode(nodeId NodeId) {
|
||||||
fmt.Println(n, "removes", node, "volumeCount =", n.activeVolumeCount)
|
fmt.Println(n, "removes", node, "volumeCount =", n.activeVolumeCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NodeImpl) CollectWritableVolumes(freshThreshHold int64, volumeSizeLimit uint64) []storage.VolumeId {
|
||||||
|
var ret []storage.VolumeId
|
||||||
|
if n.IsRack() {
|
||||||
|
for _, c := range n.Children() {
|
||||||
|
dn := c.(*DataNode) //can not cast n to DataNode
|
||||||
|
if dn.lastSeen > freshThreshHold {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, v := range dn.volumes {
|
||||||
|
if uint64(v.Size) < volumeSizeLimit {
|
||||||
|
ret = append(ret, v.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, c := range n.Children() {
|
||||||
|
ret = append(ret, c.CollectWritableVolumes(freshThreshHold, volumeSizeLimit)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
@ -3,37 +3,59 @@ package topology
|
||||||
import (
|
import (
|
||||||
_ "fmt"
|
_ "fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"pkg/sequence"
|
||||||
"pkg/storage"
|
"pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Topology struct {
|
type Topology struct {
|
||||||
NodeImpl
|
NodeImpl
|
||||||
|
|
||||||
|
//transient vid~servers mapping for each replication type
|
||||||
|
replicaType2VolumeLayout []*VolumeLayout
|
||||||
|
|
||||||
|
pulse int64
|
||||||
|
|
||||||
|
volumeSizeLimit uint64
|
||||||
|
|
||||||
|
sequence sequence.Sequencer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTopology(id string) *Topology {
|
func NewTopology(id string, dirname string, filename string, volumeSizeLimit uint64, pulse int) *Topology {
|
||||||
t := &Topology{}
|
t := &Topology{}
|
||||||
t.id = NodeId(id)
|
t.id = NodeId(id)
|
||||||
t.nodeType = "Topology"
|
t.nodeType = "Topology"
|
||||||
t.children = make(map[NodeId]Node)
|
t.children = make(map[NodeId]Node)
|
||||||
|
t.replicaType2VolumeLayout = make([]*VolumeLayout, storage.LengthRelicationType)
|
||||||
|
t.pulse = int64(pulse)
|
||||||
|
t.volumeSizeLimit = volumeSizeLimit
|
||||||
|
t.sequence = sequence.NewSequencer(dirname, filename)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
func (t *Topology) RandomlyReserveOneVolume() (bool, *DataNode, storage.VolumeId) {
|
func (t *Topology) RandomlyReserveOneVolume() (bool, *DataNode, storage.VolumeId) {
|
||||||
vid := t.NextVolumeId()
|
vid := t.NextVolumeId()
|
||||||
ret, node := t.ReserveOneVolume(rand.Intn(t.FreeSpace()), vid)
|
ret, node := t.ReserveOneVolume(rand.Intn(t.FreeSpace()), vid)
|
||||||
return ret, node, vid
|
return ret, node, vid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Topology) RandomlyReserveOneVolumeExcept(except []Node) (bool, *DataNode, storage.VolumeId) {
|
func (t *Topology) RandomlyReserveOneVolumeExcept(except []Node) (bool, *DataNode, storage.VolumeId) {
|
||||||
freeSpace := t.FreeSpace()
|
freeSpace := t.FreeSpace()
|
||||||
for _, node := range except {
|
for _, node := range except {
|
||||||
freeSpace -= node.FreeSpace()
|
freeSpace -= node.FreeSpace()
|
||||||
}
|
}
|
||||||
vid := t.NextVolumeId()
|
vid := t.NextVolumeId()
|
||||||
ret, node := t.ReserveOneVolume(rand.Intn(freeSpace), vid)
|
ret, node := t.ReserveOneVolume(rand.Intn(freeSpace), vid)
|
||||||
return ret, node, vid
|
return ret, node, vid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Topology) NextVolumeId() storage.VolumeId {
|
func (t *Topology) NextVolumeId() storage.VolumeId {
|
||||||
vid := t.GetMaxVolumeId()
|
vid := t.GetMaxVolumeId()
|
||||||
return vid.Next()
|
return vid.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Topology) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
|
||||||
|
replicationTypeIndex := storage.GetReplicationLevelIndex(v)
|
||||||
|
if t.replicaType2VolumeLayout[replicationTypeIndex] == nil {
|
||||||
|
t.replicaType2VolumeLayout[replicationTypeIndex] = NewVolumeLayout(t.volumeSizeLimit, t.pulse)
|
||||||
|
}
|
||||||
|
t.replicaType2VolumeLayout[replicationTypeIndex].RegisterVolume(v, dn)
|
||||||
|
}
|
||||||
|
|
48
weed-fs/src/pkg/topology/volume_layout.go
Normal file
48
weed-fs/src/pkg/topology/volume_layout.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package topology
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"pkg/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VolumeLayout struct {
|
||||||
|
vid2location map[storage.VolumeId]*DataNodeLocationList
|
||||||
|
writables []storage.VolumeId // transient array of writable volume id
|
||||||
|
pulse int64
|
||||||
|
volumeSizeLimit uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVolumeLayout(volumeSizeLimit uint64, pulse int64) *VolumeLayout {
|
||||||
|
return &VolumeLayout{
|
||||||
|
vid2location: make(map[storage.VolumeId]*DataNodeLocationList),
|
||||||
|
writables: *new([]storage.VolumeId),
|
||||||
|
pulse: pulse,
|
||||||
|
volumeSizeLimit: volumeSizeLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vl *VolumeLayout) RegisterVolume(v *storage.VolumeInfo, dn *DataNode) {
|
||||||
|
if _, ok := vl.vid2location[v.Id]; !ok {
|
||||||
|
vl.vid2location[v.Id] = NewDataNodeLocationList()
|
||||||
|
}
|
||||||
|
vl.vid2location[v.Id].Add(dn)
|
||||||
|
if len(vl.vid2location[v.Id].list) >= storage.GetCopyCount(v) {
|
||||||
|
vl.writables = append(vl.writables,v.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vl *VolumeLayout) PickForWrite(count int) (int, *DataNodeLocationList, error) {
|
||||||
|
len_writers := len(vl.writables)
|
||||||
|
if len_writers <= 0 {
|
||||||
|
fmt.Println("No more writable volumes!")
|
||||||
|
return 0, nil, errors.New("No more writable volumes!")
|
||||||
|
}
|
||||||
|
vid := vl.writables[rand.Intn(len_writers)]
|
||||||
|
locationList := vl.vid2location[vid]
|
||||||
|
if locationList != nil {
|
||||||
|
return count, locationList, nil
|
||||||
|
}
|
||||||
|
return 0, nil, errors.New("Strangely vid " + vid.String() + " is on no machine!")
|
||||||
|
}
|
21
weed-fs/src/pkg/topology/volume_location.go
Normal file
21
weed-fs/src/pkg/topology/volume_location.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package topology
|
||||||
|
|
||||||
|
import (
|
||||||
|
)
|
||||||
|
|
||||||
|
type DataNodeLocationList struct {
|
||||||
|
list []*DataNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDataNodeLocationList() *DataNodeLocationList {
|
||||||
|
return &DataNodeLocationList{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dnll *DataNodeLocationList) Add(loc *DataNode){
|
||||||
|
for _, dnl := range dnll.list {
|
||||||
|
if loc.ip == dnl.ip && loc.port == dnl.port {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dnll.list = append(dnll.list, loc)
|
||||||
|
}
|
Loading…
Reference in a new issue