github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/layer/migration.go (about)

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