You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.3 KiB
168 lines
4.3 KiB
package task
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
"github.com/seaweedfs/seaweedfs/weed/worker/types"
|
|
)
|
|
|
|
// ECDetector detects volumes that need erasure coding
|
|
type ECDetector struct {
|
|
minUtilization float64
|
|
minIdleTime time.Duration
|
|
}
|
|
|
|
// NewECDetector creates a new EC detector
|
|
func NewECDetector() *ECDetector {
|
|
return &ECDetector{
|
|
minUtilization: 95.0, // 95% full
|
|
minIdleTime: time.Hour, // 1 hour idle
|
|
}
|
|
}
|
|
|
|
// DetectECCandidates finds volumes that need erasure coding
|
|
func (ed *ECDetector) DetectECCandidates(volumes []*VolumeInfo) ([]*VolumeCandidate, error) {
|
|
var candidates []*VolumeCandidate
|
|
|
|
for _, vol := range volumes {
|
|
if ed.isECCandidate(vol) {
|
|
candidate := &VolumeCandidate{
|
|
VolumeID: vol.ID,
|
|
Server: vol.Server,
|
|
Collection: vol.Collection,
|
|
TaskType: types.TaskTypeErasureCoding,
|
|
Priority: ed.calculateECPriority(vol),
|
|
Reason: "Volume is full and idle, ready for erasure coding",
|
|
DetectedAt: time.Now(),
|
|
ScheduleAt: time.Now(),
|
|
Parameters: map[string]interface{}{
|
|
"utilization": vol.GetUtilization(),
|
|
"idle_time": vol.GetIdleTime().String(),
|
|
"volume_size": vol.Size,
|
|
},
|
|
}
|
|
candidates = append(candidates, candidate)
|
|
}
|
|
}
|
|
|
|
glog.V(2).Infof("EC detector found %d candidates", len(candidates))
|
|
return candidates, nil
|
|
}
|
|
|
|
// isECCandidate checks if a volume is suitable for EC
|
|
func (ed *ECDetector) isECCandidate(vol *VolumeInfo) bool {
|
|
// Skip if read-only
|
|
if vol.ReadOnly {
|
|
return false
|
|
}
|
|
|
|
// Skip if already has remote storage (likely already EC'd)
|
|
if vol.RemoteStorageKey != "" {
|
|
return false
|
|
}
|
|
|
|
// Check utilization
|
|
if vol.GetUtilization() < ed.minUtilization {
|
|
return false
|
|
}
|
|
|
|
// Check idle time
|
|
if vol.GetIdleTime() < ed.minIdleTime {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// calculateECPriority calculates priority for EC tasks
|
|
func (ed *ECDetector) calculateECPriority(vol *VolumeInfo) types.TaskPriority {
|
|
utilization := vol.GetUtilization()
|
|
idleTime := vol.GetIdleTime()
|
|
|
|
// Higher priority for fuller volumes that have been idle longer
|
|
if utilization >= 98.0 && idleTime > 24*time.Hour {
|
|
return types.TaskPriorityHigh
|
|
}
|
|
if utilization >= 96.0 && idleTime > 6*time.Hour {
|
|
return types.TaskPriorityNormal
|
|
}
|
|
return types.TaskPriorityLow
|
|
}
|
|
|
|
// VacuumDetector detects volumes that need vacuum operations
|
|
type VacuumDetector struct {
|
|
minGarbageRatio float64
|
|
minDeleteCount uint64
|
|
}
|
|
|
|
// NewVacuumDetector creates a new vacuum detector
|
|
func NewVacuumDetector() *VacuumDetector {
|
|
return &VacuumDetector{
|
|
minGarbageRatio: 0.3, // 30% garbage
|
|
minDeleteCount: 100, // At least 100 deleted files
|
|
}
|
|
}
|
|
|
|
// DetectVacuumCandidates finds volumes that need vacuum operations
|
|
func (vd *VacuumDetector) DetectVacuumCandidates(volumes []*VolumeInfo) ([]*VolumeCandidate, error) {
|
|
var candidates []*VolumeCandidate
|
|
|
|
for _, vol := range volumes {
|
|
if vd.isVacuumCandidate(vol) {
|
|
candidate := &VolumeCandidate{
|
|
VolumeID: vol.ID,
|
|
Server: vol.Server,
|
|
Collection: vol.Collection,
|
|
TaskType: types.TaskTypeVacuum,
|
|
Priority: vd.calculateVacuumPriority(vol),
|
|
Reason: "Volume has high garbage ratio and needs vacuum",
|
|
DetectedAt: time.Now(),
|
|
ScheduleAt: time.Now(),
|
|
Parameters: map[string]interface{}{
|
|
"garbage_ratio": vol.GetGarbageRatio(),
|
|
"delete_count": vol.DeleteCount,
|
|
"deleted_byte_count": vol.DeletedByteCount,
|
|
},
|
|
}
|
|
candidates = append(candidates, candidate)
|
|
}
|
|
}
|
|
|
|
glog.V(2).Infof("Vacuum detector found %d candidates", len(candidates))
|
|
return candidates, nil
|
|
}
|
|
|
|
// isVacuumCandidate checks if a volume needs vacuum
|
|
func (vd *VacuumDetector) isVacuumCandidate(vol *VolumeInfo) bool {
|
|
// Skip if read-only
|
|
if vol.ReadOnly {
|
|
return false
|
|
}
|
|
|
|
// Check garbage ratio
|
|
if vol.GetGarbageRatio() < vd.minGarbageRatio {
|
|
return false
|
|
}
|
|
|
|
// Check delete count
|
|
if vol.DeleteCount < vd.minDeleteCount {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// calculateVacuumPriority calculates priority for vacuum tasks
|
|
func (vd *VacuumDetector) calculateVacuumPriority(vol *VolumeInfo) types.TaskPriority {
|
|
garbageRatio := vol.GetGarbageRatio()
|
|
|
|
// Higher priority for volumes with more garbage
|
|
if garbageRatio >= 0.6 {
|
|
return types.TaskPriorityHigh
|
|
}
|
|
if garbageRatio >= 0.4 {
|
|
return types.TaskPriorityNormal
|
|
}
|
|
return types.TaskPriorityLow
|
|
}
|