package snapshot import ( "context" "sync" "github.com/containerd/containerd/leases" "github.com/sirupsen/logrus" bolt "go.etcd.io/bbolt" ) type sLM struct { manager leases.Manager s *snapshotter mu sync.Mutex byLease map[string]map[string]struct{} bySnapshot map[string]map[string]struct{} } func newLeaseManager(s *snapshotter, lm leases.Manager) *sLM { return &sLM{ s: s, manager: lm, byLease: map[string]map[string]struct{}{}, bySnapshot: map[string]map[string]struct{}{}, } } func (l *sLM) Create(ctx context.Context, opts ...leases.Opt) (leases.Lease, error) { return l.manager.Create(ctx, opts...) } func (l *sLM) Delete(ctx context.Context, lease leases.Lease, opts ...leases.DeleteOpt) error { if err := l.manager.Delete(ctx, lease, opts...); err != nil { return err } l.mu.Lock() if snaps, ok := l.byLease[lease.ID]; ok { for sID := range snaps { l.delRef(lease.ID, sID) } } l.mu.Unlock() return nil } func (l *sLM) List(ctx context.Context, filters ...string) ([]leases.Lease, error) { return l.manager.List(ctx, filters...) } func (l *sLM) AddResource(ctx context.Context, lease leases.Lease, resource leases.Resource) error { if err := l.manager.AddResource(ctx, lease, resource); err != nil { return err } if resource.Type == "snapshots/default" { l.mu.Lock() l.addRef(lease.ID, resource.ID) l.mu.Unlock() } return nil } func (l *sLM) DeleteResource(ctx context.Context, lease leases.Lease, resource leases.Resource) error { if err := l.manager.DeleteResource(ctx, lease, resource); err != nil { return err } if resource.Type == "snapshots/default" { l.mu.Lock() l.delRef(lease.ID, resource.ID) l.mu.Unlock() } return nil } func (l *sLM) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) { return l.manager.ListResources(ctx, lease) } func (l *sLM) addRef(lID, sID string) { load := false snapshots, ok := l.byLease[lID] if !ok { snapshots = map[string]struct{}{} l.byLease[lID] = snapshots } if _, ok := snapshots[sID]; !ok { snapshots[sID] = struct{}{} } leases, ok := l.bySnapshot[sID] if !ok { leases = map[string]struct{}{} l.byLease[sID] = leases load = true } if _, ok := leases[lID]; !ok { leases[lID] = struct{}{} } if load { l.s.getLayer(sID, true) if _, ok := l.s.chainID(sID); ok { l.s.db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(lID)) if err != nil { return err } return b.Put(keyChainID, []byte(sID)) }) } } } func (l *sLM) delRef(lID, sID string) { snapshots, ok := l.byLease[lID] if !ok { delete(snapshots, sID) if len(snapshots) == 0 { delete(l.byLease, lID) } } leases, ok := l.bySnapshot[sID] if !ok { delete(leases, lID) if len(leases) == 0 { delete(l.bySnapshot, sID) if err := l.s.remove(context.TODO(), sID); err != nil { logrus.Warnf("failed to remove snapshot %v", sID) } } } }