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.

82 lines
2.7 KiB

  1. package weed_server
  2. import (
  3. "context"
  4. "fmt"
  5. "math"
  6. "github.com/chrislusf/seaweedfs/weed/operation"
  7. "github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
  8. "github.com/chrislusf/seaweedfs/weed/storage"
  9. "github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
  10. "github.com/chrislusf/seaweedfs/weed/storage/needle"
  11. )
  12. /*
  13. Steps to apply erasure coding to .dat .idx files
  14. 0. ensure the volume is readonly
  15. 1. client call VolumeEcGenerateSlices to generate the .ecx and .ec01~.ec14 files
  16. 2. client ask master for possible servers to hold the ec files, at least 4 servers
  17. 3. client call VolumeEcCopy on above target servers to copy ec files from the source server
  18. 4. target servers report the new ec files to the master
  19. 5. master stores vid -> [14]*DataNode
  20. 6. client checks master. If all 14 slices are ready, delete the original .idx, .idx files
  21. */
  22. // VolumeEcGenerateSlices generates the .ecx and .ec01 ~ .ec14 files
  23. func (vs *VolumeServer) VolumeEcGenerateSlices(ctx context.Context, req *volume_server_pb.VolumeEcGenerateSlicesRequest) (*volume_server_pb.VolumeEcGenerateSlicesResponse, error) {
  24. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  25. if v == nil {
  26. return nil, fmt.Errorf("volume %d not found", req.VolumeId)
  27. }
  28. baseFileName := v.FileName()
  29. // write .ecx file
  30. if err := erasure_coding.WriteSortedEcxFile(baseFileName); err != nil {
  31. return nil, fmt.Errorf("WriteSortedEcxFile %s: %v", baseFileName, err)
  32. }
  33. // write .ec01 ~ .ec14 files
  34. if err := erasure_coding.WriteEcFiles(baseFileName); err != nil {
  35. return nil, fmt.Errorf("WriteEcFiles %s: %v", baseFileName, err)
  36. }
  37. return &volume_server_pb.VolumeEcGenerateSlicesResponse{}, nil
  38. }
  39. // VolumeEcCopy copy the .ecx and some ec data slices
  40. func (vs *VolumeServer) VolumeEcCopy(ctx context.Context, req *volume_server_pb.VolumeEcCopyRequest) (*volume_server_pb.VolumeEcCopyResponse, error) {
  41. location := vs.store.FindFreeLocation()
  42. if location == nil {
  43. return nil, fmt.Errorf("no space left")
  44. }
  45. baseFileName := storage.VolumeFileName(req.Collection, location.Directory, int(req.VolumeId))
  46. err := operation.WithVolumeServerClient(req.SourceDataNode, vs.grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
  47. // copy ecx file
  48. if err:=vs.doCopyFile(ctx, client, req.VolumeId, math.MaxUint32, math.MaxUint64, baseFileName, ".ecx"); err!=nil{
  49. return err
  50. }
  51. // copy ec data slices
  52. for _, ecIndex := range req.EcIndexes {
  53. if err:=vs.doCopyFile(ctx, client, req.VolumeId, math.MaxUint32, math.MaxUint64, baseFileName, erasure_coding.ToExt(int(ecIndex))); err!=nil{
  54. return err
  55. }
  56. }
  57. return nil
  58. })
  59. if err != nil {
  60. return nil, fmt.Errorf("VolumeEcCopy volume %d: %v", req.VolumeId, err)
  61. }
  62. return &volume_server_pb.VolumeEcCopyResponse{}, nil
  63. }