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.

200 lines
5.6 KiB

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