SeaweedFS tracks EC shard sizes on topology data stuctures, but this information is never
relayed to master servers :( The end result is that commands reporting disk usage, such
as `volume.list` and `cluster.status`, yield incorrect figures when EC shards are present.
As an example for a simple 5-node test cluster, before...
```
> volume.list
Topology volumeSizeLimit:30000 MB hdd(volume:6/40 active:6 free:33 remote:0)
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9001 hdd(volume:1/8 active:1 free:7 remote:0)
Disk hdd(volume:1/8 active:1 free:7 remote:0) id:0
volume id:3 size:88967096 file_count:172 replica_placement:2 version:3 modified_at_second:1766349617
ec volume id:1 collection: shards:[1 5]
Disk hdd total size:88967096 file_count:172
DataNode 192.168.10.111:9001 total size:88967096 file_count:172
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9002 hdd(volume:2/8 active:2 free:6 remote:0)
Disk hdd(volume:2/8 active:2 free:6 remote:0) id:0
volume id:2 size:77267536 file_count:166 replica_placement:2 version:3 modified_at_second:1766349617
volume id:3 size:88967096 file_count:172 replica_placement:2 version:3 modified_at_second:1766349617
ec volume id:1 collection: shards:[0 4]
Disk hdd total size:166234632 file_count:338
DataNode 192.168.10.111:9002 total size:166234632 file_count:338
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9003 hdd(volume:1/8 active:1 free:7 remote:0)
Disk hdd(volume:1/8 active:1 free:7 remote:0) id:0
volume id:2 size:77267536 file_count:166 replica_placement:2 version:3 modified_at_second:1766349617
ec volume id:1 collection: shards:[2 6]
Disk hdd total size:77267536 file_count:166
DataNode 192.168.10.111:9003 total size:77267536 file_count:166
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9004 hdd(volume:2/8 active:2 free:6 remote:0)
Disk hdd(volume:2/8 active:2 free:6 remote:0) id:0
volume id:2 size:77267536 file_count:166 replica_placement:2 version:3 modified_at_second:1766349617
volume id:3 size:88967096 file_count:172 replica_placement:2 version:3 modified_at_second:1766349617
ec volume id:1 collection: shards:[3 7]
Disk hdd total size:166234632 file_count:338
DataNode 192.168.10.111:9004 total size:166234632 file_count:338
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9005 hdd(volume:0/8 active:0 free:8 remote:0)
Disk hdd(volume:0/8 active:0 free:8 remote:0) id:0
ec volume id:1 collection: shards:[8 9 10 11 12 13]
Disk hdd total size:0 file_count:0
Rack DefaultRack total size:498703896 file_count:1014
DataCenter DefaultDataCenter total size:498703896 file_count:1014
total size:498703896 file_count:1014
```
...and after:
```
> volume.list
Topology volumeSizeLimit:30000 MB hdd(volume:6/40 active:6 free:33 remote:0)
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9001 hdd(volume:1/8 active:1 free:7 remote:0)
Disk hdd(volume:1/8 active:1 free:7 remote:0) id:0
volume id:2 size:81761800 file_count:161 replica_placement:2 version:3 modified_at_second:1766349495
ec volume id:1 collection: shards:[1 5 9] sizes:[1:8.00 MiB 5:8.00 MiB 9:8.00 MiB] total:24.00 MiB
Disk hdd total size:81761800 file_count:161
DataNode 192.168.10.111:9001 total size:81761800 file_count:161
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9002 hdd(volume:1/8 active:1 free:7 remote:0)
Disk hdd(volume:1/8 active:1 free:7 remote:0) id:0
volume id:3 size:88678712 file_count:170 replica_placement:2 version:3 modified_at_second:1766349495
ec volume id:1 collection: shards:[11 12 13] sizes:[11:8.00 MiB 12:8.00 MiB 13:8.00 MiB] total:24.00 MiB
Disk hdd total size:88678712 file_count:170
DataNode 192.168.10.111:9002 total size:88678712 file_count:170
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9003 hdd(volume:2/8 active:2 free:6 remote:0)
Disk hdd(volume:2/8 active:2 free:6 remote:0) id:0
volume id:2 size:81761800 file_count:161 replica_placement:2 version:3 modified_at_second:1766349495
volume id:3 size:88678712 file_count:170 replica_placement:2 version:3 modified_at_second:1766349495
ec volume id:1 collection: shards:[0 4 8] sizes:[0:8.00 MiB 4:8.00 MiB 8:8.00 MiB] total:24.00 MiB
Disk hdd total size:170440512 file_count:331
DataNode 192.168.10.111:9003 total size:170440512 file_count:331
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9004 hdd(volume:2/8 active:2 free:6 remote:0)
Disk hdd(volume:2/8 active:2 free:6 remote:0) id:0
volume id:2 size:81761800 file_count:161 replica_placement:2 version:3 modified_at_second:1766349495
volume id:3 size:88678712 file_count:170 replica_placement:2 version:3 modified_at_second:1766349495
ec volume id:1 collection: shards:[2 6 10] sizes:[2:8.00 MiB 6:8.00 MiB 10:8.00 MiB] total:24.00 MiB
Disk hdd total size:170440512 file_count:331
DataNode 192.168.10.111:9004 total size:170440512 file_count:331
DataCenter DefaultDataCenter hdd(volume:6/40 active:6 free:33 remote:0)
Rack DefaultRack hdd(volume:6/40 active:6 free:33 remote:0)
DataNode 192.168.10.111:9005 hdd(volume:0/8 active:0 free:8 remote:0)
Disk hdd(volume:0/8 active:0 free:8 remote:0) id:0
ec volume id:1 collection: shards:[3 7] sizes:[3:8.00 MiB 7:8.00 MiB] total:16.00 MiB
Disk hdd total size:0 file_count:0
Rack DefaultRack total size:511321536 file_count:993
DataCenter DefaultDataCenter total size:511321536 file_count:993
total size:511321536 file_count:993
```
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
package shell
|
|
|
|
import (
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/types"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
//"google.golang.org/protobuf/proto"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
|
|
)
|
|
|
|
func TestParsing(t *testing.T) {
|
|
topo := parseOutput(topoData)
|
|
|
|
assert.Equal(t, 5, len(topo.DataCenterInfos))
|
|
|
|
topo = parseOutput(topoData2)
|
|
|
|
dataNodes := topo.DataCenterInfos[0].RackInfos[0].DataNodeInfos
|
|
assert.Equal(t, 14, len(dataNodes))
|
|
diskInfo := dataNodes[0].DiskInfos[""]
|
|
assert.Equal(t, 1559, len(diskInfo.VolumeInfos))
|
|
assert.Equal(t, 6740, len(diskInfo.EcShardInfos))
|
|
|
|
}
|
|
|
|
// TODO: actually parsing all fields would be nice...
|
|
func parseOutput(output string) *master_pb.TopologyInfo {
|
|
lines := strings.Split(output, "\n")
|
|
var topo *master_pb.TopologyInfo
|
|
var dc *master_pb.DataCenterInfo
|
|
var rack *master_pb.RackInfo
|
|
var dn *master_pb.DataNodeInfo
|
|
var disk *master_pb.DiskInfo
|
|
for _, line := range lines {
|
|
line = strings.TrimSpace(line)
|
|
parts := strings.Split(line, " ")
|
|
switch parts[0] {
|
|
case "Topology":
|
|
if topo == nil {
|
|
topo = &master_pb.TopologyInfo{
|
|
Id: parts[1],
|
|
}
|
|
}
|
|
case "DataCenter":
|
|
if dc == nil {
|
|
dc = &master_pb.DataCenterInfo{
|
|
Id: parts[1],
|
|
}
|
|
topo.DataCenterInfos = append(topo.DataCenterInfos, dc)
|
|
} else {
|
|
dc = nil
|
|
}
|
|
case "Rack":
|
|
if rack == nil {
|
|
rack = &master_pb.RackInfo{
|
|
Id: parts[1],
|
|
}
|
|
dc.RackInfos = append(dc.RackInfos, rack)
|
|
} else {
|
|
rack = nil
|
|
}
|
|
case "DataNode":
|
|
if dn == nil {
|
|
dn = &master_pb.DataNodeInfo{
|
|
Id: parts[1],
|
|
DiskInfos: make(map[string]*master_pb.DiskInfo),
|
|
}
|
|
rack.DataNodeInfos = append(rack.DataNodeInfos, dn)
|
|
} else {
|
|
dn = nil
|
|
}
|
|
case "Disk":
|
|
if disk == nil {
|
|
diskType := parts[1][:strings.Index(parts[1], "(")]
|
|
volumeCountStr := parts[1][strings.Index(parts[1], ":")+1 : strings.Index(parts[1], "/")]
|
|
maxVolumeCountStr := parts[1][strings.Index(parts[1], "/")+1:]
|
|
maxVolumeCount, _ := strconv.Atoi(maxVolumeCountStr)
|
|
volumeCount, _ := strconv.Atoi(volumeCountStr)
|
|
disk = &master_pb.DiskInfo{
|
|
Type: diskType,
|
|
MaxVolumeCount: int64(maxVolumeCount),
|
|
VolumeCount: int64(volumeCount),
|
|
}
|
|
dn.DiskInfos[types.ToDiskType(diskType).String()] = disk
|
|
} else {
|
|
disk = nil
|
|
}
|
|
case "volume":
|
|
volumeLine := line[len("volume "):]
|
|
volume := &master_pb.VolumeInformationMessage{}
|
|
proto.UnmarshalText(volumeLine, volume)
|
|
disk.VolumeInfos = append(disk.VolumeInfos, volume)
|
|
case "ec":
|
|
ecVolumeLine := line[len("ec volume "):]
|
|
ecShard := &master_pb.VolumeEcShardInformationMessage{}
|
|
for _, part := range strings.Split(ecVolumeLine, " ") {
|
|
if strings.HasPrefix(part, "id:") {
|
|
id, _ := strconv.ParseInt(part[len("id:"):], 10, 64)
|
|
ecShard.Id = uint32(id)
|
|
}
|
|
if strings.HasPrefix(part, "collection:") {
|
|
ecShard.Collection = part[len("collection:"):]
|
|
}
|
|
// TODO: we need to parse EC shard sizes as well
|
|
if strings.HasPrefix(part, "shards:") {
|
|
shards := part[len("shards:["):]
|
|
shards = strings.TrimRight(shards, "]")
|
|
shardsInfo := erasure_coding.NewShardsInfo()
|
|
for _, shardId := range strings.Split(shards, ",") {
|
|
sid, _ := strconv.Atoi(shardId)
|
|
shardsInfo.Set(erasure_coding.ShardId(sid), 0)
|
|
}
|
|
ecShard.EcIndexBits = shardsInfo.Bitmap()
|
|
ecShard.ShardSizes = shardsInfo.SizesInt64()
|
|
}
|
|
}
|
|
disk.EcShardInfos = append(disk.EcShardInfos, ecShard)
|
|
}
|
|
}
|
|
|
|
return topo
|
|
}
|