Skip to content

Commit

Permalink
image: optimize file searching
Browse files Browse the repository at this point in the history
walkFunc is inefficient. If we knows which file to read, there
is no need to call w.walk().
For imageLayout, w.find() will improve the file searching speed

Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>
  • Loading branch information
Ma Shimiao committed Jan 24, 2018
1 parent bb7b937 commit 9027d58
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 26 deletions.
6 changes: 1 addition & 5 deletions image/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
Expand All @@ -35,10 +34,7 @@ func findConfig(w walker, d *v1.Descriptor) (*v1.Image, error) {
var c v1.Image
cpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())

switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if info.IsDir() || filepath.Clean(path) != cpath {
return nil
}
switch err := w.find(cpath, func(path string, r io.Reader) error {
buf, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrapf(err, "%s: error reading config", path)
Expand Down
7 changes: 2 additions & 5 deletions image/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,9 @@ func listReferences(w walker) ([]v1.Descriptor, error) {
func findDescriptor(w walker, names []string) ([]v1.Descriptor, error) {
var descs []v1.Descriptor
var index v1.Index
dpath := "index.json"

if err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if info.IsDir() || filepath.Clean(path) != indexPath {
return nil
}

if err := w.find(dpath, func(path string, r io.Reader) error {
if err := json.NewDecoder(r).Decode(&index); err != nil {
return err
}
Expand Down
20 changes: 4 additions & 16 deletions image/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ func findManifest(w walker, d *v1.Descriptor) (*v1.Manifest, error) {
var m v1.Manifest
mpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())

switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if info.IsDir() || filepath.Clean(path) != mpath {
return nil
}

switch err := w.find(mpath, func(path string, r io.Reader) error {
buf, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrapf(err, "%s: error reading manifest", path)
Expand Down Expand Up @@ -108,18 +104,10 @@ func unpackManifest(m *v1.Manifest, w walker, dest string) (retErr error) {
}
}()
for _, d := range m.Layers {
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
if info.IsDir() {
return nil
}

dd, err := filepath.Rel(filepath.Join("blobs", string(d.Digest.Algorithm())), filepath.Clean(path))
if err != nil || d.Digest.Hex() != dd {
return nil
}

lpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())
switch err := w.find(lpath, func(path string, r io.Reader) error {
if err := unpackLayer(d.MediaType, path, dest, r); err != nil {
return errors.Wrap(err, "error unpack: extracting layer")
return errors.Wrap(err, "unpack: error extracting layer")
}

return errEOW
Expand Down
82 changes: 82 additions & 0 deletions image/walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ var (
// walkFunc is a function type that gets called for each file or directory visited by the Walker.
type walkFunc func(path string, _ os.FileInfo, _ io.Reader) error

type findFunc func(path string, r io.Reader) error

// walker is the interface that defines how to access a given archival format
type walker interface {

Expand All @@ -43,6 +45,9 @@ type walker interface {
// get will copy an arbitrary blob, defined by desc, in to dst. returns
// the number of bytes copied on success.
get(desc v1.Descriptor, dst io.Writer) (int64, error)

// find calls findFunc for handling content of path
find(path string, ff findFunc) error
}

// tarWalker exposes access to image layouts in a tar file.
Expand Down Expand Up @@ -120,6 +125,34 @@ func (w *tarWalker) get(desc v1.Descriptor, dst io.Writer) (int64, error) {
return bytes, nil
}

func (w *tarWalker) find(path string, ff findFunc) error {
done := false

f := func(relpath string, info os.FileInfo, rdr io.Reader) error {
var err error
if done {
return nil
}

if filepath.Clean(relpath) == path && !info.IsDir() {
if err = ff(relpath, rdr); err != nil {
return err
}
done = true
}
return nil
}

if err := w.walk(f); err != nil {
return errors.Wrapf(err, "find failed: unable to walk")
}
if !done {
return os.ErrNotExist
}

return nil
}

type eofReader struct{}

func (eofReader) Read(_ []byte) (int, error) {
Expand Down Expand Up @@ -188,6 +221,27 @@ func (w *pathWalker) get(desc v1.Descriptor, dst io.Writer) (int64, error) {
return nbytes, nil
}

func (w *pathWalker) find(path string, ff findFunc) error {
name := filepath.Join(w.root, path)

info, err := os.Stat(name)
if err != nil {
return err
}

if info.IsDir() {
return fmt.Errorf("object is dir")
}

file, err := os.Open(name)
if err != nil {
return errors.Wrap(err, "unable to open file") // os.Open includes the path
}
defer file.Close()

return ff(name, file)
}

type zipWalker struct {
fileName string
}
Expand Down Expand Up @@ -249,3 +303,31 @@ func (w *zipWalker) get(desc v1.Descriptor, dst io.Writer) (int64, error) {

return bytes, nil
}

func (w *zipWalker) find(path string, ff findFunc) error {
done := false

f := func(relpath string, info os.FileInfo, rdr io.Reader) error {
var err error
if done {
return nil
}

if filepath.Clean(relpath) == path && !info.IsDir() {
if err = ff(relpath, rdr); err != nil {
return err
}
done = true
}
return nil
}

if err := w.walk(f); err != nil {
return errors.Wrapf(err, "find failed: unable to walk")
}
if !done {
return os.ErrNotExist
}

return nil
}

0 comments on commit 9027d58

Please sign in to comment.