~blu/artemis

0b67f715e07255acd909008a03de1e0dab3bf519 — Bryant Conquest 1 year, 4 months ago 34176cf
move metrics to respective locations
2 files changed, 46 insertions(+), 25 deletions(-)

M cache/cache.go
M main.go
M cache/cache.go => cache/cache.go +43 -13
@@ 3,6 3,7 @@ package cache
import (
	"crypto/sha256"
	"errors"
	"expvar"
	"fmt"
	"log"
	"os"


@@ 32,7 33,14 @@ type CachedAsset struct {
	DiesAt      time.Time
}

var ErrNotEnoughSpace = errors.New("not enough space on disk")
var (
	ErrNotEnoughSpace = errors.New("not enough space on disk")

	cacheHits   = expvar.NewInt("counter_artemis_cache_hits")
	cacheErrors = expvar.NewInt("counter_artemis_cache_errors")
	cacheLoads  = expvar.NewInt("counter_artemis_cache_loads")
	fileDeaths  = expvar.NewMap("guage_artemis_file_deaths")
)

func NewCache() *Cache {
	return &Cache{


@@ 56,13 64,12 @@ func (c *Cache) WithFileClient(fc b2.Actions) *Cache {
	return c
}

func (c Cache) PurgeCache(pattern string) error {
func (c *Cache) PurgeCache(pattern string) error {
	r := regexp.MustCompile(pattern)
	c.Files.Range(func(key any, value any) bool {
		f := value.(CachedAsset)
		if r.MatchString(f.Name) {
			err := os.Remove(filepath.Join(c.CacheDirectory, f.PathHash))
			if err != nil {
		a := value.(CachedAsset)
		if r.MatchString(a.Name) {
			if err := c.removeAsset(&a); err != nil {
				log.Println(err)
			}
		}


@@ 72,19 79,37 @@ func (c Cache) PurgeCache(pattern string) error {
	return nil
}

func (c *Cache) LoadOrReadAsset(path string) ([]byte, error, bool) {
func (c *Cache) DeathRunner() {
	for range time.Tick(30 * time.Minute) {
		c.Files.Range(func(key any, value any) bool {
			a := value.(CachedAsset)
			if a.DiesAt.Before(time.Now()) {
				c.removeAsset(&a)
			}
			return true
		})
	}
}

func (c *Cache) LoadOrReadAsset(path string) ([]byte, error) {
	hash := hashPath(path)
	data, err := c.readAsset(hash)
	if err == nil {
		if r, ok := c.Files.Load(hash); ok {
			if (r.(CachedAsset)).DiesAt.After(time.Now()) {
				return data, err, true
				cacheHits.Add(1)
				return data, err
			}
		}
	}

	data, err = c.downloadAsset(path)
	return data, err, false
	if err != nil {
		cacheErrors.Add(1)
	} else {
		cacheLoads.Add(1)
	}
	return data, err
}

func (c *Cache) readAsset(hash string) ([]byte, error) {


@@ 121,7 146,7 @@ func (c *Cache) freeCache(toFreeSpace uint64) error {

	for _, a := range toFree {
		log.Println(filepath.Join(c.CacheDirectory, a.PathHash))
		if err := os.Remove(filepath.Join(c.CacheDirectory, a.PathHash)); err != nil {
		if err := c.removeAsset(&a); err != nil {
			log.Println(err)
		}
		c.Files.Delete(a.ContentHash)


@@ 147,7 172,7 @@ func isSpaceAvailable(path string, fileSize uint64) (bool, error) {
	return as >= fileSize, nil
}

func (c Cache) downloadAsset(path string) ([]byte, error) {
func (c *Cache) downloadAsset(path string) ([]byte, error) {
	data, err := c.FileClient.Download(path)
	if err != nil {
		return nil, err


@@ 185,12 210,17 @@ func (c Cache) downloadAsset(path string) ([]byte, error) {
	return data, nil
}

func (c Cache) writeAsset(hash string, data []byte) error {
func (c *Cache) writeAsset(hash string, data []byte) error {
	path := filepath.Join(c.CacheDirectory, hash)

	return os.WriteFile(path, data, 0o644)
}

func (c *Cache) removeAsset(a *CachedAsset) error {
	path := filepath.Join(c.CacheDirectory, a.PathHash)
	fileDeaths.Add(a.PathHash, 1)
	return os.Remove(path)
}

func HashContent(data []byte) string {
	return fmt.Sprintf("%x", sha256.Sum256(data))
}

M main.go => main.go +3 -12
@@ 17,10 17,6 @@ import (
)

var (
	cacheHits   = expvar.NewInt("counter_artemis_cache_hits")
	cacheErrors = expvar.NewInt("counter_artemis_cache_errors")
	cacheLoads  = expvar.NewInt("counter_artemis_cache_loads")

	referers  = expvar.NewMap("guage_artemis_refers")
	assetHits = expvar.NewMap("guage_artemis_asset_hits")
)


@@ 78,20 74,13 @@ func AssetHandler(h *Handler) http.Handler {
			return
		}

		data, err, hit := h.Cache.LoadOrReadAsset(path)
		data, err := h.Cache.LoadOrReadAsset(path)
		if err != nil {
			log.Println(err)
			cacheErrors.Add(1)
			w.WriteHeader(http.StatusNotFound)
			return
		}

		if hit {
			cacheHits.Add(1)
		} else {
			cacheLoads.Add(1)
		}

		// Does not ever get invalidated
		// should etags be handled by the cache?
		etag = fmt.Sprintf("%x", sha256.Sum256(data))


@@ 152,6 141,8 @@ func main() {
		etags:    make(map[string]bool),
	}

	go cache.DeathRunner()

	mux := http.NewServeMux()
	mux.Handle("/assets/", Metrics(Logger(AssetHandler(&h))))
	mux.Handle("/purge", Metrics(Logger(Purge(&h))))