563 lines
12 KiB
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
|
|
}
|