lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file (#7624)

* lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file

* Fix wrong error returned by CLI

* Gofmt

* Better names

* Review comments

* Review comments
This commit is contained in:
Audrius Butkevicius
2021-05-03 11:28:25 +01:00
committed by GitHub
parent f09dcb98eb
commit 87a0eecc31
16 changed files with 305 additions and 111 deletions
+57 -49
View File
@@ -27,7 +27,7 @@ import (
// see readShortAt()
const randomBlockShift = 14 // 128k
// fakefs is a fake filesystem for testing and benchmarking. It has the
// fakeFS is a fake filesystem for testing and benchmarking. It has the
// following properties:
//
// - File metadata is kept in RAM. Specifically, we remember which files and
@@ -37,7 +37,7 @@ const randomBlockShift = 14 // 128k
// - File contents are generated pseudorandomly with just the file name as
// seed. Writes are discarded, other than having the effect of increasing
// the file size. If you only write data that you've read from a file with
// the same name on a different fakefs, you'll never know the difference...
// the same name on a different fakeFS, you'll never know the difference...
//
// - We totally ignore permissions - pretend you are root.
//
@@ -51,10 +51,10 @@ const randomBlockShift = 14 // 128k
// insens=b "true" makes filesystem case-insensitive Windows- or OSX-style (default false)
// latency=d to set the amount of time each "disk" operation takes, where d is time.ParseDuration format
//
// - Two fakefs:s pointing at the same root path see the same files.
// - Two fakeFS:s pointing at the same root path see the same files.
//
type fakefs struct {
counters fakefsCounters
type fakeFS struct {
counters fakeFSCounters
uri string
mut sync.Mutex
root *fakeEntry
@@ -63,7 +63,7 @@ type fakefs struct {
latency time.Duration
}
type fakefsCounters struct {
type fakeFSCounters struct {
Chmod int64
Lchown int64
Chtimes int64
@@ -81,13 +81,13 @@ type fakefsCounters struct {
}
var (
fakefsMut sync.Mutex
fakefsFs = make(map[string]*fakefs)
fakeFSMut sync.Mutex
fakeFSCache = make(map[string]*fakeFS)
)
func newFakeFilesystem(rootURI string, _ ...Option) *fakefs {
fakefsMut.Lock()
defer fakefsMut.Unlock()
func newFakeFilesystem(rootURI string, _ ...Option) *fakeFS {
fakeFSMut.Lock()
defer fakeFSMut.Unlock()
root := rootURI
var params url.Values
@@ -97,12 +97,12 @@ func newFakeFilesystem(rootURI string, _ ...Option) *fakefs {
params = uri.Query()
}
if fs, ok := fakefsFs[rootURI]; ok {
if fs, ok := fakeFSCache[rootURI]; ok {
// Already have an fs at this path
return fs
}
fs := &fakefs{
fs := &fakeFS{
uri: "fake://" + rootURI,
root: &fakeEntry{
name: "/",
@@ -157,7 +157,7 @@ func newFakeFilesystem(rootURI string, _ ...Option) *fakefs {
// the filesystem initially.
fs.latency, _ = time.ParseDuration(params.Get("latency"))
fakefsFs[root] = fs
fakeFSCache[root] = fs
return fs
}
@@ -183,7 +183,7 @@ type fakeEntry struct {
content []byte
}
func (fs *fakefs) entryForName(name string) *fakeEntry {
func (fs *fakeFS) entryForName(name string) *fakeEntry {
// bug: lookup doesn't work through symlinks.
if fs.insens {
name = UnicodeLowercase(name)
@@ -210,7 +210,7 @@ func (fs *fakefs) entryForName(name string) *fakeEntry {
return entry
}
func (fs *fakefs) Chmod(name string, mode FileMode) error {
func (fs *fakeFS) Chmod(name string, mode FileMode) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Chmod++
@@ -223,7 +223,7 @@ func (fs *fakefs) Chmod(name string, mode FileMode) error {
return nil
}
func (fs *fakefs) Lchown(name string, uid, gid int) error {
func (fs *fakeFS) Lchown(name string, uid, gid int) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Lchown++
@@ -237,7 +237,7 @@ func (fs *fakefs) Lchown(name string, uid, gid int) error {
return nil
}
func (fs *fakefs) Chtimes(name string, atime time.Time, mtime time.Time) error {
func (fs *fakeFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Chtimes++
@@ -250,7 +250,7 @@ func (fs *fakefs) Chtimes(name string, atime time.Time, mtime time.Time) error {
return nil
}
func (fs *fakefs) create(name string) (*fakeEntry, error) {
func (fs *fakeFS) create(name string) (*fakeEntry, error) {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Create++
@@ -296,7 +296,7 @@ func (fs *fakefs) create(name string) (*fakeEntry, error) {
return new, nil
}
func (fs *fakefs) Create(name string) (File, error) {
func (fs *fakeFS) Create(name string) (File, error) {
entry, err := fs.create(name)
if err != nil {
return nil, err
@@ -307,7 +307,7 @@ func (fs *fakefs) Create(name string) (File, error) {
return &fakeFile{fakeEntry: entry}, nil
}
func (fs *fakefs) CreateSymlink(target, name string) error {
func (fs *fakeFS) CreateSymlink(target, name string) error {
entry, err := fs.create(name)
if err != nil {
return err
@@ -317,7 +317,7 @@ func (fs *fakefs) CreateSymlink(target, name string) error {
return nil
}
func (fs *fakefs) DirNames(name string) ([]string, error) {
func (fs *fakeFS) DirNames(name string) ([]string, error) {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.DirNames++
@@ -336,7 +336,7 @@ func (fs *fakefs) DirNames(name string) ([]string, error) {
return names, nil
}
func (fs *fakefs) Lstat(name string) (FileInfo, error) {
func (fs *fakeFS) Lstat(name string) (FileInfo, error) {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Lstat++
@@ -355,7 +355,7 @@ func (fs *fakefs) Lstat(name string) (FileInfo, error) {
return info, nil
}
func (fs *fakefs) Mkdir(name string, perm FileMode) error {
func (fs *fakeFS) Mkdir(name string, perm FileMode) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Mkdir++
@@ -389,7 +389,7 @@ func (fs *fakefs) Mkdir(name string, perm FileMode) error {
return nil
}
func (fs *fakefs) MkdirAll(name string, perm FileMode) error {
func (fs *fakeFS) MkdirAll(name string, perm FileMode) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.MkdirAll++
@@ -426,7 +426,7 @@ func (fs *fakefs) MkdirAll(name string, perm FileMode) error {
return nil
}
func (fs *fakefs) Open(name string) (File, error) {
func (fs *fakeFS) Open(name string) (File, error) {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Open++
@@ -443,7 +443,7 @@ func (fs *fakefs) Open(name string) (File, error) {
return &fakeFile{fakeEntry: entry}, nil
}
func (fs *fakefs) OpenFile(name string, flags int, mode FileMode) (File, error) {
func (fs *fakeFS) OpenFile(name string, flags int, mode FileMode) (File, error) {
if flags&os.O_CREATE == 0 {
return fs.Open(name)
}
@@ -486,7 +486,7 @@ func (fs *fakefs) OpenFile(name string, flags int, mode FileMode) (File, error)
return &fakeFile{fakeEntry: newEntry}, nil
}
func (fs *fakefs) ReadSymlink(name string) (string, error) {
func (fs *fakeFS) ReadSymlink(name string) (string, error) {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.ReadSymlink++
@@ -501,7 +501,7 @@ func (fs *fakefs) ReadSymlink(name string) (string, error) {
return entry.dest, nil
}
func (fs *fakefs) Remove(name string) error {
func (fs *fakeFS) Remove(name string) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Remove++
@@ -524,7 +524,7 @@ func (fs *fakefs) Remove(name string) error {
return nil
}
func (fs *fakefs) RemoveAll(name string) error {
func (fs *fakeFS) RemoveAll(name string) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.RemoveAll++
@@ -536,7 +536,7 @@ func (fs *fakefs) RemoveAll(name string) error {
entry := fs.entryForName(filepath.Dir(name))
if entry == nil {
return nil // all tested real systems exibit this behaviour
return nil // all tested real systems exhibit this behaviour
}
// RemoveAll is easy when the file system uses garbage collection under
@@ -545,7 +545,7 @@ func (fs *fakefs) RemoveAll(name string) error {
return nil
}
func (fs *fakefs) Rename(oldname, newname string) error {
func (fs *fakeFS) Rename(oldname, newname string) error {
fs.mut.Lock()
defer fs.mut.Unlock()
fs.counters.Rename++
@@ -595,56 +595,56 @@ func (fs *fakefs) Rename(oldname, newname string) error {
return nil
}
func (fs *fakefs) Stat(name string) (FileInfo, error) {
func (fs *fakeFS) Stat(name string) (FileInfo, error) {
return fs.Lstat(name)
}
func (fs *fakefs) SymlinksSupported() bool {
func (fs *fakeFS) SymlinksSupported() bool {
return false
}
func (fs *fakefs) Walk(name string, walkFn WalkFunc) error {
func (fs *fakeFS) Walk(name string, walkFn WalkFunc) error {
return errors.New("not implemented")
}
func (fs *fakefs) Watch(path string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, <-chan error, error) {
func (fs *fakeFS) Watch(path string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, <-chan error, error) {
return nil, nil, ErrWatchNotSupported
}
func (fs *fakefs) Hide(name string) error {
func (fs *fakeFS) Hide(name string) error {
return nil
}
func (fs *fakefs) Unhide(name string) error {
func (fs *fakeFS) Unhide(name string) error {
return nil
}
func (fs *fakefs) Glob(pattern string) ([]string, error) {
func (fs *fakeFS) Glob(pattern string) ([]string, error) {
// gnnh we don't seem to actually require this in practice
return nil, errors.New("not implemented")
}
func (fs *fakefs) Roots() ([]string, error) {
func (fs *fakeFS) Roots() ([]string, error) {
return []string{"/"}, nil
}
func (fs *fakefs) Usage(name string) (Usage, error) {
func (fs *fakeFS) Usage(name string) (Usage, error) {
return Usage{}, errors.New("not implemented")
}
func (fs *fakefs) Type() FilesystemType {
func (fs *fakeFS) Type() FilesystemType {
return FilesystemTypeFake
}
func (fs *fakefs) URI() string {
func (fs *fakeFS) URI() string {
return fs.uri
}
func (fs *fakefs) Options() []Option {
func (fs *fakeFS) Options() []Option {
return nil
}
func (fs *fakefs) SameFile(fi1, fi2 FileInfo) bool {
func (fs *fakeFS) SameFile(fi1, fi2 FileInfo) bool {
// BUG: real systems base file sameness on path, inodes, etc
// we try our best, but FileInfo just doesn't have enough data
// so there be false positives, especially on Windows
@@ -659,17 +659,25 @@ func (fs *fakefs) SameFile(fi1, fi2 FileInfo) bool {
return ok && fi1.ModTime().Equal(fi2.ModTime()) && fi1.Mode() == fi2.Mode() && fi1.IsDir() == fi2.IsDir() && fi1.IsRegular() == fi2.IsRegular() && fi1.IsSymlink() == fi2.IsSymlink() && fi1.Owner() == fi2.Owner() && fi1.Group() == fi2.Group()
}
func (fs *fakefs) resetCounters() {
func (fs *fakeFS) underlying() (Filesystem, bool) {
return nil, false
}
func (fs *fakeFS) wrapperType() filesystemWrapperType {
return filesystemWrapperTypeNone
}
func (fs *fakeFS) resetCounters() {
fs.mut.Lock()
fs.counters = fakefsCounters{}
fs.counters = fakeFSCounters{}
fs.mut.Unlock()
}
func (fs *fakefs) reportMetricsPerOp(b *testing.B) {
func (fs *fakeFS) reportMetricsPerOp(b *testing.B) {
fs.reportMetricsPer(b, 1, "op")
}
func (fs *fakefs) reportMetricsPer(b *testing.B, divisor float64, unit string) {
func (fs *fakeFS) reportMetricsPer(b *testing.B, divisor float64, unit string) {
fs.mut.Lock()
defer fs.mut.Unlock()
b.ReportMetric(float64(fs.counters.Lstat)/divisor/float64(b.N), "Lstat/"+unit)