mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 07:40:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			153 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
						||
 | 
						||
package fsutils
 | 
						||
 | 
						||
import (
 | 
						||
	"encoding/json"
 | 
						||
	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
 | 
						||
	"github.com/iwind/TeaGo/Tea"
 | 
						||
	"github.com/shirou/gopsutil/v3/load"
 | 
						||
	"os"
 | 
						||
	"sync/atomic"
 | 
						||
	"time"
 | 
						||
)
 | 
						||
 | 
						||
type Speed int
 | 
						||
 | 
						||
func (this Speed) String() string {
 | 
						||
	switch this {
 | 
						||
	case SpeedExtremelyFast:
 | 
						||
		return "extremely fast"
 | 
						||
	case SpeedFast:
 | 
						||
		return "fast"
 | 
						||
	case SpeedLow:
 | 
						||
		return "low"
 | 
						||
	case SpeedExtremelySlow:
 | 
						||
		return "extremely slow"
 | 
						||
	}
 | 
						||
	return "unknown"
 | 
						||
}
 | 
						||
 | 
						||
const (
 | 
						||
	SpeedExtremelyFast Speed = 1
 | 
						||
	SpeedFast          Speed = 2
 | 
						||
	SpeedLow           Speed = 3
 | 
						||
	SpeedExtremelySlow Speed = 4
 | 
						||
)
 | 
						||
 | 
						||
var (
 | 
						||
	DiskSpeed           = SpeedLow
 | 
						||
	DiskMaxWrites int32 = 32
 | 
						||
	DiskSpeedMB   float64
 | 
						||
)
 | 
						||
 | 
						||
var IsInHighLoad = false
 | 
						||
var IsInExtremelyHighLoad = false
 | 
						||
 | 
						||
const (
 | 
						||
	highLoad1Threshold          = 20
 | 
						||
	extremelyHighLoad1Threshold = 40
 | 
						||
)
 | 
						||
 | 
						||
func init() {
 | 
						||
	if !teaconst.IsMain {
 | 
						||
		return
 | 
						||
	}
 | 
						||
 | 
						||
	// test disk
 | 
						||
	go func() {
 | 
						||
		// load last result from local disk
 | 
						||
		cacheData, cacheErr := os.ReadFile(Tea.Root + "/data/" + diskSpeedDataFile)
 | 
						||
		if cacheErr == nil {
 | 
						||
			var cache = &DiskSpeedCache{}
 | 
						||
			err := json.Unmarshal(cacheData, cache)
 | 
						||
			if err == nil && cache.SpeedMB > 0 {
 | 
						||
				DiskSpeedMB = cache.SpeedMB
 | 
						||
				DiskSpeed = cache.Speed
 | 
						||
				calculateDiskMaxWrites()
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		// initial check
 | 
						||
		_, _, _ = CheckDiskIsFast()
 | 
						||
 | 
						||
		// check every one hour
 | 
						||
		var ticker = time.NewTicker(1 * time.Hour)
 | 
						||
		var count = 0
 | 
						||
		for range ticker.C {
 | 
						||
			_, _, err := CheckDiskIsFast()
 | 
						||
			if err == nil {
 | 
						||
				count++
 | 
						||
				if count > 24 {
 | 
						||
					return
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}()
 | 
						||
 | 
						||
	// check high load
 | 
						||
	go func() {
 | 
						||
		var ticker = time.NewTicker(5 * time.Second)
 | 
						||
		for range ticker.C {
 | 
						||
			stat, _ := load.Avg()
 | 
						||
			IsInExtremelyHighLoad = stat != nil && stat.Load1 > extremelyHighLoad1Threshold
 | 
						||
			IsInHighLoad = stat != nil && stat.Load1 > highLoad1Threshold && !DiskIsFast()
 | 
						||
		}
 | 
						||
	}()
 | 
						||
}
 | 
						||
 | 
						||
func DiskIsFast() bool {
 | 
						||
	return DiskSpeed == SpeedExtremelyFast || DiskSpeed == SpeedFast
 | 
						||
}
 | 
						||
 | 
						||
func DiskIsExtremelyFast() bool {
 | 
						||
	// 在开发环境下返回false,以便于测试
 | 
						||
	if Tea.IsTesting() {
 | 
						||
		return false
 | 
						||
	}
 | 
						||
	return DiskSpeed == SpeedExtremelyFast
 | 
						||
}
 | 
						||
 | 
						||
var countWrites int32 = 0
 | 
						||
 | 
						||
func WriteReady() bool {
 | 
						||
	if IsInExtremelyHighLoad {
 | 
						||
		return false
 | 
						||
	}
 | 
						||
 | 
						||
	return atomic.LoadInt32(&countWrites) < DiskMaxWrites
 | 
						||
}
 | 
						||
 | 
						||
func WriteBegin() {
 | 
						||
	atomic.AddInt32(&countWrites, 1)
 | 
						||
}
 | 
						||
 | 
						||
func WriteEnd() {
 | 
						||
	atomic.AddInt32(&countWrites, -1)
 | 
						||
}
 | 
						||
 | 
						||
func calculateDiskMaxWrites() {
 | 
						||
	switch DiskSpeed {
 | 
						||
	case SpeedExtremelyFast:
 | 
						||
		DiskMaxWrites = 32
 | 
						||
	case SpeedFast:
 | 
						||
		DiskMaxWrites = 16
 | 
						||
	case SpeedLow:
 | 
						||
		DiskMaxWrites = 8
 | 
						||
	case SpeedExtremelySlow:
 | 
						||
		DiskMaxWrites = 4
 | 
						||
	default:
 | 
						||
		DiskMaxWrites = 4
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
// WaitLoad wait system load to downgrade
 | 
						||
func WaitLoad(maxLoad float64, maxLoops int, delay time.Duration) {
 | 
						||
	for i := 0; i < maxLoops; i++ {
 | 
						||
		stat, err := load.Avg()
 | 
						||
		if err == nil && stat.Load1 > maxLoad {
 | 
						||
			time.Sleep(delay)
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 |