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 keyDeleted = "cache.deleted" func setDeleted(si *metadata.StorageItem) error { v, err := metadata.NewValue(true) if err != nil { return errors.Wrap(err, "failed to create size 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 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 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 }