mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-26 06:50:45 +01:00
* feat: send EC shards in parallel per destination disk One stream per destination disk. max_shard_transfers unset means no global cap, 0 sends shards sequentially, and N is a global cap that still keeps one stream per disk. The value is persisted through TaskPolicy. The maintenance form is a checkbox plus Max transfers because unset and 0 differ. The key is intentionally omitted from GetConfigSpec. * ec shard distribution: treat negative max_shard_transfers as sequential The config layer (normalizedMaxShardTransfers) clamps negative values to 0, which selects sequential distribution. shardTransferCap diverged: a negative cap that reached ShardDistributionOptions directly would have selected uncapped parallel mode, the most aggressive setting. Align the options layer with the same normalization so invalid input degrades to the conservative mode. * ec: serialize shard transfers to a server when a target leaves disk choice to the receiver disk_id 0 is auto-placement on the receiving volume server, so an auto-placed stream can land on a disk another queued stream is pinned to. Grouping by (destNode, disk_id) alone let both run at once; collapse all of that server's transfers under the destNode key instead. * worker: clamp max_shard_transfers to the int32 wire range ReadIntConfig returned the 0 fallback for values above MaxInt32, turning a large positive cap into sequential mode. Read int64 and clamp into range instead. * worker: drop unused shard-transfer form helper The maintenance form renders and collects max_shard_transfers in plugin.templ JavaScript; the Go copy had no callers. * worker: bound max_shard_transfers conversion under an in-range guard --------- Co-authored-by: Chepurnov Simon <195125934+CHEPURNOV-S-S@users.noreply.github.com> Co-authored-by: Chris Lu <chrislusf@users.noreply.github.com>
101 lines
3.2 KiB
Go
101 lines
3.2 KiB
Go
package erasure_coding
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/worker_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/security"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
"github.com/seaweedfs/seaweedfs/weed/worker/tasks"
|
|
"github.com/seaweedfs/seaweedfs/weed/worker/tasks/base"
|
|
"github.com/seaweedfs/seaweedfs/weed/worker/types"
|
|
)
|
|
|
|
// Global variable to hold the task definition for configuration updates
|
|
var globalTaskDef *base.TaskDefinition
|
|
|
|
// Auto-register this task when the package is imported
|
|
func init() {
|
|
RegisterErasureCodingTask()
|
|
|
|
// Register config updater
|
|
tasks.AutoRegisterConfigUpdater(types.TaskTypeErasureCoding, UpdateConfigFromPersistence)
|
|
}
|
|
|
|
// RegisterErasureCodingTask registers the erasure coding task with the new architecture
|
|
func RegisterErasureCodingTask() {
|
|
// Create configuration instance
|
|
config := NewDefaultConfig()
|
|
|
|
// Create shared gRPC dial option using TLS configuration
|
|
dialOpt := security.LoadClientTLS(util.GetViper(), "grpc.worker")
|
|
|
|
// Create complete task definition
|
|
taskDef := &base.TaskDefinition{
|
|
Type: types.TaskTypeErasureCoding,
|
|
Name: "erasure_coding",
|
|
DisplayName: "Erasure Coding",
|
|
Description: "Applies erasure coding to volumes for data protection",
|
|
Icon: "fas fa-shield-alt text-success",
|
|
Capabilities: []string{"erasure_coding", "data_protection"},
|
|
|
|
Config: config,
|
|
ConfigSpec: GetConfigSpec(),
|
|
CreateTask: func(params *worker_pb.TaskParams) (types.Task, error) {
|
|
if params == nil {
|
|
return nil, fmt.Errorf("task parameters are required")
|
|
}
|
|
if len(params.Sources) == 0 {
|
|
return nil, fmt.Errorf("at least one source is required for erasure coding task")
|
|
}
|
|
task := NewErasureCodingTask(
|
|
fmt.Sprintf("erasure_coding-%d", params.VolumeId),
|
|
params.Sources[0].Node, // Use first source node
|
|
params.VolumeId,
|
|
params.Collection,
|
|
dialOpt,
|
|
)
|
|
if cfg, ok := globalTaskDef.Config.(*Config); ok {
|
|
task.maxShardTransfers = cloneMaxShardTransfers(cfg.MaxShardTransfers)
|
|
}
|
|
return task, nil
|
|
},
|
|
DetectionFunc: func(metrics []*types.VolumeHealthMetrics, clusterInfo *types.ClusterInfo, config base.TaskConfig) ([]*types.TaskDetectionResult, error) {
|
|
results, _, err := Detection(context.Background(), metrics, clusterInfo, config, 0)
|
|
return results, err
|
|
},
|
|
ScanInterval: 1 * time.Hour,
|
|
SchedulingFunc: Scheduling,
|
|
MaxConcurrent: 1,
|
|
RepeatInterval: 24 * time.Hour,
|
|
}
|
|
|
|
// Store task definition globally for configuration updates
|
|
globalTaskDef = taskDef
|
|
|
|
// Register everything with a single function call!
|
|
base.RegisterTask(taskDef)
|
|
}
|
|
|
|
// UpdateConfigFromPersistence updates the erasure coding configuration from persistence
|
|
func UpdateConfigFromPersistence(configPersistence interface{}) error {
|
|
if globalTaskDef == nil {
|
|
return fmt.Errorf("erasure coding task not registered")
|
|
}
|
|
|
|
// Load configuration from persistence
|
|
newConfig := LoadConfigFromPersistence(configPersistence)
|
|
if newConfig == nil {
|
|
return fmt.Errorf("failed to load configuration from persistence")
|
|
}
|
|
|
|
// Update the task definition's config
|
|
globalTaskDef.Config = newConfig
|
|
|
|
glog.V(1).Infof("Updated erasure coding task configuration from persistence")
|
|
return nil
|
|
}
|