Skip to content

Commit

Permalink
Use tar-split to preserve layer diffs
Browse files Browse the repository at this point in the history
Use tar-split to preserve data from layer diffs that we'd normally lose
when importing the layer, so that we can correctly reconstruct the diff
if we ever need to export it later.  For now, store the metadata in
compressed form as its own file alongside the layers data.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
  • Loading branch information
nalind committed Aug 17, 2016
1 parent 3a53c82 commit 9b04055
Showing 1 changed file with 86 additions and 2 deletions.
88 changes: 86 additions & 2 deletions storage/layers.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package storage

import (
"bytes"
"compress/gzip"
"encoding/json"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
Expand All @@ -11,6 +14,8 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/stringid"
"github.com/vbatts/tar-split/tar/asm"
"github.com/vbatts/tar-split/tar/storage"
)

var (
Expand Down Expand Up @@ -350,13 +355,18 @@ func (r *layerStore) SetMetadata(id, metadata string) error {
return ErrLayerUnknown
}

func (r *layerStore) tspath(id string) string {
return filepath.Join(r.layerdir, id+".tar-split.gz")
}

func (r *layerStore) Delete(id string) error {
if layer, ok := r.byname[id]; ok {
id = layer.ID
}
r.Unmount(id)
err := r.driver.Remove(id)
if err == nil {
os.Remove(r.tspath(id))
if layer, ok := r.byid[id]; ok {
pslice := r.byparent[layer.Parent]
newPslice := []*Layer{}
Expand Down Expand Up @@ -447,7 +457,38 @@ func (r *layerStore) Changes(from, to string) ([]archive.Change, error) {
return r.driver.Changes(to, from)
}

type simpleGetCloser struct {
r *layerStore
path string
id string
}

func (s *simpleGetCloser) Get(path string) (io.ReadCloser, error) {
return os.Open(filepath.Join(s.path, path))
}

func (s *simpleGetCloser) Close() error {
return s.r.Unmount(s.id)
}

func (r *layerStore) newFileGetter(id string) (graphdriver.FileGetCloser, error) {
if getter, ok := r.driver.(graphdriver.DiffGetterDriver); ok {
return getter.DiffGetter(id)
}
path, err := r.Mount(id, "")
if err != nil {
return nil, err
}
return &simpleGetCloser{
r: r,
path: path,
id: id,
}, nil
}

func (r *layerStore) Diff(from, to string) (archive.Reader, error) {
var metadata storage.Unpacker

if layer, ok := r.byname[from]; ok {
from = layer.ID
}
Expand All @@ -462,7 +503,33 @@ func (r *layerStore) Diff(from, to string) (archive.Reader, error) {
if to == "" {
return nil, ErrParentUnknown
}
return r.driver.Diff(to, from)
if from != r.byid[to].Parent {
return r.driver.Diff(to, from)
}

tsfile, err := os.Open(r.tspath(to))
if err != nil {
return nil, err
}
decompressor, err := gzip.NewReader(tsfile)
if err != nil {
return nil, err
}
tsbytes, err := ioutil.ReadAll(decompressor)
if err != nil {
return nil, err
}
decompressor.Close()
tsfile.Close()

metadata = storage.NewJSONUnpacker(bytes.NewBuffer(tsbytes))

if fgetter, err := r.newFileGetter(to); err != nil {
decompressor.Close()
return nil, err
} else {
return asm.NewOutputTarStream(fgetter, metadata), nil
}
}

func (r *layerStore) DiffSize(from, to string) (size int64, err error) {
Expand Down Expand Up @@ -491,12 +558,29 @@ func (r *layerStore) ApplyDiff(to string, diff archive.Reader) (size int64, err
if !ok {
return -1, ErrParentUnknown
}
tsdata := bytes.Buffer{}
compressor, err := gzip.NewWriterLevel(&tsdata, gzip.BestSpeed)
if err != nil {
compressor = gzip.NewWriter(&tsdata)
}
metadata := storage.NewJSONPacker(compressor)
if c, err := archive.DecompressStream(diff); err != nil {
return -1, err
} else {
diff = c
}
return r.driver.ApplyDiff(layer.ID, layer.Parent, diff)
payload, err := asm.NewInputTarStream(diff, metadata, storage.NewDiscardFilePutter())
if err != nil {
return -1, err
}
size, err = r.driver.ApplyDiff(layer.ID, layer.Parent, payload)
compressor.Close()
if err == nil {
if err := ioutils.AtomicWriteFile(r.tspath(layer.ID), tsdata.Bytes(), 0600); err != nil {
return -1, err
}
}
return size, err
}

func (r *layerStore) Lock() {
Expand Down

0 comments on commit 9b04055

Please sign in to comment.