Use Readdirnames to reduce number of stats we're doing.

This commit is contained in:
Tom Wilkie
2015-12-09 17:42:36 +00:00
parent efecea3714
commit 1fcd079563
4 changed files with 47 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ import (
// Interface is the filesystem interface type.
type Interface interface {
ReadDir(string) ([]os.FileInfo, error)
ReadDirNames(string) ([]string, error)
ReadFile(string) ([]byte, error)
Lstat(string, *syscall.Stat_t) error
Stat(string, *syscall.Stat_t) error
@@ -25,6 +26,15 @@ func (realFS) ReadDir(path string) ([]os.FileInfo, error) {
return ioutil.ReadDir(path)
}
func (realFS) ReadDirNames(path string) ([]string, error) {
fh, err := os.Open(path)
if err != nil {
return nil, err
}
defer fh.Close()
return fh.Readdirnames(-1)
}
func (realFS) ReadFile(path string) ([]byte, error) {
return ioutil.ReadFile(path)
}
@@ -48,6 +58,11 @@ func ReadDir(path string) ([]os.FileInfo, error) {
return fs.ReadDir(path)
}
// ReadDirNames see os.File.ReadDirNames
func ReadDirNames(path string) ([]string, error) {
return fs.ReadDirNames(path)
}
// ReadFile see ioutil.ReadFile
func ReadFile(path string) ([]byte, error) {
return fs.ReadFile(path)

View File

@@ -34,15 +34,10 @@ func walkProcPid(buf *bytes.Buffer, walker process.Walker) (map[uint64]Proc, err
walker.Walk(func(p process.Process) {
dirName := strconv.Itoa(p.PID)
fdBase := filepath.Join(procRoot, dirName, "fd")
fds, err := fs.ReadDir(fdBase)
if err != nil {
// Process is be gone by now, or we don't have access.
return
}
// Read network namespace, and if we haven't seen it before,
// read /proc/<pid>/net/tcp
err = fs.Lstat(filepath.Join(procRoot, dirName, "/ns/net"), &statT)
err := fs.Lstat(filepath.Join(procRoot, dirName, "/ns/net"), &statT)
if err != nil {
return
}
@@ -53,9 +48,14 @@ func walkProcPid(buf *bytes.Buffer, walker process.Walker) (map[uint64]Proc, err
readFile(filepath.Join(procRoot, dirName, "/net/tcp6"), buf)
}
fds, err := fs.ReadDirNames(fdBase)
if err != nil {
// Process is be gone by now, or we don't have access.
return
}
for _, fd := range fds {
// Direct use of syscall.Stat() to save garbage.
err = fs.Stat(filepath.Join(fdBase, fd.Name()), &statT)
err = fs.Stat(filepath.Join(fdBase, fd), &statT)
if err != nil {
continue
}

View File

@@ -23,13 +23,12 @@ func NewWalker(procRoot string) Walker {
// passes one-by-one to the supplied function. Walk is only made public
// so that is can be tested.
func (w *walker) Walk(f func(Process)) error {
dirEntries, err := fs.ReadDir(w.procRoot)
dirEntries, err := fs.ReadDirNames(w.procRoot)
if err != nil {
return err
}
for _, dirEntry := range dirEntries {
filename := dirEntry.Name()
for _, filename := range dirEntries {
pid, err := strconv.Atoi(filename)
if err != nil {
continue

View File

@@ -89,6 +89,24 @@ func (p dir) ReadDir(path string) ([]os.FileInfo, error) {
return fs.ReadDir(tail)
}
func (p dir) ReadDirNames(path string) ([]string, error) {
if path == "/" {
result := []string{}
for _, v := range p.entries {
result = append(result, v.Name())
}
return result, nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil, fmt.Errorf("Not found: %s", path)
}
return fs.ReadDirNames(tail)
}
func (p dir) ReadFile(path string) ([]byte, error) {
if path == "/" {
return nil, fmt.Errorf("I'm a directory!")
@@ -156,6 +174,11 @@ func (p File) ReadDir(path string) ([]os.FileInfo, error) {
return nil, fmt.Errorf("I'm a file!")
}
// ReadDirNames implements FS
func (p File) ReadDirNames(path string) ([]string, error) {
return nil, fmt.Errorf("I'm a file!")
}
// ReadFile implements FS
func (p File) ReadFile(path string) ([]byte, error) {
if path != "/" {