buildkit/cache/metadata.go

563 lines
12 KiB
Go

package cache
import (
"time"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/client"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt"
)
const sizeUnknown int64 = -1
const keySize = "snapshot.size"
const keyEqualMutable = "cache.equalMutable"
const keyCachePolicy = "cache.cachePolicy"
const keyDescription = "cache.description"
const keyCreatedAt = "cache.createdAt"
const keyLastUsedAt = "cache.lastUsedAt"
const keyUsageCount = "cache.usageCount"
const keyLayerType = "cache.layerType"
const keyRecordType = "cache.recordType"
const keyCommitted = "snapshot.committed"
const keyParent = "cache.parent"
const keyDiffID = "cache.diffID"
const keyChainID = "cache.chainID"
const keyBlobChainID = "cache.blobChainID"
const keyBlob = "cache.blob"
const keySnapshot = "cache.snapshot"
const keyBlobOnly = "cache.blobonly"
const keyMediaType = "cache.mediatype"
const keyImageRefs = "cache.imageRefs"
// BlobSize is the packed blob size as specified in the oci descriptor
const keyBlobSize = "cache.blobsize"
const keyDeleted = "cache.deleted"
func queueDiffID(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create diffID value")
}
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyDiffID, v)
})
return nil
}
func getMediaType(si *metadata.StorageItem) string {
v := si.Get(keyMediaType)
if v == nil {
return si.ID()
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueMediaType(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create mediaType value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyMediaType, v)
})
return nil
}
func getSnapshotID(si *metadata.StorageItem) string {
v := si.Get(keySnapshot)
if v == nil {
return si.ID()
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueSnapshotID(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create chainID value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keySnapshot, v)
})
return nil
}
func getDiffID(si *metadata.StorageItem) string {
v := si.Get(keyDiffID)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueChainID(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create chainID value")
}
v.Index = "chainid:" + str
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyChainID, v)
})
return nil
}
func getBlobChainID(si *metadata.StorageItem) string {
v := si.Get(keyBlobChainID)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueBlobChainID(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create chainID value")
}
v.Index = "blobchainid:" + str
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyBlobChainID, v)
})
return nil
}
func getChainID(si *metadata.StorageItem) string {
v := si.Get(keyChainID)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueBlob(si *metadata.StorageItem, str string) error {
if str == "" {
return nil
}
v, err := metadata.NewValue(str)
if err != nil {
return errors.Wrap(err, "failed to create blob value")
}
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyBlob, v)
})
return nil
}
func getBlob(si *metadata.StorageItem) string {
v := si.Get(keyBlob)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueBlobOnly(si *metadata.StorageItem, b bool) error {
v, err := metadata.NewValue(b)
if err != nil {
return errors.Wrap(err, "failed to create blobonly value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyBlobOnly, v)
})
return nil
}
func getBlobOnly(si *metadata.StorageItem) bool {
v := si.Get(keyBlobOnly)
if v == nil {
return false
}
var blobOnly bool
if err := v.Unmarshal(&blobOnly); err != nil {
return false
}
return blobOnly
}
func setDeleted(si *metadata.StorageItem) error {
v, err := metadata.NewValue(true)
if err != nil {
return errors.Wrap(err, "failed to create deleted value")
}
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyDeleted, v)
})
return nil
}
func getDeleted(si *metadata.StorageItem) bool {
v := si.Get(keyDeleted)
if v == nil {
return false
}
var deleted bool
if err := v.Unmarshal(&deleted); err != nil {
return false
}
return deleted
}
func queueCommitted(si *metadata.StorageItem) error {
v, err := metadata.NewValue(true)
if err != nil {
return errors.Wrap(err, "failed to create committed value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyCommitted, v)
})
return nil
}
func getCommitted(si *metadata.StorageItem) bool {
v := si.Get(keyCommitted)
if v == nil {
return false
}
var committed bool
if err := v.Unmarshal(&committed); err != nil {
return false
}
return committed
}
func queueParent(si *metadata.StorageItem, parent string) error {
if parent == "" {
return nil
}
v, err := metadata.NewValue(parent)
if err != nil {
return errors.Wrap(err, "failed to create parent value")
}
si.Update(func(b *bolt.Bucket) error {
return si.SetValue(b, keyParent, v)
})
return nil
}
func getParent(si *metadata.StorageItem) string {
v := si.Get(keyParent)
if v == nil {
return ""
}
var parent string
if err := v.Unmarshal(&parent); err != nil {
return ""
}
return parent
}
func setSize(si *metadata.StorageItem, s int64) error {
v, err := metadata.NewValue(s)
if err != nil {
return errors.Wrap(err, "failed to create size value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keySize, v)
})
return nil
}
func getSize(si *metadata.StorageItem) int64 {
v := si.Get(keySize)
if v == nil {
return sizeUnknown
}
var size int64
if err := v.Unmarshal(&size); err != nil {
return sizeUnknown
}
return size
}
func appendImageRef(si *metadata.StorageItem, s string) error {
return si.GetAndSetValue(keyImageRefs, func(v *metadata.Value) (*metadata.Value, error) {
var imageRefs []string
if v != nil {
if err := v.Unmarshal(&imageRefs); err != nil {
return nil, err
}
}
for _, existing := range imageRefs {
if existing == s {
return nil, metadata.ErrSkipSetValue
}
}
imageRefs = append(imageRefs, s)
v, err := metadata.NewValue(imageRefs)
if err != nil {
return nil, errors.Wrap(err, "failed to create imageRefs value")
}
return v, nil
})
}
func getImageRefs(si *metadata.StorageItem) []string {
v := si.Get(keyImageRefs)
if v == nil {
return nil
}
var refs []string
if err := v.Unmarshal(&refs); err != nil {
return nil
}
return refs
}
func queueBlobSize(si *metadata.StorageItem, s int64) error {
v, err := metadata.NewValue(s)
if err != nil {
return errors.Wrap(err, "failed to create blobsize value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyBlobSize, v)
})
return nil
}
func getBlobSize(si *metadata.StorageItem) int64 {
v := si.Get(keyBlobSize)
if v == nil {
return sizeUnknown
}
var size int64
if err := v.Unmarshal(&size); err != nil {
return sizeUnknown
}
return size
}
func getEqualMutable(si *metadata.StorageItem) string {
v := si.Get(keyEqualMutable)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func setEqualMutable(si *metadata.StorageItem, s string) error {
v, err := metadata.NewValue(s)
if err != nil {
return errors.Wrapf(err, "failed to create %s meta value", keyEqualMutable)
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyEqualMutable, v)
})
return nil
}
func clearEqualMutable(si *metadata.StorageItem) error {
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyEqualMutable, nil)
})
return nil
}
func queueCachePolicy(si *metadata.StorageItem, p cachePolicy) error {
v, err := metadata.NewValue(p)
if err != nil {
return errors.Wrap(err, "failed to create cachePolicy value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyCachePolicy, v)
})
return nil
}
func getCachePolicy(si *metadata.StorageItem) cachePolicy {
v := si.Get(keyCachePolicy)
if v == nil {
return cachePolicyDefault
}
var p cachePolicy
if err := v.Unmarshal(&p); err != nil {
return cachePolicyDefault
}
return p
}
func queueDescription(si *metadata.StorageItem, descr string) error {
v, err := metadata.NewValue(descr)
if err != nil {
return errors.Wrap(err, "failed to create description value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyDescription, v)
})
return nil
}
func GetDescription(si *metadata.StorageItem) string {
v := si.Get(keyDescription)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func queueCreatedAt(si *metadata.StorageItem, tm time.Time) error {
v, err := metadata.NewValue(tm.UnixNano())
if err != nil {
return errors.Wrap(err, "failed to create createdAt value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyCreatedAt, v)
})
return nil
}
func GetCreatedAt(si *metadata.StorageItem) time.Time {
v := si.Get(keyCreatedAt)
if v == nil {
return time.Time{}
}
var tm int64
if err := v.Unmarshal(&tm); err != nil {
return time.Time{}
}
return time.Unix(tm/1e9, tm%1e9)
}
func getLastUsed(si *metadata.StorageItem) (int, *time.Time) {
v := si.Get(keyUsageCount)
if v == nil {
return 0, nil
}
var usageCount int
if err := v.Unmarshal(&usageCount); err != nil {
return 0, nil
}
v = si.Get(keyLastUsedAt)
if v == nil {
return usageCount, nil
}
var lastUsedTs int64
if err := v.Unmarshal(&lastUsedTs); err != nil || lastUsedTs == 0 {
return usageCount, nil
}
tm := time.Unix(lastUsedTs/1e9, lastUsedTs%1e9)
return usageCount, &tm
}
func updateLastUsed(si *metadata.StorageItem) error {
count, _ := getLastUsed(si)
count++
v, err := metadata.NewValue(count)
if err != nil {
return errors.Wrap(err, "failed to create usageCount value")
}
v2, err := metadata.NewValue(time.Now().UnixNano())
if err != nil {
return errors.Wrap(err, "failed to create lastUsedAt value")
}
return si.Update(func(b *bolt.Bucket) error {
if err := si.SetValue(b, keyUsageCount, v); err != nil {
return err
}
return si.SetValue(b, keyLastUsedAt, v2)
})
}
func SetLayerType(m withMetadata, value string) error {
v, err := metadata.NewValue(value)
if err != nil {
return errors.Wrap(err, "failed to create layertype value")
}
m.Metadata().Queue(func(b *bolt.Bucket) error {
return m.Metadata().SetValue(b, keyLayerType, v)
})
return m.Metadata().Commit()
}
func GetLayerType(m withMetadata) string {
v := m.Metadata().Get(keyLayerType)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return str
}
func GetRecordType(m withMetadata) client.UsageRecordType {
v := m.Metadata().Get(keyRecordType)
if v == nil {
return ""
}
var str string
if err := v.Unmarshal(&str); err != nil {
return ""
}
return client.UsageRecordType(str)
}
func SetRecordType(m withMetadata, value client.UsageRecordType) error {
if err := queueRecordType(m.Metadata(), value); err != nil {
return err
}
return m.Metadata().Commit()
}
func queueRecordType(si *metadata.StorageItem, value client.UsageRecordType) error {
v, err := metadata.NewValue(value)
if err != nil {
return errors.Wrap(err, "failed to create recordtype value")
}
si.Queue(func(b *bolt.Bucket) error {
return si.SetValue(b, keyRecordType, v)
})
return nil
}