github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/union/policy/eplfs.go (about) 1 package policy 2 3 import ( 4 "context" 5 "errors" 6 "math" 7 8 "github.com/rclone/rclone/backend/union/upstream" 9 "github.com/rclone/rclone/fs" 10 ) 11 12 func init() { 13 registerPolicy("eplfs", &EpLfs{}) 14 } 15 16 // EpLfs stands for existing path, least free space 17 // Of all the candidates on which the path exists choose the one with the least free space. 18 type EpLfs struct { 19 EpAll 20 } 21 22 var errNoUpstreamsFound = errors.New("no upstreams found with more than min_free_space space spare") 23 24 func (p *EpLfs) lfs(upstreams []*upstream.Fs) (*upstream.Fs, error) { 25 var minFreeSpace int64 = math.MaxInt64 26 var lfsupstream *upstream.Fs 27 for _, u := range upstreams { 28 space, err := u.GetFreeSpace() 29 if err != nil { 30 fs.LogPrintf(fs.LogLevelNotice, nil, 31 "Free Space is not supported for upstream %s, treating as infinite", u.Name()) 32 } 33 if space < minFreeSpace && space > int64(u.Opt.MinFreeSpace) { 34 minFreeSpace = space 35 lfsupstream = u 36 } 37 } 38 if lfsupstream == nil { 39 return nil, errNoUpstreamsFound 40 } 41 return lfsupstream, nil 42 } 43 44 func (p *EpLfs) lfsEntries(entries []upstream.Entry) (upstream.Entry, error) { 45 var minFreeSpace int64 = math.MaxInt64 46 var lfsEntry upstream.Entry 47 for _, e := range entries { 48 u := e.UpstreamFs() 49 space, err := u.GetFreeSpace() 50 if err != nil { 51 fs.LogPrintf(fs.LogLevelNotice, nil, 52 "Free Space is not supported for upstream %s, treating as infinite", u.Name()) 53 } 54 if space < minFreeSpace && space > int64(u.Opt.MinFreeSpace) { 55 minFreeSpace = space 56 lfsEntry = e 57 } 58 } 59 if lfsEntry == nil { 60 return nil, errNoUpstreamsFound 61 } 62 return lfsEntry, nil 63 } 64 65 // Action category policy, governing the modification of files and directories 66 func (p *EpLfs) Action(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 67 upstreams, err := p.EpAll.Action(ctx, upstreams, path) 68 if err != nil { 69 return nil, err 70 } 71 u, err := p.lfs(upstreams) 72 return []*upstream.Fs{u}, err 73 } 74 75 // ActionEntries is ACTION category policy but receiving a set of candidate entries 76 func (p *EpLfs) ActionEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 77 entries, err := p.EpAll.ActionEntries(entries...) 78 if err != nil { 79 return nil, err 80 } 81 e, err := p.lfsEntries(entries) 82 return []upstream.Entry{e}, err 83 } 84 85 // Create category policy, governing the creation of files and directories 86 func (p *EpLfs) Create(ctx context.Context, upstreams []*upstream.Fs, path string) ([]*upstream.Fs, error) { 87 upstreams, err := p.EpAll.Create(ctx, upstreams, path) 88 if err != nil { 89 return nil, err 90 } 91 u, err := p.lfs(upstreams) 92 return []*upstream.Fs{u}, err 93 } 94 95 // CreateEntries is CREATE category policy but receiving a set of candidate entries 96 func (p *EpLfs) CreateEntries(entries ...upstream.Entry) ([]upstream.Entry, error) { 97 entries, err := p.EpAll.CreateEntries(entries...) 98 if err != nil { 99 return nil, err 100 } 101 e, err := p.lfsEntries(entries) 102 return []upstream.Entry{e}, err 103 } 104 105 // Search category policy, governing the access to files and directories 106 func (p *EpLfs) Search(ctx context.Context, upstreams []*upstream.Fs, path string) (*upstream.Fs, error) { 107 if len(upstreams) == 0 { 108 return nil, fs.ErrorObjectNotFound 109 } 110 upstreams, err := p.epall(ctx, upstreams, path) 111 if err != nil { 112 return nil, err 113 } 114 return p.lfs(upstreams) 115 } 116 117 // SearchEntries is SEARCH category policy but receiving a set of candidate entries 118 func (p *EpLfs) SearchEntries(entries ...upstream.Entry) (upstream.Entry, error) { 119 if len(entries) == 0 { 120 return nil, fs.ErrorObjectNotFound 121 } 122 return p.lfsEntries(entries) 123 }