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.

118 lines
2.9 KiB

  1. package operation
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "math/rand"
  7. "net/url"
  8. "strings"
  9. "time"
  10. "github.com/chrislusf/weed-fs/go/util"
  11. )
  12. type Location struct {
  13. Url string `json:"url,omitempty"`
  14. PublicUrl string `json:"publicUrl,omitempty"`
  15. }
  16. type LookupResult struct {
  17. VolumeId string `json:"volumeId,omitempty"`
  18. Locations []Location `json:"locations,omitempty"`
  19. Error string `json:"error,omitempty"`
  20. }
  21. func (lr *LookupResult) String() string {
  22. return fmt.Sprintf("VolumeId:%s, Locations:%v, Error:%s", lr.VolumeId, lr.Locations, lr.Error)
  23. }
  24. var (
  25. vc VidCache // caching of volume locations, re-check if after 10 minutes
  26. )
  27. func Lookup(server string, vid string) (ret *LookupResult, err error) {
  28. locations, cache_err := vc.Get(vid)
  29. if cache_err != nil {
  30. if ret, err = do_lookup(server, vid); err == nil {
  31. vc.Set(vid, ret.Locations, 10*time.Minute)
  32. }
  33. } else {
  34. ret = &LookupResult{VolumeId: vid, Locations: locations}
  35. }
  36. return
  37. }
  38. func do_lookup(server string, vid string) (*LookupResult, error) {
  39. values := make(url.Values)
  40. values.Add("volumeId", vid)
  41. jsonBlob, err := util.Post("http://"+server+"/dir/lookup", values)
  42. if err != nil {
  43. return nil, err
  44. }
  45. var ret LookupResult
  46. err = json.Unmarshal(jsonBlob, &ret)
  47. if err != nil {
  48. return nil, err
  49. }
  50. if ret.Error != "" {
  51. return nil, errors.New(ret.Error)
  52. }
  53. return &ret, nil
  54. }
  55. func LookupFileId(server string, fileId string) (fullUrl string, err error) {
  56. parts := strings.Split(fileId, ",")
  57. if len(parts) != 2 {
  58. return "", errors.New("Invalid fileId " + fileId)
  59. }
  60. lookup, lookupError := Lookup(server, parts[0])
  61. if lookupError != nil {
  62. return "", lookupError
  63. }
  64. if len(lookup.Locations) == 0 {
  65. return "", errors.New("File Not Found")
  66. }
  67. return "http://" + lookup.Locations[rand.Intn(len(lookup.Locations))].Url + "/" + fileId, nil
  68. }
  69. // LookupVolumeIds find volume locations by cache and actual lookup
  70. func LookupVolumeIds(server string, vids []string) (map[string]LookupResult, error) {
  71. ret := make(map[string]LookupResult)
  72. var unknown_vids []string
  73. //check vid cache first
  74. for _, vid := range vids {
  75. locations, cache_err := vc.Get(vid)
  76. if cache_err == nil {
  77. ret[vid] = LookupResult{VolumeId: vid, Locations: locations}
  78. } else {
  79. unknown_vids = append(unknown_vids, vid)
  80. }
  81. }
  82. //return success if all volume ids are known
  83. if len(unknown_vids) == 0 {
  84. return ret, nil
  85. }
  86. //only query unknown_vids
  87. values := make(url.Values)
  88. for _, vid := range unknown_vids {
  89. values.Add("volumeId", vid)
  90. }
  91. jsonBlob, err := util.Post("http://"+server+"/vol/lookup", values)
  92. if err != nil {
  93. return nil, err
  94. }
  95. err = json.Unmarshal(jsonBlob, &ret)
  96. if err != nil {
  97. return nil, errors.New(err.Error() + " " + string(jsonBlob))
  98. }
  99. //set newly checked vids to cache
  100. for _, vid := range unknown_vids {
  101. locations := ret[vid].Locations
  102. vc.Set(vid, locations, 10*time.Minute)
  103. }
  104. return ret, nil
  105. }