lib/fs: Enhance mtimefs, use everywhere (fixes #5777) (#5776)

This commit is contained in:
Audrius Butkevicius 2019-06-11 07:27:13 +01:00 committed by Jakob Borg
parent 42ce6be9b9
commit b7c70a9817
3 changed files with 186 additions and 0 deletions

2
go.sum
View File

@ -125,10 +125,12 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9 h1:jmLW6izPBVlIbk4d+XgK9+sChGbVKxxOPmd9eqRHCjw= github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9 h1:jmLW6izPBVlIbk4d+XgK9+sChGbVKxxOPmd9eqRHCjw=

View File

@ -66,6 +66,23 @@ func (f *MtimeFS) Chtimes(name string, atime, mtime time.Time) error {
return nil return nil
} }
func (f *MtimeFS) Stat(name string) (FileInfo, error) {
info, err := f.Filesystem.Stat(name)
if err != nil {
return nil, err
}
real, virtual := f.load(name)
if real == info.ModTime() {
info = mtimeFileInfo{
FileInfo: info,
mtime: virtual,
}
}
return info, nil
}
func (f *MtimeFS) Lstat(name string) (FileInfo, error) { func (f *MtimeFS) Lstat(name string) (FileInfo, error) {
info, err := f.Filesystem.Lstat(name) info, err := f.Filesystem.Lstat(name)
if err != nil { if err != nil {
@ -83,6 +100,45 @@ func (f *MtimeFS) Lstat(name string) (FileInfo, error) {
return info, nil return info, nil
} }
func (f *MtimeFS) Walk(root string, walkFn WalkFunc) error {
return f.Filesystem.Walk(root, func(path string, info FileInfo, err error) error {
if info != nil {
real, virtual := f.load(path)
if real == info.ModTime() {
info = mtimeFileInfo{
FileInfo: info,
mtime: virtual,
}
}
}
return walkFn(path, info, err)
})
}
func (f *MtimeFS) Create(name string) (File, error) {
fd, err := f.Filesystem.Create(name)
if err != nil {
return nil, err
}
return &mtimeFile{fd, f}, nil
}
func (f *MtimeFS) Open(name string) (File, error) {
fd, err := f.Filesystem.Open(name)
if err != nil {
return nil, err
}
return &mtimeFile{fd, f}, nil
}
func (f *MtimeFS) OpenFile(name string, flags int, mode FileMode) (File, error) {
fd, err := f.Filesystem.OpenFile(name, flags, mode)
if err != nil {
return nil, err
}
return &mtimeFile{fd, f}, nil
}
// "real" is the on disk timestamp // "real" is the on disk timestamp
// "virtual" is what want the timestamp to be // "virtual" is what want the timestamp to be
@ -135,6 +191,28 @@ func (m mtimeFileInfo) ModTime() time.Time {
return m.mtime return m.mtime
} }
type mtimeFile struct {
File
fs *MtimeFS
}
func (f *mtimeFile) Stat() (FileInfo, error) {
info, err := f.File.Stat()
if err != nil {
return nil, err
}
real, virtual := f.fs.load(f.Name())
if real == info.ModTime() {
info = mtimeFileInfo{
FileInfo: info,
mtime: virtual,
}
}
return info, nil
}
// The dbMtime is our database representation // The dbMtime is our database representation
type dbMtime struct { type dbMtime struct {

View File

@ -10,6 +10,7 @@ import (
"errors" "errors"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"runtime" "runtime"
"testing" "testing"
"time" "time"
@ -81,6 +82,111 @@ func TestMtimeFS(t *testing.T) {
} }
} }
func TestMtimeFSWalk(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer func() { _ = os.RemoveAll(dir) }()
underlying := NewFilesystem(FilesystemTypeBasic, dir)
mtimefs := NewMtimeFS(underlying, make(mapStore))
mtimefs.chtimes = failChtimes
if err := ioutil.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
t.Fatal(err)
}
oldStat, err := mtimefs.Lstat("file")
if err != nil {
t.Fatal(err)
}
newTime := time.Now().Add(-2 * time.Hour)
if err := mtimefs.Chtimes("file", newTime, newTime); err != nil {
t.Fatal(err)
}
if newStat, err := mtimefs.Lstat("file"); err != nil {
t.Fatal(err)
} else if !newStat.ModTime().Equal(newTime) {
t.Errorf("expected time %v, lstat time %v", newTime, newStat.ModTime())
}
if underlyingStat, err := underlying.Lstat("file"); err != nil {
t.Fatal(err)
} else if !underlyingStat.ModTime().Equal(oldStat.ModTime()) {
t.Errorf("expected time %v, lstat time %v", oldStat.ModTime(), underlyingStat.ModTime())
}
found := false
_ = mtimefs.Walk("", func(path string, info FileInfo, err error) error {
if path == "file" {
found = true
if !info.ModTime().Equal(newTime) {
t.Errorf("expected time %v, lstat time %v", newTime, info.ModTime())
}
}
return nil
})
if !found {
t.Error("did not find")
}
}
func TestMtimeFSOpen(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer func() { _ = os.RemoveAll(dir) }()
underlying := NewFilesystem(FilesystemTypeBasic, dir)
mtimefs := NewMtimeFS(underlying, make(mapStore))
mtimefs.chtimes = failChtimes
if err := ioutil.WriteFile(filepath.Join(dir, "file"), []byte("hello"), 0644); err != nil {
t.Fatal(err)
}
oldStat, err := mtimefs.Lstat("file")
if err != nil {
t.Fatal(err)
}
newTime := time.Now().Add(-2 * time.Hour)
if err := mtimefs.Chtimes("file", newTime, newTime); err != nil {
t.Fatal(err)
}
if newStat, err := mtimefs.Lstat("file"); err != nil {
t.Fatal(err)
} else if !newStat.ModTime().Equal(newTime) {
t.Errorf("expected time %v, lstat time %v", newTime, newStat.ModTime())
}
if underlyingStat, err := underlying.Lstat("file"); err != nil {
t.Fatal(err)
} else if !underlyingStat.ModTime().Equal(oldStat.ModTime()) {
t.Errorf("expected time %v, lstat time %v", oldStat.ModTime(), underlyingStat.ModTime())
}
fd, err := mtimefs.Open("file")
if err != nil {
t.Fatal(err)
}
info, err := fd.Stat()
if err != nil {
t.Fatal(err)
}
if !info.ModTime().Equal(newTime) {
t.Errorf("expected time %v, lstat time %v", newTime, info.ModTime())
}
}
func TestMtimeFSInsensitive(t *testing.T) { func TestMtimeFSInsensitive(t *testing.T) {
switch runtime.GOOS { switch runtime.GOOS {
case "darwin", "windows": case "darwin", "windows":