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.

231 lines
6.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
  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. // println("source:", volFileInfoResp.String())
  48. copyFileClient, err := client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{
  49. VolumeId: req.VolumeId,
  50. IsIdxFile: true,
  51. CompactionRevision: volFileInfoResp.CompactionRevision,
  52. StopOffset: volFileInfoResp.IdxFileSize,
  53. })
  54. if err != nil {
  55. return fmt.Errorf("failed to start copying volume %d idx file: %v", req.VolumeId, err)
  56. }
  57. err = writeToFile(copyFileClient, idxFileName)
  58. if err != nil {
  59. return fmt.Errorf("failed to copy volume %d idx file: %v", req.VolumeId, err)
  60. }
  61. copyFileClient, err = client.CopyFile(ctx, &volume_server_pb.CopyFileRequest{
  62. VolumeId: req.VolumeId,
  63. IsDatFile: true,
  64. CompactionRevision: volFileInfoResp.CompactionRevision,
  65. StopOffset: volFileInfoResp.DatFileSize,
  66. })
  67. if err != nil {
  68. return fmt.Errorf("failed to start copying volume %d dat file: %v", req.VolumeId, err)
  69. }
  70. err = writeToFile(copyFileClient, datFileName)
  71. if err != nil {
  72. return fmt.Errorf("failed to copy volume %d dat file: %v", req.VolumeId, err)
  73. }
  74. return nil
  75. })
  76. if err != nil {
  77. os.Remove(idxFileName)
  78. os.Remove(datFileName)
  79. return nil, err
  80. }
  81. if err = checkCopyFiles(volFileInfoResp, idxFileName, datFileName); err != nil { // added by panyc16
  82. return nil, err
  83. }
  84. // mount the volume
  85. err = vs.store.MountVolume(needle.VolumeId(req.VolumeId))
  86. if err != nil {
  87. return nil, fmt.Errorf("failed to mount volume %d: %v", req.VolumeId, err)
  88. }
  89. return &volume_server_pb.VolumeCopyResponse{
  90. LastAppendAtNs: volFileInfoResp.DatFileTimestampSeconds * uint64(time.Second),
  91. }, err
  92. }
  93. /**
  94. only check the the differ of the file size
  95. todo: maybe should check the received count and deleted count of the volume
  96. */
  97. func checkCopyFiles(originFileInf *volume_server_pb.ReadVolumeFileStatusResponse, idxFileName, datFileName string) error {
  98. stat, err := os.Stat(idxFileName)
  99. if err != nil {
  100. return fmt.Errorf("get idx file info failed, %v", err)
  101. }
  102. if originFileInf.IdxFileSize != uint64(stat.Size()) {
  103. return fmt.Errorf("the idx file size [%v] is not same as origin file size [%v]",
  104. stat.Size(), originFileInf.IdxFileSize)
  105. }
  106. stat, err = os.Stat(datFileName)
  107. if err != nil {
  108. return fmt.Errorf("get dat file info failed, %v", err)
  109. }
  110. if originFileInf.DatFileSize != uint64(stat.Size()) {
  111. return fmt.Errorf("the dat file size [%v] is not same as origin file size [%v]",
  112. stat.Size(), originFileInf.DatFileSize)
  113. }
  114. return nil
  115. }
  116. func writeToFile(client volume_server_pb.VolumeServer_CopyFileClient, fileName string) error {
  117. glog.V(4).Infof("writing to %s", fileName)
  118. dst, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
  119. if err != nil {
  120. return nil
  121. }
  122. defer dst.Close()
  123. for {
  124. resp, receiveErr := client.Recv()
  125. if receiveErr == io.EOF {
  126. break
  127. }
  128. if receiveErr != nil {
  129. return fmt.Errorf("receiving %s: %v", fileName, receiveErr)
  130. }
  131. dst.Write(resp.FileContent)
  132. }
  133. return nil
  134. }
  135. func (vs *VolumeServer) ReadVolumeFileStatus(ctx context.Context, req *volume_server_pb.ReadVolumeFileStatusRequest) (*volume_server_pb.ReadVolumeFileStatusResponse, error) {
  136. resp := &volume_server_pb.ReadVolumeFileStatusResponse{}
  137. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  138. if v == nil {
  139. return nil, fmt.Errorf("not found volume id %d", req.VolumeId)
  140. }
  141. resp.VolumeId = req.VolumeId
  142. datSize, idxSize, modTime := v.FileStat()
  143. resp.DatFileSize = datSize
  144. resp.IdxFileSize = idxSize
  145. resp.DatFileTimestampSeconds = uint64(modTime.Unix())
  146. resp.IdxFileTimestampSeconds = uint64(modTime.Unix())
  147. resp.FileCount = v.FileCount()
  148. resp.CompactionRevision = uint32(v.CompactionRevision)
  149. return resp, nil
  150. }
  151. func (vs *VolumeServer) CopyFile(req *volume_server_pb.CopyFileRequest, stream volume_server_pb.VolumeServer_CopyFileServer) error {
  152. v := vs.store.GetVolume(needle.VolumeId(req.VolumeId))
  153. if v == nil {
  154. return fmt.Errorf("not found volume id %d", req.VolumeId)
  155. }
  156. if uint32(v.CompactionRevision) != req.CompactionRevision {
  157. return fmt.Errorf("volume %d is compacted", req.VolumeId)
  158. }
  159. bytesToRead := int64(req.StopOffset)
  160. const BufferSize = 1024 * 1024 * 2
  161. var fileName = v.FileName()
  162. if req.IsDatFile {
  163. fileName += ".dat"
  164. } else if req.IsIdxFile {
  165. fileName += ".idx"
  166. }
  167. file, err := os.Open(fileName)
  168. if err != nil {
  169. return err
  170. }
  171. defer file.Close()
  172. buffer := make([]byte, BufferSize)
  173. for bytesToRead > 0 {
  174. bytesread, err := file.Read(buffer)
  175. // println(fileName, "read", bytesread, "bytes, with target", bytesToRead)
  176. if err != nil {
  177. if err != io.EOF {
  178. return err
  179. }
  180. // println(fileName, "read", bytesread, "bytes, with target", bytesToRead, "err", err.Error())
  181. break
  182. }
  183. if int64(bytesread) > bytesToRead {
  184. bytesread = int(bytesToRead)
  185. }
  186. err = stream.Send(&volume_server_pb.CopyFileResponse{
  187. FileContent: buffer[:bytesread],
  188. })
  189. if err != nil {
  190. // println("sending", bytesread, "bytes err", err.Error())
  191. return err
  192. }
  193. bytesToRead -= int64(bytesread)
  194. }
  195. return nil
  196. }