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.

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