github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/layer/migration.go (about)

     1  package layer
     2  
     3  import (
     4  	"compress/gzip"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  	"github.com/docker/distribution/digest"
    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 string, 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 errors.New("graph ID does not exist")
    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  	if err = ls.saveMount(m); err != nil {
    72  		return err
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  func (ls *layerStore) ChecksumForGraphID(id, parent, oldTarDataPath, newTarDataPath string) (diffID DiffID, size int64, err error) {
    79  	defer func() {
    80  		if err != nil {
    81  			logrus.Debugf("could not get checksum for %q with tar-split: %q", id, err)
    82  			diffID, size, err = ls.checksumForGraphIDNoTarsplit(id, parent, newTarDataPath)
    83  		}
    84  	}()
    85  
    86  	if oldTarDataPath == "" {
    87  		err = errors.New("no tar-split file")
    88  		return
    89  	}
    90  
    91  	tarDataFile, err := os.Open(oldTarDataPath)
    92  	if err != nil {
    93  		return
    94  	}
    95  	defer tarDataFile.Close()
    96  	uncompressed, err := gzip.NewReader(tarDataFile)
    97  	if err != nil {
    98  		return
    99  	}
   100  
   101  	dgst := digest.Canonical.New()
   102  	err = ls.assembleTarTo(id, uncompressed, &size, dgst.Hash())
   103  	if err != nil {
   104  		return
   105  	}
   106  
   107  	diffID = DiffID(dgst.Digest())
   108  	err = os.RemoveAll(newTarDataPath)
   109  	if err != nil {
   110  		return
   111  	}
   112  	err = os.Link(oldTarDataPath, newTarDataPath)
   113  
   114  	return
   115  }
   116  
   117  func (ls *layerStore) checksumForGraphIDNoTarsplit(id, parent, newTarDataPath string) (diffID DiffID, size int64, err error) {
   118  	rawarchive, err := ls.driver.Diff(id, parent)
   119  	if err != nil {
   120  		return
   121  	}
   122  	defer rawarchive.Close()
   123  
   124  	f, err := os.Create(newTarDataPath)
   125  	if err != nil {
   126  		return
   127  	}
   128  	defer f.Close()
   129  	mfz := gzip.NewWriter(f)
   130  	metaPacker := storage.NewJSONPacker(mfz)
   131  
   132  	packerCounter := &packSizeCounter{metaPacker, &size}
   133  
   134  	archive, err := asm.NewInputTarStream(rawarchive, packerCounter, nil)
   135  	if err != nil {
   136  		return
   137  	}
   138  	dgst, err := digest.FromReader(archive)
   139  	if err != nil {
   140  		return
   141  	}
   142  	diffID = DiffID(dgst)
   143  	return
   144  }
   145  
   146  func (ls *layerStore) RegisterByGraphID(graphID string, parent ChainID, diffID DiffID, tarDataFile string, size int64) (Layer, error) {
   147  	// err is used to hold the error which will always trigger
   148  	// cleanup of creates sources but may not be an error returned
   149  	// to the caller (already exists).
   150  	var err error
   151  	var p *roLayer
   152  	if string(parent) != "" {
   153  		p = ls.get(parent)
   154  		if p == nil {
   155  			return nil, ErrLayerDoesNotExist
   156  		}
   157  
   158  		// Release parent chain if error
   159  		defer func() {
   160  			if err != nil {
   161  				ls.layerL.Lock()
   162  				ls.releaseLayer(p)
   163  				ls.layerL.Unlock()
   164  			}
   165  		}()
   166  	}
   167  
   168  	// Create new roLayer
   169  	layer := &roLayer{
   170  		parent:         p,
   171  		cacheID:        graphID,
   172  		referenceCount: 1,
   173  		layerStore:     ls,
   174  		references:     map[Layer]struct{}{},
   175  		diffID:         diffID,
   176  		size:           size,
   177  		chainID:        createChainIDFromParent(parent, diffID),
   178  	}
   179  
   180  	ls.layerL.Lock()
   181  	defer ls.layerL.Unlock()
   182  
   183  	if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil {
   184  		// Set error for cleanup, but do not return
   185  		err = errors.New("layer already exists")
   186  		return existingLayer.getReference(), nil
   187  	}
   188  
   189  	tx, err := ls.store.StartTransaction()
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	defer func() {
   195  		if err != nil {
   196  			logrus.Debugf("Cleaning up transaction after failed migration for %s: %v", graphID, err)
   197  			if err := tx.Cancel(); err != nil {
   198  				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err)
   199  			}
   200  		}
   201  	}()
   202  
   203  	tsw, err := tx.TarSplitWriter(false)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	defer tsw.Close()
   208  	tdf, err := os.Open(tarDataFile)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	defer tdf.Close()
   213  	_, err = io.Copy(tsw, tdf)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	if err = storeLayer(tx, layer); err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	if err = tx.Commit(layer.chainID); err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	ls.layerMap[layer.chainID] = layer
   227  
   228  	return layer.getReference(), nil
   229  }
   230  
   231  type unpackSizeCounter struct {
   232  	unpacker storage.Unpacker
   233  	size     *int64
   234  }
   235  
   236  func (u *unpackSizeCounter) Next() (*storage.Entry, error) {
   237  	e, err := u.unpacker.Next()
   238  	if err == nil && u.size != nil {
   239  		*u.size += e.Size
   240  	}
   241  	return e, err
   242  }
   243  
   244  type packSizeCounter struct {
   245  	packer storage.Packer
   246  	size   *int64
   247  }
   248  
   249  func (p *packSizeCounter) AddEntry(e storage.Entry) (int, error) {
   250  	n, err := p.packer.AddEntry(e)
   251  	if err == nil && p.size != nil {
   252  		*p.size += e.Size
   253  	}
   254  	return n, err
   255  }