mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 10:06:14 +00:00
close: #1000362788
Signed-off-by: shuqiang-zheng <zhengshuqiang@oppo.com>
(cherry picked from commit ef8d06e97e)
1581 lines
66 KiB
Go
1581 lines
66 KiB
Go
// Copyright 2018 The CubeFS Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
// implied. See the License for the specific language governing
|
|
// permissions and limitations under the License.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/depends/tiglabs/raft/util"
|
|
"github.com/cubefs/cubefs/proto"
|
|
"github.com/cubefs/cubefs/util/strutil"
|
|
)
|
|
|
|
func formatAddr(ipAddr string, domainAddr string) (addr string) {
|
|
if len(domainAddr) != 0 {
|
|
addr = fmt.Sprintf("%v(%v)", ipAddr, domainAddr)
|
|
} else {
|
|
addr = ipAddr
|
|
}
|
|
return
|
|
}
|
|
|
|
func formatIndent(v interface{}) string {
|
|
b, _ := json.MarshalIndent(v, "", " ")
|
|
return string(b)
|
|
}
|
|
|
|
func formatClusterView(cv *proto.ClusterView, cn *proto.ClusterNodeInfo, cp *proto.ClusterIP) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" Cluster name : %v\n", cv.Name))
|
|
sb.WriteString(fmt.Sprintf(" Master leader : %v\n", cv.LeaderAddr))
|
|
for _, master := range cv.MasterNodes {
|
|
sb.WriteString(fmt.Sprintf(" Master-%d : %v\n", master.ID, master.Addr))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" Auto allocate : %v\n", formatEnabledDisabled(!cv.DisableAutoAlloc)))
|
|
|
|
metaNodeActiveCnt := 0
|
|
for _, node := range cv.MetaNodes {
|
|
if node.Status {
|
|
metaNodeActiveCnt += 1
|
|
}
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" MetaNode count (active/total) : %v/%v\n", metaNodeActiveCnt, len(cv.MetaNodes)))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode used : %v GB\n", cv.MetaNodeStatInfo.UsedGB))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode available : %v GB\n", cv.MetaNodeStatInfo.AvailGB))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode total : %v GB\n", cv.MetaNodeStatInfo.TotalGB))
|
|
|
|
dataNodeActiveCnt := 0
|
|
for _, node := range cv.DataNodes {
|
|
if node.Status {
|
|
dataNodeActiveCnt += 1
|
|
}
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" DataNode count (active/total) : %v/%v\n", dataNodeActiveCnt, len(cv.DataNodes)))
|
|
sb.WriteString(fmt.Sprintf(" DataNode used : %v GB\n", cv.DataNodeStatInfo.UsedGB))
|
|
sb.WriteString(fmt.Sprintf(" DataNode available : %v GB\n", cv.DataNodeStatInfo.AvailGB))
|
|
sb.WriteString(fmt.Sprintf(" DataNode total : %v GB\n", cv.DataNodeStatInfo.TotalGB))
|
|
|
|
sb.WriteString(fmt.Sprintf(" Volume count : %v\n", len(cv.VolStatInfo)))
|
|
sb.WriteString(fmt.Sprintf(" Allow Mp Decomm : %v\n", formatEnabledDisabled(!cv.ForbidMpDecommission)))
|
|
sb.WriteString(fmt.Sprintf(" EbsAddr : %v\n", cp.EbsAddr))
|
|
sb.WriteString(fmt.Sprintf(" LoadFactor : %v\n", cn.LoadFactor))
|
|
sb.WriteString(fmt.Sprintf(" DpRepairTimeout : %v\n", cv.DpRepairTimeout))
|
|
sb.WriteString(fmt.Sprintf(" DataPartitionTimeout : %v\n", cv.DpTimeout))
|
|
sb.WriteString(fmt.Sprintf(" MetaPartitionTimeout : %v\n", cv.MpTimeout))
|
|
sb.WriteString(fmt.Sprintf(" volDeletionDelayTime : %v h\n", cv.VolDeletionDelayTimeHour))
|
|
sb.WriteString(fmt.Sprintf(" MetaNodeGOGC : %v\n", cv.MetaNodeGOGC))
|
|
sb.WriteString(fmt.Sprintf(" DataNodeGOGC : %v\n", cv.DataNodeGOGC))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDecommission : %v\n", cv.EnableAutoDecommission))
|
|
sb.WriteString(fmt.Sprintf(" AutoDecommissionDiskInterval : %v\n", cv.AutoDecommissionDiskInterval))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDpMetaRepair : %v\n", cv.EnableAutoDpMetaRepair))
|
|
sb.WriteString(fmt.Sprintf(" AutoDpMetaRepairParallelCnt : %v\n", cv.AutoDpMetaRepairParallelCnt))
|
|
sb.WriteString(fmt.Sprintf(" MarkDiskBrokenThreshold : %v\n", strutil.FormatPercent(cv.MarkDiskBrokenThreshold)))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionFirstHostDiskParallelLimit : %v\n", cv.DecommissionFirstHostDiskParallelLimit))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionDpLimit : %v\n", cv.DecommissionLimit))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionDiskLimit : %v\n", cv.DecommissionDiskLimit))
|
|
sb.WriteString(fmt.Sprintf(" DpBackupTimeout : %v\n", cv.DpBackupTimeout))
|
|
sb.WriteString(fmt.Sprintf(" ForbidWriteOpOfProtoVersion0 : %v\n", cv.ForbidWriteOpOfProtoVer0))
|
|
sb.WriteString(fmt.Sprintf(" LegacyDataMediaType : %v\n", cv.LegacyDataMediaType))
|
|
sb.WriteString(fmt.Sprintf(" RaftPartitionCanUsingDifferentPortEnabled: %v\n", cv.RaftPartitionCanUsingDifferentPortEnabled))
|
|
|
|
sb.WriteString(fmt.Sprintf(" FlashNodeHandleReadTimeout : %v ms\n", cv.FlashNodeHandleReadTimeout))
|
|
sb.WriteString(fmt.Sprintf(" FlashNodeReadDataNodeTimeout : %v ms\n", cv.FlashNodeReadDataNodeTimeout))
|
|
sb.WriteString(fmt.Sprintf(" RemoteCacheTTL : %v s\n", cv.RemoteCacheTTL))
|
|
sb.WriteString(fmt.Sprintf(" RemoteCacheReadTimeout : %v ms\n", cv.RemoteCacheReadTimeout))
|
|
sb.WriteString(fmt.Sprintf(" RemoteCacheMultiRead : %v\n", cv.RemoteCacheMultiRead))
|
|
sb.WriteString(fmt.Sprintf(" FlashNodeTimeoutCount : %v\n", cv.FlashNodeTimeoutCount))
|
|
// sb.WriteString(fmt.Sprintf(" RemoteCacheSameZoneTimeout : %v microsecond\n", cv.RemoteCacheSameZoneTimeout))
|
|
// sb.WriteString(fmt.Sprintf(" RemoteCacheSameRegionTimeout : %v millisecond\n", cv.RemoteCacheSameRegionTimeout))
|
|
sb.WriteString(fmt.Sprintf(" FlashHotKeyMissCount : %v\n", cv.FlashHotKeyMissCount))
|
|
sb.WriteString(fmt.Sprintf(" FlashReadFlowLimit : %v\n", cv.FlashReadFlowLimit))
|
|
sb.WriteString(fmt.Sprintf(" FlashWriteFlowLimit : %v\n", cv.FlashWriteFlowLimit))
|
|
sb.WriteString(fmt.Sprintf(" FlashKeyFlowLimit : %v\n", cv.FlashKeyFlowLimit))
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
statInfoTablePattern = " %-15v %-15v %-15v %-15v\n"
|
|
statInfoTableHeader = fmt.Sprintf(statInfoTablePattern,
|
|
"TOTAL/GB", "USED/GB", "INCREASED/GB", "USED RATIO")
|
|
zoneStatInfoTablePattern = " %-10v %-10v %-15v %-15v %-15v %-15v %-10v %-10v\n"
|
|
zoneStatInfoTableHeader = fmt.Sprintf(zoneStatInfoTablePattern,
|
|
"ZONE NAME", "ROLE", "TOTAL/GB", "USED/GB", "AVAILABLE/GB ", "USED RATIO", "TOTAL NODES", "WRITEBLE NODES")
|
|
)
|
|
|
|
func formatClusterStat(cs *proto.ClusterStatInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("DataNode Status:\n")
|
|
sb.WriteString(statInfoTableHeader)
|
|
sb.WriteString(fmt.Sprintf(statInfoTablePattern, cs.DataNodeStatInfo.TotalGB, cs.DataNodeStatInfo.UsedGB, cs.DataNodeStatInfo.IncreasedGB, cs.DataNodeStatInfo.UsedRatio))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MetaNode Status:\n")
|
|
sb.WriteString(statInfoTableHeader)
|
|
sb.WriteString(fmt.Sprintf(statInfoTablePattern, cs.MetaNodeStatInfo.TotalGB, cs.MetaNodeStatInfo.UsedGB, cs.MetaNodeStatInfo.IncreasedGB, cs.MetaNodeStatInfo.UsedRatio))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zone List:\n")
|
|
sb.WriteString(zoneStatInfoTableHeader)
|
|
for zoneName, zoneStat := range cs.ZoneStatInfo {
|
|
sb.WriteString(fmt.Sprintf(zoneStatInfoTablePattern, zoneName, "DATANODE", zoneStat.DataNodeStat.Total, zoneStat.DataNodeStat.Used, zoneStat.DataNodeStat.Avail, zoneStat.DataNodeStat.UsedRatio, zoneStat.DataNodeStat.TotalNodes, zoneStat.DataNodeStat.WritableNodes))
|
|
sb.WriteString(fmt.Sprintf(zoneStatInfoTablePattern, "", "METANODE", zoneStat.MetaNodeStat.Total, zoneStat.MetaNodeStat.Used, zoneStat.MetaNodeStat.Avail, zoneStat.MetaNodeStat.UsedRatio, zoneStat.MetaNodeStat.TotalNodes, zoneStat.MetaNodeStat.WritableNodes))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataNodeOp(opv *proto.OpLogView, logNum int, dataNodeName string, filterOp string) string {
|
|
maxLines := 1000
|
|
if logNum > 0 && logNum < maxLines {
|
|
maxLines = logNum
|
|
}
|
|
sb := strings.Builder{}
|
|
lineCount := 0
|
|
for _, opLog := range opv.ClusterOpLogs {
|
|
if dataNodeName != "" && opLog.Name != dataNodeName {
|
|
continue
|
|
}
|
|
if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
continue
|
|
}
|
|
lineCount++
|
|
if lineCount > maxLines {
|
|
break
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%-30v %-20v %v\n", opLog.Name, opLog.Op, opLog.Count))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatClusterDpOp(opv *proto.OpLogView, logNum int, filterOp string) string {
|
|
maxLines := 1000
|
|
if logNum > 0 && logNum < maxLines {
|
|
maxLines = logNum
|
|
}
|
|
sb := strings.Builder{}
|
|
lineCount := 0
|
|
for _, opLog := range opv.DpOpLogs {
|
|
if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
continue
|
|
}
|
|
lineCount++
|
|
if lineCount > maxLines {
|
|
break
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%-30v %-20v %v\n", opLog.Name, opLog.Op, opLog.Count))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatClusterDiskOp(opv *proto.OpLogView, logNum int, filterOp string) string {
|
|
maxLines := 1000
|
|
if logNum > 0 && logNum < maxLines {
|
|
maxLines = logNum
|
|
}
|
|
sb := strings.Builder{}
|
|
lineCount := 0
|
|
for _, opLog := range opv.DiskOpLogs {
|
|
if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
continue
|
|
}
|
|
lineCount++
|
|
if lineCount > maxLines {
|
|
break
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%-45v %-20v %v\n", opLog.Name, opLog.Op, opLog.Count))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var nodeViewTableRowPattern = "%-6v %-65v %-8v %-8v %-8v %-12v"
|
|
|
|
func formatNodeViewTableHeader() string {
|
|
return fmt.Sprintf(nodeViewTableRowPattern, "ID", "ADDRESS", "WRITABLE", "ACTIVE", "MEDIA", "ForbidWriteOpOfProtoVer0")
|
|
}
|
|
|
|
func formatNodeView(view *proto.NodeView, tableRow bool) string {
|
|
if tableRow {
|
|
return fmt.Sprintf(nodeViewTableRowPattern, view.ID, formatAddr(view.Addr, view.DomainAddr),
|
|
formatYesNo(view.IsWritable), formatNodeStatus(view.Status), formatNodeMediaType(view.MediaType),
|
|
formatNodeForbiddenWriteOpVer(view.ForbidWriteOpOfProtoVer0))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", view.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(view.Addr, view.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" Writable: %v\n", formatYesNo(view.IsWritable)))
|
|
sb.WriteString(fmt.Sprintf(" Active : %v", formatNodeStatus(view.Status)))
|
|
sb.WriteString(fmt.Sprintf(" MEDIA : %v", formatNodeMediaType(view.MediaType)))
|
|
sb.WriteString(fmt.Sprintf(" ForbidWriteOpOfProtoVer0: %v", formatNodeForbiddenWriteOpVer(view.ForbidWriteOpOfProtoVer0)))
|
|
return sb.String()
|
|
}
|
|
|
|
var nodeViewTableRowPatternForNodeSet = "%-6v %-65v %-8v %-8v %-10v %-10v %-10v"
|
|
|
|
func formatNodeViewTableHeaderForNodeSet() string {
|
|
return fmt.Sprintf(nodeViewTableRowPatternForNodeSet, "ID", "ADDRESS", "WRITABLE", "STATUS", "TOTAL", "USED", "AVAIL")
|
|
}
|
|
|
|
func formatNodeViewForNodeSet(view *proto.NodeStatView) string {
|
|
return fmt.Sprintf(nodeViewTableRowPatternForNodeSet, view.ID, formatAddr(view.Addr, view.DomainAddr),
|
|
formatYesNo(view.IsWritable), formatNodeStatus(view.Status),
|
|
formatSize(view.Total),
|
|
formatSize(view.Used),
|
|
formatSize(view.Avail))
|
|
}
|
|
|
|
func formatSimpleVolView(svv *proto.SimpleVolView) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", svv.ID))
|
|
sb.WriteString(fmt.Sprintf(" Name : %v\n", svv.Name))
|
|
sb.WriteString(fmt.Sprintf(" Owner : %v\n", svv.Owner))
|
|
sb.WriteString(fmt.Sprintf(" Authenticate : %v\n", formatEnabledDisabled(svv.Authenticate)))
|
|
sb.WriteString(fmt.Sprintf(" Capacity : %v GB\n", svv.Capacity))
|
|
sb.WriteString(fmt.Sprintf(" Create time : %v\n", svv.CreateTime))
|
|
sb.WriteString(fmt.Sprintf(" DeleteLockTime : %v\n", svv.DeleteLockTime))
|
|
sb.WriteString(fmt.Sprintf(" Cross zone : %v\n", formatEnabledDisabled(svv.CrossZone)))
|
|
sb.WriteString(fmt.Sprintf(" DefaultPriority : %v\n", svv.DefaultPriority))
|
|
sb.WriteString(fmt.Sprintf(" Dentry count : %v\n", svv.DentryCount))
|
|
sb.WriteString(fmt.Sprintf(" Description : %v\n", string([]rune(svv.Description)[:])))
|
|
sb.WriteString(fmt.Sprintf(" DpCnt : %v\n", svv.DpCnt))
|
|
sb.WriteString(fmt.Sprintf(" DpOfSSDCnt : %v\n", svv.DpOfSSDCnt))
|
|
sb.WriteString(fmt.Sprintf(" DpOfHDDCnt : %v\n", svv.DpOfHDDCnt))
|
|
sb.WriteString(fmt.Sprintf(" DpReplicaNum : %v\n", svv.DpReplicaNum))
|
|
sb.WriteString(fmt.Sprintf(" Follower read : %v\n", formatEnabledDisabled(svv.FollowerRead)))
|
|
sb.WriteString(fmt.Sprintf(" Meta Follower read : %v\n", formatEnabledDisabled(svv.MetaFollowerRead)))
|
|
sb.WriteString(fmt.Sprintf(" Direct Read : %v\n", formatEnabledDisabled(svv.DirectRead)))
|
|
sb.WriteString(fmt.Sprintf(" Ignore TinyRecover : %v\n", formatEnabledDisabled(svv.IgnoreTinyRecover)))
|
|
sb.WriteString(fmt.Sprintf(" Maximally Read : %v\n", formatEnabledDisabled(svv.MaximallyRead)))
|
|
sb.WriteString(fmt.Sprintf(" Inode count : %v\n", svv.InodeCount))
|
|
sb.WriteString(fmt.Sprintf(" Max metaPartition ID : %v\n", svv.MaxMetaPartitionID))
|
|
sb.WriteString(fmt.Sprintf(" Max DataPartition ID : %v\n", svv.MaxDataPartitionID))
|
|
sb.WriteString(fmt.Sprintf(" MpCnt : %v\n", svv.MpCnt))
|
|
sb.WriteString(fmt.Sprintf(" MpReplicaNum : %v\n", svv.MpReplicaNum))
|
|
sb.WriteString(fmt.Sprintf(" NeedToLowerReplica : %v\n", formatEnabledDisabled(svv.NeedToLowerReplica)))
|
|
sb.WriteString(fmt.Sprintf(" RwDpCnt : %v\n", svv.RwDpCnt))
|
|
sb.WriteString(fmt.Sprintf(" RwDpOfSSDCnt : %v\n", svv.RwDpOfSSDCnt))
|
|
sb.WriteString(fmt.Sprintf(" RwDpOfHDDCnt : %v\n", svv.RwDpOfHDDCnt))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatVolumeStatus(svv.Status)))
|
|
sb.WriteString(fmt.Sprintf(" ZoneName : %v\n", svv.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" VolType : %v\n", svv.VolType))
|
|
sb.WriteString(fmt.Sprintf(" DpReadOnlyWhenVolFull : %v\n", svv.DpReadOnlyWhenVolFull))
|
|
sb.WriteString(fmt.Sprintf(" Transaction Mask : %v\n", svv.EnableTransactionV1))
|
|
sb.WriteString(fmt.Sprintf(" Transaction timeout : %v\n", svv.TxTimeout))
|
|
sb.WriteString(fmt.Sprintf(" Tx conflict retry num : %v\n", svv.TxConflictRetryNum))
|
|
sb.WriteString(fmt.Sprintf(" Tx conflict retry interval(ms) : %v\n", svv.TxConflictRetryInterval))
|
|
sb.WriteString(fmt.Sprintf(" Tx limit interval(s) : %v\n", svv.TxOpLimit))
|
|
sb.WriteString(fmt.Sprintf(" Forbidden : %v\n", svv.Forbidden))
|
|
sb.WriteString(fmt.Sprintf(" DisableAuditLog : %v\n", svv.DisableAuditLog))
|
|
sb.WriteString(fmt.Sprintf(" TrashInterval : %v\n", time.Duration(svv.TrashInterval)*time.Minute))
|
|
sb.WriteString(fmt.Sprintf(" DpRepairBlockSize : %v\n", strutil.FormatSize(svv.DpRepairBlockSize)))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDpMetaRepair : %v\n", svv.EnableAutoDpMetaRepair))
|
|
sb.WriteString(fmt.Sprintf(" Quota : %v\n", formatEnabledDisabled(svv.EnableQuota)))
|
|
sb.WriteString(fmt.Sprintf(" AccessTimeValidInterval : %v\n", time.Duration(svv.AccessTimeInterval)*time.Second))
|
|
sb.WriteString(fmt.Sprintf(" MetaLeaderRetryTimeout : %v\n", time.Duration(svv.LeaderRetryTimeOut)*time.Second))
|
|
sb.WriteString(fmt.Sprintf(" EnablePersistAccessTime : %v\n", svv.EnablePersistAccessTime))
|
|
sb.WriteString(fmt.Sprintf(" ForbidWriteOpOfProtoVer0 : %v\n", svv.ForbidWriteOpOfProtoVer0))
|
|
if svv.Forbidden && svv.Status == 1 {
|
|
sb.WriteString(fmt.Sprintf(" DeleteDelayTime : %v\n", time.Until(svv.DeleteExecTime)))
|
|
}
|
|
allowedStorageClassStr := make([]string, 0)
|
|
for _, asc := range svv.AllowedStorageClass {
|
|
allowedStorageClassStr = append(allowedStorageClassStr, proto.StorageClassString(asc))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" VolStorageClass : %v\n", proto.StorageClassString(svv.VolStorageClass)))
|
|
sb.WriteString(fmt.Sprintf(" AllowedStorageClass : %v\n", allowedStorageClassStr))
|
|
|
|
if svv.VolType == 1 {
|
|
sb.WriteString(fmt.Sprintf(" ObjBlockSize : %v byte\n", svv.ObjBlockSize))
|
|
}
|
|
|
|
for _, c := range svv.QuotaOfStorageClass {
|
|
if !proto.IsStorageClassReplica(c.StorageClass) {
|
|
continue
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" QuotaOfClass(%s) : %v\n", proto.StorageClassString(c.StorageClass), quotaLimitStr(c.QuotaGB)))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheEnable : %v\n", svv.RemoteCacheEnable))
|
|
sb.WriteString(fmt.Sprintf(" remoteCachePath : %v\n", svv.RemoteCachePath))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheAutoPrepare : %v\n", svv.RemoteCacheAutoPrepare))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheTTL : %v\n", svv.RemoteCacheTTL))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheReadTimeout : %v ms\n", svv.RemoteCacheReadTimeout))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheMaxFileSizeGB : %v G\n", svv.RemoteCacheMaxFileSizeGB))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheOnlyForNotSSD : %v\n", svv.RemoteCacheOnlyForNotSSD))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheMultiRead : %v\n", svv.RemoteCacheMultiRead))
|
|
sb.WriteString(fmt.Sprintf(" flashNodeTimeoutCount : %v\n", svv.FlashNodeTimeoutCount))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheSameZoneTimeout : %v\n", svv.RemoteCacheSameZoneTimeout))
|
|
sb.WriteString(fmt.Sprintf(" remoteCacheSameRegionTimeout : %v\n", svv.RemoteCacheSameRegionTimeout))
|
|
|
|
// qos of volume
|
|
sb.WriteString(fmt.Sprintf(" QosEnable : %v\n", svv.QosInfo.QosEnable))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatVolOp(opv *proto.OpLogView, logNum int, dpId string, filterOp string) string {
|
|
maxLines := 1000
|
|
if logNum > 0 && logNum < maxLines {
|
|
maxLines = logNum
|
|
}
|
|
sb := strings.Builder{}
|
|
lineCount := 0
|
|
for _, opLog := range opv.VolOpLogs {
|
|
parts := strings.Split(opLog.Name, "_")
|
|
if dpId != "" && parts[0] != dpId {
|
|
continue
|
|
}
|
|
if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
continue
|
|
}
|
|
lineCount++
|
|
if lineCount > maxLines {
|
|
break
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%-15v %-15v %v\n", "dp_"+parts[0], opLog.Op, opLog.Count))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatVolumeStatus(status uint8) string {
|
|
switch status {
|
|
case 0:
|
|
return "Normal"
|
|
case 1:
|
|
return "Marked delete"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
var (
|
|
volumeInfoTablePattern = "%-63v %-20v %-8v %-8v %-8v %-10v"
|
|
volumeInfoTableHeader = fmt.Sprintf(volumeInfoTablePattern, "VOLUME", "OWNER", "USED", "TOTAL", "STATUS", "CREATE TIME")
|
|
)
|
|
|
|
func formatVolInfoTableRow(vi *proto.VolInfo) string {
|
|
return fmt.Sprintf(volumeInfoTablePattern,
|
|
vi.Name, vi.Owner, formatSize(vi.UsedSize), formatSize(vi.TotalSize),
|
|
formatVolumeStatus(vi.Status), time.Unix(vi.CreateTime, 0).Local().Format(time.RFC1123))
|
|
}
|
|
|
|
func quotaLimitStr(cap uint64) string {
|
|
if cap == 0 {
|
|
return "no limit(0)"
|
|
}
|
|
return formatSize(cap * util.GB)
|
|
}
|
|
|
|
var (
|
|
volumeVersionPattern = "%-20v %-40v %-8v %-8v"
|
|
volumeVersionTableHeader = fmt.Sprintf(volumeVersionPattern, "VER", "CTIME", "STATUS", "OTHER")
|
|
)
|
|
|
|
var (
|
|
volumeAclPattern = "%-20v %-40v %-8v"
|
|
volumeAclTableHeader = fmt.Sprintf(volumeAclPattern, "IP", "CTIME", "OTHER")
|
|
)
|
|
|
|
func formatAclInfoTableRow(aclInfo *proto.AclIpInfo) string {
|
|
return fmt.Sprintf(volumeAclPattern,
|
|
aclInfo.Ip, time.Unix(aclInfo.CTime, 0).Format(time.RFC1123), "")
|
|
}
|
|
|
|
var (
|
|
volumeUidPattern = "%-20v %-40v %-8v %-8v %-8v %-8v"
|
|
volumeUidTableHeader = fmt.Sprintf(volumeUidPattern, "UID", "CTIME", "ENABLED", "LIMITED", "LIMITSIZE", "USED")
|
|
)
|
|
|
|
func formatUidInfoTableRow(uidInfo *proto.UidSpaceInfo) string {
|
|
return fmt.Sprintf(volumeUidPattern,
|
|
uidInfo.Uid, time.Unix(uidInfo.CTime, 0).Format(time.RFC1123), uidInfo.Enabled, uidInfo.Limited, uidInfo.LimitSize, uidInfo.UsedSize)
|
|
}
|
|
|
|
func formatVerInfoTableRow(verInfo *proto.VolVersionInfo) string {
|
|
return fmt.Sprintf(volumeVersionPattern,
|
|
verInfo.Ver, time.UnixMicro(int64(verInfo.Ver)).Local().Format(time.RFC1123), verInfo.Status, "")
|
|
}
|
|
|
|
var (
|
|
dataPartitionTablePattern = "%-8v %-8v %-10v %-10v %-10v %-18v %-18v"
|
|
dataPartitionTableHeader = fmt.Sprintf(dataPartitionTablePattern,
|
|
"ID", "REPLICAS", "STATUS", "ISRECOVER", "MEDIA", "LEADER", "MEMBERS")
|
|
)
|
|
|
|
func formatDataPartitionTableRow(view *proto.DataPartitionResponse) string {
|
|
return fmt.Sprintf(dataPartitionTablePattern,
|
|
view.PartitionID, view.ReplicaNum, formatDataPartitionStatus(view.Status), view.IsRecover,
|
|
proto.MediaTypeString(view.MediaType), view.LeaderAddr, strings.Join(view.Hosts, ","))
|
|
}
|
|
|
|
var (
|
|
partitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-12v %-18v"
|
|
partitionInfoTableHeader = fmt.Sprintf(partitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MediaType", "MEMBERS")
|
|
|
|
PeerAbnormalRaftPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-12v %-12v %v%v%v"
|
|
PeerAbnormalRaftPartitionInfoHeader = fmt.Sprintf(PeerAbnormalRaftPartitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MediaType", "MEMBERS", "DIFF-RAFT-MEMBERS", "|DOWN-MEMBERS", "|PEND-MEMBERS")
|
|
|
|
badMpReplicaPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-64v %-24v"
|
|
badMpReplicaPartitionInfoTableHeader = fmt.Sprintf(badMpReplicaPartitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS", "UNAVAILABLE_REPLICAS")
|
|
|
|
badReplicaPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-64v %-24v"
|
|
badReplicaPartitionInfoTableHeader = fmt.Sprintf(badReplicaPartitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS", "UNAVAILABLE_REPLICAS")
|
|
|
|
repFileCountDifferPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-24v"
|
|
RepFileCountDifferInfoTableHeader = fmt.Sprintf(repFileCountDifferPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS(fileCount)")
|
|
|
|
repUsedSizeDifferPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-24v"
|
|
RepUsedSizeDifferInfoTableHeader = fmt.Sprintf(repUsedSizeDifferPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS(usedSize)")
|
|
|
|
inodeCountNotEqualInfoTablePattern = "%-8v %-32v %-8v %-12v %-24v"
|
|
inodeCountNotEqualInfoTableHeader = fmt.Sprintf(inodeCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(inodeCount)")
|
|
maxInodeNotEqualInfoTableHeader = fmt.Sprintf(inodeCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(maxInode)")
|
|
|
|
dentryCountNotEqualInfoTablePattern = "%-8v %-32v %-8v %-12v %-24v"
|
|
dentryCountNotEqualInfoTableHeader = fmt.Sprintf(dentryCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(dentryCount)")
|
|
|
|
diskErrorReplicaPartitionInfoTablePattern = "%-8v %-32v %-8v %-12v %-64v %-24v"
|
|
diskErrorReplicaPartitionInfoTableHeader = fmt.Sprintf(badReplicaPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS", "DiskError_REPLICAS")
|
|
)
|
|
|
|
func formatDataPartitionInfoRow(partition *proto.DataPartitionInfo) string {
|
|
return fmt.Sprintf(partitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), proto.MediaTypeString(partition.MediaType), strings.Join(partition.Hosts, ", "))
|
|
}
|
|
|
|
func formatBadReplicaDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if replica.Status == proto.Unavailable {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
sb.WriteString(fmt.Sprintf("%v", replica.Addr))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(badReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
}
|
|
|
|
func formatReplicaFileCountDiffDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.FileCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.FileCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(repFileCountDifferPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatReplicaSizeDiffDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.Used))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.Used))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(repUsedSizeDifferPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionReplicaInodeNotEqualInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.InodeCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.InodeCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(inodeCountNotEqualInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionReplicaDentryNotEqualInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.DentryCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.DentryCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(dentryCountNotEqualInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
return fmt.Sprintf(partitionInfoTablePattern,
|
|
partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "N/A", strings.Join(partition.Hosts, ", "))
|
|
}
|
|
|
|
func formatMetaPartitionInfoRowWithRaft(partition *proto.MetaPartitionInfo) string {
|
|
var (
|
|
info *proto.MetaPartitionLoadResponse
|
|
addrArr = make(map[uint64]string)
|
|
diffHosts []string
|
|
downHosts []string
|
|
pendingHosts []string
|
|
)
|
|
for _, peer := range partition.Peers {
|
|
addrArr[peer.ID] = peer.Addr
|
|
}
|
|
|
|
for _, info = range partition.LoadResponse {
|
|
if info.RaftInfo.RaftStatus.Leader == info.RaftInfo.RaftStatus.NodeID {
|
|
break
|
|
}
|
|
}
|
|
if info == nil {
|
|
return ""
|
|
}
|
|
for _, peer := range info.RaftInfo.Hosts {
|
|
if _, ok := addrArr[peer.ID]; ok {
|
|
continue
|
|
}
|
|
diffHosts = append(diffHosts, peer.Addr)
|
|
addrArr[peer.ID] = peer.Addr
|
|
}
|
|
|
|
for _, dr := range info.RaftInfo.DownReplicas {
|
|
if host, ok := addrArr[dr.NodeID]; ok {
|
|
downHosts = append(downHosts, host)
|
|
}
|
|
}
|
|
for _, pr := range info.RaftInfo.PendingPeers {
|
|
if host, ok := addrArr[pr]; ok {
|
|
pendingHosts = append(pendingHosts, host)
|
|
}
|
|
}
|
|
var (
|
|
diffInfo = "N/A"
|
|
downInfo = "N/A"
|
|
pendingInfo = "N/A"
|
|
)
|
|
if len(diffHosts) != 0 {
|
|
diffInfo = strings.Join(diffHosts, ", ")
|
|
}
|
|
if len(downHosts) != 0 {
|
|
downInfo = strings.Join(downHosts, ", ")
|
|
}
|
|
if len(pendingHosts) != 0 {
|
|
pendingInfo = strings.Join(pendingHosts, ", ")
|
|
}
|
|
|
|
return fmt.Sprintf(PeerAbnormalRaftPartitionInfoTablePattern,
|
|
partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "N/A", strings.Join(partition.Hosts, ", "),
|
|
diffInfo+"|", downInfo+"|", pendingInfo)
|
|
}
|
|
|
|
func formatBadReplicaMpInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if replica.Status == proto.Unavailable {
|
|
if !firstItem {
|
|
sb.WriteString(", ")
|
|
}
|
|
|
|
sb.WriteString(fmt.Sprintf("%v", replica.Addr))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
if sb.String() == "[]" {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf(badReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
}
|
|
|
|
func formatDataPartitionInfo(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("volume name : %v\n", partition.VolName))
|
|
sb.WriteString(fmt.Sprintf("volume ID : %v\n", partition.VolID))
|
|
sb.WriteString(fmt.Sprintf("PartitionID : %v\n", partition.PartitionID))
|
|
sb.WriteString(fmt.Sprintf("PartitionType : %v\n", partition.PartitionType))
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", formatDataPartitionStatus(partition.Status)))
|
|
sb.WriteString(fmt.Sprintf("LastLoadedTime: %v\n", formatTime(partition.LastLoadedTime)))
|
|
sb.WriteString(fmt.Sprintf("OfflinePeerID : %v\n", partition.OfflinePeerID))
|
|
sb.WriteString(fmt.Sprintf("ISRdOnly : %v\n", partition.RdOnly))
|
|
sb.WriteString(fmt.Sprintf("IsDiscard : %v\n", partition.IsDiscard))
|
|
sb.WriteString(fmt.Sprintf("ReplicaNum : %v\n", partition.ReplicaNum))
|
|
sb.WriteString(fmt.Sprintf("Forbidden : %v\n", partition.Forbidden))
|
|
sb.WriteString(fmt.Sprintf("MediaType : %v\n", proto.MediaTypeString(partition.MediaType)))
|
|
sb.WriteString(fmt.Sprintf("ForbidWriteOpOfProtoVer0 : %v\n", partition.ForbidWriteOpOfProtoVer0))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Replicas : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataReplicaTableHeader()))
|
|
for idx, replica := range partition.Replicas {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataReplica(idx, replica, true)))
|
|
if replica.Status == proto.ReadOnly {
|
|
sb.WriteString("ReadOnlyReasons : \n")
|
|
reasons := parseDpReadOnlyReasons(replica.ReadOnlyReasons)
|
|
for i, reason := range reasons {
|
|
sb.WriteString(fmt.Sprintf("[%v] %v\n", i+1, reason))
|
|
}
|
|
}
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
sb.WriteString("FileInCoreMap : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataFileInCoreTableHeader()))
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataFileMetadateTableHeader()))
|
|
for id, fileCore := range partition.FileInCoreMap {
|
|
sb.WriteString(formatDataFileInCoreMap(id, "", fileCore, true))
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Peers :\n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeerTableHeader()))
|
|
for _, peer := range partition.Peers {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeer(peer)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Hosts :\n")
|
|
for _, host := range partition.Hosts {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", host))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zones :\n")
|
|
for _, zone := range partition.Zones {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", zone))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("NodeSets :\n")
|
|
for _, nodeSet := range partition.NodeSets {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", nodeSet))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MissingNodes :\n")
|
|
for partitionHost, id := range partition.MissingNodes {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", partitionHost, id))
|
|
}
|
|
sb.WriteString("FilesWithMissingReplica : \n")
|
|
for file, id := range partition.FilesWithMissingReplica {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", file, id))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatMetaPartitionInfo(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("volume name : %v\n", partition.VolName))
|
|
sb.WriteString(fmt.Sprintf("PartitionID : %v\n", partition.PartitionID))
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", formatMetaPartitionStatus(partition.Status)))
|
|
sb.WriteString(fmt.Sprintf("Recovering : %v\n", formatIsRecover(partition.IsRecover)))
|
|
sb.WriteString(fmt.Sprintf("Start : %v\n", partition.Start))
|
|
sb.WriteString(fmt.Sprintf("End : %v\n", partition.End))
|
|
sb.WriteString(fmt.Sprintf("MaxInodeID : %v\n", partition.MaxInodeID))
|
|
sb.WriteString(fmt.Sprintf("Forbidden : %v\n", partition.Forbidden))
|
|
sb.WriteString(fmt.Sprintf("Freeze : %v\n", formatMetaPartitionFreeze(partition.Freeze)))
|
|
sb.WriteString(fmt.Sprintf("ForbidWriteOpOfProtoVer0 : %v\n", partition.ForbidWriteOpOfProtoVer0))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Replicas : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatMetaReplicaTableHeader()))
|
|
for _, replica := range partition.Replicas {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatMetaReplica("", replica, true)))
|
|
if replica.Status == proto.ReadOnly {
|
|
sb.WriteString("ReadOnlyReasons : \n")
|
|
reasons := parseMpReadOnlyReasons(replica.ReadOnlyReasons)
|
|
for i, reason := range reasons {
|
|
sb.WriteString(fmt.Sprintf("[%v] %v\n", i+1, reason))
|
|
}
|
|
}
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Peers :\n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeerTableHeader()))
|
|
for _, peer := range partition.Peers {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeer(peer)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Hosts :\n")
|
|
for _, host := range partition.Hosts {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", host))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zones :\n")
|
|
for _, zone := range partition.Zones {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", zone))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("NodeSets :\n")
|
|
for _, nodeSet := range partition.NodeSets {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", nodeSet))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MissingNodes :\n")
|
|
for partitionHost, id := range partition.MissNodes {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", partitionHost, id))
|
|
}
|
|
|
|
if len(partition.StatByStorageClass) != 0 {
|
|
sb.WriteString("\n")
|
|
sort.Slice(partition.StatByStorageClass, func(i, j int) bool {
|
|
return partition.StatByStorageClass[i].StorageClass < partition.StatByStorageClass[j].StorageClass
|
|
})
|
|
sb.WriteString("Usage by storageClass:\n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", hybridCloudStorageTableHeader))
|
|
for _, view := range partition.StatByStorageClass {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatHybridCloudStorageTableRow(view)))
|
|
}
|
|
}
|
|
|
|
if len(partition.StatByMigrateStorageClass) != 0 {
|
|
sb.WriteString("\n")
|
|
sort.Slice(partition.StatByMigrateStorageClass, func(i, j int) bool {
|
|
return partition.StatByMigrateStorageClass[i].StorageClass < partition.StatByMigrateStorageClass[j].StorageClass
|
|
})
|
|
sb.WriteString("\nMigration Usage by storage class:\n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", hybridCloudStorageTableHeader))
|
|
for _, view := range partition.StatByMigrateStorageClass {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatHybridCloudStorageTableRow(view)))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
metaPartitionTablePattern = "%-8v %-12v %-10v %-12v %-12v %-12v %-8v %-12v %-18v"
|
|
metaPartitionTableHeader = fmt.Sprintf(metaPartitionTablePattern,
|
|
"ID", "MAX INODE", "DENTRY COUNT", "INODE COUNT", "START", "END", "STATUS", "LEADER", "MEMBERS")
|
|
)
|
|
|
|
func formatMetaPartitionTableRow(view *proto.MetaPartitionView) string {
|
|
rangeToString := func(num uint64) string {
|
|
if num >= math.MaxInt64 {
|
|
return "unlimited"
|
|
}
|
|
return strconv.FormatUint(num, 10)
|
|
}
|
|
return fmt.Sprintf(metaPartitionTablePattern,
|
|
view.PartitionID, view.MaxInodeID, view.DentryCount, view.InodeCount, view.Start, rangeToString(view.End), formatMetaPartitionStatus(view.Status),
|
|
view.LeaderAddr, strings.Join(view.Members, ","))
|
|
}
|
|
|
|
var (
|
|
userInfoTablePattern = "%-20v %-6v %-16v %-32v %-10v"
|
|
userInfoTableHeader = fmt.Sprintf(userInfoTablePattern,
|
|
"ID", "TYPE", "ACCESS KEY", "SECRET KEY", "CREATE TIME")
|
|
)
|
|
|
|
func formatUserInfoTableRow(userInfo *proto.UserInfo) string {
|
|
return fmt.Sprintf(userInfoTablePattern,
|
|
userInfo.UserID, formatUserType(userInfo.UserType), userInfo.AccessKey, userInfo.SecretKey, userInfo.CreateTime)
|
|
}
|
|
|
|
func formatDataPartitionStatus(status int8) string {
|
|
switch status {
|
|
case proto.Recovering:
|
|
return "Recovering"
|
|
case proto.ReadOnly:
|
|
return "ReadOnly"
|
|
case proto.ReadWrite:
|
|
return "ReadWrite"
|
|
case proto.Unavailable:
|
|
return "Unavailable"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func formatIsRecover(isRecover bool) string {
|
|
switch isRecover {
|
|
case true:
|
|
return "Yes"
|
|
default:
|
|
return "No"
|
|
}
|
|
}
|
|
|
|
func formatMetaPartitionStatus(status int8) string {
|
|
switch status {
|
|
case 1:
|
|
return "Read only"
|
|
case 2:
|
|
return "Writable"
|
|
case -1:
|
|
return "Unavailable"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func formatUserType(userType proto.UserType) string {
|
|
switch userType {
|
|
case proto.UserTypeRoot:
|
|
return "Root"
|
|
case proto.UserTypeAdmin:
|
|
return "Admin"
|
|
case proto.UserTypeNormal:
|
|
return "Normal"
|
|
default:
|
|
}
|
|
return "Unknown"
|
|
}
|
|
|
|
func formatYesNo(b bool) string {
|
|
if b {
|
|
return "Yes"
|
|
}
|
|
return "No"
|
|
}
|
|
|
|
func formatEnabledDisabled(b bool) string {
|
|
if b {
|
|
return "Enabled"
|
|
}
|
|
return "Disabled"
|
|
}
|
|
|
|
func formatNodeStatus(status bool) string {
|
|
if status {
|
|
return "Active"
|
|
}
|
|
return "Inactive"
|
|
}
|
|
|
|
func formatNodeOfflineStatus(status bool) string {
|
|
if status {
|
|
return "True"
|
|
}
|
|
return "False"
|
|
}
|
|
|
|
func formatNodeMediaType(mediaType uint32) string {
|
|
if mediaType == proto.MediaType_Unspecified {
|
|
return "N/A"
|
|
}
|
|
return proto.MediaTypeString(mediaType)
|
|
}
|
|
|
|
func formatNodeForbiddenWriteOpVer(forbidWriteOpOfProtoVer0 bool) string {
|
|
if forbidWriteOpOfProtoVer0 {
|
|
return "forbidden"
|
|
}
|
|
|
|
return "notForbid"
|
|
}
|
|
|
|
var (
|
|
units = []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
|
step float64 = 1024
|
|
)
|
|
|
|
func fixUnit(curSize float64, curUnitIndex int) (newSize float64, newUnitIndex int) {
|
|
if curSize >= step && curUnitIndex < len(units)-1 {
|
|
return fixUnit(curSize/step, curUnitIndex+1)
|
|
}
|
|
return curSize, curUnitIndex
|
|
}
|
|
|
|
func formatSize(size uint64) string {
|
|
fixedSize, fixedUnitIndex := fixUnit(float64(size), 0)
|
|
return fmt.Sprintf("%.2f %v", fixedSize, units[fixedUnitIndex])
|
|
}
|
|
|
|
func formatTime(timeUnix int64) string {
|
|
return time.Unix(timeUnix, 0).Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
func formatTimeToString(t time.Time) string {
|
|
return t.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
var dataReplicaTableRowPattern = "%-65v %-12v %-12v %-12v %-12v %-12v %-12v %-12v %-12v %-18v %-10v"
|
|
|
|
func formatDataReplicaTableHeader() string {
|
|
return fmt.Sprintf(dataReplicaTableRowPattern, "ADDR", "USEDSIZE", "TOTALSIZE", "ISLEADER", "FILECOUNT", "HASLOADRESPONSE", "NEEDSTOCOMPARE", "ISREPAIRING", "STATUS", "DISKPATH", "REPORT TIME")
|
|
}
|
|
|
|
var dataFileInCoreTableRowPattern = "%-12v %-12v %-10v %-10v"
|
|
|
|
func formatDataFileInCoreTableHeader() string {
|
|
return fmt.Sprintf(dataFileInCoreTableRowPattern, "KEY", "NAME", "LASTMODIFY", "FILEMETADATE")
|
|
}
|
|
|
|
var dataFileMetadateTableRowPattern = "%-12v %-12v %-10v %-10v %-10v %-18v"
|
|
|
|
func formatDataFileMetadateTableHeader() string {
|
|
return fmt.Sprintf(dataFileMetadateTableRowPattern, "", "", "", "CRC", "SIZE", "LOCADDR")
|
|
}
|
|
|
|
func formatDataFileInCoreMap(id string, indentation string, fileCore *proto.FileInCore, rowTable bool) string {
|
|
sb := strings.Builder{}
|
|
if rowTable {
|
|
sb.WriteString(fmt.Sprintf(dataFileInCoreTableRowPattern, id, fileCore.Name, fileCore.LastModify, ""))
|
|
for _, v := range fileCore.MetadataArray {
|
|
sb.WriteString("\n")
|
|
sb.WriteString(formatDataFileMetadate("", v))
|
|
}
|
|
sb.WriteString("\n")
|
|
return sb.String()
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%v- Name : %v\n", indentation, fileCore.Name))
|
|
sb.WriteString(fmt.Sprintf("%v LastModify : %v\n", indentation, fileCore.LastModify))
|
|
sb.WriteString(fmt.Sprintf("%v FileMetadate : %v\n", indentation, fileCore.MetadataArray))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataFileMetadate(indentation string, fileMeta *proto.FileMetadata) string {
|
|
return fmt.Sprintf(dataFileMetadateTableRowPattern, "", "", "", fileMeta.Crc, fileMeta.Size, fileMeta.LocAddr)
|
|
}
|
|
|
|
func formatDataReplica(index int, replica *proto.DataReplica, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(dataReplicaTableRowPattern, formatAddr(replica.Addr, replica.DomainAddr),
|
|
formatSize(replica.Used), formatSize(replica.Total), replica.IsLeader, replica.FileCount,
|
|
replica.HasLoadResponse, replica.NeedsToCompare, replica.IsRepairing, formatDataPartitionStatus(replica.Status),
|
|
replica.DiskPath, formatTime(replica.ReportTime))
|
|
}
|
|
return alignColumnIndex(index,
|
|
arow("Addr", formatAddr(replica.Addr, replica.DomainAddr)),
|
|
arow("Allocated", formatSize(replica.Used)),
|
|
arow("Total", formatSize(replica.Total)),
|
|
arow("IsLeader", replica.IsLeader),
|
|
arow("FileCount", replica.FileCount),
|
|
arow("HasLoadResponse", replica.HasLoadResponse),
|
|
arow("NeedsToCompare", replica.NeedsToCompare),
|
|
arow("IsRepairing", replica.IsRepairing),
|
|
arow("Status", formatDataPartitionStatus(replica.Status)),
|
|
arow("DiskPath", replica.DiskPath),
|
|
arow("ReportTime", formatTime(replica.ReportTime)),
|
|
)
|
|
}
|
|
|
|
func parseDpReadOnlyReasons(mask uint32) []string {
|
|
reasons := make([]string, 0)
|
|
for reason, msg := range proto.DpReasonMessages {
|
|
if mask&reason != 0 {
|
|
reasons = append(reasons, msg)
|
|
mask ^= reason
|
|
}
|
|
}
|
|
return reasons
|
|
}
|
|
|
|
var metaReplicaTableRowPattern = "%-65v %-6v %-6v %-6v %-10v"
|
|
|
|
func formatMetaReplicaTableHeader() string {
|
|
return fmt.Sprintf(metaReplicaTableRowPattern, "ADDRESS", "MaxInodeID", "ISLEADER", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatMetaReplica(indentation string, replica *proto.MetaReplicaInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(metaReplicaTableRowPattern, formatAddr(replica.Addr, replica.DomainAddr), replica.MaxInodeID,
|
|
replica.IsLeader, formatMetaPartitionStatus(replica.Status), formatTime(replica.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("%v- Addr : %v\n", indentation, formatAddr(replica.Addr, replica.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf("%v- MaxInodeID : %v\n", indentation, replica.MaxInodeID))
|
|
sb.WriteString(fmt.Sprintf("%v Status : %v\n", indentation, formatMetaPartitionStatus(replica.Status)))
|
|
sb.WriteString(fmt.Sprintf("%v IsLeader : %v\n", indentation, replica.IsLeader))
|
|
sb.WriteString(fmt.Sprintf("%v ReportTime : %v\n", indentation, formatTime(replica.ReportTime)))
|
|
return sb.String()
|
|
}
|
|
|
|
func parseMpReadOnlyReasons(mask uint32) []string {
|
|
reasons := make([]string, 0)
|
|
for reason, msg := range proto.MpReasonMessages {
|
|
if mask&reason != 0 {
|
|
reasons = append(reasons, msg)
|
|
mask ^= reason
|
|
}
|
|
}
|
|
return reasons
|
|
}
|
|
|
|
var peerTableRowPattern = "%-6v %-18v %-12v %-12v"
|
|
|
|
func formatPeerTableHeader() string {
|
|
return fmt.Sprintf(peerTableRowPattern, "ID", "ADDR", "HEARTBEATPORT", "REPLICAPORT")
|
|
}
|
|
|
|
func formatPeer(peer proto.Peer) string {
|
|
return fmt.Sprintf(peerTableRowPattern, peer.ID, peer.Addr, peer.HeartbeatPort, peer.ReplicaPort)
|
|
}
|
|
|
|
var dataNodeDetailTableRowPattern = "%-6v %-10v %-65v %-10v %-10v %-10v %-10v"
|
|
|
|
func formatDataNodeDetailTableHeader() string {
|
|
return fmt.Sprintf(dataNodeDetailTableRowPattern, "ID", "ZONE", "ADDRESS", "USED", "TOTAL", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatDataNodeDetail(dn *proto.DataNodeInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(dataNodeDetailTableRowPattern, dn.ID, dn.ZoneName, formatAddr(dn.Addr, dn.DomainAddr),
|
|
formatSize(dn.Used), formatSize(dn.Total), formatNodeStatus(dn.IsActive), formatTimeToString(dn.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", dn.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(dn.Addr, dn.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" RaftHeartbeatPort : %v\n", dn.RaftHeartbeatPort))
|
|
sb.WriteString(fmt.Sprintf(" RaftReplicaPort : %v\n", dn.RaftReplicaPort))
|
|
sb.WriteString(fmt.Sprintf(" Allocated ratio : %v\n", dn.UsageRatio))
|
|
sb.WriteString(fmt.Sprintf(" Allocated : %v\n", formatSize(dn.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Available : %v\n", formatSize(dn.AvailableSpace)))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(dn.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Zone : %v\n", dn.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" Rdonly : %v\n", dn.RdOnly))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatNodeStatus(dn.IsActive)))
|
|
sb.WriteString(fmt.Sprintf(" MediaType : %v\n", proto.MediaTypeString(dn.MediaType)))
|
|
sb.WriteString(fmt.Sprintf(" ToBeOffline : %v\n", formatNodeOfflineStatus(dn.ToBeOffline)))
|
|
sb.WriteString(fmt.Sprintf(" Report time : %v\n", formatTimeToString(dn.ReportTime)))
|
|
sb.WriteString(fmt.Sprintf(" Partition count : %v\n", dn.DataPartitionCount))
|
|
sb.WriteString(fmt.Sprintf(" AllDisks : %v\n", dn.AllDisks))
|
|
sb.WriteString(fmt.Sprintf(" Bad disks : %v\n", dn.BadDisks))
|
|
sb.WriteString(fmt.Sprintf(" Lost disks : %v\n", dn.LostDisks))
|
|
sb.WriteString(fmt.Sprintf(" Decommissioned disks : %v\n", dn.DecommissionedDisk))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionSuccess disks : %v\n", dn.DecommissionSuccessDisk))
|
|
sb.WriteString(fmt.Sprintf(" Persist partitions : %v\n", dn.PersistenceDataPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Backup partitions : %v\n", dn.BackupDataPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Can alloc partition : %v\n", dn.CanAllocPartition))
|
|
sb.WriteString(fmt.Sprintf(" Max partition count : %v\n", dn.MaxDpCntLimit))
|
|
sb.WriteString(fmt.Sprintf(" CpuUtil : %.1f%%\n", dn.CpuUtil))
|
|
sb.WriteString(" IoUtils :\n")
|
|
for device, used := range dn.IoUtils {
|
|
sb.WriteString(fmt.Sprintf(" %v:%.1f%%\n", device, used))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// func formatDataNodeDiskOp(dn *proto.DataNodeInfo, logNum int, diskName string, filterOp string) string {
|
|
// maxLines := 1000
|
|
// if logNum > 0 && logNum < maxLines {
|
|
// maxLines = logNum
|
|
// }
|
|
// sb := strings.Builder{}
|
|
// lineCount := 0
|
|
// for _, opLog := range dn.DiskOpLogs {
|
|
// if diskName != "" && opLog.Name != diskName {
|
|
// continue
|
|
// }
|
|
// if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
// continue
|
|
// }
|
|
// lineCount++
|
|
// if lineCount > maxLines {
|
|
// break
|
|
// }
|
|
// sb.WriteString(fmt.Sprintf("%-30v %-20v %v\n", opLog.Name, opLog.Op, opLog.Count))
|
|
// }
|
|
// return sb.String()
|
|
// }
|
|
|
|
// func formatDataNodeDpOp(dn *proto.DataNodeInfo, logNum int, dpId string, filterOp string) string {
|
|
// maxLines := 1000
|
|
// if logNum > 0 && logNum < maxLines {
|
|
// maxLines = logNum
|
|
// }
|
|
// sb := strings.Builder{}
|
|
// lineCount := 0
|
|
// for _, opLog := range dn.DpOpLogs {
|
|
// arr := strings.Split(opLog.Name, "_")
|
|
// if dpId != "" && arr[1] != dpId {
|
|
// continue
|
|
// }
|
|
// if filterOp != "" && !strings.Contains(opLog.Op, filterOp) {
|
|
// continue
|
|
// }
|
|
// lineCount++
|
|
// if lineCount > maxLines {
|
|
// break
|
|
// }
|
|
// sb.WriteString(fmt.Sprintf("%-30v %-20v %v\n", opLog.Name, opLog.Op, opLog.Count))
|
|
// }
|
|
// return sb.String()
|
|
// }
|
|
|
|
var metaNodeDetailTableRowPattern = "%-6v %-6v %-65v %-6v %-6v %-6v %-10v"
|
|
|
|
func formatMetaNodeDetailTableHeader() string {
|
|
return fmt.Sprintf(metaNodeDetailTableRowPattern, "ID", "ZONE", "ADDRESS", "USED", "TOTAL", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatMetaNodeDetail(mn *proto.MetaNodeInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(metaNodeDetailTableRowPattern, mn.ID, mn.ZoneName, formatAddr(mn.Addr, mn.DomainAddr),
|
|
mn.Used, mn.Total, mn.IsActive, formatTimeToString(mn.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", mn.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(mn.Addr, mn.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" RaftHeartbeatPort : %v\n", mn.RaftHeartbeatPort))
|
|
sb.WriteString(fmt.Sprintf(" RaftReplicaPort : %v\n", mn.RaftReplicaPort))
|
|
sb.WriteString(fmt.Sprintf(" Threshold : %v\n", mn.Threshold))
|
|
sb.WriteString(fmt.Sprintf(" MaxMemAvailWeight : %v\n", formatSize(mn.MaxMemAvailWeight)))
|
|
sb.WriteString(fmt.Sprintf(" Allocated : %v\n", formatSize(mn.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(mn.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Zone : %v\n", mn.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatNodeStatus(mn.IsActive)))
|
|
sb.WriteString(fmt.Sprintf(" Rdonly : %v\n", mn.RdOnly))
|
|
sb.WriteString(fmt.Sprintf(" Report time : %v\n", formatTimeToString(mn.ReportTime)))
|
|
sb.WriteString(fmt.Sprintf(" Partition count : %v\n", mn.MetaPartitionCount))
|
|
sb.WriteString(fmt.Sprintf(" Persist partitions : %v\n", mn.PersistenceMetaPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Can alloc partition : %v\n", mn.CanAllowPartition))
|
|
sb.WriteString(fmt.Sprintf(" Max partition count : %v\n", mn.MaxMpCntLimit))
|
|
sb.WriteString(fmt.Sprintf(" CpuUtil : %.1f%%\n", mn.CpuUtil))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatNodeSetView(ns *proto.NodeSetStatInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("NodeSet ID: %v\n", ns.ID))
|
|
sb.WriteString(fmt.Sprintf("Capacity: %v\n", ns.Capacity))
|
|
sb.WriteString(fmt.Sprintf("Zone: %v\n", ns.Zone))
|
|
sb.WriteString(fmt.Sprintf("CanAllocDataNode: %v\n", ns.CanAllocDataNodeCnt))
|
|
sb.WriteString(fmt.Sprintf("CanAllocMetaNode: %v\n", ns.CanAllocMetaNodeCnt))
|
|
sb.WriteString(fmt.Sprintf("DataNodeSelector: %v\n", ns.DataNodeSelector))
|
|
sb.WriteString(fmt.Sprintf("MetaNodeSelector: %v\n", ns.MetaNodeSelector))
|
|
var dataTotal, dataUsed, dataAvail, metaTotal, metaUsed, metaAvail uint64
|
|
for _, dn := range ns.DataNodes {
|
|
dataTotal += dn.Total
|
|
dataUsed += dn.Used
|
|
dataAvail += dn.Avail
|
|
}
|
|
for _, mn := range ns.MetaNodes {
|
|
metaTotal += mn.Total
|
|
metaUsed += mn.Used
|
|
metaAvail += mn.Avail
|
|
}
|
|
sb.WriteString(fmt.Sprintf("DataTotal: %v\n", formatSize(dataTotal)))
|
|
sb.WriteString(fmt.Sprintf("DataUsed: %v\n", formatSize(dataUsed)))
|
|
sb.WriteString(fmt.Sprintf("DataAvail: %v\n", formatSize(dataAvail)))
|
|
sb.WriteString(fmt.Sprintf("MetaTotal: %v\n", formatSize(metaTotal)))
|
|
sb.WriteString(fmt.Sprintf("MetaUsed: %v\n", formatSize(metaUsed)))
|
|
sb.WriteString(fmt.Sprintf("MetaAvail: %v\n", formatSize(metaAvail)))
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("DataNodes[%v]:\n", len(ns.DataNodes)))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeaderForNodeSet()))
|
|
for _, dn := range ns.DataNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewForNodeSet(dn)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("MetaNodes[%v]:\n", len(ns.MetaNodes)))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeaderForNodeSet()))
|
|
for _, mn := range ns.MetaNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewForNodeSet(mn)))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatZoneView(zv *proto.ZoneView) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Zone Name: %v\n", zv.Name))
|
|
sb.WriteString(fmt.Sprintf("Status: %v\n", zv.Status))
|
|
sb.WriteString(fmt.Sprintf("DataMediaType: %v\n", zv.DataMediaType))
|
|
sb.WriteString("Nodeset Selector:\n")
|
|
sb.WriteString(fmt.Sprintf(" Data:%v\n", zv.DataNodesetSelector))
|
|
sb.WriteString(fmt.Sprintf(" Meta:%v\n", zv.MetaNodesetSelector))
|
|
sb.WriteString("\n")
|
|
for index, ns := range zv.NodeSet {
|
|
sb.WriteString(fmt.Sprintf("NodeSet-%v:\n", index))
|
|
sb.WriteString(fmt.Sprintf(" DataNodes[%v]:\n", ns.DataNodeLen))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeader()))
|
|
for _, nv := range ns.DataNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeView(&nv, true)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf(" MetaNodes[%v]:\n", ns.MetaNodeLen))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeader()))
|
|
for _, nv := range ns.MetaNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeView(&nv, true)))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var quotaTableRowPattern = "%-6v %-30v %-15v %-20v %-15v %-10v %-12v %-12v %-10v %-10v %-10v %-10v"
|
|
|
|
func formatQuotaTableHeader() string {
|
|
return fmt.Sprintf(quotaTableRowPattern, "ID", "PATH", "VOL", "CTIME",
|
|
"PID", "RINODE", "LIMITEDFILES", "LIMITEDBYTES", "USEDFILES", "USEDBYTES", "MAXFILES", "MAXBYTES")
|
|
}
|
|
|
|
func formatQuotaInfo(info *proto.QuotaInfo) string {
|
|
t := time.Unix(info.CTime, 0)
|
|
var ret string
|
|
firstLine := true
|
|
for _, pathInfo := range info.PathInfos {
|
|
if firstLine {
|
|
ret = fmt.Sprintf(quotaTableRowPattern, info.QuotaId, pathInfo.FullPath, info.VolName, t.Format("2006-01-02 15:04:05"), pathInfo.PartitionId,
|
|
pathInfo.RootInode, info.LimitedInfo.LimitedFiles, info.LimitedInfo.LimitedBytes, info.UsedInfo.UsedFiles, info.UsedInfo.UsedBytes,
|
|
info.MaxFiles, info.MaxBytes)
|
|
firstLine = false
|
|
} else {
|
|
ret += "\n"
|
|
ret += fmt.Sprintf(quotaTableRowPattern, "", pathInfo.FullPath, "", "", pathInfo.PartitionId, pathInfo.RootInode,
|
|
"", "", "", "", "", "")
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
var badDiskDetailTableRowPattern = "%-18v %-18v %-18v %-18v %-18v"
|
|
|
|
func formatBadDiskTableHeader() string {
|
|
return fmt.Sprintf(badDiskDetailTableRowPattern, "Address", "Path", "TotalPartitionCnt", "DiskErrPartitionCnt", "PartitionIdsWithDiskErr")
|
|
}
|
|
|
|
func formatBadDiskInfoRow(disk proto.BadDiskInfo) string {
|
|
msgDpIdList := fmt.Sprintf("%v", disk.DiskErrPartitionList)
|
|
return fmt.Sprintf(badDiskDetailTableRowPattern, disk.Address, disk.Path, disk.TotalPartitionCnt, len(disk.DiskErrPartitionList), msgDpIdList)
|
|
}
|
|
|
|
func formatDiskList(disks []proto.DiskInfo) string {
|
|
if len(disks) == 0 {
|
|
return ""
|
|
}
|
|
diskRows := table{
|
|
arow("NodeId", "Address", "Path", "Status", "TotalPartitionCnt"),
|
|
}
|
|
for _, d := range disks {
|
|
diskRows = diskRows.append(arow(d.NodeId, d.Address, d.Path, d.Status, d.TotalPartitionCnt))
|
|
}
|
|
return alignTable(diskRows...)
|
|
}
|
|
|
|
func formatDiskDetailSummary(detail *proto.DiskInfo) string {
|
|
errDataPartitions := fmt.Sprintf("%v", detail.DiskErrPartitionList)
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" NodeId : %v\n", detail.NodeId))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", detail.Address))
|
|
sb.WriteString(fmt.Sprintf(" Path : %v\n", detail.Path))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", detail.Status))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(detail.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Used : %v\n", formatSize(detail.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Available : %v\n", formatSize(detail.Available)))
|
|
sb.WriteString(fmt.Sprintf(" IOUtil : %v\n", fmt.Sprintf("%.1f%%", detail.IOUtil)))
|
|
sb.WriteString(fmt.Sprintf(" DataPartitionCnt : %v\n", detail.TotalPartitionCnt))
|
|
sb.WriteString(fmt.Sprintf(" ErrDataPartitions : %v\n", errDataPartitions))
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
diskDataPartitionTablePattern = "%-8v %-8v %-8v %-8v %-8v %-8v %-8v %-8v %-8v"
|
|
diskDataPartitionTableHeader = fmt.Sprintf(diskDataPartitionTablePattern,
|
|
"DpID", "Vol", "Stat", "Total", "Used", "IsLeader", "ExtentCnt", "NeedCompare", "DecommRepairProgress")
|
|
)
|
|
|
|
func formatDiskDataPartitionTableRow(view *proto.DataPartitionReport) string {
|
|
return fmt.Sprintf(diskDataPartitionTablePattern,
|
|
view.PartitionID, view.VolName, formatDataPartitionStatus(int8(view.PartitionStatus)),
|
|
formatSize(view.Total), formatSize(view.Used), view.IsLeader, view.ExtentCount, view.NeedCompare, view.DecommissionRepairProgress)
|
|
}
|
|
|
|
func formatDataNodeDecommissionProgress(progress *proto.DataDecommissionProgress) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", progress.StatusMessage))
|
|
sb.WriteString(fmt.Sprintf("Weight : %v\n", progress.Weight))
|
|
sb.WriteString(fmt.Sprintf("Progress : %v\n", progress.Progress))
|
|
sb.WriteString(fmt.Sprintf("TotalDpCnt : %v\n", progress.TotalDpCnt))
|
|
sb.WriteString(fmt.Sprintf("RemainingDpCnt: %v\n", progress.RemainingDpCnt))
|
|
if len(progress.RunningDps) != 0 {
|
|
sb.WriteString("running Dps: \n")
|
|
for i, info := range progress.RunningDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.RunningDps), info))
|
|
}
|
|
}
|
|
if len(progress.FailedDps) != 0 {
|
|
sb.WriteString("Failed Dps: \n")
|
|
for i, info := range progress.FailedDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.FailedDps), info.PartitionID))
|
|
sb.WriteString(fmt.Sprintf(" Error Message : %v\n", info.ErrMsg))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDecommissionProgress(progress *proto.DecommissionProgress) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", progress.StatusMessage))
|
|
sb.WriteString(fmt.Sprintf("Type : %v\n", progress.DecommissionType))
|
|
sb.WriteString(fmt.Sprintf("Weight : %v\n", progress.Weight))
|
|
sb.WriteString(fmt.Sprintf("Progress : %v\n", progress.Progress))
|
|
sb.WriteString(fmt.Sprintf("TotalDpCnt : %v\n", progress.TotalDpCnt))
|
|
sb.WriteString(fmt.Sprintf("RemainingDpCnt: %v\n", progress.RemainingDpCnt))
|
|
if len(progress.RunningDps) != 0 {
|
|
sb.WriteString("running Dps: \n")
|
|
for i, info := range progress.RunningDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.RunningDps), info))
|
|
}
|
|
}
|
|
if len(progress.FailedDps) != 0 {
|
|
sb.WriteString("Failed Dps: \n")
|
|
for i, info := range progress.FailedDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.FailedDps), info.PartitionID))
|
|
sb.WriteString(fmt.Sprintf(" Error Message : %v\n", info.ErrMsg))
|
|
}
|
|
}
|
|
if len(progress.RetryOverLimitDps) != 0 {
|
|
sb.WriteString("retryOverLimit Dps:\n")
|
|
for i, info := range progress.RetryOverLimitDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.RetryOverLimitDps), info))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataPartitionDecommissionProgress(info *proto.DecommissionDataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Status: %v\n", info.Status))
|
|
sb.WriteString(fmt.Sprintf("SpecialStep: %v\n", info.SpecialStep))
|
|
sb.WriteString(fmt.Sprintf("Progress: %v\n", info.Progress))
|
|
sb.WriteString(fmt.Sprintf("DiskRetryMap: %v\n", info.DiskRetryMap))
|
|
sb.WriteString(fmt.Sprintf("Retry: %v\n", info.Retry))
|
|
sb.WriteString(fmt.Sprintf("RaftForce: %v\n", info.RaftForce))
|
|
sb.WriteString(fmt.Sprintf("Recover: %v\n", info.Recover))
|
|
sb.WriteString(fmt.Sprintf("SrcAddress: %v\n", info.SrcAddress))
|
|
sb.WriteString(fmt.Sprintf("SrcDiskPath: %v\n", info.SrcDiskPath))
|
|
sb.WriteString(fmt.Sprintf("DstAddress: %v\n", info.DstAddress))
|
|
sb.WriteString(fmt.Sprintf("DstNodeSet: %v\n", info.DstNodeSet))
|
|
sb.WriteString(fmt.Sprintf("Term: %v\n", info.Term))
|
|
sb.WriteString(fmt.Sprintf("Weight: %v\n", info.Weight))
|
|
sb.WriteString(fmt.Sprintf("Replicas: %v\n", info.Replicas))
|
|
sb.WriteString(fmt.Sprintf("NeedRollbackTimes: %v\n", info.NeedRollbackTimes))
|
|
sb.WriteString(fmt.Sprintf("ErrorMessage: %v\n", info.ErrorMessage))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataPartitionDecommissionStatusUpdateRecords(records []*proto.DecommissionStatusRecord) string {
|
|
sb := strings.Builder{}
|
|
if len(records) != 0 {
|
|
sb.WriteString("decommission status update records: \n")
|
|
for _, record := range records {
|
|
sb.WriteString(fmt.Sprintf(" Condition : %v\n", record.Condition))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", record.Status))
|
|
sb.WriteString(fmt.Sprintf(" Time : %v\n", record.Time))
|
|
sb.WriteString(fmt.Sprintf(" ErrMessage : %v\n", record.ErrMessage))
|
|
sb.WriteString("\n")
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataPartitionDecommissionInfoStat(infos []*proto.DecommissionInfoStat) string {
|
|
sb := strings.Builder{}
|
|
if len(infos) != 0 {
|
|
sb.WriteString("decommission info stat: \n")
|
|
for _, info := range infos {
|
|
sb.WriteString(fmt.Sprintf(" Key : %v\n", info.Key))
|
|
sb.WriteString(fmt.Sprintf(" RunningDpNum : %v\n", info.RunningDpNum))
|
|
sb.WriteString(" RepairSourceDps : [")
|
|
for i, id := range info.RepairSourceDp {
|
|
if i == 0 {
|
|
sb.WriteString(fmt.Sprintf(" %v", id))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf(", %v", id))
|
|
}
|
|
}
|
|
sb.WriteString(" ]\n")
|
|
sb.WriteString(" RepairTargetDps : [")
|
|
for i, id := range info.RepairTargetDp {
|
|
if i == 0 {
|
|
sb.WriteString(fmt.Sprintf(" %v", id))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf(", %v", id))
|
|
}
|
|
}
|
|
sb.WriteString(" ]\n")
|
|
sb.WriteString("\n")
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDiskErrorReplicaDpInfoRow(partition *proto.DataPartitionInfo, infos []proto.DiskErrReplicaInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, info := range infos {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
// if dp is not loaded, remove replica cannot delete dp from disk heartbeat report
|
|
if replicaInHost(partition.Hosts, info.Addr) {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", info.Addr, info.Disk))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
if !firstItem {
|
|
return fmt.Sprintf(diskErrorReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
} else {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func formatDecommissionFailedDiskInfo(info *proto.DecommissionFailedDiskInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("SrcAddr: %v\n", info.SrcAddr))
|
|
sb.WriteString(fmt.Sprintf("DiskPath: %v\n", info.DiskPath))
|
|
sb.WriteString(fmt.Sprintf("DpTotal: %v\n", info.DecommissionDpTotal))
|
|
sb.WriteString(fmt.Sprintf("RaftForce: %v\n", info.DecommissionRaftForce))
|
|
sb.WriteString(fmt.Sprintf("Retry: %v\n", info.DecommissionTimes))
|
|
sb.WriteString(fmt.Sprintf("Weight: %v\n", info.DecommissionWeight))
|
|
sb.WriteString(fmt.Sprintf("AutoDecommission: %v\n", info.IsAutoDecommission))
|
|
return sb.String()
|
|
}
|
|
|
|
func replicaInHost(hosts []string, replica string) bool {
|
|
for _, host := range hosts {
|
|
if replica == host {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func formatDecommissionTokenStatus(status *proto.DecommissionTokenStatus) string {
|
|
return fmt.Sprintf("Nodeset %v: %v/%v", status.NodesetID, status.CurTokenNum, status.MaxTokenNum)
|
|
}
|
|
|
|
var (
|
|
qosPattern = "%-12v %-12v %-12v"
|
|
hybridCloudStorageTablePattern = "%-12v %-12v %-12v %-12v"
|
|
hybridCloudStorageTableHeader = fmt.Sprintf(hybridCloudStorageTablePattern,
|
|
"STORAGE CLASS", "INODE COUNT", "USED SIZE", "QUOTA")
|
|
formatFlashNodeSimpleViewTableTitle = arow("Zone", "ID", "Address", "Active", "Enable", "FlashGroupID", "ReportTime")
|
|
formatFlashNodeViewTableTitle = append(formatFlashNodeSimpleViewTableTitle[:], "DataPath", "HitRate", "Evicts", "Limit", "MaxAlloc", "HasAlloc", "Num", "Status")
|
|
formatFlashGroupViewTile = arow("ID", "Weight", "Slots", "ReservedSlots", "Status", "SlotStatus", "PendingSlots", "Step", "FlashNodeCount", "ReducingSlots")
|
|
QosHeader = fmt.Sprintf(qosPattern, "NAME", "TOTAL-MB", "USED-MB")
|
|
)
|
|
|
|
func formatHybridCloudStorageTableRow(view *proto.StatOfStorageClass) (row string) {
|
|
row = fmt.Sprintf(hybridCloudStorageTablePattern, proto.StorageClassString(view.StorageClass), view.InodeCount, strutil.FormatSize(view.UsedSizeBytes), quotaLimitStr(view.QuotaGB))
|
|
return
|
|
}
|
|
|
|
func formatFlashNodeView(fn *proto.FlashNodeViewInfo) string {
|
|
return "[FlashNode]\n" + alignColumn(
|
|
arow(" ID", fn.ID),
|
|
arow(" Address", fn.Addr),
|
|
arow(" Version", fn.Version),
|
|
arow(" ZoneName", fn.ZoneName),
|
|
arow(" FlashGroupID", fn.FlashGroupID),
|
|
arow(" ReportTime", formatTimeToString(fn.ReportTime)),
|
|
arow(" IsActive", fn.IsActive),
|
|
arow(" IsEnable", fn.IsEnable),
|
|
)
|
|
}
|
|
|
|
func formatFlashGroupView(fg *proto.FlashGroupAdminView) string {
|
|
return "[FlashGroup]\n" +
|
|
fmt.Sprintf(" ID:%v\n", fg.ID) +
|
|
fmt.Sprintf(" Weight:%v\n", fg.Weight) +
|
|
fmt.Sprintf(" Slots:%v\n", fg.Slots) +
|
|
fmt.Sprintf(" ReservedSlots:%v\n", fg.ReservedSlots) +
|
|
fmt.Sprintf(" IsReducingSlots:%v\n", fg.IsReducingSlots) +
|
|
fmt.Sprintf(" Status:%v\n", fg.Status) +
|
|
fmt.Sprintf(" SlotStatus:%v\n", fg.SlotStatus) +
|
|
fmt.Sprintf(" PedningSlots:%v\n", fg.PendingSlots) +
|
|
fmt.Sprintf(" Step:%v\n", fg.Step) +
|
|
fmt.Sprintf(" FlashNodeCount:%v\n", fg.FlashNodeCount)
|
|
}
|
|
|
|
var (
|
|
flashnodeSlotStatTablePattern = "%-12v %-12v %-12v %-12v %-12v\n"
|
|
flashnodeSlotStatTableHeader = fmt.Sprintf(flashnodeSlotStatTablePattern,
|
|
"SlotId", "OwnerSlotId", "HitCount", "HitRate", "RecentTime")
|
|
)
|
|
|
|
func formatFlashNodeSlotStat(stat *proto.FlashNodeSlotStat) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(flashnodeSlotStatTableHeader)
|
|
for _, slot := range stat.SlotStat {
|
|
hitrate := fmt.Sprintf("%.2f%%", slot.HitRate*100)
|
|
recentTime := formatTimeToString(slot.RecentTime)
|
|
sb.WriteString(fmt.Sprintf(flashnodeSlotStatTablePattern, slot.SlotId, slot.OwnerSlotId, slot.HitCount, hitrate, recentTime))
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
func formatMetaPartitionFreeze(freeze int8) string {
|
|
switch freeze {
|
|
case proto.FreezeMetaPartitionInit:
|
|
return "unfreeze"
|
|
case proto.FreezingMetaPartition:
|
|
return "freezing"
|
|
case proto.FreezedMetaPartition:
|
|
return "freezed"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|