github.com/rawahars/moby@v24.0.4+incompatible/layer/migration.go (about)

     1  package layer // import "github.com/docker/docker/layer"
     2  
     3  import (
     4  	"compress/gzip"
     5  	"errors"
     6  	"io"
     7  	"os"
     8  
     9  	"github.com/opencontainers/go-digest"
    10  	"github.com/sirupsen/logrus"
    11  	"github.com/vbatts/tar-split/tar/asm"
    12  	"github.com/vbatts/tar-split/tar/storage"
    13  )
    14  
    15  func (ls *layerStore) ChecksumForGraphID(id, parent, oldTarDataPath, newTarDataPath string) (diffID DiffID, size int64, err error) {
    16  	defer func() {
    17  		if err != nil {
    18  			diffID, size, err = ls.checksumForGraphIDNoTarsplit(id, parent, newTarDataPath)
    19  		}
    20  	}()
    21  
    22  	if oldTarDataPath == "" {
    23  		err = errors.New("no tar-split file")
    24  		return
    25  	}
    26  
    27  	tarDataFile, err := os.Open(oldTarDataPath)
    28  	if err != nil {
    29  		return
    30  	}
    31  	defer tarDataFile.Close()
    32  	uncompressed, err := gzip.NewReader(tarDataFile)
    33  	if err != nil {
    34  		return
    35  	}
    36  
    37  	dgst := digest.Canonical.Digester()
    38  	err = ls.assembleTarTo(id, uncompressed, &size, dgst.Hash())
    39  	if err != nil {
    40  		return
    41  	}
    42  
    43  	diffID = DiffID(dgst.Digest())
    44  	err = os.RemoveAll(newTarDataPath)
    45  	if err != nil {
    46  		return
    47  	}
    48  	err = os.Link(oldTarDataPath, newTarDataPath)
    49  
    50  	return
    51  }
    52  
    53  func (ls *layerStore) checksumForGraphIDNoTarsplit(id, parent, newTarDataPath string) (diffID DiffID, size int64, err error) {
    54  	rawarchive, err := ls.driver.Diff(id, parent)
    55  	if err != nil {
    56  		return
    57  	}
    58  	defer rawarchive.Close()
    59  
    60  	f, err := os.Create(newTarDataPath)
    61  	if err != nil {
    62  		return
    63  	}
    64  	defer f.Close()
    65  	mfz := gzip.NewWriter(f)
    66  	defer mfz.Close()
    67  	metaPacker := storage.NewJSONPacker(mfz)
    68  
    69  	packerCounter := &packSizeCounter{metaPacker, &size}
    70  
    71  	archive, err := asm.NewInputTarStream(rawarchive, packerCounter, nil)
    72  	if err != nil {
    73  		return
    74  	}
    75  	dgst, err := digest.FromReader(archive)
    76  	if err != nil {
    77  		return
    78  	}
    79  	diffID = DiffID(dgst)
    80  	return
    81  }
    82  
    83  func (ls *layerStore) RegisterByGraphID(graphID string, parent ChainID, diffID DiffID, tarDataFile string, size int64) (Layer, error) {
    84  	// err is used to hold the error which will always trigger
    85  	// cleanup of creates sources but may not be an error returned
    86  	// to the caller (already exists).
    87  	var err error
    88  	var p *roLayer
    89  	if string(parent) != "" {
    90  		ls.layerL.Lock()
    91  		p = ls.get(parent)
    92  		ls.layerL.Unlock()
    93  		if p == nil {
    94  			return nil, ErrLayerDoesNotExist
    95  		}
    96  
    97  		// Release parent chain if error
    98  		defer func() {
    99  			if err != nil {
   100  				ls.layerL.Lock()
   101  				ls.releaseLayer(p)
   102  				ls.layerL.Unlock()
   103  			}
   104  		}()
   105  	}
   106  
   107  	// Create new roLayer
   108  	layer := &roLayer{
   109  		parent:         p,
   110  		cacheID:        graphID,
   111  		referenceCount: 1,
   112  		layerStore:     ls,
   113  		references:     map[Layer]struct{}{},
   114  		diffID:         diffID,
   115  		size:           size,
   116  		chainID:        createChainIDFromParent(parent, diffID),
   117  	}
   118  
   119  	ls.layerL.Lock()
   120  	defer ls.layerL.Unlock()
   121  
   122  	if existingLayer := ls.get(layer.chainID); existingLayer != nil {
   123  		// Set error for cleanup, but do not return
   124  		err = errors.New("layer already exists")
   125  		return existingLayer.getReference(), nil
   126  	}
   127  
   128  	tx, err := ls.store.StartTransaction()
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	defer func() {
   134  		if err != nil {
   135  			logrus.Debugf("Cleaning up transaction after failed migration for %s: %v", graphID, err)
   136  			if err := tx.Cancel(); err != nil {
   137  				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err)
   138  			}
   139  		}
   140  	}()
   141  
   142  	tsw, err := tx.TarSplitWriter(false)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	defer tsw.Close()
   147  	tdf, err := os.Open(tarDataFile)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	defer tdf.Close()
   152  	_, err = io.Copy(tsw, tdf)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	if err = storeLayer(tx, layer); err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	if err = tx.Commit(layer.chainID); err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	ls.layerMap[layer.chainID] = layer
   166  
   167  	return layer.getReference(), nil
   168  }
   169  
   170  type unpackSizeCounter struct {
   171  	unpacker storage.Unpacker
   172  	size     *int64
   173  }
   174  
   175  func (u *unpackSizeCounter) Next() (*storage.Entry, error) {
   176  	e, err := u.unpacker.Next()
   177  	if err == nil && u.size != nil {
   178  		*u.size += e.Size
   179  	}
   180  	return e, err
   181  }
   182  
   183  type packSizeCounter struct {
   184  	packer storage.Packer
   185  	size   *int64
   186  }
   187  
   188  func (p *packSizeCounter) AddEntry(e storage.Entry) (int, error) {
   189  	n, err := p.packer.AddEntry(e)
   190  	if err == nil && p.size != nil {
   191  		*p.size += e.Size
   192  	}
   193  	return n, err
   194  }