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 }