Skip to content

Commit eeca175

Browse files
committed
vfs: do lazy revalidation of the directory cache per the poll interval
local: added custom bufferpool-backed path.Join & filepath.Join implementations to reduce allocations Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
1 parent 98ab56c commit eeca175

File tree

23 files changed

+464
-47
lines changed

23 files changed

+464
-47
lines changed

backend/drive/drive.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
"github.com/rclone/rclone/lib/dircache"
4343
"github.com/rclone/rclone/lib/encoder"
4444
"github.com/rclone/rclone/lib/env"
45+
"github.com/rclone/rclone/lib/join"
4546
"github.com/rclone/rclone/lib/oauthutil"
4647
"github.com/rclone/rclone/lib/pacer"
4748
"github.com/rclone/rclone/lib/readers"
@@ -2024,7 +2025,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
20242025

20252026
var iErr error
20262027
_, err = f.list(ctx, []string{directoryID}, "", false, false, f.opt.TrashedOnly, false, func(item *drive.File) bool {
2027-
entry, err := f.itemToDirEntry(ctx, path.Join(dir, item.Name), item)
2028+
entry, err := f.itemToDirEntry(ctx, join.PathJoin(dir, item.Name), item)
20282029
if err != nil {
20292030
iErr = err
20302031
return true
@@ -2136,7 +2137,7 @@ func (f *Fs) listRRunner(ctx context.Context, wg *sync.WaitGroup, in chan listRE
21362137
continue
21372138
}
21382139
}
2139-
remote := path.Join(paths[i], item.Name)
2140+
remote := join.PathJoin(paths[i], item.Name)
21402141
entry, err := f.itemToDirEntry(ctx, remote, item)
21412142
if err != nil {
21422143
iErr = err
@@ -2716,7 +2717,7 @@ func (f *Fs) delete(ctx context.Context, id string, useTrash bool) error {
27162717
// purgeCheck removes the dir directory, if check is set then it
27172718
// refuses to do so if it has anything in
27182719
func (f *Fs) purgeCheck(ctx context.Context, dir string, check bool) error {
2719-
root := path.Join(f.root, dir)
2720+
root := join.PathJoin(f.root, dir)
27202721
dc := f.dirCache
27212722
directoryID, err := dc.FindDir(ctx, dir, false)
27222723
if err != nil {
@@ -2919,7 +2920,7 @@ func (r cleanupResult) Error() string {
29192920

29202921
func (f *Fs) cleanupTeamDrive(ctx context.Context, dir string, directoryID string) (r cleanupResult, err error) {
29212922
_, err = f.list(ctx, []string{directoryID}, "", false, false, true, false, func(item *drive.File) bool {
2922-
remote := path.Join(dir, item.Name)
2923+
remote := join.PathJoin(dir, item.Name)
29232924
if item.ExplicitlyTrashed { // description is wrong - can also be set for folders - no need to recurse them
29242925
err := f.delete(ctx, item.Id, false)
29252926
if err != nil {
@@ -3437,7 +3438,7 @@ func (f *Fs) unTrash(ctx context.Context, dir string, directoryID string, recurs
34373438
directoryID = actualID(directoryID)
34383439
fs.Debugf(dir, "finding trash to restore in directory %q", directoryID)
34393440
_, err = f.list(ctx, []string{directoryID}, "", false, false, f.opt.TrashedOnly, true, func(item *drive.File) bool {
3440-
remote := path.Join(dir, item.Name)
3441+
remote := join.PathJoin(dir, item.Name)
34413442
if item.ExplicitlyTrashed {
34423443
fs.Infof(remote, "restoring %q", item.Id)
34433444
if operations.SkipDestructive(ctx, remote, "restore") {

backend/drive/drive_notify.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package drive
22

33
import (
44
"context"
5-
"path"
65

76
"github.com/rclone/rclone/fs"
7+
"github.com/rclone/rclone/lib/join"
88
"google.golang.org/api/drive/v3"
99
)
1010

@@ -169,7 +169,7 @@ func (f *Fs) changeNotifyRunner(ctx context.Context, notifyFunc func(string, fs.
169169
// translate the parent dir of this object
170170
if parentPath, ok := f.dirCache.GetInv(parent); ok {
171171
// and append the drive file name to compute the full file name
172-
newPath := path.Join(parentPath, change.File.Name)
172+
newPath := join.PathJoin(parentPath, change.File.Name)
173173
// this will now clear the actual file too
174174
pathsToClear = append(pathsToClear, entryType{
175175
path: newPath, entryType: changeType})

backend/local/local.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"fmt"
99
"io"
1010
"os"
11-
"path"
1211
"path/filepath"
1312
"runtime"
1413
"strings"
@@ -27,6 +26,7 @@ import (
2726
"github.com/rclone/rclone/fs/hash"
2827
"github.com/rclone/rclone/lib/encoder"
2928
"github.com/rclone/rclone/lib/file"
29+
"github.com/rclone/rclone/lib/join"
3030
"github.com/rclone/rclone/lib/readers"
3131
"golang.org/x/text/unicode/norm"
3232
)
@@ -261,9 +261,9 @@ cause disk fragmentation and can be slow to work with.`,
261261
Help: `Disable setting modtime.
262262
263263
Normally rclone updates modification time of files after they are done
264-
uploading. This can cause permissions issues on Linux platforms when
264+
uploading. This can cause permissions issues on Linux platforms when
265265
the user rclone is running as does not own the file uploaded, such as
266-
when copying to a CIFS mount owned by another user. If this option is
266+
when copying to a CIFS mount owned by another user. If this option is
267267
enabled, rclone will no longer update the modtime after copying a file.`,
268268
Default: false,
269269
Advanced: true,
@@ -451,6 +451,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
451451
// return an error with an fs which points to the parent
452452
return f, fs.ErrorIsFile
453453
}
454+
454455
return f, nil
455456
}
456457

@@ -632,8 +633,9 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
632633
break
633634
}
634635
if err == nil {
636+
// TODO: Parallelise this loop
635637
for _, name := range names {
636-
namepath := filepath.Join(fsDirPath, name)
638+
namepath := join.FilePathJoin(fsDirPath, name)
637639
fi, fierr := os.Lstat(namepath)
638640
if os.IsNotExist(fierr) {
639641
// skip entry removed by a concurrent goroutine
@@ -660,13 +662,14 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
660662
return nil, fmt.Errorf("failed to read directory entry: %w", err)
661663
}
662664

665+
// TODO: Parallelise this loop
663666
for _, fi := range fis {
664667
name := fi.Name()
665668
mode := fi.Mode()
666669
newRemote := f.cleanRemote(dir, name)
667670
// Follow symlinks if required
668671
if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 {
669-
localPath := filepath.Join(fsDirPath, name)
672+
localPath := join.FilePathJoin(fsDirPath, name)
670673
fi, err = os.Stat(localPath)
671674
// Quietly skip errors on excluded files and directories
672675
if err != nil && useFilter && !filter.IncludeRemote(newRemote) {
@@ -718,7 +721,8 @@ func (f *Fs) cleanRemote(dir, filename string) (remote string) {
718721
if f.opt.UTFNorm {
719722
filename = norm.NFC.String(filename)
720723
}
721-
remote = path.Join(dir, f.opt.Enc.ToStandardName(filename))
724+
725+
remote = join.PathJoin(dir, f.opt.Enc.ToStandardName(filename))
722726

723727
if !utf8.ValidString(filename) {
724728
f.warnedMu.Lock()
@@ -728,11 +732,12 @@ func (f *Fs) cleanRemote(dir, filename string) (remote string) {
728732
}
729733
f.warnedMu.Unlock()
730734
}
735+
731736
return
732737
}
733738

734739
func (f *Fs) localPath(name string) string {
735-
return filepath.Join(f.root, filepath.FromSlash(f.opt.Enc.FromStandardPath(name)))
740+
return join.FilePathJoin(f.root, filepath.FromSlash(f.opt.Enc.FromStandardPath(name)))
736741
}
737742

738743
// Put the Object to the local filesystem

backend/local/metadata.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (o *Object) parseMetadataTime(m fs.Metadata, key string) (t time.Time, ok b
6868
return t, ok
6969
}
7070

71-
// parse am int from metadata with key and base
71+
// parse an int from metadata with key and base
7272
func (o *Object) parseMetadataInt(m fs.Metadata, key string, base int) (result int, ok bool) {
7373
value, ok := m[key]
7474
if ok {

backend/local/metadata_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func readMetadataFromFileFstatat(o *Object, m *fs.Metadata) (err error) {
107107
}
108108
setTime := func(key string, t unix.Timespec) {
109109
// The types of t.Sec and t.Nsec vary from int32 to int64 on
110-
// different Linux architectures so we need to cast them to
110+
// different Linux architectures, so we need to cast them to
111111
// int64 here and hence need to quiet the linter about
112112
// unnecessary casts.
113113
//

fs/asyncreader/asyncreader.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ func (a *AsyncReader) getBuffer() *buffer {
125125
}
126126
}
127127

128-
// Read will return the next available data.
129128
func (a *AsyncReader) fill() (err error) {
130129
if a.cur.isEmpty() {
131130
if a.cur != nil {

fs/rc/internal.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,10 @@ memory problems.
162162

163163
// Do a garbage collection run
164164
func rcGc(ctx context.Context, in Params) (out Params, err error) {
165+
oldGCPercent := debug.SetGCPercent(25)
165166
runtime.GC()
167+
debug.FreeOSMemory()
168+
_ = debug.SetGCPercent(oldGCPercent)
166169
return nil, nil
167170
}
168171

fs/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ type Object interface {
9595
// return an error or update the object properly (rather than e.g. calling panic).
9696
Update(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) error
9797

98-
// Removes this object
98+
// Remove this object
9999
Remove(ctx context.Context) error
100100
}
101101

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ require (
5151
github.com/klauspost/compress v1.17.11
5252
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988
5353
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6
54+
github.com/libp2p/go-buffer-pool v0.1.0
5455
github.com/mattn/go-colorable v0.1.14
5556
github.com/mattn/go-runewidth v0.0.16
5657
github.com/minio/minio-go/v7 v7.0.83

lib/debug/common.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ func SetGCPercent(percent int) int {
1616
func SetMemoryLimit(limit int64) int64 {
1717
return debug.SetMemoryLimit(limit)
1818
}
19+
20+
// FreeOSMemory calls the runtime/debug.FreeOSMemory function to free memory
21+
// that is no longer in use.
22+
func FreeOSMemory() {
23+
debug.FreeOSMemory()
24+
}

0 commit comments

Comments
 (0)