196 lines
7.0 KiB
Go
196 lines
7.0 KiB
Go
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package metadata
|
|
|
|
import (
|
|
"github.com/boltdb/bolt"
|
|
digest "github.com/opencontainers/go-digest"
|
|
)
|
|
|
|
// The layout where a "/" delineates a bucket is desribed in the following
|
|
// section. Please try to follow this as closely as possible when adding
|
|
// functionality. We can bolster this with helpers and more structure if that
|
|
// becomes an issue.
|
|
//
|
|
// Generically, we try to do the following:
|
|
//
|
|
// <version>/<namespace>/<object>/<key> -> <field>
|
|
//
|
|
// version: Currently, this is "v1". Additions can be made to v1 in a backwards
|
|
// compatible way. If the layout changes, a new version must be made, along
|
|
// with a migration.
|
|
//
|
|
// namespace: the namespace to which this object belongs.
|
|
//
|
|
// object: defines which object set is stored in the bucket. There are two
|
|
// special objects, "labels" and "indexes". The "labels" bucket stores the
|
|
// labels for the parent namespace. The "indexes" object is reserved for
|
|
// indexing objects, if we require in the future.
|
|
//
|
|
// key: object-specific key identifying the storage bucket for the objects
|
|
// contents.
|
|
var (
|
|
bucketKeyVersion = []byte(schemaVersion)
|
|
bucketKeyDBVersion = []byte("version") // stores the version of the schema
|
|
bucketKeyObjectLabels = []byte("labels") // stores the labels for a namespace.
|
|
bucketKeyObjectImages = []byte("images") // stores image objects
|
|
bucketKeyObjectContainers = []byte("containers") // stores container objects
|
|
bucketKeyObjectSnapshots = []byte("snapshots") // stores snapshot references
|
|
bucketKeyObjectContent = []byte("content") // stores content references
|
|
bucketKeyObjectBlob = []byte("blob") // stores content links
|
|
bucketKeyObjectIngests = []byte("ingests") // stores ingest objects
|
|
bucketKeyObjectLeases = []byte("leases") // stores leases
|
|
|
|
bucketKeyDigest = []byte("digest")
|
|
bucketKeyMediaType = []byte("mediatype")
|
|
bucketKeySize = []byte("size")
|
|
bucketKeyImage = []byte("image")
|
|
bucketKeyRuntime = []byte("runtime")
|
|
bucketKeyName = []byte("name")
|
|
bucketKeyParent = []byte("parent")
|
|
bucketKeyChildren = []byte("children")
|
|
bucketKeyOptions = []byte("options")
|
|
bucketKeySpec = []byte("spec")
|
|
bucketKeySnapshotKey = []byte("snapshotKey")
|
|
bucketKeySnapshotter = []byte("snapshotter")
|
|
bucketKeyTarget = []byte("target")
|
|
bucketKeyExtensions = []byte("extensions")
|
|
bucketKeyCreatedAt = []byte("createdat")
|
|
bucketKeyExpected = []byte("expected")
|
|
bucketKeyRef = []byte("ref")
|
|
|
|
deprecatedBucketKeyObjectIngest = []byte("ingest") // stores ingest links, deprecated in v1.2
|
|
)
|
|
|
|
func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
|
|
bkt := tx.Bucket(keys[0])
|
|
|
|
for _, key := range keys[1:] {
|
|
if bkt == nil {
|
|
break
|
|
}
|
|
bkt = bkt.Bucket(key)
|
|
}
|
|
|
|
return bkt
|
|
}
|
|
|
|
func createBucketIfNotExists(tx *bolt.Tx, keys ...[]byte) (*bolt.Bucket, error) {
|
|
bkt, err := tx.CreateBucketIfNotExists(keys[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, key := range keys[1:] {
|
|
bkt, err = bkt.CreateBucketIfNotExists(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return bkt, nil
|
|
}
|
|
|
|
func namespaceLabelsBucketPath(namespace string) [][]byte {
|
|
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectLabels}
|
|
}
|
|
|
|
func withNamespacesLabelsBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error {
|
|
bkt, err := createBucketIfNotExists(tx, namespaceLabelsBucketPath(namespace)...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return fn(bkt)
|
|
}
|
|
|
|
func getNamespaceLabelsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, namespaceLabelsBucketPath(namespace)...)
|
|
}
|
|
|
|
func imagesBucketPath(namespace string) [][]byte {
|
|
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectImages}
|
|
}
|
|
|
|
func createImagesBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
|
|
return createBucketIfNotExists(tx, imagesBucketPath(namespace)...)
|
|
}
|
|
|
|
func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, imagesBucketPath(namespace)...)
|
|
}
|
|
|
|
func createContainersBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
|
|
return createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
|
|
}
|
|
|
|
func getContainersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers)
|
|
}
|
|
|
|
func getContainerBucket(tx *bolt.Tx, namespace, id string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContainers, []byte(id))
|
|
}
|
|
|
|
func createSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) (*bolt.Bucket, error) {
|
|
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bkt, nil
|
|
}
|
|
|
|
func getSnapshottersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots)
|
|
}
|
|
|
|
func getSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter))
|
|
}
|
|
|
|
func createBlobBucket(tx *bolt.Tx, namespace string, dgst digest.Digest) (*bolt.Bucket, error) {
|
|
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(dgst.String()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bkt, nil
|
|
}
|
|
|
|
func getBlobsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob)
|
|
}
|
|
|
|
func getBlobBucket(tx *bolt.Tx, namespace string, dgst digest.Digest) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(dgst.String()))
|
|
}
|
|
|
|
func getIngestsBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests)
|
|
}
|
|
|
|
func createIngestBucket(tx *bolt.Tx, namespace, ref string) (*bolt.Bucket, error) {
|
|
bkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bkt, nil
|
|
}
|
|
|
|
func getIngestBucket(tx *bolt.Tx, namespace, ref string) *bolt.Bucket {
|
|
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(ref))
|
|
}
|