浏览代码

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

Audrius Butkevicius 6 年之前
父节点
当前提交
b7c70a9817
共有 3 个文件被更改,包括 186 次插入0 次删除
  1. 2 0
      go.sum
  2. 78 0
      lib/fs/mtimefs.go
  3. 106 0
      lib/fs/mtimefs_test.go

+ 2 - 0
go.sum

@@ -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.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
 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/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/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/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rcrowley/go-metrics v0.0.0-20171128170426-e181e095bae9 h1:jmLW6izPBVlIbk4d+XgK9+sChGbVKxxOPmd9eqRHCjw=

+ 78 - 0
lib/fs/mtimefs.go

@@ -66,6 +66,23 @@ func (f *MtimeFS) Chtimes(name string, atime, mtime time.Time) error {
 	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) {
 	info, err := f.Filesystem.Lstat(name)
 	if err != nil {
@@ -83,6 +100,45 @@ func (f *MtimeFS) Lstat(name string) (FileInfo, error) {
 	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
 // "virtual" is what want the timestamp to be
 
@@ -135,6 +191,28 @@ func (m mtimeFileInfo) ModTime() time.Time {
 	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
 
 type dbMtime struct {

+ 106 - 0
lib/fs/mtimefs_test.go

@@ -10,6 +10,7 @@ import (
 	"errors"
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"runtime"
 	"testing"
 	"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) {
 	switch runtime.GOOS {
 	case "darwin", "windows":