mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-12-14 10:39:24 +08:00
cc724305b6
Originally there are only url(ip + port), and publicUrl. Because ip was used to listen for http service, it has less flexibility and volume server has to be accessed via publicUrl. Recently we added ip.bind, for binding http service. With this change, url can be used to connect to volume servers. And publicUrl becomes a free style piece of url information, it does not even need to be unique.
119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package operation
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/chrislusf/weed-fs/go/util"
|
|
)
|
|
|
|
type Location struct {
|
|
Url string `json:"url,omitempty"`
|
|
PublicUrl string `json:"publicUrl,omitempty"`
|
|
}
|
|
type LookupResult struct {
|
|
VolumeId string `json:"volumeId,omitempty"`
|
|
Locations []Location `json:"locations,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func (lr *LookupResult) String() string {
|
|
return fmt.Sprintf("VolumeId:%s, Locations:%v, Error:%s", lr.VolumeId, lr.Locations, lr.Error)
|
|
}
|
|
|
|
var (
|
|
vc VidCache // caching of volume locations, re-check if after 10 minutes
|
|
)
|
|
|
|
func Lookup(server string, vid string) (ret *LookupResult, err error) {
|
|
locations, cache_err := vc.Get(vid)
|
|
if cache_err != nil {
|
|
if ret, err = do_lookup(server, vid); err == nil {
|
|
vc.Set(vid, ret.Locations, 10*time.Minute)
|
|
}
|
|
} else {
|
|
ret = &LookupResult{VolumeId: vid, Locations: locations}
|
|
}
|
|
return
|
|
}
|
|
|
|
func do_lookup(server string, vid string) (*LookupResult, error) {
|
|
values := make(url.Values)
|
|
values.Add("volumeId", vid)
|
|
jsonBlob, err := util.Post("http://"+server+"/dir/lookup", values)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var ret LookupResult
|
|
err = json.Unmarshal(jsonBlob, &ret)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ret.Error != "" {
|
|
return nil, errors.New(ret.Error)
|
|
}
|
|
return &ret, nil
|
|
}
|
|
|
|
func LookupFileId(server string, fileId string) (fullUrl string, err error) {
|
|
parts := strings.Split(fileId, ",")
|
|
if len(parts) != 2 {
|
|
return "", errors.New("Invalid fileId " + fileId)
|
|
}
|
|
lookup, lookupError := Lookup(server, parts[0])
|
|
if lookupError != nil {
|
|
return "", lookupError
|
|
}
|
|
if len(lookup.Locations) == 0 {
|
|
return "", errors.New("File Not Found")
|
|
}
|
|
return "http://" + lookup.Locations[rand.Intn(len(lookup.Locations))].Url + "/" + fileId, nil
|
|
}
|
|
|
|
// LookupVolumeIds find volume locations by cache and actual lookup
|
|
func LookupVolumeIds(server string, vids []string) (map[string]LookupResult, error) {
|
|
ret := make(map[string]LookupResult)
|
|
var unknown_vids []string
|
|
|
|
//check vid cache first
|
|
for _, vid := range vids {
|
|
locations, cache_err := vc.Get(vid)
|
|
if cache_err == nil {
|
|
ret[vid] = LookupResult{VolumeId: vid, Locations: locations}
|
|
} else {
|
|
unknown_vids = append(unknown_vids, vid)
|
|
}
|
|
}
|
|
//return success if all volume ids are known
|
|
if len(unknown_vids) == 0 {
|
|
return ret, nil
|
|
}
|
|
|
|
//only query unknown_vids
|
|
values := make(url.Values)
|
|
for _, vid := range unknown_vids {
|
|
values.Add("volumeId", vid)
|
|
}
|
|
jsonBlob, err := util.Post("http://"+server+"/vol/lookup", values)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(jsonBlob, &ret)
|
|
if err != nil {
|
|
return nil, errors.New(err.Error() + " " + string(jsonBlob))
|
|
}
|
|
|
|
//set newly checked vids to cache
|
|
for _, vid := range unknown_vids {
|
|
locations := ret[vid].Locations
|
|
vc.Set(vid, locations, 10*time.Minute)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|