| 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 |
| } |