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.

203 lines
5.7 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. package weed_server
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/glog"
  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/needle"
  10. "io"
  11. "os"
  12. )
  13. // VolumeCopy copy the .idx .dat files, and mount the volume
  14. func (vs *VolumeServer) VolumeCopy(ctx context.Context, req *volume_server_pb.VolumeCopyRequest) (*volume_server_pb.VolumeCopyResponse, error) {
  15. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  16. if v != nil {
  17. // unmount the volume
  18. err := vs.store.UnmountVolume(needle.VolumeId(req.VolumeId))
  19. if err != nil {
  20. return nil, fmt.Errorf("failed to unmount volume %d: %v", req.VolumeId, err)
  21. }
  22. }
  23. location := vs.store.FindFreeLocation()
  24. if location == nil {
  25. return nil, fmt.Errorf("no space left")
  26. }
  27. volumeFileName := storage.VolumeFileName(req.Collection, location.Directory, int(req.VolumeId))
  28. // the master will not start compaction for read-only volumes, so it is safe to just copy files directly
  29. // copy .dat and .idx files
  30. // read .idx .dat file size and timestamp
  31. // send .idx file
  32. // send .dat file
  33. // confirm size and timestamp
  34. var volFileInfoResp *volume_server_pb.ReadVolumeFileStatusResponse
  35. datFileName := volumeFileName + ".dat"
  36. idxFileName := volumeFileName + ".idx"
  37. err := operation.WithVolumeServerClient(req.SourceDataNode, vs.grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
  38. var err error
  39. volFileInfoResp, err = client.ReadVolumeFileStatus(ctx,
  40. &volume_server_pb.ReadVolumeFileStatusRequest{
  41. VolumeId: req.VolumeId,
  42. })
  43. if nil != err {
  44. return fmt.Errorf("read volume file status failed, %v", err)
  45. }
  46. copyFileClient, err := client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{
  47. VolumeId: req.VolumeId,
  48. IsIdxFile: true,
  49. })
  50. if err != nil {
  51. return fmt.Errorf("failed to start copying volume %d idx file: %v", req.VolumeId, err)
  52. }
  53. err = writeToFile(copyFileClient, idxFileName)
  54. if err != nil {
  55. return fmt.Errorf("failed to copy volume %d idx file: %v", req.VolumeId, err)
  56. }
  57. copyFileClient, err = client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{
  58. VolumeId: req.VolumeId,
  59. IsDatFile: true,
  60. })
  61. if err != nil {
  62. return fmt.Errorf("failed to start copying volume %d dat file: %v", req.VolumeId, err)
  63. }
  64. err = writeToFile(copyFileClient, datFileName)
  65. if err != nil {
  66. return fmt.Errorf("failed to copy volume %d dat file: %v", req.VolumeId, err)
  67. }
  68. return nil
  69. })
  70. if err != nil {
  71. os.Remove(idxFileName)
  72. os.Remove(datFileName)
  73. return nil, err
  74. }
  75. if err = checkCopyFiles(volFileInfoResp, idxFileName, datFileName); err != nil { // added by panyc16
  76. return nil, err
  77. }
  78. // mount the volume
  79. err = vs.store.MountVolume(needle.VolumeId(req.VolumeId))
  80. if err != nil {
  81. return nil, fmt.Errorf("failed to mount volume %d: %v", req.VolumeId, err)
  82. }
  83. return &volume_server_pb.VolumeCopyResponse{}, err
  84. }
  85. /**
  86. only check the the differ of the file size
  87. todo: maybe should check the received count and deleted count of the volume
  88. */
  89. func checkCopyFiles(originFileInf *volume_server_pb.ReadVolumeFileStatusResponse, idxFileName, datFileName string) error {
  90. stat, err := os.Stat(idxFileName)
  91. if err != nil {
  92. return fmt.Errorf("get idx file info failed, %v", err)
  93. }
  94. if originFileInf.IdxFileSize != uint64(stat.Size()) {
  95. return fmt.Errorf("the idx file size [%v] is not same as origin file size [%v]",
  96. stat.Size(), originFileInf.IdxFileSize)
  97. }
  98. stat, err = os.Stat(datFileName)
  99. if err != nil {
  100. return fmt.Errorf("get dat file info failed, %v", err)
  101. }
  102. if originFileInf.DatFileSize != uint64(stat.Size()) {
  103. return fmt.Errorf("the dat file size [%v] is not same as origin file size [%v]",
  104. stat.Size(), originFileInf.DatFileSize)
  105. }
  106. return nil
  107. }
  108. func writeToFile(client volume_server_pb.VolumeServer_CopyFileClient, fileName string) error {
  109. glog.V(4).Infof("writing to %s", fileName)
  110. dst, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
  111. if err != nil {
  112. return nil
  113. }
  114. defer dst.Close()
  115. for {
  116. resp, receiveErr := client.Recv()
  117. if receiveErr == io.EOF {
  118. break
  119. }
  120. if receiveErr != nil {
  121. return fmt.Errorf("receiving %s: %v", fileName, receiveErr)
  122. }
  123. dst.Write(resp.FileContent)
  124. }
  125. return nil
  126. }
  127. func (vs *VolumeServer) ReadVolumeFileStatus(ctx context.Context, req *volume_server_pb.ReadVolumeFileStatusRequest) (*volume_server_pb.ReadVolumeFileStatusResponse, error) {
  128. resp := &volume_server_pb.ReadVolumeFileStatusResponse{}
  129. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  130. if v == nil {
  131. return nil, fmt.Errorf("not found volume id %d", req.VolumeId)
  132. }
  133. resp.VolumeId = req.VolumeId
  134. resp.DatFileSize = v.DataFileSize()
  135. resp.IdxFileSize = v.IndexFileSize()
  136. resp.DatFileTimestamp = v.LastModifiedTime()
  137. resp.IdxFileTimestamp = v.LastModifiedTime()
  138. resp.FileCount = v.FileCount()
  139. return resp, nil
  140. }
  141. func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream volume_server_pb.VolumeServer_CopyFileServer) error {
  142. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  143. if v == nil {
  144. return fmt.Errorf("not found volume id %d", req.VolumeId)
  145. }
  146. const BufferSize = 1024 * 16
  147. var fileName = v.FileName()
  148. if req.IsDatFile {
  149. fileName += ".dat"
  150. } else if req.IsIdxFile {
  151. fileName += ".idx"
  152. }
  153. file, err := os.Open(fileName)
  154. if err != nil {
  155. return err
  156. }
  157. defer file.Close()
  158. buffer := make([]byte, BufferSize)
  159. for {
  160. bytesread, err := file.Read(buffer)
  161. if err != nil {
  162. if err != io.EOF {
  163. return err
  164. }
  165. break
  166. }
  167. stream.Send(&volume_server_pb.CopyFileResponse{
  168. FileContent: buffer[:bytesread],
  169. })
  170. }
  171. return nil
  172. }