github.com/containerd/Containerd@v1.4.13/metadata/snapshot.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package metadata 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/containerd/containerd/errdefs" 28 "github.com/containerd/containerd/filters" 29 "github.com/containerd/containerd/labels" 30 "github.com/containerd/containerd/log" 31 "github.com/containerd/containerd/metadata/boltutil" 32 "github.com/containerd/containerd/mount" 33 "github.com/containerd/containerd/namespaces" 34 "github.com/containerd/containerd/snapshots" 35 "github.com/pkg/errors" 36 bolt "go.etcd.io/bbolt" 37 ) 38 39 const ( 40 inheritedLabelsPrefix = "containerd.io/snapshot/" 41 labelSnapshotRef = "containerd.io/snapshot.ref" 42 ) 43 44 type snapshotter struct { 45 snapshots.Snapshotter 46 name string 47 db *DB 48 l sync.RWMutex 49 } 50 51 // newSnapshotter returns a new Snapshotter which namespaces the given snapshot 52 // using the provided name and database. 53 func newSnapshotter(db *DB, name string, sn snapshots.Snapshotter) *snapshotter { 54 return &snapshotter{ 55 Snapshotter: sn, 56 name: name, 57 db: db, 58 } 59 } 60 61 func createKey(id uint64, namespace, key string) string { 62 return fmt.Sprintf("%s/%d/%s", namespace, id, key) 63 } 64 65 func getKey(tx *bolt.Tx, ns, name, key string) string { 66 bkt := getSnapshotterBucket(tx, ns, name) 67 if bkt == nil { 68 return "" 69 } 70 bkt = bkt.Bucket([]byte(key)) 71 if bkt == nil { 72 return "" 73 } 74 v := bkt.Get(bucketKeyName) 75 if len(v) == 0 { 76 return "" 77 } 78 return string(v) 79 } 80 81 func (s *snapshotter) resolveKey(ctx context.Context, key string) (string, error) { 82 ns, err := namespaces.NamespaceRequired(ctx) 83 if err != nil { 84 return "", err 85 } 86 87 var id string 88 if err := view(ctx, s.db, func(tx *bolt.Tx) error { 89 id = getKey(tx, ns, s.name, key) 90 if id == "" { 91 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) 92 } 93 return nil 94 }); err != nil { 95 return "", err 96 } 97 98 return id, nil 99 } 100 101 func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { 102 ns, err := namespaces.NamespaceRequired(ctx) 103 if err != nil { 104 return snapshots.Info{}, err 105 } 106 107 var ( 108 bkey string 109 local = snapshots.Info{ 110 Name: key, 111 } 112 ) 113 if err := view(ctx, s.db, func(tx *bolt.Tx) error { 114 bkt := getSnapshotterBucket(tx, ns, s.name) 115 if bkt == nil { 116 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) 117 } 118 sbkt := bkt.Bucket([]byte(key)) 119 if sbkt == nil { 120 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) 121 } 122 local.Labels, err = boltutil.ReadLabels(sbkt) 123 if err != nil { 124 return errors.Wrap(err, "failed to read labels") 125 } 126 if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { 127 return errors.Wrap(err, "failed to read timestamps") 128 } 129 bkey = string(sbkt.Get(bucketKeyName)) 130 local.Parent = string(sbkt.Get(bucketKeyParent)) 131 132 return nil 133 }); err != nil { 134 return snapshots.Info{}, err 135 } 136 137 info, err := s.Snapshotter.Stat(ctx, bkey) 138 if err != nil { 139 return snapshots.Info{}, err 140 } 141 142 return overlayInfo(info, local), nil 143 } 144 145 func (s *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { 146 s.l.RLock() 147 defer s.l.RUnlock() 148 149 ns, err := namespaces.NamespaceRequired(ctx) 150 if err != nil { 151 return snapshots.Info{}, err 152 } 153 154 if info.Name == "" { 155 return snapshots.Info{}, errors.Wrap(errdefs.ErrInvalidArgument, "") 156 } 157 158 var ( 159 bkey string 160 local = snapshots.Info{ 161 Name: info.Name, 162 } 163 updated bool 164 ) 165 if err := update(ctx, s.db, func(tx *bolt.Tx) error { 166 bkt := getSnapshotterBucket(tx, ns, s.name) 167 if bkt == nil { 168 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) 169 } 170 sbkt := bkt.Bucket([]byte(info.Name)) 171 if sbkt == nil { 172 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) 173 } 174 175 local.Labels, err = boltutil.ReadLabels(sbkt) 176 if err != nil { 177 return errors.Wrap(err, "failed to read labels") 178 } 179 if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { 180 return errors.Wrap(err, "failed to read timestamps") 181 } 182 183 // Handle field updates 184 if len(fieldpaths) > 0 { 185 for _, path := range fieldpaths { 186 if strings.HasPrefix(path, "labels.") { 187 if local.Labels == nil { 188 local.Labels = map[string]string{} 189 } 190 191 key := strings.TrimPrefix(path, "labels.") 192 local.Labels[key] = info.Labels[key] 193 continue 194 } 195 196 switch path { 197 case "labels": 198 local.Labels = info.Labels 199 default: 200 return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) 201 } 202 } 203 } else { 204 local.Labels = info.Labels 205 } 206 if err := validateSnapshot(&local); err != nil { 207 return err 208 } 209 local.Updated = time.Now().UTC() 210 211 if err := boltutil.WriteTimestamps(sbkt, local.Created, local.Updated); err != nil { 212 return errors.Wrap(err, "failed to read timestamps") 213 } 214 if err := boltutil.WriteLabels(sbkt, local.Labels); err != nil { 215 return errors.Wrap(err, "failed to read labels") 216 } 217 bkey = string(sbkt.Get(bucketKeyName)) 218 local.Parent = string(sbkt.Get(bucketKeyParent)) 219 220 inner := snapshots.Info{ 221 Name: bkey, 222 Labels: snapshots.FilterInheritedLabels(local.Labels), 223 } 224 225 // NOTE: Perform this inside the transaction to reduce the 226 // chances of out of sync data. The backend snapshotters 227 // should perform the Update as fast as possible. 228 if info, err = s.Snapshotter.Update(ctx, inner, fieldpaths...); err != nil { 229 return err 230 } 231 updated = true 232 233 return nil 234 }); err != nil { 235 if updated { 236 log.G(ctx).WithField("snapshotter", s.name).WithField("key", local.Name).WithError(err).Error("transaction failed after updating snapshot backend") 237 } 238 return snapshots.Info{}, err 239 } 240 241 return overlayInfo(info, local), nil 242 } 243 244 func overlayInfo(info, overlay snapshots.Info) snapshots.Info { 245 // Merge info 246 info.Name = overlay.Name 247 info.Created = overlay.Created 248 info.Updated = overlay.Updated 249 info.Parent = overlay.Parent 250 if info.Labels == nil { 251 info.Labels = overlay.Labels 252 } else { 253 for k, v := range overlay.Labels { 254 info.Labels[k] = v 255 } 256 } 257 return info 258 } 259 260 func (s *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { 261 bkey, err := s.resolveKey(ctx, key) 262 if err != nil { 263 return snapshots.Usage{}, err 264 } 265 return s.Snapshotter.Usage(ctx, bkey) 266 } 267 268 func (s *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { 269 bkey, err := s.resolveKey(ctx, key) 270 if err != nil { 271 return nil, err 272 } 273 return s.Snapshotter.Mounts(ctx, bkey) 274 } 275 276 func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { 277 return s.createSnapshot(ctx, key, parent, false, opts) 278 } 279 280 func (s *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { 281 return s.createSnapshot(ctx, key, parent, true, opts) 282 } 283 284 func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, readonly bool, opts []snapshots.Opt) ([]mount.Mount, error) { 285 s.l.RLock() 286 defer s.l.RUnlock() 287 288 ns, err := namespaces.NamespaceRequired(ctx) 289 if err != nil { 290 return nil, err 291 } 292 293 var base snapshots.Info 294 for _, opt := range opts { 295 if err := opt(&base); err != nil { 296 return nil, err 297 } 298 } 299 300 if err := validateSnapshot(&base); err != nil { 301 return nil, err 302 } 303 304 var ( 305 target = base.Labels[labelSnapshotRef] 306 bparent string 307 bkey string 308 bopts = []snapshots.Opt{ 309 snapshots.WithLabels(snapshots.FilterInheritedLabels(base.Labels)), 310 } 311 ) 312 313 if err := update(ctx, s.db, func(tx *bolt.Tx) error { 314 bkt, err := createSnapshotterBucket(tx, ns, s.name) 315 if err != nil { 316 return err 317 } 318 319 // Check if target exists, if so, return already exists 320 if target != "" { 321 if tbkt := bkt.Bucket([]byte(target)); tbkt != nil { 322 return errors.Wrapf(errdefs.ErrAlreadyExists, "target snapshot %q", target) 323 } 324 } 325 326 if bbkt := bkt.Bucket([]byte(key)); bbkt != nil { 327 return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", key) 328 } 329 330 if parent != "" { 331 pbkt := bkt.Bucket([]byte(parent)) 332 if pbkt == nil { 333 return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", parent) 334 } 335 bparent = string(pbkt.Get(bucketKeyName)) 336 } 337 338 sid, err := bkt.NextSequence() 339 if err != nil { 340 return err 341 } 342 bkey = createKey(sid, ns, key) 343 344 return err 345 }); err != nil { 346 return nil, err 347 } 348 349 var ( 350 m []mount.Mount 351 created string 352 rerr error 353 ) 354 if readonly { 355 m, err = s.Snapshotter.View(ctx, bkey, bparent, bopts...) 356 } else { 357 m, err = s.Snapshotter.Prepare(ctx, bkey, bparent, bopts...) 358 } 359 360 // An already exists error should indicate the backend found a snapshot 361 // matching a provided target reference. 362 if errdefs.IsAlreadyExists(err) { 363 if target != "" { 364 var tinfo *snapshots.Info 365 filter := fmt.Sprintf(`labels."containerd.io/snapshot.ref"==%s,parent==%q`, target, bparent) 366 if err := s.Snapshotter.Walk(ctx, func(ctx context.Context, i snapshots.Info) error { 367 if tinfo == nil && i.Kind == snapshots.KindCommitted { 368 if i.Labels["containerd.io/snapshot.ref"] != target { 369 // Walk did not respect filter 370 return nil 371 } 372 if i.Parent != bparent { 373 // Walk did not respect filter 374 return nil 375 } 376 tinfo = &i 377 } 378 return nil 379 380 }, filter); err != nil { 381 return nil, errors.Wrap(err, "failed walking backend snapshots") 382 } 383 384 if tinfo == nil { 385 return nil, errors.Wrapf(errdefs.ErrNotFound, "target snapshot %q in backend", target) 386 } 387 388 key = target 389 bkey = tinfo.Name 390 bparent = tinfo.Parent 391 base.Created = tinfo.Created 392 base.Updated = tinfo.Updated 393 if base.Labels == nil { 394 base.Labels = tinfo.Labels 395 } else { 396 for k, v := range tinfo.Labels { 397 if _, ok := base.Labels[k]; !ok { 398 base.Labels[k] = v 399 } 400 } 401 } 402 403 // Propagate this error after the final update 404 rerr = errors.Wrapf(errdefs.ErrAlreadyExists, "target snapshot %q from snapshotter", target) 405 } else { 406 // This condition is unexpected as the key provided is expected 407 // to be new and unique, return as unknown response from backend 408 // to avoid confusing callers handling already exists. 409 return nil, errors.Wrapf(errdefs.ErrUnknown, "unexpected error from snapshotter: %v", err) 410 } 411 } else if err != nil { 412 return nil, err 413 } else { 414 ts := time.Now().UTC() 415 base.Created = ts 416 base.Updated = ts 417 created = bkey 418 } 419 420 if txerr := update(ctx, s.db, func(tx *bolt.Tx) error { 421 bkt := getSnapshotterBucket(tx, ns, s.name) 422 if bkt == nil { 423 return errors.Wrapf(errdefs.ErrNotFound, "can not find snapshotter %q", s.name) 424 } 425 426 if err := addSnapshotLease(ctx, tx, s.name, key); err != nil { 427 return err 428 } 429 430 bbkt, err := bkt.CreateBucket([]byte(key)) 431 if err != nil { 432 if err != bolt.ErrBucketExists { 433 return err 434 } 435 if rerr == nil { 436 rerr = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", key) 437 } 438 return nil 439 } 440 441 if parent != "" { 442 pbkt := bkt.Bucket([]byte(parent)) 443 if pbkt == nil { 444 return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", parent) 445 } 446 447 // Ensure the backend's parent matches the metadata store's parent 448 // If it is mismatched, then a target was provided for a snapshotter 449 // which has a different parent then requested. 450 // NOTE: The backend snapshotter is responsible for enforcing the 451 // uniqueness of the reference relationships, the metadata store 452 // can only error out to prevent inconsistent data. 453 if bparent != string(pbkt.Get(bucketKeyName)) { 454 return errors.Wrapf(errdefs.ErrInvalidArgument, "mismatched parent %s from target %s", parent, target) 455 } 456 457 cbkt, err := pbkt.CreateBucketIfNotExists(bucketKeyChildren) 458 if err != nil { 459 return err 460 } 461 if err := cbkt.Put([]byte(key), nil); err != nil { 462 return err 463 } 464 465 if err := bbkt.Put(bucketKeyParent, []byte(parent)); err != nil { 466 return err 467 } 468 } 469 470 if err := boltutil.WriteTimestamps(bbkt, base.Created, base.Updated); err != nil { 471 return err 472 } 473 if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { 474 return err 475 } 476 477 return bbkt.Put(bucketKeyName, []byte(bkey)) 478 }); txerr != nil { 479 rerr = txerr 480 } 481 482 if rerr != nil { 483 // If the created reference is not stored, attempt clean up 484 if created != "" { 485 if err := s.Snapshotter.Remove(ctx, created); err != nil { 486 log.G(ctx).WithField("snapshotter", s.name).WithField("key", created).WithError(err).Error("failed to cleanup unreferenced snapshot") 487 } 488 } 489 return nil, rerr 490 } 491 492 return m, nil 493 } 494 495 func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { 496 s.l.RLock() 497 defer s.l.RUnlock() 498 499 ns, err := namespaces.NamespaceRequired(ctx) 500 if err != nil { 501 return err 502 } 503 504 var base snapshots.Info 505 for _, opt := range opts { 506 if err := opt(&base); err != nil { 507 return err 508 } 509 } 510 511 if err := validateSnapshot(&base); err != nil { 512 return err 513 } 514 515 var bname string 516 if err := update(ctx, s.db, func(tx *bolt.Tx) error { 517 bkt := getSnapshotterBucket(tx, ns, s.name) 518 if bkt == nil { 519 return errors.Wrapf(errdefs.ErrNotFound, 520 "can not find snapshotter %q", s.name) 521 } 522 523 bbkt, err := bkt.CreateBucket([]byte(name)) 524 if err != nil { 525 if err == bolt.ErrBucketExists { 526 err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", name) 527 } 528 return err 529 } 530 if err := addSnapshotLease(ctx, tx, s.name, name); err != nil { 531 return err 532 } 533 534 obkt := bkt.Bucket([]byte(key)) 535 if obkt == nil { 536 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) 537 } 538 539 bkey := string(obkt.Get(bucketKeyName)) 540 541 sid, err := bkt.NextSequence() 542 if err != nil { 543 return err 544 } 545 546 nameKey := createKey(sid, ns, name) 547 548 if err := bbkt.Put(bucketKeyName, []byte(nameKey)); err != nil { 549 return err 550 } 551 552 parent := obkt.Get(bucketKeyParent) 553 if len(parent) > 0 { 554 pbkt := bkt.Bucket(parent) 555 if pbkt == nil { 556 return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", string(parent)) 557 } 558 559 cbkt, err := pbkt.CreateBucketIfNotExists(bucketKeyChildren) 560 if err != nil { 561 return err 562 } 563 if err := cbkt.Delete([]byte(key)); err != nil { 564 return err 565 } 566 if err := cbkt.Put([]byte(name), nil); err != nil { 567 return err 568 } 569 570 if err := bbkt.Put(bucketKeyParent, parent); err != nil { 571 return err 572 } 573 } 574 ts := time.Now().UTC() 575 if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { 576 return err 577 } 578 if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { 579 return err 580 } 581 582 if err := bkt.DeleteBucket([]byte(key)); err != nil { 583 return err 584 } 585 if err := removeSnapshotLease(ctx, tx, s.name, key); err != nil { 586 return err 587 } 588 589 inheritedOpt := snapshots.WithLabels(snapshots.FilterInheritedLabels(base.Labels)) 590 591 // NOTE: Backend snapshotters should commit fast and reliably to 592 // prevent metadata store locking and minimizing rollbacks. 593 // This operation should be done in the transaction to minimize the 594 // risk of the committed keys becoming out of sync. If this operation 595 // succeed and the overall transaction fails then the risk of out of 596 // sync data is higher and may require manual cleanup. 597 if err := s.Snapshotter.Commit(ctx, nameKey, bkey, inheritedOpt); err != nil { 598 if errdefs.IsNotFound(err) { 599 log.G(ctx).WithField("snapshotter", s.name).WithField("key", key).WithError(err).Error("uncommittable snapshot: missing in backend, snapshot should be removed") 600 } 601 // NOTE: Consider handling already exists here from the backend. Currently 602 // already exists from the backend may be confusing to the client since it 603 // may require the client to re-attempt from prepare. However, if handling 604 // here it is not clear what happened with the existing backend key and 605 // whether the already prepared snapshot would still be used or must be 606 // discarded. It is best that all implementations of the snapshotter 607 // interface behave the same, in which case the backend should handle the 608 // mapping of duplicates and not error. 609 return err 610 } 611 bname = nameKey 612 613 return nil 614 }); err != nil { 615 if bname != "" { 616 log.G(ctx).WithField("snapshotter", s.name).WithField("key", key).WithField("bname", bname).WithError(err).Error("uncommittable snapshot: transaction failed after commit, snapshot should be removed") 617 618 } 619 return err 620 } 621 622 return nil 623 624 } 625 626 func (s *snapshotter) Remove(ctx context.Context, key string) error { 627 s.l.RLock() 628 defer s.l.RUnlock() 629 630 ns, err := namespaces.NamespaceRequired(ctx) 631 if err != nil { 632 return err 633 } 634 635 return update(ctx, s.db, func(tx *bolt.Tx) error { 636 var sbkt *bolt.Bucket 637 bkt := getSnapshotterBucket(tx, ns, s.name) 638 if bkt != nil { 639 sbkt = bkt.Bucket([]byte(key)) 640 } 641 if sbkt == nil { 642 return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) 643 } 644 645 cbkt := sbkt.Bucket(bucketKeyChildren) 646 if cbkt != nil { 647 if child, _ := cbkt.Cursor().First(); child != nil { 648 return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot remove snapshot with child") 649 } 650 } 651 652 parent := sbkt.Get(bucketKeyParent) 653 if len(parent) > 0 { 654 pbkt := bkt.Bucket(parent) 655 if pbkt == nil { 656 return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", string(parent)) 657 } 658 cbkt := pbkt.Bucket(bucketKeyChildren) 659 if cbkt != nil { 660 if err := cbkt.Delete([]byte(key)); err != nil { 661 return errors.Wrap(err, "failed to remove child link") 662 } 663 } 664 } 665 666 if err := bkt.DeleteBucket([]byte(key)); err != nil { 667 return err 668 } 669 if err := removeSnapshotLease(ctx, tx, s.name, key); err != nil { 670 return err 671 } 672 673 // Mark snapshotter as dirty for triggering garbage collection 674 atomic.AddUint32(&s.db.dirty, 1) 675 s.db.dirtySS[s.name] = struct{}{} 676 677 return nil 678 }) 679 } 680 681 type infoPair struct { 682 bkey string 683 info snapshots.Info 684 } 685 686 func (s *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { 687 ns, err := namespaces.NamespaceRequired(ctx) 688 if err != nil { 689 return err 690 } 691 692 var ( 693 batchSize = 100 694 pairs = []infoPair{} 695 lastKey string 696 ) 697 698 filter, err := filters.ParseAll(fs...) 699 if err != nil { 700 return err 701 } 702 703 for { 704 if err := view(ctx, s.db, func(tx *bolt.Tx) error { 705 bkt := getSnapshotterBucket(tx, ns, s.name) 706 if bkt == nil { 707 return nil 708 } 709 710 c := bkt.Cursor() 711 712 var k, v []byte 713 if lastKey == "" { 714 k, v = c.First() 715 } else { 716 k, v = c.Seek([]byte(lastKey)) 717 } 718 719 for k != nil { 720 if v == nil { 721 if len(pairs) >= batchSize { 722 break 723 } 724 sbkt := bkt.Bucket(k) 725 726 pair := infoPair{ 727 bkey: string(sbkt.Get(bucketKeyName)), 728 info: snapshots.Info{ 729 Name: string(k), 730 Parent: string(sbkt.Get(bucketKeyParent)), 731 }, 732 } 733 734 err := boltutil.ReadTimestamps(sbkt, &pair.info.Created, &pair.info.Updated) 735 if err != nil { 736 return err 737 } 738 pair.info.Labels, err = boltutil.ReadLabels(sbkt) 739 if err != nil { 740 return err 741 } 742 743 pairs = append(pairs, pair) 744 } 745 746 k, v = c.Next() 747 } 748 749 lastKey = string(k) 750 751 return nil 752 }); err != nil { 753 return err 754 } 755 756 for _, pair := range pairs { 757 info, err := s.Snapshotter.Stat(ctx, pair.bkey) 758 if err != nil { 759 if errdefs.IsNotFound(err) { 760 continue 761 } 762 return err 763 } 764 765 info = overlayInfo(info, pair.info) 766 if filter.Match(adaptSnapshot(info)) { 767 if err := fn(ctx, info); err != nil { 768 return err 769 } 770 } 771 } 772 773 if lastKey == "" { 774 break 775 } 776 777 pairs = pairs[:0] 778 779 } 780 781 return nil 782 } 783 784 func validateSnapshot(info *snapshots.Info) error { 785 for k, v := range info.Labels { 786 if err := labels.Validate(k, v); err != nil { 787 return errors.Wrapf(err, "info.Labels") 788 } 789 } 790 791 return nil 792 } 793 794 func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err error) { 795 s.l.Lock() 796 t1 := time.Now() 797 defer func() { 798 s.l.Unlock() 799 if err == nil { 800 if c, ok := s.Snapshotter.(snapshots.Cleaner); ok { 801 err = c.Cleanup(ctx) 802 if errdefs.IsNotImplemented(err) { 803 err = nil 804 } 805 } 806 } 807 if err == nil { 808 d = time.Since(t1) 809 } 810 }() 811 812 seen := map[string]struct{}{} 813 if err := s.db.View(func(tx *bolt.Tx) error { 814 v1bkt := tx.Bucket(bucketKeyVersion) 815 if v1bkt == nil { 816 return nil 817 } 818 819 // iterate through each namespace 820 v1c := v1bkt.Cursor() 821 822 for k, v := v1c.First(); k != nil; k, v = v1c.Next() { 823 if v != nil { 824 continue 825 } 826 827 sbkt := v1bkt.Bucket(k).Bucket(bucketKeyObjectSnapshots) 828 if sbkt == nil { 829 continue 830 } 831 832 // Load specific snapshotter 833 ssbkt := sbkt.Bucket([]byte(s.name)) 834 if ssbkt == nil { 835 continue 836 } 837 838 if err := ssbkt.ForEach(func(sk, sv []byte) error { 839 if sv == nil { 840 bkey := ssbkt.Bucket(sk).Get(bucketKeyName) 841 if len(bkey) > 0 { 842 seen[string(bkey)] = struct{}{} 843 } 844 } 845 return nil 846 }); err != nil { 847 return err 848 } 849 } 850 851 return nil 852 }); err != nil { 853 return 0, err 854 } 855 856 roots, err := s.walkTree(ctx, seen) 857 if err != nil { 858 return 0, err 859 } 860 861 // TODO: Unlock before removal (once nodes are fully unavailable). 862 // This could be achieved through doing prune inside the lock 863 // and having a cleanup method which actually performs the 864 // deletions on the snapshotters which support it. 865 866 for _, node := range roots { 867 if err := s.pruneBranch(ctx, node); err != nil { 868 return 0, err 869 } 870 } 871 872 return 873 } 874 875 type treeNode struct { 876 info snapshots.Info 877 remove bool 878 children []*treeNode 879 } 880 881 func (s *snapshotter) walkTree(ctx context.Context, seen map[string]struct{}) ([]*treeNode, error) { 882 roots := []*treeNode{} 883 nodes := map[string]*treeNode{} 884 885 if err := s.Snapshotter.Walk(ctx, func(ctx context.Context, info snapshots.Info) error { 886 _, isSeen := seen[info.Name] 887 node, ok := nodes[info.Name] 888 if !ok { 889 node = &treeNode{} 890 nodes[info.Name] = node 891 } 892 893 node.remove = !isSeen 894 node.info = info 895 896 if info.Parent == "" { 897 roots = append(roots, node) 898 } else { 899 parent, ok := nodes[info.Parent] 900 if !ok { 901 parent = &treeNode{} 902 nodes[info.Parent] = parent 903 } 904 parent.children = append(parent.children, node) 905 } 906 907 return nil 908 }); err != nil { 909 return nil, err 910 } 911 912 return roots, nil 913 } 914 915 func (s *snapshotter) pruneBranch(ctx context.Context, node *treeNode) error { 916 for _, child := range node.children { 917 if err := s.pruneBranch(ctx, child); err != nil { 918 return err 919 } 920 } 921 922 if node.remove { 923 logger := log.G(ctx).WithField("snapshotter", s.name) 924 if err := s.Snapshotter.Remove(ctx, node.info.Name); err != nil { 925 if !errdefs.IsFailedPrecondition(err) { 926 return err 927 } 928 logger.WithError(err).WithField("key", node.info.Name).Warnf("failed to remove snapshot") 929 } else { 930 logger.WithField("key", node.info.Name).Debug("removed snapshot") 931 } 932 } 933 934 return nil 935 } 936 937 // Close closes s.Snapshotter but not db 938 func (s *snapshotter) Close() error { 939 return s.Snapshotter.Close() 940 }