|
|
|
@ -10,6 +10,7 @@ import ( |
|
|
|
"time" |
|
|
|
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/stats" |
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding" |
|
|
|
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/topology" |
|
|
|
|
|
|
|
@ -291,6 +292,77 @@ func (ms *MasterServer) LookupEcVolume(ctx context.Context, req *master_pb.Looku |
|
|
|
return resp, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (ms *MasterServer) ActivateEcGeneration(ctx context.Context, req *master_pb.ActivateEcGenerationRequest) (*master_pb.ActivateEcGenerationResponse, error) { |
|
|
|
if !ms.Topo.IsLeader() { |
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: false, |
|
|
|
Error: "not leader", |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
// Basic request validation
|
|
|
|
if req.VolumeId == 0 { |
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: false, |
|
|
|
Error: "invalid volume ID: cannot be 0", |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
volumeId := needle.VolumeId(req.VolumeId) |
|
|
|
targetGeneration := req.Generation |
|
|
|
|
|
|
|
glog.V(1).Infof("ActivateEcGeneration: Activating generation %d for EC volume %d in collection %s", |
|
|
|
targetGeneration, req.VolumeId, req.Collection) |
|
|
|
|
|
|
|
// Validate that the target generation exists and has sufficient shards
|
|
|
|
ready, availableShards, err := ms.Topo.ValidateEcGenerationReadiness(volumeId, targetGeneration) |
|
|
|
if err != nil { |
|
|
|
errMsg := err.Error() |
|
|
|
glog.Warningf("ActivateEcGeneration: %s", errMsg) |
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: false, |
|
|
|
Error: errMsg, |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
if !ready { |
|
|
|
errMsg := fmt.Sprintf("generation %d for EC volume %d not ready: has %d shards, needs %d", |
|
|
|
targetGeneration, req.VolumeId, availableShards, erasure_coding.DataShardsCount) |
|
|
|
glog.Warningf("ActivateEcGeneration: %s", errMsg) |
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: false, |
|
|
|
Error: errMsg, |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
glog.V(2).Infof("ActivateEcGeneration: Generation %d for volume %d is ready with %d available shards", |
|
|
|
targetGeneration, req.VolumeId, availableShards) |
|
|
|
|
|
|
|
// Check current active generation for logging
|
|
|
|
var currentActiveGeneration uint32 |
|
|
|
if current, exists := ms.Topo.GetEcActiveGeneration(volumeId); exists { |
|
|
|
currentActiveGeneration = current |
|
|
|
if current == targetGeneration { |
|
|
|
glog.V(2).Infof("ActivateEcGeneration: Generation %d is already active for volume %d", targetGeneration, req.VolumeId) |
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: true, |
|
|
|
Error: "", |
|
|
|
}, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Perform the atomic activation
|
|
|
|
ms.Topo.SetEcActiveGeneration(volumeId, targetGeneration) |
|
|
|
|
|
|
|
glog.V(0).Infof("ActivateEcGeneration: Successfully activated generation %d for EC volume %d (was: %d)", |
|
|
|
targetGeneration, req.VolumeId, currentActiveGeneration) |
|
|
|
|
|
|
|
return &master_pb.ActivateEcGenerationResponse{ |
|
|
|
Success: true, |
|
|
|
Error: "", |
|
|
|
}, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (ms *MasterServer) VacuumVolume(ctx context.Context, req *master_pb.VacuumVolumeRequest) (*master_pb.VacuumVolumeResponse, error) { |
|
|
|
|
|
|
|
if !ms.Topo.IsLeader() { |
|
|
|
|