github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/builder/builder-next/adapters/snapshot/snapshot.go (about) 1 package snapshot 2 3 import ( 4 "context" 5 "path/filepath" 6 "strconv" 7 "strings" 8 "sync" 9 10 "github.com/containerd/containerd/mount" 11 "github.com/containerd/containerd/snapshots" 12 "github.com/docker/docker/daemon/graphdriver" 13 "github.com/docker/docker/layer" 14 "github.com/moby/buildkit/identity" 15 "github.com/moby/buildkit/snapshot" 16 digest "github.com/opencontainers/go-digest" 17 "github.com/pkg/errors" 18 bolt "go.etcd.io/bbolt" 19 ) 20 21 var keyParent = []byte("parent") 22 var keyCommitted = []byte("committed") 23 var keyChainID = []byte("chainid") 24 var keySize = []byte("size") 25 26 // Opt defines options for creating the snapshotter 27 type Opt struct { 28 GraphDriver graphdriver.Driver 29 LayerStore layer.Store 30 Root string 31 } 32 33 type graphIDRegistrar interface { 34 RegisterByGraphID(string, layer.ChainID, layer.DiffID, string, int64) (layer.Layer, error) 35 Release(layer.Layer) ([]layer.Metadata, error) 36 checksumCalculator 37 } 38 39 type checksumCalculator interface { 40 ChecksumForGraphID(id, parent, oldTarDataPath, newTarDataPath string) (diffID layer.DiffID, size int64, err error) 41 } 42 43 type snapshotter struct { 44 opt Opt 45 46 refs map[string]layer.Layer 47 db *bolt.DB 48 mu sync.Mutex 49 reg graphIDRegistrar 50 } 51 52 var _ snapshot.SnapshotterBase = &snapshotter{} 53 54 // NewSnapshotter creates a new snapshotter 55 func NewSnapshotter(opt Opt) (snapshot.SnapshotterBase, error) { 56 dbPath := filepath.Join(opt.Root, "snapshots.db") 57 db, err := bolt.Open(dbPath, 0600, nil) 58 if err != nil { 59 return nil, errors.Wrapf(err, "failed to open database file %s", dbPath) 60 } 61 62 reg, ok := opt.LayerStore.(graphIDRegistrar) 63 if !ok { 64 return nil, errors.Errorf("layerstore doesn't support graphID registration") 65 } 66 67 s := &snapshotter{ 68 opt: opt, 69 db: db, 70 refs: map[string]layer.Layer{}, 71 reg: reg, 72 } 73 return s, nil 74 } 75 76 func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) error { 77 origParent := parent 78 if parent != "" { 79 if l, err := s.getLayer(parent, false); err != nil { 80 return err 81 } else if l != nil { 82 parent, err = getGraphID(l) 83 if err != nil { 84 return err 85 } 86 } else { 87 parent, _ = s.getGraphDriverID(parent) 88 } 89 } 90 if err := s.opt.GraphDriver.Create(key, parent, nil); err != nil { 91 return err 92 } 93 return s.db.Update(func(tx *bolt.Tx) error { 94 b, err := tx.CreateBucketIfNotExists([]byte(key)) 95 if err != nil { 96 return err 97 } 98 return b.Put(keyParent, []byte(origParent)) 99 }) 100 } 101 102 func (s *snapshotter) chainID(key string) (layer.ChainID, bool) { 103 if strings.HasPrefix(key, "sha256:") { 104 dgst, err := digest.Parse(key) 105 if err != nil { 106 return "", false 107 } 108 return layer.ChainID(dgst), true 109 } 110 return "", false 111 } 112 113 func (s *snapshotter) GetLayer(key string) (layer.Layer, error) { 114 return s.getLayer(key, true) 115 } 116 117 func (s *snapshotter) getLayer(key string, withCommitted bool) (layer.Layer, error) { 118 s.mu.Lock() 119 l, ok := s.refs[key] 120 if !ok { 121 id, ok := s.chainID(key) 122 if !ok { 123 if !withCommitted { 124 s.mu.Unlock() 125 return nil, nil 126 } 127 if err := s.db.View(func(tx *bolt.Tx) error { 128 b := tx.Bucket([]byte(key)) 129 if b == nil { 130 return nil 131 } 132 v := b.Get(keyChainID) 133 if v != nil { 134 id = layer.ChainID(v) 135 } 136 return nil 137 }); err != nil { 138 s.mu.Unlock() 139 return nil, err 140 } 141 if id == "" { 142 s.mu.Unlock() 143 return nil, nil 144 } 145 } 146 var err error 147 l, err = s.opt.LayerStore.Get(id) 148 if err != nil { 149 s.mu.Unlock() 150 return nil, err 151 } 152 s.refs[key] = l 153 if err := s.db.Update(func(tx *bolt.Tx) error { 154 _, err := tx.CreateBucketIfNotExists([]byte(key)) 155 return err 156 }); err != nil { 157 s.mu.Unlock() 158 return nil, err 159 } 160 } 161 s.mu.Unlock() 162 163 return l, nil 164 } 165 166 func (s *snapshotter) getGraphDriverID(key string) (string, bool) { 167 var gdID string 168 if err := s.db.View(func(tx *bolt.Tx) error { 169 b := tx.Bucket([]byte(key)) 170 if b == nil { 171 return errors.Errorf("not found") // TODO: typed 172 } 173 v := b.Get(keyCommitted) 174 if v != nil { 175 gdID = string(v) 176 } 177 return nil 178 }); err != nil || gdID == "" { 179 return key, false 180 } 181 return gdID, true 182 } 183 184 func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { 185 inf := snapshots.Info{ 186 Kind: snapshots.KindActive, 187 } 188 189 l, err := s.getLayer(key, false) 190 if err != nil { 191 return snapshots.Info{}, err 192 } 193 if l != nil { 194 if p := l.Parent(); p != nil { 195 inf.Parent = p.ChainID().String() 196 } 197 inf.Kind = snapshots.KindCommitted 198 inf.Name = key 199 return inf, nil 200 } 201 202 l, err = s.getLayer(key, true) 203 if err != nil { 204 return snapshots.Info{}, err 205 } 206 207 id, committed := s.getGraphDriverID(key) 208 if committed { 209 inf.Kind = snapshots.KindCommitted 210 } 211 212 if err := s.db.View(func(tx *bolt.Tx) error { 213 b := tx.Bucket([]byte(id)) 214 if b == nil && l == nil { 215 return errors.Errorf("snapshot %s not found", id) // TODO: typed 216 } 217 inf.Name = key 218 if b != nil { 219 v := b.Get(keyParent) 220 if v != nil { 221 inf.Parent = string(v) 222 return nil 223 } 224 } 225 if l != nil { 226 if p := l.Parent(); p != nil { 227 inf.Parent = p.ChainID().String() 228 } 229 inf.Kind = snapshots.KindCommitted 230 } 231 return nil 232 }); err != nil { 233 return snapshots.Info{}, err 234 } 235 return inf, nil 236 } 237 238 func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountable, error) { 239 l, err := s.getLayer(key, true) 240 if err != nil { 241 return nil, err 242 } 243 if l != nil { 244 id := identity.NewID() 245 var rwlayer layer.RWLayer 246 return &mountable{ 247 acquire: func() ([]mount.Mount, error) { 248 rwlayer, err = s.opt.LayerStore.CreateRWLayer(id, l.ChainID(), nil) 249 if err != nil { 250 return nil, err 251 } 252 rootfs, err := rwlayer.Mount("") 253 if err != nil { 254 return nil, err 255 } 256 return []mount.Mount{{ 257 Source: rootfs.Path(), 258 Type: "bind", 259 Options: []string{"rbind"}, 260 }}, nil 261 }, 262 release: func() error { 263 _, err := s.opt.LayerStore.ReleaseRWLayer(rwlayer) 264 return err 265 }, 266 }, nil 267 } 268 269 id, _ := s.getGraphDriverID(key) 270 271 return &mountable{ 272 acquire: func() ([]mount.Mount, error) { 273 rootfs, err := s.opt.GraphDriver.Get(id, "") 274 if err != nil { 275 return nil, err 276 } 277 return []mount.Mount{{ 278 Source: rootfs.Path(), 279 Type: "bind", 280 Options: []string{"rbind"}, 281 }}, nil 282 }, 283 release: func() error { 284 return s.opt.GraphDriver.Put(id) 285 }, 286 }, nil 287 } 288 289 func (s *snapshotter) Remove(ctx context.Context, key string) error { 290 l, err := s.getLayer(key, true) 291 if err != nil { 292 return err 293 } 294 295 id, _ := s.getGraphDriverID(key) 296 297 var found bool 298 if err := s.db.Update(func(tx *bolt.Tx) error { 299 found = tx.Bucket([]byte(key)) != nil 300 if found { 301 tx.DeleteBucket([]byte(key)) 302 if id != key { 303 tx.DeleteBucket([]byte(id)) 304 } 305 } 306 return nil 307 }); err != nil { 308 return err 309 } 310 311 if l != nil { 312 s.mu.Lock() 313 delete(s.refs, key) 314 s.mu.Unlock() 315 _, err := s.opt.LayerStore.Release(l) 316 return err 317 } 318 319 if !found { // this happens when removing views 320 return nil 321 } 322 323 return s.opt.GraphDriver.Remove(id) 324 } 325 326 func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { 327 return s.db.Update(func(tx *bolt.Tx) error { 328 b, err := tx.CreateBucketIfNotExists([]byte(name)) 329 if err != nil { 330 return err 331 } 332 return b.Put(keyCommitted, []byte(key)) 333 }) 334 } 335 336 func (s *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) (snapshot.Mountable, error) { 337 return s.Mounts(ctx, parent) 338 } 339 340 func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { 341 return errors.Errorf("not-implemented") 342 } 343 344 func (s *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { 345 // not implemented 346 return s.Stat(ctx, info.Name) 347 } 348 349 func (s *snapshotter) Usage(ctx context.Context, key string) (us snapshots.Usage, retErr error) { 350 usage := snapshots.Usage{} 351 if l, err := s.getLayer(key, true); err != nil { 352 return usage, err 353 } else if l != nil { 354 s, err := l.DiffSize() 355 if err != nil { 356 return usage, err 357 } 358 usage.Size = s 359 return usage, nil 360 } 361 362 size := int64(-1) 363 if err := s.db.View(func(tx *bolt.Tx) error { 364 b := tx.Bucket([]byte(key)) 365 if b == nil { 366 return nil 367 } 368 v := b.Get(keySize) 369 if v != nil { 370 s, err := strconv.Atoi(string(v)) 371 if err != nil { 372 return err 373 } 374 size = int64(s) 375 } 376 return nil 377 }); err != nil { 378 return usage, err 379 } 380 381 if size != -1 { 382 usage.Size = size 383 return usage, nil 384 } 385 386 id, _ := s.getGraphDriverID(key) 387 388 info, err := s.Stat(ctx, key) 389 if err != nil { 390 return usage, err 391 } 392 var parent string 393 if info.Parent != "" { 394 if l, err := s.getLayer(info.Parent, false); err != nil { 395 return usage, err 396 } else if l != nil { 397 parent, err = getGraphID(l) 398 if err != nil { 399 return usage, err 400 } 401 } else { 402 parent, _ = s.getGraphDriverID(info.Parent) 403 } 404 } 405 406 diffSize, err := s.opt.GraphDriver.DiffSize(id, parent) 407 if err != nil { 408 return usage, err 409 } 410 411 if err := s.db.Update(func(tx *bolt.Tx) error { 412 b, err := tx.CreateBucketIfNotExists([]byte(key)) 413 if err != nil { 414 return err 415 } 416 return b.Put(keySize, []byte(strconv.Itoa(int(diffSize)))) 417 }); err != nil { 418 return usage, err 419 } 420 usage.Size = diffSize 421 return usage, nil 422 } 423 424 func (s *snapshotter) Close() error { 425 return s.db.Close() 426 } 427 428 type mountable struct { 429 mu sync.Mutex 430 mounts []mount.Mount 431 acquire func() ([]mount.Mount, error) 432 release func() error 433 refCount int 434 } 435 436 func (m *mountable) Mount() ([]mount.Mount, error) { 437 m.mu.Lock() 438 defer m.mu.Unlock() 439 440 if m.mounts != nil { 441 m.refCount++ 442 return m.mounts, nil 443 } 444 445 mounts, err := m.acquire() 446 if err != nil { 447 return nil, err 448 } 449 m.mounts = mounts 450 m.refCount = 1 451 452 return m.mounts, nil 453 } 454 455 func (m *mountable) Release() error { 456 m.mu.Lock() 457 defer m.mu.Unlock() 458 459 if m.refCount > 1 { 460 m.refCount-- 461 return nil 462 } 463 464 m.refCount = 0 465 if m.release == nil { 466 return nil 467 } 468 469 m.mounts = nil 470 return m.release() 471 }