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 }