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 }