diff options
Diffstat (limited to 'weed/wdclient/vid_map.go')
| -rw-r--r-- | weed/wdclient/vid_map.go | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/weed/wdclient/vid_map.go b/weed/wdclient/vid_map.go index aef29f56f..97df49cb6 100644 --- a/weed/wdclient/vid_map.go +++ b/weed/wdclient/vid_map.go @@ -3,14 +3,18 @@ package wdclient import ( "errors" "fmt" - "math/rand" "strconv" "strings" "sync" + "sync/atomic" "github.com/chrislusf/seaweedfs/weed/glog" ) +const ( + maxCursorIndex = 4096 +) + type Location struct { Url string `json:"url,omitempty"` PublicUrl string `json:"publicUrl,omitempty"` @@ -19,14 +23,27 @@ type Location struct { type vidMap struct { sync.RWMutex vid2Locations map[uint32][]Location + + cursor int32 } func newVidMap() vidMap { return vidMap{ vid2Locations: make(map[uint32][]Location), + cursor: -1, } } +func (vc *vidMap) getLocationIndex(length int) (int, error) { + if length <= 0 { + return 0, fmt.Errorf("invalid length: %d", length) + } + if atomic.LoadInt32(&vc.cursor) == maxCursorIndex { + atomic.CompareAndSwapInt32(&vc.cursor, maxCursorIndex, -1) + } + return int(atomic.AddInt32(&vc.cursor, 1)) % length, nil +} + func (vc *vidMap) LookupVolumeServerUrl(vid string) (serverUrl string, err error) { id, err := strconv.Atoi(vid) if err != nil { @@ -34,12 +51,7 @@ func (vc *vidMap) LookupVolumeServerUrl(vid string) (serverUrl string, err error return "", err } - locations := vc.GetLocations(uint32(id)) - if len(locations) == 0 { - return "", fmt.Errorf("volume %d not found", id) - } - - return locations[rand.Intn(len(locations))].Url, nil + return vc.GetRandomLocation(uint32(id)) } func (vc *vidMap) LookupFileId(fileId string) (fullUrl string, err error) { @@ -66,20 +78,42 @@ func (vc *vidMap) LookupVolumeServer(fileId string) (volumeServer string, err er return serverUrl, nil } -func (vc *vidMap) GetVidLocations(vid string) (locations []Location) { +func (vc *vidMap) GetVidLocations(vid string) (locations []Location, err error) { id, err := strconv.Atoi(vid) if err != nil { glog.V(1).Infof("Unknown volume id %s", vid) - return nil + return nil, fmt.Errorf("Unknown volume id %s", vid) + } + foundLocations, found := vc.GetLocations(uint32(id)) + if found { + return foundLocations, nil } - return vc.GetLocations(uint32(id)) + return nil, fmt.Errorf("volume id %s not found", vid) } -func (vc *vidMap) GetLocations(vid uint32) (locations []Location) { +func (vc *vidMap) GetLocations(vid uint32) (locations []Location, found bool) { vc.RLock() defer vc.RUnlock() - return vc.vid2Locations[vid] + locations, found = vc.vid2Locations[vid] + return +} + +func (vc *vidMap) GetRandomLocation(vid uint32) (serverUrl string, err error) { + vc.RLock() + defer vc.RUnlock() + + locations := vc.vid2Locations[vid] + if len(locations) == 0 { + return "", fmt.Errorf("volume %d not found", vid) + } + + index, err := vc.getLocationIndex(len(locations)) + if err != nil { + return "", fmt.Errorf("volume %d: %v", vid, err) + } + + return locations[index].Url, nil } func (vc *vidMap) addLocation(vid uint32, location Location) { @@ -114,6 +148,7 @@ func (vc *vidMap) deleteLocation(vid uint32, location Location) { for i, loc := range locations { if loc.Url == location.Url { vc.vid2Locations[vid] = append(locations[0:i], locations[i+1:]...) + break } } |
