Refactor to optimize storage driver ApplyDiff()
To avoid an expensive call to archive.ChangesDirs() which walks two directory trees and compares every entry, archive.ApplyLayer() has been extended to also return the size of the layer changes. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
This commit is contained in:
parent
52679b2b7f
commit
c57c03f841
5 changed files with 61 additions and 29 deletions
|
@ -1,6 +1,8 @@
|
|||
package chrootarchive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -14,6 +16,10 @@ import (
|
|||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
||||
type applyLayerResponse struct {
|
||||
LayerSize int64 `json:"layerSize"`
|
||||
}
|
||||
|
||||
func applyLayer() {
|
||||
runtime.LockOSThread()
|
||||
flag.Parse()
|
||||
|
@ -21,6 +27,7 @@ func applyLayer() {
|
|||
if err := chroot(flag.Arg(0)); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
// We need to be able to set any perms
|
||||
oldmask := syscall.Umask(0)
|
||||
defer syscall.Umask(oldmask)
|
||||
|
@ -28,33 +35,53 @@ func applyLayer() {
|
|||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
os.Setenv("TMPDIR", tmpDir)
|
||||
err = archive.UnpackLayer("/", os.Stdin)
|
||||
size, err := archive.UnpackLayer("/", os.Stdin)
|
||||
os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
os.RemoveAll(tmpDir)
|
||||
|
||||
encoder := json.NewEncoder(os.Stdout)
|
||||
if err := encoder.Encode(applyLayerResponse{size}); err != nil {
|
||||
fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err))
|
||||
}
|
||||
|
||||
flush(os.Stdout)
|
||||
flush(os.Stdin)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func ApplyLayer(dest string, layer archive.ArchiveReader) error {
|
||||
func ApplyLayer(dest string, layer archive.ArchiveReader) (size int64, err error) {
|
||||
dest = filepath.Clean(dest)
|
||||
decompressed, err := archive.DecompressStream(layer)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if c, ok := decompressed.(io.Closer); ok {
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
cmd := reexec.Command("docker-applyLayer", dest)
|
||||
cmd.Stdin = decompressed
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ApplyLayer %s %s", err, out)
|
||||
|
||||
outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
|
||||
cmd.Stdout, cmd.Stderr = outBuf, errBuf
|
||||
|
||||
if err = cmd.Run(); err != nil {
|
||||
return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf)
|
||||
}
|
||||
return nil
|
||||
|
||||
// Stdout should be a valid JSON struct representing an applyLayerResponse.
|
||||
response := applyLayerResponse{}
|
||||
decoder := json.NewDecoder(outBuf)
|
||||
if err = decoder.Decode(&response); err != nil {
|
||||
return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err)
|
||||
}
|
||||
|
||||
return response.LayerSize, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue