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  }