wip: 重新整理 install cmd
This commit is contained in:
157
pkg/syscheck/disk.go
Normal file
157
pkg/syscheck/disk.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package syscheck
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetDiskSpace returns available disk space in bytes for the root partition
|
||||
func GetDiskSpace(ctx context.Context) (int64, error) {
|
||||
var stat unix.Statfs_t
|
||||
if err := unix.Statfs("/", &stat); err != nil {
|
||||
return 0, fmt.Errorf("failed to get disk space: %w", err)
|
||||
}
|
||||
|
||||
// Available space = Available blocks * Block size
|
||||
availableSpace := int64(stat.Bavail) * int64(stat.Bsize)
|
||||
return availableSpace, nil
|
||||
}
|
||||
|
||||
// GetDiskSpeed measures disk read/write speed by writing and reading a 1GB test file
|
||||
// Returns read speed and write speed in bytes per second
|
||||
func GetDiskSpeed(ctx context.Context) (int64, int64, error) {
|
||||
const (
|
||||
testSize = 1024 * 1024 * 1024 // 1GB
|
||||
bufferSize = 1024 * 1024 // 1MB buffer
|
||||
)
|
||||
|
||||
tmpFile := "/tmp/diskspeed_test_" + strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
defer func() {
|
||||
// Clean up test file
|
||||
_ = os.Remove(tmpFile)
|
||||
}()
|
||||
|
||||
// Test write speed
|
||||
writeSpeed, err := measureWriteSpeed(ctx, tmpFile, testSize, bufferSize)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("failed to measure write speed: %w", err)
|
||||
}
|
||||
|
||||
// Test read speed
|
||||
readSpeed, err := measureReadSpeed(ctx, tmpFile, bufferSize)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("failed to measure read speed: %w", err)
|
||||
}
|
||||
|
||||
return readSpeed, writeSpeed, nil
|
||||
}
|
||||
|
||||
// measureWriteSpeed writes test data to a file and measures the speed
|
||||
func measureWriteSpeed(ctx context.Context, filename string, totalSize, bufferSize int64) (int64, error) {
|
||||
// Create file
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to create test file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Prepare buffer with random data
|
||||
buffer := make([]byte, bufferSize)
|
||||
if _, err := rand.Read(buffer); err != nil {
|
||||
return 0, fmt.Errorf("failed to generate random data: %w", err)
|
||||
}
|
||||
|
||||
// Start timing
|
||||
startTime := time.Now()
|
||||
var written int64
|
||||
|
||||
// Write data in chunks
|
||||
for written < totalSize {
|
||||
// Check context cancellation
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return 0, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// Write buffer
|
||||
n, err := file.Write(buffer)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to write data: %w", err)
|
||||
}
|
||||
written += int64(n)
|
||||
}
|
||||
|
||||
// Sync to ensure data is written to disk
|
||||
if err := file.Sync(); err != nil {
|
||||
return 0, fmt.Errorf("failed to sync file: %w", err)
|
||||
}
|
||||
|
||||
// Calculate speed
|
||||
duration := time.Since(startTime)
|
||||
speed := int64(float64(written) / duration.Seconds())
|
||||
|
||||
return speed, nil
|
||||
}
|
||||
|
||||
// measureReadSpeed reads the test file and measures the speed
|
||||
func measureReadSpeed(ctx context.Context, filename string, bufferSize int64) (int64, error) {
|
||||
// Open file
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to open test file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Get file size
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to stat file: %w", err)
|
||||
}
|
||||
totalSize := fileInfo.Size()
|
||||
|
||||
// Prepare buffer
|
||||
buffer := make([]byte, bufferSize)
|
||||
|
||||
// Start timing
|
||||
startTime := time.Now()
|
||||
var totalRead int64
|
||||
|
||||
// Read data in chunks
|
||||
for {
|
||||
// Check context cancellation
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return 0, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// Read buffer
|
||||
n, err := file.Read(buffer)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to read data: %w", err)
|
||||
}
|
||||
totalRead += int64(n)
|
||||
}
|
||||
|
||||
// Calculate speed
|
||||
duration := time.Since(startTime)
|
||||
speed := int64(float64(totalRead) / duration.Seconds())
|
||||
|
||||
// Verify we read the entire file
|
||||
if totalRead != totalSize {
|
||||
return 0, fmt.Errorf("read size mismatch: expected %d, got %d", totalSize, totalRead)
|
||||
}
|
||||
|
||||
return speed, nil
|
||||
}
|
||||
Reference in New Issue
Block a user