github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/layer/migration.go (about)

     1  package layer // import "github.com/docker/docker/layer"
     2  
     3  import (
     4  	"compress/gzip"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/opencontainers/go-digest"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/vbatts/tar-split/tar/asm"
    13  	"github.com/vbatts/tar-split/tar/storage"
    14  )
    15  
    16  // CreateRWLayerByGraphID creates a RWLayer in the layer store using
    17  // the provided name with the given graphID. To get the RWLayer
    18  // after migration the layer may be retrieved by the given name.
    19  func (ls *layerStore) CreateRWLayerByGraphID(name, graphID string, parent ChainID) (err error) {
    20  	ls.mountL.Lock()
    21  	defer ls.mountL.Unlock()
    22  	m, ok := ls.mounts[name]
    23  	if ok {
    24  		if m.parent.chainID != parent {
    25  			return errors.New("name conflict, mismatched parent")
    26  		}
    27  		if m.mountID != graphID {
    28  			return errors.New("mount already exists")
    29  		}
    30  
    31  		return nil
    32  	}
    33  
    34  	if !ls.driver.Exists(graphID) {
    35  		return fmt.Errorf("graph ID does not exist: %q", graphID)
    36  	}
    37  
    38  	var p *roLayer
    39  	if string(parent) != "" {
    40  		p = ls.get(parent)
    41  		if p == nil {
    42  			return ErrLayerDoesNotExist
    43  		}
    44  
    45  		// Release parent chain if error
    46  		defer func() {
    47  			if err != nil {
    48  				ls.layerL.Lock()
    49  				ls.releaseLayer(p)
    50  				ls.layerL.Unlock()
    51  			}
    52  		}()
    53  	}
    54  
    55  	// TODO: Ensure graphID has correct parent
    56  
    57  	m = &mountedLayer{
    58  		name:       name,
    59  		parent:     p,
    60  		mountID:    graphID,
    61  		layerStore: ls,
    62  		references: map[RWLayer]*referencedRWLayer{},
    63  	}
    64  
    65  	// Check for existing init layer
    66  	initID := fmt.Sprintf("%s-init", graphID)
    67  	if ls.driver.Exists(initID) {
    68  		m.initID = initID
    69  	}
    70  
    71  	return ls.saveMount(m)
    72  }
    73  
    74  func (ls *layerStore) ChecksumForGraphID(id, parent, oldTarDataPath, newTarDataPath string) (diffID DiffID, size int64, err error) {
    75  	defer func() {
    76  		if err != nil {
    77  			logrus.Debugf("could not get checksum for %q with tar-split: %q", id, err)
    78  			diffID, size, err = ls.checksumForGraphIDNoTarsplit(id, parent, newTarDataPath)
    79  		}
    80  	}()
    81  
    82  	if oldTarDataPath == "" {
    83  		err = errors.New("no tar-split file")
    84  		return
    85  	}
    86  
    87  	tarDataFile, err := os.Open(oldTarDataPath)
    88  	if err != nil {
    89  		return
    90  	}
    91  	defer tarDataFile.Close()
    92  	uncompressed, err := gzip.NewReader(tarDataFile)
    93  	if err != nil {
    94  		return
    95  	}
    96  
    97  	dgst := digest.Canonical.Digester()
    98  	err = ls.assembleTarTo(id, uncompressed, &size, dgst.Hash())
    99  	if err != nil {
   100  		return
   101  	}
   102  
   103  	diffID = DiffID(dgst.Digest())
   104  	err = os.RemoveAll(newTarDataPath)
   105  	if err != nil {
   106  		return
   107  	}
   108  	err = os.Link(oldTarDataPath, newTarDataPath)
   109  
   110  	return
   111  }
   112  
   113  func (ls *layerStore) checksumForGraphIDNoTarsplit(id, parent, newTarDataPath string) (diffID DiffID, size int64, err error) {
   114  	rawarchive, err := ls.driver.Diff(id, parent)
   115  	if err != nil {
   116  		return
   117  	}
   118  	defer rawarchive.Close()
   119  
   120  	f, err := os.Create(newTarDataPath)
   121  	if err != nil {
   122  		return
   123  	}
   124  	defer f.Close()
   125  	mfz := gzip.NewWriter(f)
   126  	defer mfz.Close()
   127  	metaPacker := storage.NewJSONPacker(mfz)
   128  
   129  	packerCounter := &packSizeCounter{metaPacker, &size}
   130  
   131  	archive, err := asm.NewInputTarStream(rawarchive, packerCounter, nil)
   132  	if err != nil {
   133  		return
   134  	}
   135  	dgst, err := digest.FromReader(archive)
   136  	if err != nil {
   137  		return
   138  	}
   139  	diffID = DiffID(dgst)
   140  	return
   141  }
   142  
   143  func (ls *layerStore) RegisterByGraphID(graphID string, parent ChainID, diffID DiffID, tarDataFile string, size int64) (Layer, error) {
   144  	// err is used to hold the error which will always trigger
   145  	// cleanup of creates sources but may not be an error returned
   146  	// to the caller (already exists).
   147  	var err error
   148  	var p *roLayer
   149  	if string(parent) != "" {
   150  		p = ls.get(parent)
   151  		if p == nil {
   152  			return nil, ErrLayerDoesNotExist
   153  		}
   154  
   155  		// Release parent chain if error
   156  		defer func() {
   157  			if err != nil {
   158  				ls.layerL.Lock()
   159  				ls.releaseLayer(p)
   160  				ls.layerL.Unlock()
   161  			}
   162  		}()
   163  	}
   164  
   165  	// Create new roLayer
   166  	layer := &roLayer{
   167  		parent:         p,
   168  		cacheID:        graphID,
   169  		referenceCount: 1,
   170  		layerStore:     ls,
   171  		references:     map[Layer]struct{}{},
   172  		diffID:         diffID,
   173  		size:           size,
   174  		chainID:        createChainIDFromParent(parent, diffID),
   175  	}
   176  
   177  	ls.layerL.Lock()
   178  	defer ls.layerL.Unlock()
   179  
   180  	if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil {
   181  		// Set error for cleanup, but do not return
   182  		err = errors.New("layer already exists")
   183  		return existingLayer.getReference(), nil
   184  	}
   185  
   186  	tx, err := ls.store.StartTransaction()
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  
   191  	defer func() {
   192  		if err != nil {
   193  			logrus.Debugf("Cleaning up transaction after failed migration for %s: %v", graphID, err)
   194  			if err := tx.Cancel(); err != nil {
   195  				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err)
   196  			}
   197  		}
   198  	}()
   199  
   200  	tsw, err := tx.TarSplitWriter(false)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	defer tsw.Close()
   205  	tdf, err := os.Open(tarDataFile)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	defer tdf.Close()
   210  	_, err = io.Copy(tsw, tdf)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	if err = storeLayer(tx, layer); err != nil {
   216  		return nil, err
   217  	}
   218  
   219  	if err = tx.Commit(layer.chainID); err != nil {
   220  		return nil, err
   221  	}
   222  
   223  	ls.layerMap[layer.chainID] = layer
   224  
   225  	return layer.getReference(), nil
   226  }
   227  
   228  type unpackSizeCounter struct {
   229  	unpacker storage.Unpacker
   230  	size     *int64
   231  }
   232  
   233  func (u *unpackSizeCounter) Next() (*storage.Entry, error) {
   234  	e, err := u.unpacker.Next()
   235  	if err == nil && u.size != nil {
   236  		*u.size += e.Size
   237  	}
   238  	return e, err
   239  }
   240  
   241  type packSizeCounter struct {
   242  	packer storage.Packer
   243  	size   *int64
   244  }
   245  
   246  func (p *packSizeCounter) AddEntry(e storage.Entry) (int, error) {
   247  	n, err := p.packer.AddEntry(e)
   248  	if err == nil && p.size != nil {
   249  		*p.size += e.Size
   250  	}
   251  	return n, err
   252  }