refactor: obj name mapping and internal path processing (#2733)

* refactor:Prepare to remove the get interface

* feat:add obj Unwarp interface

* refactor:obj name mapping and program internal path processing

* chore: fix typo

* feat: unwrap get

* fix: no use op.Get to get parent id

* fix: set the path uniformly

Co-authored-by: Noah Hsu <i@nn.ci>
This commit is contained in:
foxxorcat
2022-12-17 19:49:05 +08:00
committed by GitHub
parent 3d336b328a
commit fb64f00640
50 changed files with 297 additions and 381 deletions

View File

@ -19,7 +19,7 @@ var metaCache = cache.NewMemCache(cache.WithShards[*model.Meta](2))
var metaG singleflight.Group[*model.Meta]
func GetNearestMeta(path string) (*model.Meta, error) {
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
meta, err := GetMetaByPath(path)
if err == nil {
return meta, nil

View File

@ -30,6 +30,7 @@ func BatchCreateSearchNodes(nodes *[]model.SearchNode) error {
}
func DeleteSearchNodesByParent(prefix string) error {
prefix = utils.FixAndCleanPath(prefix)
err := db.Where(whereInParent(prefix)).Delete(&model.SearchNode{}).Error
if err != nil {
return err
@ -37,7 +38,7 @@ func DeleteSearchNodesByParent(prefix string) error {
dir, name := path.Split(prefix)
return db.Where(fmt.Sprintf("%s = ? AND %s = ?",
columnName("parent"), columnName("name")),
utils.StandardizePath(dir), name).Delete(&model.SearchNode{}).Error
dir, name).Delete(&model.SearchNode{}).Error
}
func ClearSearchNodes() error {

View File

@ -39,7 +39,7 @@ type Reader interface {
}
type Getter interface {
Get(ctx context.Context, path string) (model.Obj, error)
GetRoot(ctx context.Context) (model.Obj, error)
}
type Writer interface {

View File

@ -80,7 +80,7 @@ func Remove(ctx context.Context, path string) error {
return err
}
func PutDirectly(ctx context.Context, dstDirPath string, file model.FileStreamer) error {
func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream) error {
err := putDirectly(ctx, dstDirPath, file)
if err != nil {
log.Errorf("failed put %s: %+v", dstDirPath, err)
@ -88,7 +88,7 @@ func PutDirectly(ctx context.Context, dstDirPath string, file model.FileStreamer
return err
}
func PutAsTask(dstDirPath string, file model.FileStreamer) error {
func PutAsTask(dstDirPath string, file *model.FileStream) error {
err := putAsTask(dstDirPath, file)
if err != nil {
log.Errorf("failed put %s: %+v", dstDirPath, err)

View File

@ -12,7 +12,7 @@ import (
)
func get(ctx context.Context, path string) (model.Obj, error) {
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
// maybe a virtual file
if path != "/" {
virtualFiles := op.GetStorageVirtualFilesByPath(stdpath.Dir(path))

View File

@ -18,7 +18,7 @@ var UploadTaskManager = task.NewTaskManager(3, func(tid *uint64) {
})
// putAsTask add as a put task and return immediately
func putAsTask(dstDirPath string, file model.FileStreamer) error {
func putAsTask(dstDirPath string, file *model.FileStream) error {
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
if err != nil {
return errors.WithMessage(err, "failed get storage")
@ -43,7 +43,7 @@ func putAsTask(dstDirPath string, file model.FileStreamer) error {
}
// putDirect put the file and return after finish
func putDirectly(ctx context.Context, dstDirPath string, file model.FileStreamer) error {
func putDirectly(ctx context.Context, dstDirPath string, file *model.FileStream) error {
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
if err != nil {
return errors.WithMessage(err, "failed get storage")

View File

@ -35,7 +35,7 @@ func containsByName(files []model.Obj, file model.Obj) bool {
var httpClient = &http.Client{}
func getFileStreamFromLink(file model.Obj, link *model.Link) (model.FileStreamer, error) {
func getFileStreamFromLink(file model.Obj, link *model.Link) (*model.FileStream, error) {
var rc io.ReadCloser
mimetype := utils.GetMimeType(file.GetName())
if link.Data != nil {

View File

@ -8,11 +8,18 @@ import (
"github.com/maruel/natural"
)
type UnwrapObj interface {
Unwrap() Obj
}
type Obj interface {
GetSize() int64
GetName() string
ModTime() time.Time
IsDir() bool
// The internal information of the driver.
// If you want to use it, please understand what it means
GetID() string
GetPath() string
}
@ -24,6 +31,7 @@ type FileStreamer interface {
SetReadCloser(io.ReadCloser)
NeedStore() bool
GetReadCloser() io.ReadCloser
GetOld() Obj
}
type URL interface {
@ -86,3 +94,9 @@ func ExtractFolder(objs []Obj, extractFolder string) {
return false
})
}
func WrapObjsName(objs []Obj) {
for i := 0; i < len(objs); i++ {
objs[i] = &ObjWrapName{Obj: objs[i]}
}
}

View File

@ -6,6 +6,22 @@ import (
"github.com/alist-org/alist/v3/pkg/utils"
)
type ObjWrapName struct {
Name string
Obj
}
func (o *ObjWrapName) Unwrap() Obj {
return o.Obj
}
func (o *ObjWrapName) GetName() string {
if o.Name == "" {
o.Name = utils.MappingName(o.Obj.GetName())
}
return o.Name
}
type Object struct {
ID string
Path string
@ -16,7 +32,7 @@ type Object struct {
}
func (o *Object) GetName() string {
return utils.MappingName(o.Name)
return o.Name
}
func (o *Object) GetSize() int64 {

View File

@ -9,6 +9,7 @@ type FileStream struct {
io.ReadCloser
Mimetype string
WebPutAsTask bool
Old Obj
}
func (f *FileStream) GetMimetype() string {
@ -26,3 +27,7 @@ func (f *FileStream) GetReadCloser() io.ReadCloser {
func (f *FileStream) SetReadCloser(rc io.ReadCloser) {
f.ReadCloser = rc
}
func (f *FileStream) GetOld() Obj {
return f.Old
}

View File

@ -1,3 +1,6 @@
package op
var WORK = "work"
const (
WORK = "work"
RootName = "root"
)

View File

@ -4,7 +4,6 @@ import (
"context"
"os"
stdpath "path"
"strings"
"time"
"github.com/Xhofe/go-cache"
@ -23,12 +22,11 @@ var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
var listG singleflight.Group[[]model.Obj]
func ClearCache(storage driver.Driver, path string) {
key := stdpath.Join(storage.GetStorage().MountPath, path)
listCache.Del(key)
listCache.Del(Key(storage, path))
}
func Key(storage driver.Driver, path string) string {
return stdpath.Join(storage.GetStorage().MountPath, utils.StandardizePath(path))
return stdpath.Join(storage.GetStorage().MountPath, utils.FixAndCleanPath(path))
}
// List files in storage, not contains virtual file
@ -36,7 +34,7 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
log.Debugf("op.List %s", path)
key := Key(storage, path)
if len(refresh) == 0 || !refresh[0] {
@ -45,7 +43,7 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
return files, nil
}
}
dir, err := Get(ctx, storage, path)
dir, err := GetUnwrap(ctx, storage, path)
if err != nil {
return nil, errors.WithMessage(err, "failed get dir")
}
@ -58,6 +56,14 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
if err != nil {
return nil, errors.Wrapf(err, "failed to list objs")
}
// set path
for _, f := range files {
if s, ok := f.(model.SetPath); ok && f.GetPath() == "" && dir.GetPath() != "" {
s.SetPath(stdpath.Join(dir.GetPath(), f.GetName()))
}
}
// warp obj name
model.WrapObjsName(files)
// call hooks
go func(reqPath string, files []model.Obj) {
for _, hook := range objsUpdateHooks {
@ -78,48 +84,49 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
return objs, err
}
func isRoot(path, rootFolderPath string) bool {
if utils.PathEqual(path, rootFolderPath) {
return true
}
rootFolderPath = strings.TrimSuffix(rootFolderPath, "/")
rootFolderPath = strings.TrimPrefix(rootFolderPath, "\\")
// relative path, this shouldn't happen, because root folder path is absolute
if utils.PathEqual(path, "/") && rootFolderPath == "." {
return true
}
return false
}
// Get object from list of files
func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
log.Debugf("op.Get %s", path)
if g, ok := storage.(driver.Getter); ok {
obj, err := g.Get(ctx, path)
if err == nil {
return obj, nil
}
}
// is root folder
if r, ok := storage.GetAddition().(driver.IRootId); ok && utils.PathEqual(path, "/") {
return &model.Object{
ID: r.GetRootId(),
Name: "root",
Size: 0,
Modified: storage.GetStorage().Modified,
IsFolder: true,
}, nil
}
if r, ok := storage.GetAddition().(driver.IRootPath); ok && isRoot(path, r.GetRootPath()) {
return &model.Object{
Path: r.GetRootPath(),
Name: "root",
Size: 0,
Modified: storage.GetStorage().Modified,
IsFolder: true,
if utils.PathEqual(path, "/") {
var rootObj model.Obj
switch r := storage.GetAddition().(type) {
case driver.IRootId:
rootObj = &model.Object{
ID: r.GetRootId(),
Name: RootName,
Size: 0,
Modified: storage.GetStorage().Modified,
IsFolder: true,
}
case driver.IRootPath:
rootObj = &model.Object{
Path: r.GetRootPath(),
Name: RootName,
Size: 0,
Modified: storage.GetStorage().Modified,
IsFolder: true,
}
default:
if storage, ok := storage.(driver.Getter); ok {
obj, err := storage.GetRoot(ctx)
if err != nil {
return nil, errors.WithMessage(err, "failed get root obj")
}
rootObj = obj
}
}
if rootObj == nil {
return nil, errors.Errorf("please implement IRootPath or IRootId or Getter method")
}
return &model.ObjWrapName{
Name: RootName,
Obj: rootObj,
}, nil
}
// not root folder
dir, name := stdpath.Split(path)
files, err := List(ctx, storage, dir, model.ListArgs{})
@ -129,13 +136,6 @@ func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, er
for _, f := range files {
// TODO maybe copy obj here
if f.GetName() == name {
// use path as id, why don't set id in List function?
// because files maybe cache, set id here can reduce memory usage
if f.GetPath() == "" {
if s, ok := f.(model.SetPath); ok {
s.SetPath(path)
}
}
return f, nil
}
}
@ -143,6 +143,17 @@ func Get(ctx context.Context, storage driver.Driver, path string) (model.Obj, er
return nil, errors.WithStack(errs.ObjectNotFound)
}
func GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.Obj, error) {
obj, err := Get(ctx, storage, path)
if err != nil {
return nil, err
}
if unwrap, ok := obj.(model.UnwrapObj); ok {
obj = unwrap.Unwrap()
}
return obj, err
}
var linkCache = cache.NewMemCache(cache.WithShards[*model.Link](16))
var linkG singleflight.Group[*model.Link]
@ -151,7 +162,7 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return nil, nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
file, err := Get(ctx, storage, path)
file, err := GetUnwrap(ctx, storage, path)
if err != nil {
return nil, nil, errors.WithMessage(err, "failed to get file")
}
@ -178,7 +189,7 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li
// Other api
func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (interface{}, error) {
obj, err := Get(ctx, storage, args.Path)
obj, err := GetUnwrap(ctx, storage, args.Path)
if err != nil {
return nil, errors.WithMessagef(err, "failed to get obj")
}
@ -199,11 +210,11 @@ func MakeDir(ctx context.Context, storage driver.Driver, path string) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
key := Key(storage, path)
_, err, _ := mkdirG.Do(key, func() (interface{}, error) {
// check if dir exists
f, err := Get(ctx, storage, path)
f, err := GetUnwrap(ctx, storage, path)
if err != nil {
if errs.IsObjectNotFound(err) {
parentPath, dirName := stdpath.Split(path)
@ -211,7 +222,7 @@ func MakeDir(ctx context.Context, storage driver.Driver, path string) error {
if err != nil {
return nil, errors.WithMessagef(err, "failed to make parent dir [%s]", parentPath)
}
parentDir, err := Get(ctx, storage, parentPath)
parentDir, err := GetUnwrap(ctx, storage, parentPath)
// this should not happen
if err != nil {
return nil, errors.WithMessagef(err, "failed to get parent dir [%s]", parentPath)
@ -242,11 +253,11 @@ func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
srcObj, err := Get(ctx, storage, srcPath)
srcObj, err := GetUnwrap(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
}
dstDir, err := Get(ctx, storage, dstDirPath)
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
if err != nil {
return errors.WithMessage(err, "failed to get dst dir")
}
@ -257,7 +268,7 @@ func Rename(ctx context.Context, storage driver.Driver, srcPath, dstName string)
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
srcObj, err := Get(ctx, storage, srcPath)
srcObj, err := GetUnwrap(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
}
@ -269,11 +280,11 @@ func Copy(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
srcObj, err := Get(ctx, storage, srcPath)
srcObj, err := GetUnwrap(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
}
dstDir, err := Get(ctx, storage, dstDirPath)
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
return errors.WithStack(storage.Copy(ctx, srcObj, dstDir))
}
@ -281,7 +292,7 @@ func Remove(ctx context.Context, storage driver.Driver, path string) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
obj, err := Get(ctx, storage, path)
obj, err := GetUnwrap(ctx, storage, path)
if err != nil {
// if object not found, it's ok
if errs.IsObjectNotFound(err) {
@ -313,7 +324,7 @@ func Remove(ctx context.Context, storage driver.Driver, path string) error {
return errors.WithStack(err)
}
func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file model.FileStreamer, up driver.UpdateProgress) error {
func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *model.FileStream, up driver.UpdateProgress) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
@ -332,21 +343,22 @@ func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file mod
}()
// if file exist and size = 0, delete it
dstPath := stdpath.Join(dstDirPath, file.GetName())
fi, err := Get(ctx, storage, dstPath)
fi, err := GetUnwrap(ctx, storage, dstPath)
if err == nil {
if fi.GetSize() == 0 {
err = Remove(ctx, storage, dstPath)
if err != nil {
return errors.WithMessagef(err, "failed remove file that exist and have size 0")
}
} else {
file.Old = fi
}
}
err = MakeDir(ctx, storage, dstDirPath)
if err != nil {
return errors.WithMessagef(err, "failed to make dir [%s]", dstDirPath)
}
parentDir, err := Get(ctx, storage, dstDirPath)
parentDir, err := GetUnwrap(ctx, storage, dstDirPath)
// this should not happen
if err != nil {
return errors.WithMessagef(err, "failed to get dir [%s]", dstDirPath)

View File

@ -1,7 +1,6 @@
package op
import (
stdpath "path"
"strings"
"github.com/alist-org/alist/v3/internal/driver"
@ -10,30 +9,17 @@ import (
log "github.com/sirupsen/logrus"
)
// ActualPath Get the actual path
// !!! maybe and \ in the path when use windows local
func ActualPath(storage driver.Additional, rawPath string) string {
if i, ok := storage.(driver.IRootPath); ok {
rawPath = stdpath.Join(i.GetRootPath(), rawPath)
}
return utils.StandardizePath(rawPath)
}
// GetStorageAndActualPath Get the corresponding storage and actual path
// for path: remove the mount path prefix and join the actual root folder if exists
func GetStorageAndActualPath(rawPath string) (driver.Driver, string, error) {
rawPath = utils.StandardizePath(rawPath)
// why can remove this check? because reqPath has joined the base_path of user, no relative path
//if strings.Contains(rawPath, "..") {
// return nil, "", errors.WithStack(errs.RelativePath)
//}
storage := GetBalancedStorage(rawPath)
func GetStorageAndActualPath(rawPath string) (storage driver.Driver, actualPath string, err error) {
rawPath = utils.FixAndCleanPath(rawPath)
storage = GetBalancedStorage(rawPath)
if storage == nil {
return nil, "", errors.Errorf("can't find storage with rawPath: %s", rawPath)
err = errors.Errorf("can't find storage with rawPath: %s", rawPath)
return
}
log.Debugln("use storage: ", storage.GetStorage().MountPath)
virtualPath := utils.GetActualVirtualPath(storage.GetStorage().MountPath)
actualPath := strings.TrimPrefix(rawPath, virtualPath)
actualPath = ActualPath(storage.GetAddition(), actualPath)
return storage, actualPath, nil
actualPath = utils.FixAndCleanPath(strings.TrimPrefix(rawPath, virtualPath))
return
}

View File

@ -11,6 +11,7 @@ import (
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/generic_sync"
"github.com/alist-org/alist/v3/pkg/utils"
mapset "github.com/deckarep/golang-set/v2"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
@ -25,10 +26,11 @@ func GetAllStorages() []driver.Driver {
}
func HasStorage(mountPath string) bool {
return storagesMap.Has(mountPath)
return storagesMap.Has(utils.FixAndCleanPath(mountPath))
}
func GetStorageByVirtualPath(virtualPath string) (driver.Driver, error) {
virtualPath = utils.FixAndCleanPath(virtualPath)
storageDriver, ok := storagesMap.Load(virtualPath)
if !ok {
return nil, errors.Errorf("no mount path for an storage is: %s", virtualPath)
@ -40,7 +42,7 @@ func GetStorageByVirtualPath(virtualPath string) (driver.Driver, error) {
// then instantiate corresponding driver and save it in memory
func CreateStorage(ctx context.Context, storage model.Storage) (uint, error) {
storage.Modified = time.Now()
storage.MountPath = utils.StandardizePath(storage.MountPath)
storage.MountPath = utils.FixAndCleanPath(storage.MountPath)
var err error
// check driver first
driverName := storage.Driver
@ -65,7 +67,7 @@ func CreateStorage(ctx context.Context, storage model.Storage) (uint, error) {
// LoadStorage load exist storage in db to memory
func LoadStorage(ctx context.Context, storage model.Storage) error {
storage.MountPath = utils.StandardizePath(storage.MountPath)
storage.MountPath = utils.FixAndCleanPath(storage.MountPath)
// check driver first
driverName := storage.Driver
driverNew, err := GetDriverNew(driverName)
@ -158,7 +160,7 @@ func UpdateStorage(ctx context.Context, storage model.Storage) error {
return errors.Errorf("driver cannot be changed")
}
storage.Modified = time.Now()
storage.MountPath = utils.StandardizePath(storage.MountPath)
storage.MountPath = utils.FixAndCleanPath(storage.MountPath)
err = db.UpdateStorage(&storage)
if err != nil {
return errors.WithMessage(err, "failed update storage in database")
@ -237,25 +239,20 @@ func saveDriverStorage(driver driver.Driver) error {
func getStoragesByPath(path string) []driver.Driver {
storages := make([]driver.Driver, 0)
curSlashCount := 0
storagesMap.Range(func(key string, value driver.Driver) bool {
virtualPath := utils.GetActualVirtualPath(value.GetStorage().MountPath)
if virtualPath == "/" {
virtualPath = ""
storagesMap.Range(func(mountPath string, value driver.Driver) bool {
virtualPath := utils.GetActualVirtualPath(mountPath)
// is this path
if strings.HasPrefix(path, virtualPath) {
slashCount := strings.Count(utils.PathAddSeparatorSuffix(virtualPath), "/")
// not the longest match
if slashCount > curSlashCount {
storages = storages[:0]
curSlashCount = slashCount
}
if slashCount == curSlashCount {
storages = append(storages, value)
}
}
// not this
if path != virtualPath && !strings.HasPrefix(path, virtualPath+"/") {
return true
}
slashCount := strings.Count(virtualPath, "/")
// not the longest match
if slashCount < curSlashCount {
return true
}
if slashCount > curSlashCount {
storages = storages[:0]
curSlashCount = slashCount
}
storages = append(storages, value)
return true
})
// make sure the order is the same for same input
@ -277,36 +274,25 @@ func GetStorageVirtualFilesByPath(prefix string) []model.Obj {
}
return storages[i].GetStorage().Order < storages[j].GetStorage().Order
})
prefix = utils.StandardizePath(prefix)
if prefix != "/" {
prefix += "/"
}
set := make(map[string]interface{})
prefix = utils.FixAndCleanPath(prefix)
set := mapset.NewSet[string]()
for _, v := range storages {
// TODO should save a balanced storage
// balance storage
if utils.IsBalance(v.GetStorage().MountPath) {
virtualPath := utils.GetActualVirtualPath(v.GetStorage().MountPath)
// Exclude prefix itself and non prefix
if len(prefix) >= len(virtualPath) || !strings.HasPrefix(virtualPath, prefix) {
continue
}
virtualPath := v.GetStorage().MountPath
if len(virtualPath) <= len(prefix) {
continue
name := strings.SplitN(strings.TrimPrefix(virtualPath[len(prefix):], "/"), "/", 1)[0]
if set.Add(name) {
files = append(files, &model.Object{
Name: name,
Size: 0,
Modified: v.GetStorage().Modified,
IsFolder: true,
})
}
// not prefixed with `prefix`
if !strings.HasPrefix(virtualPath, prefix) {
continue
}
name := strings.Split(strings.TrimPrefix(virtualPath, prefix), "/")[0]
if _, ok := set[name]; ok {
continue
}
files = append(files, &model.Object{
Name: name,
Size: 0,
Modified: v.GetStorage().Modified,
IsFolder: true,
})
set[name] = nil
}
return files
}
@ -315,7 +301,7 @@ var balanceMap generic_sync.MapOf[string, int]
// GetBalancedStorage get storage by path
func GetBalancedStorage(path string) driver.Driver {
path = utils.StandardizePath(path)
path = utils.FixAndCleanPath(path)
storages := getStoragesByPath(path)
storageNum := len(storages)
switch storageNum {
@ -325,15 +311,9 @@ func GetBalancedStorage(path string) driver.Driver {
return storages[0]
default:
virtualPath := utils.GetActualVirtualPath(storages[0].GetStorage().MountPath)
cur, ok := balanceMap.Load(virtualPath)
i := 0
if ok {
i = cur
i = (i + 1) % storageNum
balanceMap.Store(virtualPath, i)
} else {
balanceMap.Store(virtualPath, i)
}
i, _ := balanceMap.LoadOrStore(virtualPath, 0)
i = (i + 1) % storageNum
balanceMap.Store(virtualPath, i)
return storages[i]
}
}