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.

163 lines
3.9 KiB

  1. package filer2
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  9. "github.com/chrislusf/seaweedfs/weed/util"
  10. )
  11. func VolumeId(fileId string) string {
  12. lastCommaIndex := strings.LastIndex(fileId, ",")
  13. if lastCommaIndex > 0 {
  14. return fileId[:lastCommaIndex]
  15. }
  16. return fileId
  17. }
  18. type FilerClient interface {
  19. WithFilerClient(ctx context.Context, fn func(filer_pb.SeaweedFilerClient) error) error
  20. }
  21. func ReadIntoBuffer(ctx context.Context, filerClient FilerClient, fullFilePath string, buff []byte, chunkViews []*ChunkView, baseOffset int64) (totalRead int64, err error) {
  22. var vids []string
  23. for _, chunkView := range chunkViews {
  24. vids = append(vids, VolumeId(chunkView.FileId))
  25. }
  26. vid2Locations := make(map[string]*filer_pb.Locations)
  27. err = filerClient.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error {
  28. glog.V(4).Infof("read fh lookup volume id locations: %v", vids)
  29. resp, err := client.LookupVolume(ctx, &filer_pb.LookupVolumeRequest{
  30. VolumeIds: vids,
  31. })
  32. if err != nil {
  33. return err
  34. }
  35. vid2Locations = resp.LocationsMap
  36. return nil
  37. })
  38. if err != nil {
  39. return 0, fmt.Errorf("failed to lookup volume ids %v: %v", vids, err)
  40. }
  41. var wg sync.WaitGroup
  42. for _, chunkView := range chunkViews {
  43. wg.Add(1)
  44. go func(chunkView *ChunkView) {
  45. defer wg.Done()
  46. glog.V(4).Infof("read fh reading chunk: %+v", chunkView)
  47. locations := vid2Locations[VolumeId(chunkView.FileId)]
  48. if locations == nil || len(locations.Locations) == 0 {
  49. glog.V(0).Infof("failed to locate %s", chunkView.FileId)
  50. err = fmt.Errorf("failed to locate %s", chunkView.FileId)
  51. return
  52. }
  53. var n int64
  54. n, err = util.ReadUrl(
  55. fmt.Sprintf("http://%s/%s", locations.Locations[0].Url, chunkView.FileId),
  56. chunkView.Offset,
  57. int(chunkView.Size),
  58. buff[chunkView.LogicOffset-baseOffset:chunkView.LogicOffset-baseOffset+int64(chunkView.Size)],
  59. !chunkView.IsFullChunk)
  60. if err != nil {
  61. glog.V(0).Infof("%v read http://%s/%v %v bytes: %v", fullFilePath, locations.Locations[0].Url, chunkView.FileId, n, err)
  62. err = fmt.Errorf("failed to read http://%s/%s: %v",
  63. locations.Locations[0].Url, chunkView.FileId, err)
  64. return
  65. }
  66. glog.V(4).Infof("read fh read %d bytes: %+v", n, chunkView)
  67. totalRead += n
  68. }(chunkView)
  69. }
  70. wg.Wait()
  71. return
  72. }
  73. func GetEntry(ctx context.Context, filerClient FilerClient, fullFilePath string) (entry *filer_pb.Entry, err error) {
  74. dir, name := FullPath(fullFilePath).DirAndName()
  75. err = filerClient.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error {
  76. request := &filer_pb.LookupDirectoryEntryRequest{
  77. Directory: dir,
  78. Name: name,
  79. }
  80. glog.V(3).Infof("read %s request: %v", fullFilePath, request)
  81. resp, err := client.LookupDirectoryEntry(ctx, request)
  82. if err != nil {
  83. if err == ErrNotFound || strings.Contains(err.Error(), ErrNotFound.Error()) {
  84. return nil
  85. }
  86. glog.V(3).Infof("read %s attr %v: %v", fullFilePath, request, err)
  87. return err
  88. }
  89. if resp.Entry != nil {
  90. entry = resp.Entry
  91. }
  92. return nil
  93. })
  94. return
  95. }
  96. func ReadDirAllEntries(ctx context.Context, filerClient FilerClient, fullDirPath string, fn func(entry *filer_pb.Entry)) (err error) {
  97. err = filerClient.WithFilerClient(ctx, func(client filer_pb.SeaweedFilerClient) error {
  98. paginationLimit := 1024
  99. lastEntryName := ""
  100. for {
  101. request := &filer_pb.ListEntriesRequest{
  102. Directory: fullDirPath,
  103. StartFromFileName: lastEntryName,
  104. Limit: uint32(paginationLimit),
  105. }
  106. glog.V(3).Infof("read directory: %v", request)
  107. resp, err := client.ListEntries(ctx, request)
  108. if err != nil {
  109. return fmt.Errorf("list %s: %v", fullDirPath, err)
  110. }
  111. for _, entry := range resp.Entries {
  112. fn(entry)
  113. lastEntryName = entry.Name
  114. }
  115. if len(resp.Entries) < paginationLimit {
  116. break
  117. }
  118. }
  119. return nil
  120. })
  121. return
  122. }