style(common): using generic version of functions

. #1000657118

Signed-off-by: slasher <shenjie1@oppo.com>
This commit is contained in:
slasher 2026-01-19 15:47:28 +08:00 committed by 梁曟風
parent a07809fc95
commit dec013044a
7 changed files with 83 additions and 85 deletions

View File

@ -95,7 +95,7 @@ func showClusters(c *grumble.Context) error {
fmt.Println()
}
fmt.Printf("\tspace in region: %s (%s / %s)\n", region,
common.ColorizeInt64(-available, capacity).Sprint(humanize.IBytes(uint64(available))),
common.ColorizeInteger(-available, capacity).Sprint(humanize.IBytes(uint64(available))),
humanize.IBytes(uint64(capacity)))
}
@ -126,7 +126,7 @@ func showClusterWithConfig() error {
fmt.Println()
fmt.Printf("\tspace in cluster: %s (%s / %s)\n", clusterID,
common.ColorizeInt64(-stat.BlobNodeSpaceStat.WritableSpace, stat.BlobNodeSpaceStat.TotalSpace).
common.ColorizeInteger(-stat.BlobNodeSpaceStat.WritableSpace, stat.BlobNodeSpaceStat.TotalSpace).
Sprint(humanize.IBytes(uint64(stat.BlobNodeSpaceStat.WritableSpace))),
humanize.IBytes(uint64(stat.BlobNodeSpaceStat.TotalSpace)))
}

View File

