mirror of
https://github.com/project-zot/zot.git
synced 2024-12-23 22:27:35 -05:00
af77876306
Go version changed to 1.14.4 Golangci-lint changed to 1.26.0 Bazel version changed to 3.0.0 Bazel rules_go version changed to 0.23.3 Bazel gazelle version changed to v0.21.0 Bazel build tools version changed to 0.25.1 Bazel skylib version changed to 1.0.2
188 lines
4.2 KiB
Go
188 lines
4.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/anuvu/zot/errors"
|
|
zlog "github.com/anuvu/zot/pkg/log"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
const (
|
|
BlobsCache = "blobs"
|
|
)
|
|
|
|
type Cache struct {
|
|
rootDir string
|
|
db *bbolt.DB
|
|
log zlog.Logger
|
|
}
|
|
|
|
// Blob is a blob record.
|
|
type Blob struct {
|
|
Path string
|
|
}
|
|
|
|
func NewCache(rootDir string, name string, log zlog.Logger) *Cache {
|
|
dbPath := path.Join(rootDir, name+".db")
|
|
db, err := bbolt.Open(dbPath, 0600, nil)
|
|
|
|
if err != nil {
|
|
log.Error().Err(err).Str("dbPath", dbPath).Msg("unable to create cache db")
|
|
return nil
|
|
}
|
|
|
|
if err := db.Update(func(tx *bbolt.Tx) error {
|
|
if _, err := tx.CreateBucketIfNotExists([]byte(BlobsCache)); err != nil {
|
|
// this is a serious failure
|
|
log.Error().Err(err).Str("dbPath", dbPath).Msg("unable to create a root bucket")
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
// something went wrong
|
|
log.Error().Err(err).Msg("unable to create a cache")
|
|
return nil
|
|
}
|
|
|
|
return &Cache{rootDir: rootDir, db: db, log: log}
|
|
}
|
|
|
|
func (c *Cache) PutBlob(digest string, path string) error {
|
|
// use only relative (to rootDir) paths on blobs
|
|
relp, err := filepath.Rel(c.rootDir, path)
|
|
if err != nil {
|
|
c.log.Error().Err(err).Str("path", path).Msg("unable to get relative path")
|
|
}
|
|
|
|
if err := c.db.Update(func(tx *bbolt.Tx) error {
|
|
root := tx.Bucket([]byte(BlobsCache))
|
|
if root == nil {
|
|
// this is a serious failure
|
|
err := errors.ErrCacheRootBucket
|
|
c.log.Error().Err(err).Msg("unable to access root bucket")
|
|
return err
|
|
}
|
|
b, err := root.CreateBucketIfNotExists([]byte(digest))
|
|
if err != nil {
|
|
// this is a serious failure
|
|
c.log.Error().Err(err).Str("bucket", digest).Msg("unable to create a bucket")
|
|
return err
|
|
}
|
|
if err := b.Put([]byte(relp), nil); err != nil {
|
|
c.log.Error().Err(err).Str("bucket", digest).Str("value", relp).Msg("unable to put record")
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Cache) GetBlob(digest string) (string, error) {
|
|
var blobPath strings.Builder
|
|
|
|
if err := c.db.View(func(tx *bbolt.Tx) error {
|
|
root := tx.Bucket([]byte(BlobsCache))
|
|
if root == nil {
|
|
// this is a serious failure
|
|
err := errors.ErrCacheRootBucket
|
|
c.log.Error().Err(err).Msg("unable to access root bucket")
|
|
return err
|
|
}
|
|
|
|
b := root.Bucket([]byte(digest))
|
|
if b != nil {
|
|
// get first key
|
|
c := b.Cursor()
|
|
k, _ := c.First()
|
|
blobPath.WriteString(string(k))
|
|
return nil
|
|
}
|
|
|
|
return errors.ErrCacheMiss
|
|
}); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(blobPath.String()) == 0 {
|
|
return "", nil
|
|
}
|
|
|
|
return blobPath.String(), nil
|
|
}
|
|
|
|
func (c *Cache) HasBlob(digest string, blob string) bool {
|
|
if err := c.db.View(func(tx *bbolt.Tx) error {
|
|
root := tx.Bucket([]byte(BlobsCache))
|
|
if root == nil {
|
|
// this is a serious failure
|
|
err := errors.ErrCacheRootBucket
|
|
c.log.Error().Err(err).Msg("unable to access root bucket")
|
|
return err
|
|
}
|
|
|
|
b := root.Bucket([]byte(digest))
|
|
if b == nil {
|
|
return errors.ErrCacheMiss
|
|
}
|
|
if b.Get([]byte(blob)) == nil {
|
|
return errors.ErrCacheMiss
|
|
}
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (c *Cache) DeleteBlob(digest string, path string) error {
|
|
// use only relative (to rootDir) paths on blobs
|
|
relp, err := filepath.Rel(c.rootDir, path)
|
|
if err != nil {
|
|
c.log.Error().Err(err).Str("path", path).Msg("unable to get relative path")
|
|
}
|
|
|
|
if err := c.db.Update(func(tx *bbolt.Tx) error {
|
|
root := tx.Bucket([]byte(BlobsCache))
|
|
if root == nil {
|
|
// this is a serious failure
|
|
err := errors.ErrCacheRootBucket
|
|
c.log.Error().Err(err).Msg("unable to access root bucket")
|
|
return err
|
|
}
|
|
|
|
b := root.Bucket([]byte(digest))
|
|
if b == nil {
|
|
return errors.ErrCacheMiss
|
|
}
|
|
|
|
if err := b.Delete([]byte(relp)); err != nil {
|
|
c.log.Error().Err(err).Str("digest", digest).Str("path", relp).Msg("unable to delete")
|
|
return err
|
|
}
|
|
|
|
cur := b.Cursor()
|
|
k, _ := cur.First()
|
|
|
|
if k == nil {
|
|
c.log.Debug().Str("digest", digest).Str("path", relp).Msg("deleting empty bucket")
|
|
if err := root.DeleteBucket([]byte(digest)); err != nil {
|
|
c.log.Error().Err(err).Str("digest", digest).Str("path", relp).Msg("unable to delete")
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|