github.com/lalkh/containerd@v1.4.3/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  }