@ -207,33 +207,26 @@ func cmdListVolumeUnits(c *grumble.Context) error {
n := len(volumeInfo.Units)
loader := common.Loader(n)
taskArgs := make([]any, n)
for i, arg := range volumeInfo.Units {
taskArgs[i] = arg
}
chunkInfos := make([]string, n)
task.C(func(i int, taskArgs any) {
unit := taskArgs.(clustermgr.Unit)
chunkInfos := task.ConcurrentResult(func(_ int, unit clustermgr.Unit) string {
disk, err := cmClient.DiskInfo(ctx, unit.DiskID)
if err != nil {
chunkInfos[i] = fmt.Sprintf("ERROR: get disk %d %s", unit.DiskID, err.Error())
loader <- 1
return
return fmt.Sprintf("ERROR: get disk %d %s", unit.DiskID, err.Error())
}
info, err := blobnodeCli.StatChunk(ctx, disk.Host,
&blobnode.StatChunkArgs{
DiskID: unit.DiskID,
Vuid: unit.Vuid,
})
if err != nil {
chunkInfos[i] = fmt.Sprintf("ERROR: %s %d %s", disk.Host, unit.Vuid, err.Error())
} else if verbose {
chunkInfos[i] = cfmt.ChunkInfoJoin(info, "\t")
} else {
chunkInfos[i] = fmt.Sprint(info)
}
loader <- 1
}, taskArgs)
if err != nil {
return fmt.Sprintf("ERROR: %s %d %s", disk.Host, unit.Vuid, err.Error())
} else if verbose {
return cfmt.ChunkInfoJoin(info, "\t")
}
return fmt.Sprint(info)
}, volumeInfo.Units...)
time.Sleep(100 * time.Millisecond)
fmt.Println("chunks:")

View File

@ -33,8 +33,8 @@ func VolumeInfoF(vol *clustermgr.VolumeInfo) []string {
if vol == nil {
return nilStrings[:]
}
usedC := common.ColorizeUint64(vol.Used, vol.Total)
freeC := common.ColorizeUint64Free(vol.Free, vol.Total)
usedC := common.ColorizeInteger(vol.Used, vol.Total)
freeC := common.ColorizeIntegerFree(vol.Free, vol.Total)
vals := make([]string, 0, 32)
vals = append(vals, []string{
fmt.Sprintf("Vid : %d", vol.Vid),
@ -92,7 +92,7 @@ func ClusterInfoF(info *clustermgr.ClusterInfo) []string {
if info == nil {
return nilStrings[:]
}
avaiC := common.ColorizeInt64(-info.Available, info.Capacity)
avaiC := common.ColorizeInteger(-info.Available, info.Capacity)
vals := make([]string, 0, 8)
vals = append(vals, []string{
fmt.Sprintf("Region : %s", info.Region),

View File

@ -16,6 +16,8 @@ package common
import (
"github.com/fatih/color"
"github.com/cubefs/cubefs/blobstore/util"
)
// colorize defined
@ -97,7 +99,7 @@ func Colorize(percent int) *color.Color {
}
// ColorizeFloat color by float64 [-1.0, 1.0] ratio
func ColorizeFloat(ratio float64) *color.Color {
func ColorizeFloat[T util.Float](ratio T) *color.Color {
return Colorize(int(ratio * 100))
}
@ -108,37 +110,13 @@ func percentIfFree(free bool, percent int) int {
return percent
}
// ColorizeInt by int
func ColorizeInt(used, total int) *color.Color {
return Colorize(percentIfFree(used < 0, used*100/total))
}
// ColorizeInt32 by int32
func ColorizeInt32(used, total int32) *color.Color {
// ColorizeInteger colorize by any integer type
// When used < 0 (signed types only), it indicates free space calculation
func ColorizeInteger[T util.Integer](used, total T) *color.Color {
return Colorize(percentIfFree(used < 0, int(used*100/total)))
}
// ColorizeInt64 by int64
func ColorizeInt64(used, total int64) *color.Color {
return Colorize(percentIfFree(used < 0, int(used*100/total)))
}
// ColorizeUint32 by uint32
func ColorizeUint32(used, total uint32) *color.Color {
return Colorize(int(used * 100 / total))
}
// ColorizeUint64 by uint64
func ColorizeUint64(used, total uint64) *color.Color {
return Colorize(int(used * 100 / total))
}
// ColorizeUint32Free free by uint32
func ColorizeUint32Free(free, total uint32) *color.Color {
return Colorize(percentIfFree(true, -int(free*100/total)))
}
// ColorizeUint64Free free by uint64
func ColorizeUint64Free(free, total uint64) *color.Color {
// ColorizeIntegerFree colorize free space by any integer type
func ColorizeIntegerFree[T util.Integer](free, total T) *color.Color {
return Colorize(percentIfFree(true, -int(free*100/total)))
}

View File

@ -17,7 +17,6 @@ package common_test
import (
"math/rand"
"testing"
"time"
"github.com/cubefs/cubefs/blobstore/cli/common"
"github.com/cubefs/cubefs/blobstore/cli/common/fmt"
@ -59,7 +58,6 @@ func TestCmdCommonColorRatio(t *testing.T) {
{1000, 100, "highlight [Dead]"},
}
rand.Seed(time.Now().Unix())
for _, cs := range cases {
for i := 0; i < 10; i++ {
percent := rand.Intn(cs.rand) + cs.offset
@ -78,24 +76,19 @@ func TestCmdCommonColorRatio(t *testing.T) {
f := rand.Float64()
c := common.ColorizeFloat(f)
c.Printf("used(%.3f) unknow ", f)
c = common.ColorizeFloat(-f)
c = common.ColorizeFloat(-float32(f))
c.Printf("free(%.3f) unknow ", -f)
fmt.Println()
}
fmt.Println()
common.ColorizeInt(0, 100).Printf("ColorizeInt --> used(%d/%d) white\n", 0, 100)
common.ColorizeInt(-1, 1000).Printf("ColorizeInt --> free(%d/%d) dead", -1, 10000)
common.ColorizeInteger(0, 100).Printf("Int --> used(%d/%d) white\n", 0, 100)
common.ColorizeInteger(-1, 1000).Printf("Int --> free(%d/%d) dead", -1, 10000)
fmt.Println()
common.ColorizeInt(80, 100).Printf("ColorizeInt --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeInt(-80, 100).Printf("ColorizeInt --> free(%d/%d) green\n", 80, 100)
common.ColorizeInt32(80, 100).Printf("ColorizeInt32 --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeInt32(-80, 100).Printf("ColorizeInt32 --> free(%d/%d) green\n", 80, 100)
common.ColorizeInt64(80, 100).Printf("ColorizeInt64 --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeInt64(-80, 100).Printf("ColorizeInt64 --> free(%d/%d) green\n", 80, 100)
common.ColorizeUint32(80, 100).Printf("ColorizeUint32 --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeUint32Free(80, 100).Printf("ColorizeUint32Free --> free(%d/%d) green\n", 80, 100)
common.ColorizeUint64(80, 100).Printf("ColorizeUint64 --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeUint64Free(80, 100).Printf("ColorizeUint64Free --> free(%d/%d) green\n", 80, 100)
common.ColorizeInteger(80, 100).Printf("Int --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeInteger(-80, 100).Printf("Int --> free(%d/%d) green\n", 80, 100)
common.ColorizeInteger(int32(80), 100).Printf("Int32 --> used(%d/%d) yellow\n", 80, 100)
common.ColorizeInteger(-80, int32(100)).Printf("Int32 --> free(%d/%d) green\n", 80, 100)
common.ColorizeIntegerFree(uint64(80), 100).Printf("Uint64 --> free(%d/%d) green\n", 80, 100)
}

View File

@ -16,23 +16,15 @@ package task
import "context"
var (
// C alias of Concurrent
C = Concurrent
// CC alias of ConcurrentContext
CC = ConcurrentContext
)
// Concurrent is tasks run concurrently.
func Concurrent(f func(index int, arg interface{}), args []interface{}) {
ConcurrentContext(context.Background(), f, args)
func Concurrent[T any](f func(index int, arg T), args ...T) {
ConcurrentContext(context.Background(), f, args...)
}
// ConcurrentContext is tasks run concurrently with context.
// How to make []interface{} see: https://golang.org/doc/faq#convert_slice_of_interface
func ConcurrentContext(ctx context.Context, f func(index int, arg interface{}), args []interface{}) {
func ConcurrentContext[T any](ctx context.Context, f func(index int, arg T), args ...T) {
tasks := make([]func() error, len(args))
for ii := 0; ii < len(args); ii++ {
for ii := range args {
index, arg := ii, args[ii]
tasks[ii] = func() error {
f(index, arg)
@ -41,3 +33,23 @@ func ConcurrentContext(ctx context.Context, f func(index int, arg interface{}),
}
Run(ctx, tasks...)
}
// ConcurrentResult runs tasks concurrently and collects results.
func ConcurrentResult[T, R any](f func(index int, arg T) R, args ...T) []R {
return ConcurrentResultContext(context.Background(), f, args...)
}
// ConcurrentResultContext runs tasks concurrently with context and collects results.
func ConcurrentResultContext[T, R any](ctx context.Context, f func(index int, arg T) R, args ...T) []R {
results := make([]R, len(args))
tasks := make([]func() error, len(args))
for ii := range args {
idx, arg := ii, args[ii]
tasks[ii] = func() error {
results[idx] = f(idx, arg)
return nil
}
}
Run(ctx, tasks...)
return results
}

View File

@ -28,11 +28,18 @@ import (
func TestTaskExecuteConcurrent(t *testing.T) {
unique := uint32(0)
args := []interface{}{uint32(1), uint32(2), uint32(4)}
task.C(func(index int, arg interface{}) {
task.Concurrent(func(index int, arg uint32) {
time.Sleep(time.Millisecond * 100)
atomic.AddUint32(&unique, arg.(uint32))
}, args)
atomic.AddUint32(&unique, arg)
}, 1, 2, 4) // copy mode, call Concurrent will create args = []uint32{1, 2, 4}
require.Equal(t, uint32(7), atomic.LoadUint32(&unique))
atomic.StoreUint32(&unique, 0)
args := []uint32{1, 2, 4}
task.Concurrent(func(index int, arg uint32) {
time.Sleep(time.Millisecond * 100)
atomic.AddUint32(&unique, arg)
}, args...) // reference mode
require.Equal(t, uint32(7), atomic.LoadUint32(&unique))
}
@ -40,10 +47,10 @@ func TestTaskExecuteContextCancel(t *testing.T) {
unique := uint32(0)
ctx, cancel := context.WithCancel(context.Background())
err := task.Run(ctx, func() error {
task.C(func(index int, arg interface{}) {
task.Concurrent(func(index int, arg uint32) {
time.Sleep(time.Millisecond * 2000)
atomic.AddUint32(&unique, 1)
}, []interface{}{1, 2, 4})
}, 1, 2, 4)
return nil
}, func() error {
time.Sleep(time.Millisecond * 5000)
@ -55,3 +62,18 @@ func TestTaskExecuteContextCancel(t *testing.T) {
require.Contains(t, err.Error(), "canceled")
require.Equal(t, uint32(0), atomic.LoadUint32(&unique))
}
func TestTaskExecuteConcurrentResult(t *testing.T) {
{
results := task.ConcurrentResult(func(index int, arg string) int {
return len(arg)
})
require.Empty(t, len(results))
}
{
results := task.ConcurrentResult(func(index int, arg int) int {
return arg * arg
}, 1, 2, 4, 7)
require.Equal(t, []int{1, 4, 16, 49}, results)
}
}