github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/metadata/buckets.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 stores all labels and object specific metadata by namespace.
    18  // This package also contains the main garbage collection logic  for cleaning up
    19  // resources consistently and atomically. Resources used by backends will be
    20  // tracked in the metadata store to be exposed to consumers of this package.
    21  //
    22  // The layout where a "/" delineates a bucket is described in the following
    23  // section. Please try to follow this as closely as possible when adding
    24  // functionality. We can bolster this with helpers and more structure if that
    25  // becomes an issue.
    26  //
    27  // Generically, we try to do the following:
    28  //
    29  // 	<version>/<namespace>/<object>/<key> -> <field>
    30  //
    31  // version: Currently, this is "v1". Additions can be made to v1 in a backwards
    32  // compatible way. If the layout changes, a new version must be made, along
    33  // with a migration.
    34  //
    35  // namespace: the namespace to which this object belongs.
    36  //
    37  // object: defines which object set is stored in the bucket. There are two
    38  // special objects, "labels" and "indexes". The "labels" bucket stores the
    39  // labels for the parent namespace. The "indexes" object is reserved for
    40  // indexing objects, if we require in the future.
    41  //
    42  // key: object-specific key identifying the storage bucket for the objects
    43  // contents.
    44  //
    45  // Below is the current database schema. This should be updated each time
    46  // the structure is changed in addition to adding a migration and incrementing
    47  // the database version. Note that `╘══*...*` refers to maps with arbitrary
    48  // keys.
    49  //  ├──version : <varint>                        - Latest version, see migrations
    50  //  └──v1                                        - Schema version bucket
    51  //     ╘══*namespace*
    52  //        ├──labels
    53  //        │  ╘══*key* : <string>                 - Label value
    54  //        ├──image
    55  //        │  ╘══*image name*
    56  //        │     ├──createdat : <binary time>     - Created at
    57  //        │     ├──updatedat : <binary time>     - Updated at
    58  //        │     ├──target
    59  //        │     │  ├──digest : <digest>          - Descriptor digest
    60  //        │     │  ├──mediatype : <string>       - Descriptor media type
    61  //        │     │  └──size : <varint>            - Descriptor size
    62  //        │     └──labels
    63  //        │        ╘══*key* : <string>           - Label value
    64  //        ├──containers
    65  //        │  ╘══*container id*
    66  //        │     ├──createdat : <binary time>     - Created at
    67  //        │     ├──updatedat : <binary time>     - Updated at
    68  //        │     ├──spec : <binary>               - Proto marshaled spec
    69  //        │     ├──image : <string>              - Image name
    70  //        │     ├──snapshotter : <string>        - Snapshotter name
    71  //        │     ├──snapshotKey : <string>        - Snapshot key
    72  //        │     ├──runtime
    73  //        │     │  ├──name : <string>            - Runtime name
    74  //        │     │  ├──extensions
    75  //        │     │  │  ╘══*name* : <binary>       - Proto marshaled extension
    76  //        │     │  └──options : <binary>         - Proto marshaled options
    77  //        │     └──labels
    78  //        │        ╘══*key* : <string>           - Label value
    79  //        ├──snapshots
    80  //        │  ╘══*snapshotter*
    81  //        │     ╘══*snapshot key*
    82  //        │        ├──name : <string>            - Snapshot name in backend
    83  //        │        ├──createdat : <binary time>  - Created at
    84  //        │        ├──updatedat : <binary time>  - Updated at
    85  //        │        ├──parent : <string>          - Parent snapshot name
    86  //        │        ├──children
    87  //        │        │  ╘══*snapshot key* : <nil>  - Child snapshot reference
    88  //        │        └──labels
    89  //        │           ╘══*key* : <string>        - Label value
    90  //        ├──content
    91  //        │  ├──blob
    92  //        │  │  ╘══*blob digest*
    93  //        │  │     ├──createdat : <binary time>  - Created at
    94  //        │  │     ├──updatedat : <binary time>  - Updated at
    95  //        │  │     ├──size : <varint>            - Blob size
    96  //        │  │     └──labels
    97  //        │  │        ╘══*key* : <string>        - Label value
    98  //        │  └──ingests
    99  //        │     ╘══*ingest reference*
   100  //        │        ├──ref : <string>             - Ingest reference in backend
   101  //        │        ├──expireat : <binary time>   - Time to expire ingest
   102  //        │        └──expected : <digest>        - Expected commit digest
   103  //        └──leases
   104  //           ╘══*lease id*
   105  //              ├──createdat : <binary time>     - Created at
   106  //              ├──labels
   107  //              │  ╘══*key* : <string>           - Label value
   108  //              ├──snapshots
   109  //              │  ╘══*snapshotter*
   110  //              │     ╘══*snapshot key* : <nil>  - Snapshot reference
   111  //              ├──content
   112  //              │  ╘══*blob digest* : <nil>      - Content blob reference
   113  //              └──ingests
   114  //                 ╘══*ingest reference* : <nil> - Content ingest reference
   115  package metadata
   116  
   117  import (
   118  	digest "github.com/opencontainers/go-digest"
   119  	bolt "go.etcd.io/bbolt"
   120  )
   121  
   122  var (
   123  	bucketKeyVersion          = []byte(schemaVersion)
   124  	bucketKeyDBVersion        = []byte("version")    // stores the version of the schema
   125  	bucketKeyObjectLabels     = []byte("labels")     // stores the labels for a namespace.
   126  	bucketKeyObjectImages     = []byte("images")     // stores image objects
   127  	bucketKeyObjectContainers = []byte("containers") // stores container objects
   128  	bucketKeyObjectSnapshots  = []byte("snapshots")  // stores snapshot references
   129  	bucketKeyObjectContent    = []byte("content")    // stores content references
   130  	bucketKeyObjectBlob       = []byte("blob")       // stores content links
   131  	bucketKeyObjectIngests    = []byte("ingests")    // stores ingest objects
   132  	bucketKeyObjectLeases     = []byte("leases")     // stores leases
   133  
   134  	bucketKeyDigest      = []byte("digest")
   135  	bucketKeyMediaType   = []byte("mediatype")
   136  	bucketKeySize        = []byte("size")
   137  	bucketKeyImage       = []byte("image")
   138  	bucketKeyRuntime     = []byte("runtime")
   139  	bucketKeyName        = []byte("name")
   140  	bucketKeyParent      = []byte("parent")
   141  	bucketKeyChildren    = []byte("children")
   142  	bucketKeyOptions     = []byte("options")
   143  	bucketKeySpec        = []byte("spec")
   144  	bucketKeySnapshotKey = []byte("snapshotKey")
   145  	bucketKeySnapshotter = []byte("snapshotter")
   146  	bucketKeyTarget      = []byte("target")
   147  	bucketKeyExtensions  = []byte("extensions")
   148  	bucketKeyCreatedAt   = []byte("createdat")
   149  	bucketKeyExpected    = []byte("expected")
   150  	bucketKeyRef         = []byte("ref")
   151  	bucketKeyExpireAt    = []byte("expireat")
   152  
   153  	deprecatedBucketKeyObjectIngest = []byte("ingest") // stores ingest links, deprecated in v1.2
   154  )
   155  
   156  func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
   157  	bkt := tx.Bucket(keys[0])
   158  
   159  	for _, key := range keys[1:] {
   160  		if bkt == nil {
   161  			break
   162  		}
   163  		bkt = bkt.Bucket(key)
   164  	}
   165  
   166  	return bkt
   167  }
   168  
   169  func createBucketIfNotExists(tx *bolt.Tx, keys ...[]byte) (*bolt.Bucket, error) {
   170  	bkt, err := tx.CreateBucketIfNotExists(keys[0])
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	for _, key := range keys[1:] {
   176  		bkt, err = bkt.CreateBucketIfNotExists(key)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  	}
   181  
   182  	return bkt, nil
   183  }
   184  
   185  func namespaceLabelsBucketPath(namespace string) [][]byte {
   186  	return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectLabels}
   187  }
   188  
   189  func withNamespacesLabelsBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error {
   190  	bkt, err := createBucketIfNotExists(tx, namespaceLabelsBucketPath(namespace)...)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	return fn(bkt)
   196  }
   197  
   198  func getNamespaceLabelsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   199  	return getBucket(tx, namespaceLabelsBucketPath(namespace)...)
   200  }
   201  
   202  func imagesBucketPath(namespace string) [][]byte {
   203  	return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectImages}
   204  }
   205  
   206  func createImagesBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
   207  	return createBucketIfNotExists(tx, imagesBucketPath(namespace)...)
   208  }
   209  
   210  func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   211  	return getBucket(tx, imagesBucketPath(namespace)...)
   212  }
   213  
   214  func createContainersBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
   215  	return createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
   216  }
   217  
   218  func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   219  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
   220  }
   221  
   222  func getContainerBucket(tx *bolt.Tx, namespace, id string) *bolt.Bucket {
   223  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers, []byte(id))
   224  }
   225  
   226  func createSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) (*bolt.Bucket, error) {
   227  	bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter))
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	return bkt, nil
   232  }
   233  
   234  func getSnapshottersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   235  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots)
   236  }
   237  
   238  func getSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) *bolt.Bucket {
   239  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter))
   240  }
   241  
   242  func createBlobBucket(tx *bolt.Tx, namespace string, dgst digest.Digest) (*bolt.Bucket, error) {
   243  	bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	return bkt.CreateBucket([]byte(dgst.String()))
   248  }
   249  
   250  func getBlobsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   251  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob)
   252  }
   253  
   254  func getBlobBucket(tx *bolt.Tx, namespace string, dgst digest.Digest) *bolt.Bucket {
   255  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(dgst.String()))
   256  }
   257  
   258  func getIngestsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
   259  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests)
   260  }
   261  
   262  func createIngestBucket(tx *bolt.Tx, namespace, ref string) (*bolt.Bucket, error) {
   263  	bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	return bkt, nil
   268  }
   269  
   270  func getIngestBucket(tx *bolt.Tx, namespace, ref string) *bolt.Bucket {
   271  	return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
   272  }