Skip to content

Commit 9027d58

Browse files
author
Ma Shimiao
committed
image: optimize file searching
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 <[email protected]>
1 parent bb7b937 commit 9027d58

File tree

4 files changed

+89
-26
lines changed

4 files changed

+89
-26
lines changed

image/config.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"fmt"
2121
"io"
2222
"io/ioutil"
23-
"os"
2423
"path/filepath"
2524
"strconv"
2625
"strings"
@@ -35,10 +34,7 @@ func findConfig(w walker, d *v1.Descriptor) (*v1.Image, error) {
3534
var c v1.Image
3635
cpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())
3736

38-
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
39-
if info.IsDir() || filepath.Clean(path) != cpath {
40-
return nil
41-
}
37+
switch err := w.find(cpath, func(path string, r io.Reader) error {
4238
buf, err := ioutil.ReadAll(r)
4339
if err != nil {
4440
return errors.Wrapf(err, "%s: error reading config", path)

image/descriptor.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,9 @@ func listReferences(w walker) ([]v1.Descriptor, error) {
5353
func findDescriptor(w walker, names []string) ([]v1.Descriptor, error) {
5454
var descs []v1.Descriptor
5555
var index v1.Index
56+
dpath := "index.json"
5657

57-
if err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
58-
if info.IsDir() || filepath.Clean(path) != indexPath {
59-
return nil
60-
}
61-
58+
if err := w.find(dpath, func(path string, r io.Reader) error {
6259
if err := json.NewDecoder(r).Decode(&index); err != nil {
6360
return err
6461
}

image/manifest.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,7 @@ func findManifest(w walker, d *v1.Descriptor) (*v1.Manifest, error) {
3939
var m v1.Manifest
4040
mpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())
4141

42-
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
43-
if info.IsDir() || filepath.Clean(path) != mpath {
44-
return nil
45-
}
46-
42+
switch err := w.find(mpath, func(path string, r io.Reader) error {
4743
buf, err := ioutil.ReadAll(r)
4844
if err != nil {
4945
return errors.Wrapf(err, "%s: error reading manifest", path)
@@ -108,18 +104,10 @@ func unpackManifest(m *v1.Manifest, w walker, dest string) (retErr error) {
108104
}
109105
}()
110106
for _, d := range m.Layers {
111-
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
112-
if info.IsDir() {
113-
return nil
114-
}
115-
116-
dd, err := filepath.Rel(filepath.Join("blobs", string(d.Digest.Algorithm())), filepath.Clean(path))
117-
if err != nil || d.Digest.Hex() != dd {
118-
return nil
119-
}
120-
107+
lpath := filepath.Join("blobs", string(d.Digest.Algorithm()), d.Digest.Hex())
108+
switch err := w.find(lpath, func(path string, r io.Reader) error {
121109
if err := unpackLayer(d.MediaType, path, dest, r); err != nil {
122-
return errors.Wrap(err, "error unpack: extracting layer")
110+
return errors.Wrap(err, "unpack: error extracting layer")
123111
}
124112

125113
return errEOW

image/walker.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ var (
3434
// walkFunc is a function type that gets called for each file or directory visited by the Walker.
3535
type walkFunc func(path string, _ os.FileInfo, _ io.Reader) error
3636

37+
type findFunc func(path string, r io.Reader) error
38+
3739
// walker is the interface that defines how to access a given archival format
3840
type walker interface {
3941

@@ -43,6 +45,9 @@ type walker interface {
4345
// get will copy an arbitrary blob, defined by desc, in to dst. returns
4446
// the number of bytes copied on success.
4547
get(desc v1.Descriptor, dst io.Writer) (int64, error)
48+
49+
// find calls findFunc for handling content of path
50+
find(path string, ff findFunc) error
4651
}
4752

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

128+
func (w *tarWalker) find(path string, ff findFunc) error {
129+
done := false
130+
131+
f := func(relpath string, info os.FileInfo, rdr io.Reader) error {
132+
var err error
133+
if done {
134+
return nil
135+
}
136+
137+
if filepath.Clean(relpath) == path && !info.IsDir() {
138+
if err = ff(relpath, rdr); err != nil {
139+
return err
140+
}
141+
done = true
142+
}
143+
return nil
144+
}
145+
146+
if err := w.walk(f); err != nil {
147+
return errors.Wrapf(err, "find failed: unable to walk")
148+
}
149+
if !done {
150+
return os.ErrNotExist
151+
}
152+
153+
return nil
154+
}
155+
123156
type eofReader struct{}
124157

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

224+
func (w *pathWalker) find(path string, ff findFunc) error {
225+
name := filepath.Join(w.root, path)
226+
227+
info, err := os.Stat(name)
228+
if err != nil {
229+
return err
230+
}
231+
232+
if info.IsDir() {
233+
return fmt.Errorf("object is dir")
234+
}
235+
236+
file, err := os.Open(name)
237+
if err != nil {
238+
return errors.Wrap(err, "unable to open file") // os.Open includes the path
239+
}
240+
defer file.Close()
241+
242+
return ff(name, file)
243+
}
244+
191245
type zipWalker struct {
192246
fileName string
193247
}
@@ -249,3 +303,31 @@ func (w *zipWalker) get(desc v1.Descriptor, dst io.Writer) (int64, error) {
249303

250304
return bytes, nil
251305
}
306+
307+
func (w *zipWalker) find(path string, ff findFunc) error {
308+
done := false
309+
310+
f := func(relpath string, info os.FileInfo, rdr io.Reader) error {
311+
var err error
312+
if done {
313+
return nil
314+
}
315+
316+
if filepath.Clean(relpath) == path && !info.IsDir() {
317+
if err = ff(relpath, rdr); err != nil {
318+
return err
319+
}
320+
done = true
321+
}
322+
return nil
323+
}
324+
325+
if err := w.walk(f); err != nil {
326+
return errors.Wrapf(err, "find failed: unable to walk")
327+
}
328+
if !done {
329+
return os.ErrNotExist
330+
}
331+
332+
return nil
333+
}

0 commit comments

Comments
 (0)