@@ -18,6 +18,7 @@ package metadata
1818
1919import (
2020 "context"
21+ "strings"
2122
2223 "github.com/containerd/containerd/errdefs"
2324 "github.com/containerd/containerd/identifiers"
@@ -140,10 +141,17 @@ func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...n
140141 }
141142 }
142143 bkt := getBucket (s .tx , bucketKeyVersion )
143- if empty , err := s .namespaceEmpty (ctx , namespace ); err != nil {
144+ types , err := s .listNs (namespace )
145+ if err != nil {
144146 return err
145- } else if ! empty {
146- return errors .Wrapf (errdefs .ErrFailedPrecondition , "namespace %q must be empty" , namespace )
147+ }
148+
149+ if len (types ) > 0 {
150+ return errors .Wrapf (
151+ errdefs .ErrFailedPrecondition ,
152+ "namespace %q must be empty, but it still has %s" ,
153+ namespace , strings .Join (types , ", " ),
154+ )
147155 }
148156
149157 if err := bkt .DeleteBucket ([]byte (namespace )); err != nil {
@@ -157,32 +165,35 @@ func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...n
157165 return nil
158166}
159167
160- func (s * namespaceStore ) namespaceEmpty (ctx context.Context , namespace string ) (bool , error ) {
161- // Get all data buckets
162- buckets := []* bolt.Bucket {
163- getImagesBucket (s .tx , namespace ),
164- getBlobsBucket (s .tx , namespace ),
165- getContainersBucket (s .tx , namespace ),
168+ // listNs returns the types of the remaining objects inside the given namespace.
169+ // It doesn't return exact objects due to performance concerns.
170+ func (s * namespaceStore ) listNs (namespace string ) ([]string , error ) {
171+ var out []string
172+
173+ if ! isBucketEmpty (getImagesBucket (s .tx , namespace )) {
174+ out = append (out , "images" )
175+ }
176+ if ! isBucketEmpty (getBlobsBucket (s .tx , namespace )) {
177+ out = append (out , "blobs" )
166178 }
179+ if ! isBucketEmpty (getContainersBucket (s .tx , namespace )) {
180+ out = append (out , "containers" )
181+ }
182+
167183 if snbkt := getSnapshottersBucket (s .tx , namespace ); snbkt != nil {
168184 if err := snbkt .ForEach (func (k , v []byte ) error {
169185 if v == nil {
170- buckets = append (buckets , snbkt .Bucket (k ))
186+ if ! isBucketEmpty (snbkt .Bucket (k )) {
187+ out = append (out , "snapshot-" + string (k ))
188+ }
171189 }
172190 return nil
173191 }); err != nil {
174- return false , err
175- }
176- }
177-
178- // Ensure data buckets are empty
179- for _ , bkt := range buckets {
180- if ! isBucketEmpty (bkt ) {
181- return false , nil
192+ return nil , err
182193 }
183194 }
184195
185- return true , nil
196+ return out , nil
186197}
187198
188199func isBucketEmpty (bkt * bolt.Bucket ) bool {
0 commit comments