diff --git a/weed/server/master_ui/templates.go b/weed/server/master_ui/templates.go index ceb0528cf..b674e3f82 100644 --- a/weed/server/master_ui/templates.go +++ b/weed/server/master_ui/templates.go @@ -76,6 +76,7 @@ var StatusTpl = template.Must(template.New("status").Parse(` Rack RemoteAddr #Volumes + #ErasureCodingShards Max @@ -88,6 +89,7 @@ var StatusTpl = template.Must(template.New("status").Parse(` {{ $rack.Id }} {{ $dn.Url }} {{ $dn.Volumes }} + {{ $dn.EcShards }} {{ $dn.Max }} {{ end }} diff --git a/weed/server/volume_server_handlers_ui.go b/weed/server/volume_server_handlers_ui.go index 17d20a36e..852f0b751 100644 --- a/weed/server/volume_server_handlers_ui.go +++ b/weed/server/volume_server_handlers_ui.go @@ -24,6 +24,7 @@ func (vs *VolumeServer) uiStatusHandler(w http.ResponseWriter, r *http.Request) Version string Masters []string Volumes interface{} + EcVolumes interface{} DiskStatuses interface{} Stats interface{} Counters *stats.ServerStats @@ -31,6 +32,7 @@ func (vs *VolumeServer) uiStatusHandler(w http.ResponseWriter, r *http.Request) util.VERSION, vs.SeedMasterNodes, vs.store.Status(), + vs.store.EcVolumes(), ds, infos, serverStats, diff --git a/weed/server/volume_server_ui/templates.go b/weed/server/volume_server_ui/templates.go index b9740510f..eafc0aaeb 100644 --- a/weed/server/volume_server_ui/templates.go +++ b/weed/server/volume_server_ui/templates.go @@ -128,6 +128,32 @@ var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(` +
+

Erasure Coding Shards

+ + + + + + + + + + + + {{ range .EcVolumes }} + + + + + + + + {{ end }} + +
IdCollectionShard SizeShardsCreatedAt
{{ .VolumeId }}{{ .Collection }}{{ .ShardSize }} Bytes{{ .ShardIdList }}{{ .CreatedAt.Format "02 Jan 06 15:04 -0700" }}
+
+ diff --git a/weed/storage/erasure_coding/ec_shard.go b/weed/storage/erasure_coding/ec_shard.go index 9eeb35725..7b9f2dc07 100644 --- a/weed/storage/erasure_coding/ec_shard.go +++ b/weed/storage/erasure_coding/ec_shard.go @@ -39,6 +39,10 @@ func NewEcVolumeShard(dirname string, collection string, id needle.VolumeId, sha return } +func (shard *EcVolumeShard) Size() int64 { + return shard.ecdFileSize +} + func (shard *EcVolumeShard) String() string { return fmt.Sprintf("ec shard %v:%v, dir:%s, Collection:%s", shard.VolumeId, shard.ShardId, shard.dir, shard.Collection) } diff --git a/weed/storage/erasure_coding/ec_volume.go b/weed/storage/erasure_coding/ec_volume.go index 44d8ca80f..17e7f2935 100644 --- a/weed/storage/erasure_coding/ec_volume.go +++ b/weed/storage/erasure_coding/ec_volume.go @@ -20,6 +20,7 @@ type EcVolume struct { dir string ecxFile *os.File ecxFileSize int64 + ecxCreatedAt time.Time Shards []*EcVolumeShard ShardLocations map[ShardId][]string ShardLocationsRefreshTime time.Time @@ -41,6 +42,7 @@ func NewEcVolume(dir string, collection string, vid needle.VolumeId) (ev *EcVolu return nil, fmt.Errorf("can not stat ec volume index %s.ecx: %v", baseFileName, statErr) } ev.ecxFileSize = ecxFi.Size() + ev.ecxCreatedAt = ecxFi.ModTime() ev.ShardLocations = make(map[ShardId][]string) @@ -113,6 +115,24 @@ func (ev *EcVolume) FileName() string { } +func (ev *EcVolume) ShardSize() int64 { + if len(ev.Shards) > 0 { + return ev.Shards[0].Size() + } + return 0 +} + +func (ev *EcVolume) CreatedAt() time.Time { + return ev.ecxCreatedAt +} + +func (ev *EcVolume) ShardIdList() (shardIds []ShardId) { + for _, s := range ev.Shards { + shardIds = append(shardIds, s.ShardId) + } + return +} + func (ev *EcVolume) ToVolumeEcShardInformationMessage() (messages []*master_pb.VolumeEcShardInformationMessage) { prevVolumeId := needle.VolumeId(math.MaxUint32) var m *master_pb.VolumeEcShardInformationMessage diff --git a/weed/storage/store_ec.go b/weed/storage/store_ec.go index 1fddb8285..4ac01c4a9 100644 --- a/weed/storage/store_ec.go +++ b/weed/storage/store_ec.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "sort" "sync" "time" @@ -365,3 +366,17 @@ func (s *Store) recoverOneRemoteEcShardInterval(ctx context.Context, ecVolume *e return len(buf), nil } + +func (s *Store) EcVolumes() (ecVolumes []*erasure_coding.EcVolume) { + for _, location := range s.Locations { + location.ecVolumesLock.RLock() + for _, v := range location.ecVolumes { + ecVolumes = append(ecVolumes, v) + } + location.ecVolumesLock.RUnlock() + } + sort.Slice(ecVolumes, func(i, j int) bool { + return ecVolumes[i].VolumeId > ecVolumes[j].VolumeId + }) + return ecVolumes +} diff --git a/weed/topology/data_node.go b/weed/topology/data_node.go index 5edc9c580..bb9970446 100644 --- a/weed/topology/data_node.go +++ b/weed/topology/data_node.go @@ -146,6 +146,7 @@ func (dn *DataNode) ToMap() interface{} { ret := make(map[string]interface{}) ret["Url"] = dn.Url() ret["Volumes"] = dn.GetVolumeCount() + ret["EcShards"] = dn.GetEcShardsCount() ret["Max"] = dn.GetMaxVolumeCount() ret["Free"] = dn.FreeSpace() ret["PublicUrl"] = dn.PublicUrl diff --git a/weed/topology/data_node_ec.go b/weed/topology/data_node_ec.go index 2ea7fc6ad..a0e3a699f 100644 --- a/weed/topology/data_node_ec.go +++ b/weed/topology/data_node_ec.go @@ -14,6 +14,17 @@ func (dn *DataNode) GetEcShards() (ret []*erasure_coding.EcVolumeInfo) { return ret } +func (dn *DataNode) GetEcShardsCount() (count int) { + dn.RLock() + defer dn.RUnlock() + + for _, ecVolumeInfo := range dn.ecShards { + count += ecVolumeInfo.ShardBits.ShardIdCount() + } + + return count +} + func (dn *DataNode) UpdateEcShards(actualShards []*erasure_coding.EcVolumeInfo) (newShards, deletedShards []*erasure_coding.EcVolumeInfo) { // prepare the new ec shard map actualEcShardMap := make(map[needle.VolumeId]*erasure_coding.EcVolumeInfo)