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:
Josh Hawn 2014-12-17 18:26:03 -08:00
parent 52679b2b7f
commit c57c03f841
5 changed files with 61 additions and 29 deletions

View file

@ -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
}