github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/layer/migration.go (about) 1 package layer // import "github.com/docker/docker/layer" 2 3 import ( 4 "compress/gzip" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 10 "github.com/opencontainers/go-digest" 11 "github.com/sirupsen/logrus" 12 "github.com/vbatts/tar-split/tar/asm" 13 "github.com/vbatts/tar-split/tar/storage" 14 ) 15 16 // CreateRWLayerByGraphID creates a RWLayer in the layer store using 17 // the provided name with the given graphID. To get the RWLayer 18 // after migration the layer may be retrieved by the given name. 19 func (ls *layerStore) CreateRWLayerByGraphID(name, graphID string, parent ChainID) (err error) { 20 ls.mountL.Lock() 21 defer ls.mountL.Unlock() 22 m, ok := ls.mounts[name] 23 if ok { 24 if m.parent.chainID != parent { 25 return errors.New("name conflict, mismatched parent") 26 } 27 if m.mountID != graphID { 28 return errors.New("mount already exists") 29 } 30 31 return nil 32 } 33 34 if !ls.driver.Exists(graphID) { 35 return fmt.Errorf("graph ID does not exist: %q", graphID) 36 } 37 38 var p *roLayer 39 if string(parent) != "" { 40 p = ls.get(parent) 41 if p == nil { 42 return ErrLayerDoesNotExist 43 } 44 45 // Release parent chain if error 46 defer func() { 47 if err != nil { 48 ls.layerL.Lock() 49 ls.releaseLayer(p) 50 ls.layerL.Unlock() 51 } 52 }() 53 } 54 55 // TODO: Ensure graphID has correct parent 56 57 m = &mountedLayer{ 58 name: name, 59 parent: p, 60 mountID: graphID, 61 layerStore: ls, 62 references: map[RWLayer]*referencedRWLayer{}, 63 } 64 65 // Check for existing init layer 66 initID := fmt.Sprintf("%s-init", graphID) 67 if ls.driver.Exists(initID) { 68 m.initID = initID 69 } 70 71 return ls.saveMount(m) 72 } 73 74 func (ls *layerStore) ChecksumForGraphID(id, parent, oldTarDataPath, newTarDataPath string) (diffID DiffID, size int64, err error) { 75 defer func() { 76 if err != nil { 77 logrus.Debugf("could not get checksum for %q with tar-split: %q", id, err) 78 diffID, size, err = ls.checksumForGraphIDNoTarsplit(id, parent, newTarDataPath) 79 } 80 }() 81 82 if oldTarDataPath == "" { 83 err = errors.New("no tar-split file") 84 return 85 } 86 87 tarDataFile, err := os.Open(oldTarDataPath) 88 if err != nil { 89 return 90 } 91 defer tarDataFile.Close() 92 uncompressed, err := gzip.NewReader(tarDataFile) 93 if err != nil { 94 return 95 } 96 97 dgst := digest.Canonical.Digester() 98 err = ls.assembleTarTo(id, uncompressed, &size, dgst.Hash()) 99 if err != nil { 100 return 101 } 102 103 diffID = DiffID(dgst.Digest()) 104 err = os.RemoveAll(newTarDataPath) 105 if err != nil { 106 return 107 } 108 err = os.Link(oldTarDataPath, newTarDataPath) 109 110 return 111 } 112 113 func (ls *layerStore) checksumForGraphIDNoTarsplit(id, parent, newTarDataPath string) (diffID DiffID, size int64, err error) { 114 rawarchive, err := ls.driver.Diff(id, parent) 115 if err != nil { 116 return 117 } 118 defer rawarchive.Close() 119 120 f, err := os.Create(newTarDataPath) 121 if err != nil { 122 return 123 } 124 defer f.Close() 125 mfz := gzip.NewWriter(f) 126 defer mfz.Close() 127 metaPacker := storage.NewJSONPacker(mfz) 128 129 packerCounter := &packSizeCounter{metaPacker, &size} 130 131 archive, err := asm.NewInputTarStream(rawarchive, packerCounter, nil) 132 if err != nil { 133 return 134 } 135 dgst, err := digest.FromReader(archive) 136 if err != nil { 137 return 138 } 139 diffID = DiffID(dgst) 140 return 141 } 142 143 func (ls *layerStore) RegisterByGraphID(graphID string, parent ChainID, diffID DiffID, tarDataFile string, size int64) (Layer, error) { 144 // err is used to hold the error which will always trigger 145 // cleanup of creates sources but may not be an error returned 146 // to the caller (already exists). 147 var err error 148 var p *roLayer 149 if string(parent) != "" { 150 p = ls.get(parent) 151 if p == nil { 152 return nil, ErrLayerDoesNotExist 153 } 154 155 // Release parent chain if error 156 defer func() { 157 if err != nil { 158 ls.layerL.Lock() 159 ls.releaseLayer(p) 160 ls.layerL.Unlock() 161 } 162 }() 163 } 164 165 // Create new roLayer 166 layer := &roLayer{ 167 parent: p, 168 cacheID: graphID, 169 referenceCount: 1, 170 layerStore: ls, 171 references: map[Layer]struct{}{}, 172 diffID: diffID, 173 size: size, 174 chainID: createChainIDFromParent(parent, diffID), 175 } 176 177 ls.layerL.Lock() 178 defer ls.layerL.Unlock() 179 180 if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil { 181 // Set error for cleanup, but do not return 182 err = errors.New("layer already exists") 183 return existingLayer.getReference(), nil 184 } 185 186 tx, err := ls.store.StartTransaction() 187 if err != nil { 188 return nil, err 189 } 190 191 defer func() { 192 if err != nil { 193 logrus.Debugf("Cleaning up transaction after failed migration for %s: %v", graphID, err) 194 if err := tx.Cancel(); err != nil { 195 logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err) 196 } 197 } 198 }() 199 200 tsw, err := tx.TarSplitWriter(false) 201 if err != nil { 202 return nil, err 203 } 204 defer tsw.Close() 205 tdf, err := os.Open(tarDataFile) 206 if err != nil { 207 return nil, err 208 } 209 defer tdf.Close() 210 _, err = io.Copy(tsw, tdf) 211 if err != nil { 212 return nil, err 213 } 214 215 if err = storeLayer(tx, layer); err != nil { 216 return nil, err 217 } 218 219 if err = tx.Commit(layer.chainID); err != nil { 220 return nil, err 221 } 222 223 ls.layerMap[layer.chainID] = layer 224 225 return layer.getReference(), nil 226 } 227 228 type unpackSizeCounter struct { 229 unpacker storage.Unpacker 230 size *int64 231 } 232 233 func (u *unpackSizeCounter) Next() (*storage.Entry, error) { 234 e, err := u.unpacker.Next() 235 if err == nil && u.size != nil { 236 *u.size += e.Size 237 } 238 return e, err 239 } 240 241 type packSizeCounter struct { 242 packer storage.Packer 243 size *int64 244 } 245 246 func (p *packSizeCounter) AddEntry(e storage.Entry) (int, error) { 247 n, err := p.packer.AddEntry(e) 248 if err == nil && p.size != nil { 249 *p.size += e.Size 250 } 251 return n, err 252 }