From 9be6f1a70ec3f9e658376d8e578d01515a401db4 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Fri, 19 Feb 2021 11:06:25 +0100 Subject: [PATCH] lib/fs: Consider options in case-fs caching (fixes #7371) (#7381) --- lib/config/folderconfiguration.go | 2 +- lib/fs/basicfs.go | 17 ++++++++++------- lib/fs/casefs.go | 28 ++++++++++++++++++++++------ lib/fs/filesystem.go | 5 ++++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go index 3c0fea2c0..ef7ee980d 100644 --- a/lib/config/folderconfiguration.go +++ b/lib/config/folderconfiguration.go @@ -50,7 +50,7 @@ func (f FolderConfiguration) Filesystem() fs.Filesystem { } filesystem := fs.NewFilesystem(f.FilesystemType, f.Path, opts...) if !f.CaseSensitiveFS { - filesystem = fs.NewCaseFilesystem(filesystem) + filesystem = fs.NewCaseFilesystem(filesystem, opts...) } return filesystem } diff --git a/lib/fs/basicfs.go b/lib/fs/basicfs.go index fc983636f..242e658a3 100644 --- a/lib/fs/basicfs.go +++ b/lib/fs/basicfs.go @@ -27,12 +27,15 @@ var ( ) func WithJunctionsAsDirs() Option { - return func(fs Filesystem) { - if basic, ok := fs.(*BasicFilesystem); !ok { - l.Warnln("WithJunctionsAsDirs must only be used with FilesystemTypeBasic") - } else { - basic.junctionsAsDirs = true - } + return Option{ + apply: func(fs Filesystem) { + if basic, ok := fs.(*BasicFilesystem); !ok { + l.Warnln("WithJunctionsAsDirs must only be used with FilesystemTypeBasic") + } else { + basic.junctionsAsDirs = true + } + }, + id: "junctionsAsDirs", } } @@ -82,7 +85,7 @@ func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem { root: root, } for _, opt := range opts { - opt(fs) + opt.apply(fs) } return fs } diff --git a/lib/fs/casefs.go b/lib/fs/casefs.go index c2cc12b90..6a27be845 100644 --- a/lib/fs/casefs.go +++ b/lib/fs/casefs.go @@ -43,8 +43,8 @@ type realCaser interface { } type fskey struct { - fstype FilesystemType - uri string + fstype FilesystemType + uri, opts string } // caseFilesystemRegistry caches caseFilesystems and runs a routine to drop @@ -55,8 +55,22 @@ type caseFilesystemRegistry struct { startCleaner sync.Once } -func (r *caseFilesystemRegistry) get(fs Filesystem) Filesystem { - k := fskey{fs.Type(), fs.URI()} +func newFSKey(fs Filesystem, opts ...Option) fskey { + k := fskey{ + fstype: fs.Type(), + uri: fs.URI(), + } + if len(opts) > 0 { + k.opts = opts[0].id + for _, o := range opts[1:] { + k.opts += "&" + o.id + } + } + return k +} + +func (r *caseFilesystemRegistry) get(fs Filesystem, opts ...Option) Filesystem { + k := newFSKey(fs, opts...) // Use double locking when getting a caseFs. In the common case it will // already exist and we take the read lock fast path. If it doesn't, we @@ -122,8 +136,10 @@ type caseFilesystem struct { // from the real path. It is safe to use with any filesystem, i.e. also a // case-sensitive one. However it will add some overhead and thus shouldn't be // used if the filesystem is known to already behave case-sensitively. -func NewCaseFilesystem(fs Filesystem) Filesystem { - return wrapFilesystem(fs, globalCaseFilesystemRegistry.get) +func NewCaseFilesystem(fs Filesystem, opts ...Option) Filesystem { + return wrapFilesystem(fs, func(fs Filesystem) Filesystem { + return globalCaseFilesystemRegistry.get(fs, opts...) + }) } func (f *caseFilesystem) Chmod(name string, mode FileMode) error { diff --git a/lib/fs/filesystem.go b/lib/fs/filesystem.go index 77caf3ac2..7580d425e 100644 --- a/lib/fs/filesystem.go +++ b/lib/fs/filesystem.go @@ -178,7 +178,10 @@ var IsPermission = os.IsPermission // IsPathSeparator is the equivalent of os.IsPathSeparator var IsPathSeparator = os.IsPathSeparator -type Option func(Filesystem) +type Option struct { + apply func(Filesystem) + id string +} func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem { var fs Filesystem