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.
		
		
		
		
		
			
		
			
				
					
					
						
							133 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							133 lines
						
					
					
						
							4.6 KiB
						
					
					
				| package vacuum | |
| 
 | |
| import ( | |
| 	"fmt" | |
| 	"time" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/glog" | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb/worker_pb" | |
| 	"github.com/seaweedfs/seaweedfs/weed/worker/tasks/base" | |
| 	"github.com/seaweedfs/seaweedfs/weed/worker/types" | |
| ) | |
| 
 | |
| // Detection implements the detection logic for vacuum tasks | |
| func Detection(metrics []*types.VolumeHealthMetrics, clusterInfo *types.ClusterInfo, config base.TaskConfig) ([]*types.TaskDetectionResult, error) { | |
| 	if !config.IsEnabled() { | |
| 		return nil, nil | |
| 	} | |
| 
 | |
| 	vacuumConfig := config.(*Config) | |
| 	var results []*types.TaskDetectionResult | |
| 	minVolumeAge := time.Duration(vacuumConfig.MinVolumeAgeSeconds) * time.Second | |
| 
 | |
| 	debugCount := 0 | |
| 	skippedDueToGarbage := 0 | |
| 	skippedDueToAge := 0 | |
| 
 | |
| 	for _, metric := range metrics { | |
| 		// Check if volume needs vacuum | |
| 		if metric.GarbageRatio >= vacuumConfig.GarbageThreshold && metric.Age >= minVolumeAge { | |
| 			priority := types.TaskPriorityNormal | |
| 			if metric.GarbageRatio > 0.6 { | |
| 				priority = types.TaskPriorityHigh | |
| 			} | |
| 
 | |
| 			// Generate task ID for future ActiveTopology integration | |
| 			taskID := fmt.Sprintf("vacuum_vol_%d_%d", metric.VolumeID, time.Now().Unix()) | |
| 
 | |
| 			result := &types.TaskDetectionResult{ | |
| 				TaskID:     taskID, // For future ActiveTopology integration | |
| 				TaskType:   types.TaskTypeVacuum, | |
| 				VolumeID:   metric.VolumeID, | |
| 				Server:     metric.Server, | |
| 				Collection: metric.Collection, | |
| 				Priority:   priority, | |
| 				Reason:     "Volume has excessive garbage requiring vacuum", | |
| 				ScheduleAt: time.Now(), | |
| 			} | |
| 
 | |
| 			// Create typed parameters for vacuum task | |
| 			result.TypedParams = createVacuumTaskParams(result, metric, vacuumConfig, clusterInfo) | |
| 			results = append(results, result) | |
| 		} else { | |
| 			// Debug why volume was not selected | |
| 			if debugCount < 5 { // Limit debug output to first 5 volumes | |
| 				if metric.GarbageRatio < vacuumConfig.GarbageThreshold { | |
| 					skippedDueToGarbage++ | |
| 				} | |
| 				if metric.Age < minVolumeAge { | |
| 					skippedDueToAge++ | |
| 				} | |
| 			} | |
| 			debugCount++ | |
| 		} | |
| 	} | |
| 
 | |
| 	// Log debug summary if no tasks were created | |
| 	if len(results) == 0 && len(metrics) > 0 { | |
| 		totalVolumes := len(metrics) | |
| 		glog.Infof("VACUUM: No tasks created for %d volumes. Threshold=%.2f%%, MinAge=%s. Skipped: %d (garbage<threshold), %d (age<minimum)", | |
| 			totalVolumes, vacuumConfig.GarbageThreshold*100, minVolumeAge, skippedDueToGarbage, skippedDueToAge) | |
| 
 | |
| 		// Show details for first few volumes | |
| 		for i, metric := range metrics { | |
| 			if i >= 3 { // Limit to first 3 volumes | |
| 				break | |
| 			} | |
| 			glog.Infof("VACUUM: Volume %d: garbage=%.2f%% (need ≥%.2f%%), age=%s (need ≥%s)", | |
| 				metric.VolumeID, metric.GarbageRatio*100, vacuumConfig.GarbageThreshold*100, | |
| 				metric.Age.Truncate(time.Minute), minVolumeAge.Truncate(time.Minute)) | |
| 		} | |
| 	} | |
| 
 | |
| 	return results, nil | |
| } | |
| 
 | |
| // createVacuumTaskParams creates typed parameters for vacuum tasks | |
| // This function is moved from MaintenanceIntegration.createVacuumTaskParams to the detection logic | |
| func createVacuumTaskParams(task *types.TaskDetectionResult, metric *types.VolumeHealthMetrics, vacuumConfig *Config, clusterInfo *types.ClusterInfo) *worker_pb.TaskParams { | |
| 	// Use configured values or defaults | |
| 	garbageThreshold := 0.3                    // Default 30% | |
| 	verifyChecksum := true                     // Default to verify | |
| 	batchSize := int32(1000)                   // Default batch size | |
| 	workingDir := "/tmp/seaweedfs_vacuum_work" // Default working directory | |
|  | |
| 	if vacuumConfig != nil { | |
| 		garbageThreshold = vacuumConfig.GarbageThreshold | |
| 		// Note: VacuumTaskConfig has GarbageThreshold, MinVolumeAgeHours, MinIntervalSeconds | |
| 		// Other fields like VerifyChecksum, BatchSize, WorkingDir would need to be added | |
| 		// to the protobuf definition if they should be configurable | |
| 	} | |
| 
 | |
| 	// Use DC and rack information directly from VolumeHealthMetrics | |
| 	sourceDC, sourceRack := metric.DataCenter, metric.Rack | |
| 
 | |
| 	// Create typed protobuf parameters with unified sources | |
| 	return &worker_pb.TaskParams{ | |
| 		TaskId:     task.TaskID, // Link to ActiveTopology pending task (if integrated) | |
| 		VolumeId:   task.VolumeID, | |
| 		Collection: task.Collection, | |
| 		VolumeSize: metric.Size, // Store original volume size for tracking changes | |
|  | |
| 		// Unified sources array | |
| 		Sources: []*worker_pb.TaskSource{ | |
| 			{ | |
| 				Node:          task.Server, | |
| 				VolumeId:      task.VolumeID, | |
| 				EstimatedSize: metric.Size, | |
| 				DataCenter:    sourceDC, | |
| 				Rack:          sourceRack, | |
| 			}, | |
| 		}, | |
| 
 | |
| 		TaskParams: &worker_pb.TaskParams_VacuumParams{ | |
| 			VacuumParams: &worker_pb.VacuumTaskParams{ | |
| 				GarbageThreshold: garbageThreshold, | |
| 				ForceVacuum:      false, | |
| 				BatchSize:        batchSize, | |
| 				WorkingDir:       workingDir, | |
| 				VerifyChecksum:   verifyChecksum, | |
| 			}, | |
| 		}, | |
| 	} | |
| }
 |