github.com/moby/docker@v26.1.3+incompatible/builder/builder-next/adapters/snapshot/layer.go (about)

     1  package snapshot
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/docker/docker/layer"
     9  	"github.com/docker/docker/pkg/longpath"
    10  	"github.com/pkg/errors"
    11  	bolt "go.etcd.io/bbolt"
    12  	"golang.org/x/sync/errgroup"
    13  )
    14  
    15  func (s *snapshotter) GetDiffIDs(ctx context.Context, key string) ([]layer.DiffID, error) {
    16  	if l, err := s.getLayer(key, true); err != nil {
    17  		return nil, err
    18  	} else if l != nil {
    19  		return getDiffChain(l), nil
    20  	}
    21  	return nil, nil
    22  }
    23  
    24  func (s *snapshotter) EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error) {
    25  	s.layerCreateLocker.Lock(key)
    26  	defer s.layerCreateLocker.Unlock(key)
    27  
    28  	diffIDs, err := s.GetDiffIDs(ctx, key)
    29  	if err != nil {
    30  		return nil, err
    31  	} else if diffIDs != nil {
    32  		return diffIDs, nil
    33  	}
    34  
    35  	id, committed := s.getGraphDriverID(key)
    36  	if !committed {
    37  		return nil, errors.Errorf("can not convert active %s to layer", key)
    38  	}
    39  
    40  	info, err := s.Stat(ctx, key)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	eg, gctx := errgroup.WithContext(ctx)
    46  
    47  	// TODO: add flightcontrol
    48  
    49  	var parentChainID layer.ChainID
    50  	if info.Parent != "" {
    51  		eg.Go(func() error {
    52  			diffIDs, err := s.EnsureLayer(gctx, info.Parent)
    53  			if err != nil {
    54  				return err
    55  			}
    56  			parentChainID = layer.CreateChainID(diffIDs)
    57  			return nil
    58  		})
    59  	}
    60  
    61  	tmpDir, err := longpath.MkdirTemp("", "docker-tarsplit")
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	defer os.RemoveAll(tmpDir)
    66  	tarSplitPath := filepath.Join(tmpDir, "tar-split")
    67  
    68  	var diffID layer.DiffID
    69  	var size int64
    70  	eg.Go(func() error {
    71  		parent := ""
    72  		if p := info.Parent; p != "" {
    73  			if l, err := s.getLayer(p, true); err != nil {
    74  				return err
    75  			} else if l != nil {
    76  				parent, err = getGraphID(l)
    77  				if err != nil {
    78  					return err
    79  				}
    80  			} else {
    81  				parent, _ = s.getGraphDriverID(info.Parent)
    82  			}
    83  		}
    84  		diffID, size, err = s.reg.ChecksumForGraphID(id, parent, tarSplitPath)
    85  		return err
    86  	})
    87  
    88  	if err := eg.Wait(); err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	l, err := s.reg.RegisterByGraphID(id, parentChainID, diffID, tarSplitPath, size)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	if err := s.db.Update(func(tx *bolt.Tx) error {
    98  		b := tx.Bucket([]byte(key))
    99  		b.Put(keyChainID, []byte(l.ChainID()))
   100  		return nil
   101  	}); err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	s.mu.Lock()
   106  	s.refs[key] = l
   107  	s.mu.Unlock()
   108  
   109  	return getDiffChain(l), nil
   110  }
   111  
   112  func getDiffChain(l layer.Layer) []layer.DiffID {
   113  	if p := l.Parent(); p != nil {
   114  		return append(getDiffChain(p), l.DiffID())
   115  	}
   116  	return []layer.DiffID{l.DiffID()}
   117  }
   118  
   119  func getGraphID(l layer.Layer) (string, error) {
   120  	if l, ok := l.(interface {
   121  		CacheID() string
   122  	}); ok {
   123  		return l.CacheID(), nil
   124  	}
   125  	return "", errors.Errorf("couldn't access cacheID for %s", l.ChainID())
   126  }